Exemplo n.º 1
0
void CChainComparer::DoSentenceComparison(short cStopChar)
{
	// decompose unmatched chunks..
	m_pAnchor1->DecomposeSentences(cStopChar);
	m_pAnchor2->DecomposeSentences(cStopChar);
	
	m_Binder.ExpandBridges(m_pAnchor1, m_pAnchor2);
	
	// repeat binding procedure..
	// Now we're working essentially a word at a time, so we want to favour local matches rather
	// than those a zillion miles across the document, so we local bind first.
	m_Binder.LocalBind(m_pAnchor1, Binder::eDefault);
	CheckCancel();
	// however, we need to global bind too, otherwise you'd never spot moves that also changed 
	// slightly
	m_Binder.GlobalBind(m_pAnchor1, m_pAnchor2);
	CheckCancel();
	
	m_Binder.LocalBind(m_pAnchor1, Binder::eDefault);
	CheckCancel();
	
	VerifyListBridgesOnBothChains();
	
	// and identify any moves that we've found
	m_pAnchor2->FindMoves(m_pAnchor1);
}
void Unreal3DExport::WriteModel()
{
    // Progress
        pInt->ProgressUpdate(Progress, FALSE, GetString(IDS_INFO_WRITE));

        // Open data file
        fMesh = _tfopen(ModelFileName,_T("wb"));
        if( !fMesh ) 
        {
            ProgressMsg.printf(GetString(IDS_ERR_FMODEL),ModelFileName);
            throw MAXException(ProgressMsg.data());
        }

        // Open anim file
        fAnim = _tfopen(AnimFileName,_T("wb"));
        if( !fAnim )
        {
            ProgressMsg.printf(GetString(IDS_ERR_FANIM),AnimFileName);
            throw MAXException(ProgressMsg.data());
        }
        
        // data headers
        hData.NumPolys = Tris.Count();
        hData.NumVertices = VertsPerFrame;

        // anim headers
        hAnim.FrameSize = VertsPerFrame * sizeof(FMeshVert); 
        hAnim.NumFrames = FrameCount;


        // Progress
        CheckCancel();
        pInt->ProgressUpdate(Progress, FALSE, GetString(IDS_INFO_WMESH));
        

        // Write data
        fwrite(&hData,sizeof(FJSDataHeader),1,fMesh);
        if( Tris.Count() > 0 )
        {
            fwrite(Tris.Addr(0),sizeof(FJSMeshTri),Tris.Count(),fMesh);
        }
        Progress += U3D_PROGRESS_WMESH;

        // Progress
        CheckCancel();
        pInt->ProgressUpdate(Progress, FALSE, GetString(IDS_INFO_WANIM));

        // Write anim
        fwrite(&hAnim,sizeof(FJSAnivHeader),1,fAnim);
        if( Verts.Count() > 0 )
        {
            fwrite(Verts.Addr(0),sizeof(FMeshVert),Verts.Count(),fAnim);
        }
        Progress += U3D_PROGRESS_WANIM;
}
Exemplo n.º 3
0
void CChainComparer::GlobalThenLocalBind()
{
	// perform first stage binding on max length chunks..
	// these chunks are as read in from the RTF, merged if font characteristics are
	// insignificantly different (to avoid problems with \hich\loch\dbch part words)

	m_Binder.GlobalBind(m_pAnchor1, m_pAnchor2);
	CheckCancel();
	m_Binder.LocalBind(m_pAnchor1, Binder::eDefault); 
	CheckCancel();

	DUMP_CHAIN(DBG_AFTER_LOCAL_GLOBAL_1, "After first global/local binding pair");
}
void Unreal3DExport::GetAnim()
{
    
    // Export vertex animation
    int lastvert = 0;
    FMeshVert nullvert = FMeshVert();
    Points.SetCount(VertsPerFrame*FrameCount,TRUE);
    for( int t=0; t<FrameCount; ++t )
    {            
        // Progress
        CheckCancel();
        ProgressMsg.printf(GetString(IDS_INFO_ANIM),t+1,FrameCount);
        pInt->ProgressUpdate(Progress+((float)t/FrameCount*U3D_PROGRESS_ANIM), FALSE, ProgressMsg.data());
        
        // Set frame
        int frameverts = 0;
        int curframe = FrameStart + t;
        pScene->SetStaticFrame(curframe);
        
        // Write mesh verts
        for( int n=0; n<Nodes.Count(); ++n )
        {
            CheckCancel();

            IGameMesh * mesh = (IGameMesh*)Nodes[n]->GetIGameObject();          
            if( mesh->InitializeData() )
            {
                int vertcount = mesh->GetNumberOfVerts();
                for( int i=0; i<vertcount; ++i )
                {
                    Point3 p;
                    if( mesh->GetVertex(i,p) )
                    {
                        Points[lastvert++] = p;
                    }
                }
                frameverts += vertcount;
            }
            Nodes[n]->ReleaseIGameObject();
        }

        // Check number of verts in this frame
        if( frameverts != VertsPerFrame )
        {
            ProgressMsg.printf(GetString(IDS_ERR_NOVERTS),curframe,frameverts,VertsPerFrame);
            throw MAXException(ProgressMsg.data());
        }
    }
    Progress += U3D_PROGRESS_ANIM;

}
Exemplo n.º 5
0
void CChainComparer::LocalThenGlobalBind()
{
	// repeat binding procedure..
	// Now we're working essentially a word at a time, so we want to favour local matches rather
	// than those a zillion miles across the document, so we local bind first.
	
	m_Binder.LocalBind(m_pAnchor1, Binder::eDefault);
	CheckCancel();
	// however, we need to global bind too, otherwise you'd never spot moves that also changed 
	// slightly
	m_Binder.GlobalBind(m_pAnchor1, m_pAnchor2);
	CheckCancel();


	DUMP_CHAIN(DBG_AFTER_GLOBAL_LOCAL_2, "After second local / global pair");
}
void Unreal3DExport::WriteTracking()
{
    Tab<Point3> Loc;
    Tab<Quat> Quat;
    Tab<Point3> Euler;

    Loc.SetCount(FrameCount);
    Quat.SetCount(FrameCount);
    Euler.SetCount(FrameCount);

    for( int n=0; n<TrackedNodes.Count(); ++n )
    {
        IGameNode* node = TrackedNodes[n];

        for( int t=0; t<FrameCount; ++t )
        {            
            // Progress
            CheckCancel();
            
            // Set frame
            int curframe = FrameStart + t;
            pScene->SetStaticFrame(curframe);

            // Write tracking
            GMatrix objTM = node->GetWorldTM();
            Loc[t] = objTM.Translation();
            Quat[t] = objTM.Rotation();

            float eu[3];
            QuatToEuler(Quat[t],eu);
            Euler[t]=Point3(eu[0],eu[1],eu[2]);
            Euler[t] *= 180.0f/pi;

            eu[1] *= -1;
            EulerToQuat(eu,Quat[t],EULERTYPE_YXZ);
        }
        
        for( int t=0; t<FrameCount; ++t )
        {    
            _ftprintf( fLog, _T("%sLoc[%d]=(X=%f,Y=%f,Z=%f)\n"), node->GetName(), t, Loc[t].x, Loc[t].y, Loc[t].z );
        }
        
        for( int t=0; t<FrameCount; ++t )
        {    
            _ftprintf( fLog, _T("%sQuat[%d]=(W=%f,X=%f,Y=%f,Z=%f)\n"), node->GetName(), t, Quat[t].w, Quat[t].x, Quat[t].y, Quat[t].z ); 
        }
        
        for( int t=0; t<FrameCount; ++t )
        {    
            _ftprintf( fLog, _T("%sEuler[%d]=(X=%f,Y=%f,Z=%f)\n"), node->GetName(), t, Euler[t].x, Euler[t].y, Euler[t].z ); 
        }
    }
}
Exemplo n.º 7
0
void CChainComparer::DuplicateBindBySection(Binder::BindingMethod eMethod, DWORD dwChainDumpFlags)
{
	// now perform duplicate binding on these chunks, performing a local bind before each
	// duplicate bind.

	m_Binder.LocalBind(m_pAnchor1, eMethod);
	CheckCancel();

	ExpandBridges(false, DBG_AFTER_EXPAND_BRIDGE_1);
	m_Binder.DuplicateBindSectionBySection(m_pAnchor1, eMethod);

	// when no more matches can be made, proceed to next stage
}
void Unreal3DExport::ExportNode( IGameNode * child )
{
    DebugPrint( _T("ExportNode: %s\n"), child->GetName() );
    CheckCancel();

    ProgressMsg.printf(GetString(IDS_INFO_ENUM_OBJ),NodeIdx,NodeCount,TSTR(child->GetName()));
    pInt->ProgressUpdate(Progress+((float)NodeIdx/NodeCount*U3D_PROGRESS_ENUM), FALSE, ProgressMsg.data());
    ++NodeIdx;
    
    if( child->IsGroupOwner() )
    {
        // do nothing
    }
    else
    {
        IGameObject * obj = child->GetIGameObject();

        switch(obj->GetIGameType())
        {
            case IGameObject::IGAME_MESH:
            { 
                if( !bIgnoreHidden || !child->IsNodeHidden() )
                {
                    Nodes.Append(1,&child);
                }
                break;
            }
			case IGameObject::IGAME_HELPER:
            {
                if( !bIgnoreHidden || !child->IsNodeHidden() )
                {
                    TrackedNodes.Append(1,&child);
                }
            }
            break;
        }

        child->ReleaseIGameObject();
    }   
    
    for( int i=0; i<child->GetChildCount(); ++i )
    {
        IGameNode * n = child->GetNodeChild(i);
        ExportNode(n);
    }
}
void Unreal3DExport::Init()
{
    // Init
    CheckCancel();
    pScene = GetIGameInterface();
    GetConversionManager()->SetUserCoordSystem(UnrealCoords);
    if( bExportSelected )
    {
        Tab<INode*> selnodes;;
        for( int i=0; i<pInt->GetSelNodeCount(); ++i )
        {
            INode* n = pInt->GetSelNode(i);
            selnodes.Append(1,&n);
        }
        if( !pScene->InitialiseIGame(selnodes,false)  )
            throw MAXException(GetString(IDS_ERR_IGAME));
    }
    else
    {
        if( !pScene->InitialiseIGame() )
            throw MAXException(GetString(IDS_ERR_IGAME));
    }


    // Enumerate scene
    NodeCount = pScene->GetTotalNodeCount();
    for( int i=0; i<pScene->GetTopLevelNodeCount(); ++i )
    {
        IGameNode * n = pScene->GetTopLevelNode(i);
        ExportNode(n);
    }
    Progress += U3D_PROGRESS_ENUM;


    // Get animation info
    FrameStart = pScene->GetSceneStartTime() / pScene->GetSceneTicks();
    FrameEnd = pScene->GetSceneEndTime() / pScene->GetSceneTicks();
    FrameCount = FrameEnd - FrameStart+1;
    if( FrameCount <= 0 || FrameEnd < FrameStart ) 
    {
        ProgressMsg.printf(GetString(IDS_ERR_FRAMERANGE),FrameStart,FrameEnd);
        throw MAXException(ProgressMsg.data());
    }
    pScene->SetStaticFrame(FrameStart);
}
Exemplo n.º 10
0
void CChainComparer::CompareOptionalArtefacts()
{
	// If these types of object don't compare they probably have to mark them as matched
	// so you DO have to make that call!

	// we want to actually compare the tables, so pretend now they don't bridge
	m_pAnchor1->SetIgnorePreComparedTableBridge(true);
	m_pAnchor1->CompareTables(m_pHost, m_pAnchor2, ShallWeCompareTheseTables());
	CheckCancel();
	m_pAnchor1->SetIgnorePreComparedTableBridge(false);
	
	m_pAnchor1->CompareNotes(m_pHost, m_pAnchor2, m_pHost->m_Options.Flags.m_bCompare_Footnotes);
	CheckCancel();

	m_pAnchor1->CompareFields(m_pHost, m_pAnchor2, m_pHost->m_Options.Flags.m_bIgnoreFieldCodes == 0);
	CheckCancel();

// RWG 31/1/01 - do sections before parfmts to get correct comparison of headers where
// one doc has section -> parfmt and the other parfmt -> section
// hopefully no nasty side effects
	m_pAnchor1->CompareSections(m_pHost, m_pAnchor2,m_pHost->m_Options.Flags.m_bCompareHeaderFooter);
	CheckCancel();

	m_pAnchor1->CompareShapes(m_pHost, m_pAnchor2, m_pHost->m_Options.Flags.m_bIgnoreTextBoxes == 0);
	CheckCancel();

	// CS (3/5/2007) do these before pars for custom xml tags
	m_pAnchor1->CompareBlobs(m_pHost, m_pAnchor2);
	CheckCancel();

	m_pAnchor1->CompareParfmts(m_pHost, m_pAnchor2);
	CheckCancel();

	//m_pAnchor1->CompareBlobs(m_pHost, m_pAnchor2);
	//CheckCancel();
}
Exemplo n.º 11
0
int
pbsdboot(TCHAR *wkernel_name, int argc, char *argv[], struct bootinfo* bi)
{
	int i;
	caddr_t start, end;
	caddr_t argbuf, p;
	struct bootinfo *bibuf;
	int fd = -1;

	stat_printf(TEXT("open %s..."), wkernel_name);
	if (CheckCancel(0) || (fd = open((char*)wkernel_name, O_RDONLY)) < 0) {
		msg_printf(MSG_ERROR, whoami, TEXT("open failed.\n"));
		stat_printf(TEXT("open %s...failed"), wkernel_name);
		goto cancel;
	}

	stat_printf(TEXT("read information from %s..."), wkernel_name);
	if (CheckCancel(0) || getinfo(fd, &start, &end) < 0) {
		stat_printf(TEXT("read information failed"), wkernel_name);
		goto cancel;
	}

	stat_printf(TEXT("create memory map..."));
	if (CheckCancel(0) || vmem_init(start, end) < 0) {
		stat_printf(TEXT("create memory map...failed"));
		goto cancel;
	}
	//vmem_dump_map();

	stat_printf(TEXT("prepare boot information..."));
	if ((argbuf = vmem_alloc()) == NULL ||
		(bibuf = (struct bootinfo*)vmem_alloc()) == NULL) {
		msg_printf(MSG_ERROR, whoami, TEXT("can't allocate argument page\n"));
		stat_printf(TEXT("prepare boot information...failed"));
		goto cancel;
	}

	memcpy(bibuf, bi, sizeof(struct bootinfo));
	for (p = &argbuf[sizeof(char*) * argc], i = 0; i < argc; i++) {
		int arglen = strlen(argv[i]) + 1;
		((char**)argbuf)[i] = p;
		memcpy(p, argv[i], arglen);
		p += arglen;
	}

	stat_printf(TEXT("loading..."));
	if (CheckCancel(0) || loadfile(fd, &start) < 0) {
		stat_printf(TEXT("loading...failed"));
		goto cancel;
	}

	/* last chance to cancel */
	if (CheckCancel(-1)) {
		goto cancel;
	}

	stat_printf(TEXT("execute kernel..."));
	vmem_exec(start, argc, (char**)argbuf, bibuf);
	stat_printf(TEXT("execute kernel...failed"));

cancel:
	if (0 <= fd) {
		close(fd);
	}
	vmem_free();

	return (-1);
}
Exemplo n.º 12
0
BOOL __saveds CheckCancelInterface(rsiCONTEXT *rc)
{
	return CheckCancel(rc);
}
Exemplo n.º 13
0
void CUpdateThread::Update()
{
	// 读取本地配置
	UpdateCommandButton(COMMAND_BUTTON_CANCEL);
	UpdateMainProgress(0);
	UpdateSubProgress(0);

	UpdateStatusText(_T("读取站点列表……"));
	CString strIniPath = theApp.GetProfileFile();
	CString strSites;
	DWORD dwSize = 0;
	do 
	{
		dwSize += 4096;
	} while(GetPrivateProfileSection(_T("Sites"), strSites.GetBuffer(dwSize), dwSize, strIniPath.GetString()) == dwSize - 2);
	UpdateSubProgress(100);

	CArray<CString> sites;
	LPCTSTR lpszSite = strSites.GetBuffer();
	while (lpszSite[0]) 
	{
		sites.Add(lpszSite);
		lpszSite += _tcslen(lpszSite) + 1;
	}
	strSites.ReleaseBuffer();

	UpdateMainProgress(2);

	CMap<CString, LPCTSTR, AddonFile, AddonFile&> files;
	// 下载文件列表
	double step = 6.0 / sites.GetSize();
	for (int i = 0; i < sites.GetSize() && CheckCancel(); ++i) 
	{
		CString &strSite = sites.GetAt(i);
		if (!GetFileList(strSite, files))
		{
			UpdateSubProgress(100);
			UpdateMainProgress(100);
			UpdateStatusText(_T("无法下载文件列表。"));
			return;
		}
		UpdateMainProgress(2 + (int)(step * i + 0.5));
	}
	if (!CheckCancel())
		return;
	UpdateMainProgress(8);
		
	UpdateStatusText(_T("正在检测需要更新的文件……"));

	CString strWOWPath = theApp.GetWOWPath();
	CString strTempPath = theApp.GetTempPath();
	CArray <AddonFile *> aDownloadList;
	// 需要下载的文件
	CMap<CString, LPCTSTR, AddonFile, AddonFile&>::CPair *pair = files.PGetFirstAssoc();
	while (pair && CheckCancel())
	{
		CString strMD5;
		try 
		{
			CString strFilePath;
			strFilePath.Append(strWOWPath);
			strFilePath.Append(pair->value.m_strPath);
			md5_state_t md5;
			md5_init(&md5);
			md5_byte_t digest[16] = {0};
			CFile file(strFilePath, CFile::shareDenyRead | CFile::modeRead);
			char buf[4096];
			UINT nCount;
			while ((nCount = file.Read(buf, 4096)) > 0)
			{
				md5_append(&md5, buf, nCount);	
			}
			file.Close();
			md5_finish(&md5, digest);
			for (int i = 0; i < 16; ++i)
			{
				strMD5.AppendFormat(_T("%02x"), digest[i]);
			}
		}
		catch (CFileException *e)
		{
			e->Delete();
		}
		if (strMD5.Compare(pair->value.m_strMD5) != 0)
		{
			aDownloadList.Add(&pair->value);
		}

		pair = files.PGetNextAssoc(pair);
	}

	if (!CheckCancel())
		return;

	ULONG uTotalSize = 0;
	for (int i = 0; i < aDownloadList.GetSize(); ++i)
	{
		uTotalSize += aDownloadList.GetAt(i)->m_uCompressedSize;
	}

	if (!CheckCancel())
		return;

	CString strStatus;
	strStatus.AppendFormat(_T("共有%u个文件需要更新,%.2fMB。"), aDownloadList.GetSize(), uTotalSize * 1.0f / 1024 / 1024);
	UpdateStatusText(strStatus);
	UpdateMainProgress(10);

	step = 88.0 / uTotalSize;
	ULONG uDownload = 0;
	for (int i = 0; i < aDownloadList.GetSize() && CheckCancel(); ++i)
	{
		AddonFile *pAddonFile = aDownloadList.GetAt(i);
		UpdateStatusText(CString(_T("下载 ") + pAddonFile->m_strPath).GetString());
		CString strUrl = pAddonFile->m_strSite + pAddonFile->m_strPath + _T(".z");
		strUrl.Replace(_T('\\'), _T('/'));
		CString strPath = strTempPath + pAddonFile->m_strPath + _T(".z");
		CString strFolder = strPath.Mid(0, strPath.ReverseFind(_T('\\')));
		SHCreateDirectoryEx(NULL, strFolder, NULL);
		if (!Download(strUrl, strPath, pAddonFile->m_uCompressedSize))
		{
			UpdateStatusText(CString(_T("下载 ") + pAddonFile->m_strPath + _T("失败")).GetString());
			Cancel();
			CheckCancel();
			return;
		}
		UpdateSubProgress(100);
		UpdateStatusText(CString(_T("解压 ") + pAddonFile->m_strPath + _T("...")).GetString());
		CFile file(strPath, CFile::modeRead | CFile::shareDenyNone);
		unsigned char *compressed = new unsigned char[file.GetLength()];
		UINT uRead = 0;
		UINT uTotalRead = 0;
		file.Read(compressed, file.GetLength());
		ULONG uCompSize = file.GetLength();
		file.Close();
		unsigned char *uncompressed = new unsigned char[pAddonFile->m_uSize];
		DWORD uSize = pAddonFile->m_uSize;
		if (uncompress(uncompressed, &uSize, compressed, uCompSize) != Z_OK)
		{
			delete[] compressed;
			delete[] uncompressed;
			UpdateStatusText(CString(_T("解压 ") + pAddonFile->m_strPath + _T("失败")).GetString());
			Cancel();
			CheckCancel();
			return;
		}
		strPath = strWOWPath + pAddonFile->m_strPath;
		strFolder = strPath.Mid(0, strPath.ReverseFind(_T('\\')));
		SHCreateDirectoryEx(NULL, strFolder, NULL);
		if (!file.Open(strPath, CFile::modeCreate | CFile::shareExclusive | CFile::modeReadWrite))
		{
			delete[] compressed;
			delete[] uncompressed;
			UpdateStatusText(CString(_T("创建 ")) + strPath + _T("失败。"));
			Cancel();
			CheckCancel();
			return;
		}
		file.Write(uncompressed, pAddonFile->m_uSize);
		file.Close();

		delete[] compressed;
		delete[] uncompressed;
		uDownload += pAddonFile->m_uCompressedSize;
		UpdateMainProgress(8 + uDownload * step + 0.5);
	}

	if (!CheckCancel())
		return;

	// 需要删除的文件
	CArray<CString, LPCTSTR> oldFiles;
	LoadOldList(oldFiles);
	for (int i = 0; i < oldFiles.GetSize(); ++i)
	{
		CString &strPath = oldFiles.GetAt(i);
		if (!files.PLookup(strPath.MakeLower()))
		{
			CString strFilePath = strWOWPath + strPath;
			DeleteFile(strFilePath);
			RemoveFolderIfEmpty(strWOWPath, strFilePath.Mid(0, strFilePath.ReverseFind(_T('\\'))));
		}
	}

	// 保存本次更新的列表
	TiXmlDocument doc;
	TiXmlElement *root = new TiXmlElement("Files");
	pair = files.PGetFirstAssoc();
	USES_CONVERSION;
	while (pair)
	{
		TiXmlElement *file = new TiXmlElement("File");
		file->SetAttribute("Path", T2A(pair->value.m_strPath));
		root->LinkEndChild(file);
		pair = files.PGetNextAssoc(pair);
	}

	doc.LinkEndChild(root);
	doc.SaveFile(T2A(theApp.GetApplicationPath() + _T("AddonUpdater.xml")));
	UpdateStatusText(_T("更新完毕。"));
	UpdateMainProgress(100);
	UpdateCommandButton(COMMAND_BUTTON_PLAY);
}
Exemplo n.º 14
0
void CChainComparer::PreCompareTables()
{
// Set up bookmark points in tables, as required for ref docs
	m_pAnchor1->PreCompareTables(m_pHost ,m_pAnchor2, ShallWePrecompareTheseTables());
	CheckCancel();
}
Exemplo n.º 15
0
/*************
 * DESCRIPTION:   check if cancel button is pressed
 * INPUT:         none
 * OUTPUT:        TRUE if pressed else FALSE
 *************/
