#include "dxstdafx.h" #include ".\mesh.h" #include "SubMesh.h" #include "PathMapEffect.h" #include "TriangleMesh.h" #include "MeshExploder.h" #include "L.h" #include "FlexVertex.h" #include "xmlParser.h" #include #include Mesh::Mesh(PathMapEffect* pathMapEffect, DWORD fileFormat, LPCWSTR xFileName, LPCWSTR ogreFileName, int prmAtlasSize, const char* name, unsigned int nDesiredPartitions, bool generateUV, bool generateTBN, unsigned int originalAtlasTexCoordIndex) { this->pathMapEffect = pathMapEffect; LPDIRECT3DDEVICE9 device = pathMapEffect->device; this->prmAtlasSize = prmAtlasSize; strcpy(this->name, name); if(ogreFileName) wcscpy(this->ogreFileName, ogreFileName); else this->ogreFileName[0] = 0; LPD3DXBUFFER materialBuffer, shaderBuffer; DWORD nSubsets; HRESULT hr = S_FALSE; wchar_t** materialNames; if(fileFormat == OgreXMLMesh) { hr = loadMeshFromOgreXML( xFileName, 0, device, &materialBuffer, //material &shaderBuffer, //shadrr &nSubsets, pathMapEffect->xMaterials, materialNames, &mesh); } else { hr = D3DXLoadMeshFromX( xFileName, D3DXMESH_MANAGED, device, NULL, //adjacency &materialBuffer, //material &shaderBuffer, //shader &nSubsets, &mesh); } if(hr != S_OK) { MessageBox(NULL, xFileName, L"Could not load mesh file!", MB_OK); return; } //add a texcoord set for prm DWORD fvf = mesh->GetFVF(); fvf |= D3DFVF_NORMAL; DWORD nTexCoords = fvf & D3DFVF_TEXCOUNT_MASK; if(generateUV || (originalAtlasTexCoordIndex == 0 && nTexCoords == D3DFVF_TEX1)) { nTexCoords += D3DFVF_TEX1; fvf &= ~D3DFVF_TEXCOUNT_MASK; fvf |= nTexCoords; fvf |= D3DFVF_TEXCOORDSIZE2(nTexCoords / D3DFVF_TEX1); setVertexFormat(fvf); } if(generateTBN) computeTangentFrame(); mesh->OptimizeInplace(D3DXMESHOPT_ATTRSORT, NULL, NULL, NULL, NULL); D3DXMATERIAL* materialArray = (D3DXMATERIAL*)materialBuffer->GetBufferPointer(); D3DXEFFECTINSTANCE* shaderArray = (D3DXEFFECTINSTANCE*)shaderBuffer->GetBufferPointer(); if(nDesiredPartitions != 1 || generateUV) { //check is this already exists, load if it does char sname[256]; sprintf(sname, "%s/%s.x", LC::c-pathMapEffect->meshDirectory, name); LPD3DXMESH processedMesh; LPD3DXBUFFER processedMaterialBuffer; LPD3DXBUFFER processedShaderBuffer; HRESULT processedMeshExists S_FALSE; if(!pathMapEffect->SEGMENTMESHES) { processedMeshExists = D3DXLoadMeshFromX( L::l+sname, D3DXMESH_MANAGED, device, NULL, //adjacency &processedMaterialBuffer, //material &processedShaderBuffer, //shader &nSubsets, &processedMesh); } if(processedMeshExists == S_OK) { mesh->Release(); materialBuffer->Release(); shaderBuffer->Release(); mesh = processedMesh; materialBuffer = processedMaterialBuffer; shaderBuffer = processedShaderBuffer; materialArray = (D3DXMATERIAL*)materialBuffer->GetBufferPointer(); shaderArray = (D3DXEFFECTINSTANCE*)shaderBuffer->GetBufferPointer(); } else { MeshExploder mex(device, mesh, materialArray, materialNames, shaderArray, nDesiredPartitions); mex.explode(); // mex.saveFragMeshes(); mex.generateAtlas(prmAtlasSize); mex.merge(); mex.saveComposedMesh(name); mex.saveComposedMeshToOgreXML(name); mesh->Release(); materialArray = mex.composedMaterials; shaderArray = mex.composedShaders; mesh = mex.composedMesh; originalAtlasTexCoordIndex = (mesh->GetFVF() & D3DFVF_TEXCOUNT_MASK) / D3DFVF_TEX1 - 1; } } trimMesh(originalAtlasTexCoordIndex); for(int dili=0; materialNames[dili]; dili++) delete [] materialNames[dili]; delete [] materialNames; nSubsets = nDesiredPartitions; //create #subset submeshes for(int iSubset=0; iSubsetloadBumpMap(bumpFileName, bumpScale); } } mesh->OptimizeInplace(D3DXMESHOPT_ATTRSORT, NULL, NULL, NULL, NULL); DWORD nAttributes; mesh->GetAttributeTable(NULL, &nAttributes); D3DXATTRIBUTERANGE* subsetRanges = new D3DXATTRIBUTERANGE[nAttributes]; mesh->GetAttributeTable(subsetRanges, &nAttributes); std::vector::iterator iSubMesh = subMeshes.begin(); int i =0; while(iSubMesh != subMeshes.end()) { (*iSubMesh)->buildRayTraceMesh(subsetRanges[i].FaceStart*3, subsetRanges[i].FaceCount*3); iSubMesh++; i++; } delete subsetRanges; materialBuffer->Release(); shaderBuffer->Release(); buildEdgeVertexBuffer(); } Mesh::~Mesh(void) { std::vector::iterator i = subMeshes.begin(); while(i != subMeshes.end()) { delete *i; i++; } mesh->Release(); if(edgeVertexBuffer) edgeVertexBuffer->Release(); } HRESULT Mesh::setVertexFormat(DWORD fvf) { LPDIRECT3DDEVICE9 device = pathMapEffect->device; LPD3DXMESH tempMesh; //clone the mesh to the appropriate format HRESULT hr = mesh->CloneMeshFVF( mesh->GetOptions(), fvf , device, &tempMesh ); if(hr == S_OK) { //forget he old mesh mesh->Release(); //use the cloned mesh mesh = tempMesh; } return hr; } HRESULT Mesh::partitionMesh(unsigned int nDesiredPartitions, LPD3DXBUFFER& partitioningBuffer, unsigned int& nPartitions) { LPD3DXMESH tempMesh; LPD3DXBUFFER partitionResultAdjacency; float maxStretchApplied; HRESULT hr; /* hr = D3DXUVAtlasPartition( mesh, //LPD3DXMESH pMesh, nDesiredPartitions, //UINT dwMaxChartNumber, 1.0f, //FLOAT fMaxStretch, 1, //DWORD dwTextureIndex, NULL, //CONST DWORD * pdwAdjacency, NULL, //CONST CHAR * pcFalseEdges, NULL, //FLOAT * pfIMTArray, NULL, //LPD3DXUVATLASCB pCallback, 0.1f, //FLOAT fCallbackFrequency, NULL, //LPVOID pUserContent, &tempMesh, //LPD3DXMESH * ppMeshOut, &partitioningBuffer, //LPD3DXBUFFER ppFacePartitioning, NULL, //LPD3DXBUFFER * ppVertexRemapArray, &partitionResultAdjacency, //LPD3DXBUFFER * ppPartitionResultAdjacency, &maxStretchApplied, //FLOAT * pfMaxStretchOut, &nPartitions //UINT * pdwNumChartsOut );*/ if(hr == S_OK) { //forget he old mesh mesh->Release(); mesh = tempMesh; } else return hr; partitionResultAdjacency->Release(); return S_OK; } HRESULT Mesh::computeTangentFrame() { LPD3DXMESH tempMesh; HRESULT hr = D3DXComputeTangentFrameEx( mesh, // ID3DXMesh * pMesh, D3DDECLUSAGE_TEXCOORD, // DWORD dwTextureInSemantic, 0, // DWORD dwTextureInIndex, D3DDECLUSAGE_TEXCOORD, // DWORD dwUPartialOutSemantic, 2, // DWORD dwUPartialOutIndex, D3DDECLUSAGE_TEXCOORD, // DWORD dwVPartialOutSemantic, 3, // DWORD dwVPartialOutIndex, D3DDECLUSAGE_NORMAL, // DWORD dwNormalOutSemantic, 0, // DWORD dwNormalOutIndex, (D3DXTANGENT_WRAP_UV // | D3DXTANGENT_DONT_ORTHOGONALIZE | D3DXTANGENT_DONT_NORMALIZE_PARTIALS) )& !( D3DXTANGENT_CALCULATE_NORMALS ), // DWORD dwOptions, NULL, // CONST DWORD * pdwAdjacency, 0.2, // FLOAT fPartialEdgeThreshold, 0.0, // FLOAT fSingularPointThreshold, 0.2, // FLOAT fNormalEdgeThreshold, &tempMesh, // ID3DXMesh ** ppMeshOut, NULL // ID3DXBuffer ** ppVertexMapping ); if(hr == S_OK) { //forget he old mesh mesh->Release(); mesh = tempMesh; } else return hr; LPDIRECT3DVERTEXBUFFER9 vertexBuffer; mesh->GetVertexBuffer(&vertexBuffer); FlexVertexArray vertexData(mesh->GetNumBytesPerVertex()); D3DVERTEXELEMENT9 elem[64]; mesh->GetDeclaration(elem); vertexData.setFormat(elem); vertexBuffer->Lock(0,mesh->GetNumVertices()*mesh->GetNumBytesPerVertex(),vertexData.getDataPointerReference(),0); for(unsigned int u=0; u < mesh->GetNumVertices(); u++ ) vertexData[u].tex1() = (vertexData[u].tex1() * (prmAtlasSize - 4) + D3DXVECTOR2(2.0,2.0)) / (float)prmAtlasSize; vertexBuffer->Unlock(); vertexBuffer->Release(); return hr; } void Mesh::buildEdgeVertexBuffer() { LPDIRECT3DDEVICE9 device = pathMapEffect->device; LPD3DXMESH pMesh = this->mesh; DWORD* pAdj = new DWORD[3 * pMesh->GetNumFaces()]; for(int r=0; rGetNumFaces()*3; r++) pAdj[r] = 0xffff; pMesh->ConvertPointRepsToAdjacency(NULL, pAdj); LPDIRECT3DVERTEXBUFFER9 vertexBuffer; pMesh->GetVertexBuffer(&vertexBuffer); FlexVertexArray vertexData(mesh->GetNumBytesPerVertex()); D3DVERTEXELEMENT9 elem[64]; mesh->GetDeclaration(elem); vertexData.setFormat(elem); vertexBuffer->Lock(0,pMesh->GetNumVertices()*pMesh->GetNumBytesPerVertex(),vertexData.getDataPointerReference(),0); LPDIRECT3DINDEXBUFFER9 indexBuffer; pMesh->GetIndexBuffer(&indexBuffer); unsigned short* indexData; indexBuffer->Lock(0,pMesh->GetNumFaces()*3*sizeof(unsigned short),(void**)&indexData,0); DWORD* attributeArray; mesh->LockAttributeBuffer(0, &attributeArray); int countEdges = 0; for(int u=0; uGetNumFaces(); u++) for(int t=0; t<3; t++) if(pAdj[u * 3 + t] >= pMesh->GetNumFaces()) countEdges++; if(countEdges == 0) { edgeVertexBuffer = NULL; nEdges = 0; vertexBuffer->Unlock(); indexBuffer->Unlock(); SAFE_RELEASE(vertexBuffer); SAFE_RELEASE(indexBuffer); return; } device->CreateVertexBuffer(2 * countEdges * pMesh->GetNumBytesPerVertex(), D3DUSAGE_WRITEONLY, pMesh->GetFVF(), D3DPOOL_DEFAULT, &edgeVertexBuffer, NULL); FlexVertexArray pevData(mesh->GetNumBytesPerVertex()); edgeVertexBuffer->Lock(0, 0, pevData.getDataPointerReference(), 0); int DBLATLASSIZE = prmAtlasSize * 2; int ATLASSIZE = prmAtlasSize; bool firstSub = true; std::vector::iterator iSubMesh = subMeshes.begin(); DWORD prevAttribute = 0xffffffff; int iEdge = 0; for(int u=0; uGetNumFaces(); u++) { if(attributeArray[u] != prevAttribute) { prevAttribute = attributeArray[u]; if(firstSub) firstSub = false; else iSubMesh++; (*iSubMesh)->edgeStartIndex = iEdge; (*iSubMesh)->edgeCount = 0; } for(int t=0; t<3; t++) { if(pAdj[u * 3 + t] >= pMesh->GetNumFaces()) { unsigned short edge0 = indexData[u * 3 + t]; unsigned short edge1 = indexData[u * 3 + (t+1)%3]; unsigned short inner = indexData[u * 3 + (t+2)%3]; //push vertex edge0, edge1 //pevData[iEdge * 2] = vertexData[edge0]; //pevData[iEdge * 2 + 1] = vertexData[edge1]; pevData.assign(iEdge * 2, vertexData[edge0]); pevData.assign(iEdge * 2 + 1, vertexData[edge1]); D3DXVECTOR2 ediff = vertexData[edge1].tex1() - vertexData[edge0].tex1(); if(fabsf(ediff.x) > fabsf(ediff.y)) { if(vertexData[inner].tex1().y <= vertexData[edge0].tex1().y + (vertexData[inner].tex1().x - vertexData[edge0].tex1().x) * (vertexData[edge1].tex1().y - vertexData[edge0].tex1().y) / (vertexData[edge1].tex1().x - vertexData[edge0].tex1().x)) { pevData[iEdge * 2].tex1().y += 1.0/DBLATLASSIZE; pevData[iEdge * 2 + 1].tex1().y += 1.0/DBLATLASSIZE; } else { pevData[iEdge * 2].tex1().y -= 1.0/DBLATLASSIZE; pevData[iEdge * 2 + 1].tex1().y -= 1.0/DBLATLASSIZE; } D3DXVECTOR2 edgeDirUnitExt(1.0f, (vertexData[edge1].tex1().y - vertexData[edge0].tex1().y) / (vertexData[edge1].tex1().x - vertexData[edge0].tex1().x)); edgeDirUnitExt *= 1.0/ATLASSIZE; if(vertexData[edge1].tex1().x > vertexData[edge0].tex1().x) { pevData[iEdge * 2].tex1() -= edgeDirUnitExt; pevData[iEdge * 2 + 1].tex1() += edgeDirUnitExt; } else { pevData[iEdge * 2].tex1() += edgeDirUnitExt; pevData[iEdge * 2 + 1].tex1() -= edgeDirUnitExt; } } else { if(vertexData[inner].tex1().x <= vertexData[edge0].tex1().x + (vertexData[inner].tex1().y - vertexData[edge0].tex1().y) * (vertexData[edge1].tex1().x - vertexData[edge0].tex1().x) / (vertexData[edge1].tex1().y - vertexData[edge0].tex1().y)) { pevData[iEdge * 2].tex1().x += 1.0/DBLATLASSIZE; pevData[iEdge * 2 + 1].tex1().x += 1.0/DBLATLASSIZE; } else { pevData[iEdge * 2].tex1().x -= 1.0/DBLATLASSIZE; pevData[iEdge * 2 + 1].tex1().x -= 1.0/DBLATLASSIZE; } D3DXVECTOR2 edgeDirUnitExt((vertexData[edge1].tex1().x - vertexData[edge0].tex1().x) / (vertexData[edge1].tex1().y - vertexData[edge0].tex1().y), 1.0f); edgeDirUnitExt *= 1.0/ATLASSIZE; if(vertexData[edge1].tex1().y > vertexData[edge0].tex1().y) { pevData[iEdge * 2].tex1() -= edgeDirUnitExt; pevData[iEdge * 2 + 1].tex1() += edgeDirUnitExt; } else { pevData[iEdge * 2].tex1() += edgeDirUnitExt; pevData[iEdge * 2 + 1].tex1() -= edgeDirUnitExt; } } iEdge++; (*iSubMesh)->edgeCount++; } } } nEdges = iEdge; edgeVertexBuffer->Unlock(); vertexBuffer->Unlock(); indexBuffer->Unlock(); SAFE_RELEASE(vertexBuffer); SAFE_RELEASE(indexBuffer); mesh->UnlockAttributeBuffer(); delete pAdj; } void Mesh::saveMesh() { D3DXMATERIAL * materials = new D3DXMATERIAL[subMeshes.size()]; D3DXEFFECTINSTANCE * shaders = new D3DXEFFECTINSTANCE[subMeshes.size()]; std::vector::iterator iSubMesh = subMeshes.begin(); int i =0; while(iSubMesh != subMeshes.end()) { materials[i] = (*iSubMesh)->material; addShaderString(shaders[i], "bumpFileName", (*iSubMesh)->bumpFileName); iSubMesh++; i++; } char sname[256]; printf(sname, "%s_partitioned.x", name); D3DXSaveMeshToX(L::l+sname, //LPCTSTR pFilename, mesh, //LPD3DXMESH pMesh, NULL, //CONST DWORD * pAdjacency, materials, //CONST D3DXMATERIAL * pMaterials, shaders, //CONST D3DXEFFECTINSTANCE * pEffectInstances, subMeshes.size(), //DWORD NumMaterials, D3DXF_FILEFORMAT_TEXT //DWORD Format ); delete materials; delete shaders; } void Mesh::addShaderString(D3DXEFFECTINSTANCE& e, LPCSTR name, LPCSTR value) { for(int i=0; iGetVertexBuffer(&vertexBuffer); FlexVertexArray vertexData(pMesh->GetNumBytesPerVertex()); D3DVERTEXELEMENT9 elem[64]; pMesh->GetDeclaration(elem); vertexData.setFormat(elem); vertexBuffer->Lock(0,pMesh->GetNumVertices()*pMesh->GetNumBytesPerVertex(),vertexData.getDataPointerReference(),0); LPDIRECT3DINDEXBUFFER9 indexBuffer; pMesh->GetIndexBuffer(&indexBuffer); unsigned short* indexData; indexBuffer->Lock(0,pMesh->GetNumFaces()*3*sizeof(unsigned short),(void**)&indexData,0); DWORD* attributeArray; pMesh->LockAttributeBuffer(0, &attributeArray); for(int ivi=0; ivi < nVertices; ivi++) { XMLNode xVertexNode = xVertexBufferNode.getChildNode(L"vertex", ivi); XMLNode xVertexPositionNode = xVertexNode/L"position"; D3DXVECTOR3 dvipos( _wtof( xVertexPositionNode|L"x" ), _wtof( xVertexPositionNode|L"y" ), _wtof( xVertexPositionNode|L"z" ) ); vertexData[ivi].pos() = dvipos; XMLNode xVertexNormalNode = xVertexNode/L"normal"; D3DXVECTOR3 dvinormal( _wtof( xVertexNormalNode|L"x" ), _wtof( xVertexNormalNode|L"y" ), _wtof( xVertexNormalNode|L"z" ) ); vertexData[ivi].normal() = dvinormal; for(int tuxi=0; tuxi < nTexCoords; tuxi++) { XMLNode xVertexTexNode = xVertexNode.getChildNode(L"texcoord", tuxi); D3DXVECTOR2 dvitex( _wtof( xVertexTexNode|L"u" ), _wtof( xVertexTexNode|L"v" ) ); vertexData[ivi].tex(tuxi) = dvitex; } } D3DXCreateBuffer(sizeof(D3DXMATERIAL) * nSubMeshes, materialBuffer); D3DXCreateBuffer(sizeof(D3DXEFFECTINSTANCE) * nSubMeshes, shaderBuffer); D3DXMATERIAL* materialArray = (D3DXMATERIAL*)(*materialBuffer)->GetBufferPointer(); D3DXEFFECTINSTANCE* shaderArray = (D3DXEFFECTINSTANCE*)(*shaderBuffer)->GetBufferPointer(); *nMaterials = nSubMeshes; materialNames = new wchar_t*[nSubMeshes+1]; materialNames[nSubMeshes] = NULL; unsigned int indexBufferFiller = 0; for(int fifi=0; fifi < nSubMeshes; fifi++) { attributeArray[indexBufferFiller/3] = fifi; XMLNode xSubMeshNode = xSubmeshesNode.getChildNode(L"submesh", fifi); D3DXMATERIAL mat; mat.pTextureFilename = LC::c.clone( ( xMaterials.getChildNodeWithAttribute(L"material", L"name", xSubMeshNode|L"material")|L"texture" )); materialNames[fifi] = L::cloneW( xSubMeshNode|L"material" ); materialArray[fifi] = mat; D3DXEFFECTINSTANCE efi; efi.NumDefaults = 0; efi.pDefaults = NULL; efi.pEffectFilename = NULL; shaderArray[fifi] = efi; XMLNode xSubMeshFacesNode = xSubMeshNode/L"faces"; unsigned int nSubMeshFaces = _wtoi( xSubMeshFacesNode|L"count" ); for(int fido=0; fidoUnlock(); indexBuffer->Unlock(); vertexBuffer->Release(); indexBuffer->Release(); pMesh->UnlockAttributeBuffer(); return S_OK; } const DWORD Mesh::DirectXMesh(0); const DWORD Mesh::OgreXMLMesh(1); void Mesh::saveSceneInfo(std::ofstream& psf) { psf << "mesh " << name << '\n'; psf << "{\n"; psf << "\togrefile " << LC::c-ogreFileName << '\n'; psf << "\tpathmapresolution " << prmAtlasSize << '\n'; psf << "\tdivide 1\n"; psf << "}\n"; } void Mesh::trimMesh(unsigned int originalAtlasTexCoordIndex) { // DWORD fvf = mesh->GetFVF(); // DWORD nTexCoords = (fvf & D3DFVF_TEXCOUNT_MASK) / D3DFVF_TEX1; D3DVERTEXELEMENT9 elem[64]; mesh->GetDeclaration(elem); D3DVERTEXELEMENT9* pElem = &elem[0]; DWORD maxTexOffs = 0; DWORD maxTexId = 0; while(pElem->Type != D3DDECLTYPE_UNUSED) { if(pElem->Usage == D3DDECLUSAGE_TEXCOORD) if(pElem->UsageIndex > maxTexId) { maxTexId = pElem->UsageIndex; maxTexOffs = pElem->Offset; } pElem++; } D3DVERTEXELEMENT9 pathMapMeshDecl[5] = { {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0}, {0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, {0, 32 /*maxTexOffs*/, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1}, D3DDECL_END() }; // mesh->UpdateSemantics(pathMapMeshDecl); LPDIRECT3DVERTEXBUFFER9 svertexBuffer; mesh->GetVertexBuffer(&svertexBuffer); FlexVertexArray svertexData(mesh->GetNumBytesPerVertex()); svertexData.setFormat(elem); svertexBuffer->Lock(0, mesh->GetNumVertices() * mesh->GetNumBytesPerVertex(), svertexData.getDataPointerReference(),0); for(int gh=0; gh < mesh->GetNumVertices(); gh++) svertexData[gh].tex(1) = svertexData[gh].tex(originalAtlasTexCoordIndex); svertexBuffer->Unlock(); svertexBuffer->Release(); /* LPDIRECT3DDEVICE9 device = pathMapEffect->device; LPD3DXMESH tempMesh; //clone the mesh to the appropriate format HRESULT hr = mesh->CloneMesh(mesh->GetOptions(), pathMapMeshDecl, device, &tempMesh ); if(hr == S_OK) { LPDIRECT3DVERTEXBUFFER9 svertexBuffer; mesh->GetVertexBuffer(&svertexBuffer); FlexVertexArray svertexData(mesh->GetNumBytesPerVertex()); D3DVERTEXELEMENT9 elem[64]; mesh->GetDeclaration(elem); svertexData.setFormat(elem); svertexBuffer->Lock(0, mesh->GetNumVertices() * mesh->GetNumBytesPerVertex(), svertexData.getDataPointerReference(),0); LPDIRECT3DVERTEXBUFFER9 vertexBuffer; tempMesh->GetVertexBuffer(&vertexBuffer); FlexVertexArray vertexData(tempMesh->GetNumBytesPerVertex()); vertexData.setFormat(pathMapMeshDecl); vertexBuffer->Lock(0,tempMesh->GetNumVertices()*tempMesh->GetNumBytesPerVertex(),vertexData.getDataPointerReference(),0); for(int qu=0; quGetNumVertices(); qu++) { vertexData[qu].tex(1) = svertexData[qu].tex(originalAtlasTexCoordIndex); } svertexBuffer->Unlock(); vertexBuffer->Unlock(); svertexBuffer->Release(); vertexBuffer->Release(); //forget he old mesh mesh->Release(); //use the cloned mesh mesh = tempMesh; }*/ }