static BOOL SAVEDS CheckCancelInterface(rsiCONTEXT *rc)
{
	return CheckCancel(rc);
}
Exemplo n.º 16
0
void CDialogEditAllele::OnCancel(wxCommandEvent &)
{
  CheckCancel();
}
void Unreal3DExport::GetTris()
{
    
    // Export triangle data
    FJSMeshTri nulltri = FJSMeshTri();
    for( int n=0; n<Nodes.Count(); ++n )
    {
        CheckCancel();
        
        IGameNode* node = Nodes[n];
        IGameMesh* mesh = static_cast<IGameMesh*>(node->GetIGameObject());
        if( mesh->InitializeData() )
        {
            int vertcount = mesh->GetNumberOfVerts();
            int tricount = mesh->GetNumberOfFaces();
            if( vertcount > 0 && tricount > 0 )
            {
                // Progress
                ProgressMsg.printf(GetString(IDS_INFO_MESH),n+1,Nodes.Count(),TSTR(node->GetName()));
                pInt->ProgressUpdate(Progress+(static_cast<float>(n)/Nodes.Count()*U3D_PROGRESS_MESH), FALSE, ProgressMsg.data());

                // Alloc triangles space
                Tris.Resize(Tris.Count()+tricount);

                // Append triangles
                for( int i=0; i!=tricount; ++i )
                {
                    FaceEx* f = mesh->GetFace(i);
                    if( f )
                    {
                        FJSMeshTri tri(nulltri);

                        // TODO: add material id listing
                        RegisterMaterial( node, mesh, f, &tri );

                        tri.iVertex[0] = VertsPerFrame + f->vert[0];
                        tri.iVertex[1] = VertsPerFrame + f->vert[1];
                        tri.iVertex[2] = VertsPerFrame + f->vert[2];

                        Point2 p;
                        if( mesh->GetTexVertex(f->texCoord[0],p) ){
                            tri.Tex[0] = FMeshUV(p);
                        }
                        if( mesh->GetTexVertex(f->texCoord[1],p) ){
                            tri.Tex[1] = FMeshUV(p);
                        }
                        if( mesh->GetTexVertex(f->texCoord[2],p) ){
                            tri.Tex[2] = FMeshUV(p);
                        }
                        
                        Tris.Append(1,&tri);                       
                    }
                }

                VertsPerFrame += vertcount;
            }
            else
            {
                // remove invalid node
                Nodes.Delete(n--,1);
            }
        }
        node->ReleaseIGameObject();
    }
    Progress += U3D_PROGRESS_MESH;
}