void cMyASELoader::LoadMesh(){ #ifdef _DEBUG _ASSERT(m_bLoaded && "Data Not Loaded"); #endif int check = 0; for (size_t i = 0; i < m_vecASENode.size(); i++){ if (m_vecASENode[i].nRef != INT_MAX){ m_vecsubSet.push_back(m_vecASENode[i].nRef); LPD3DXMESH pMesh = NULL; HRESULT hr = D3DXCreateMeshFVF(m_vecASENode[i].vecVertex.size() / 3, m_vecASENode[i].vecVertex.size(), D3DXMESH_MANAGED, ST_PNT_VERTEX::FVF, g_pD3DDevice, &pMesh); ST_PNT_VERTEX* pV = NULL; pMesh->LockVertexBuffer(0, (LPVOID*)&pV); memcpy(pV, &m_vecASENode[i].vecVertex[0], m_vecASENode[i].vecVertex.size() * sizeof(ST_PNT_VERTEX)); pMesh->UnlockVertexBuffer(); WORD* pI = NULL; pMesh->LockIndexBuffer(0, (LPVOID*)&pI); for (size_t j = 0; j < pMesh->GetNumVertices(); ++j) { pI[j] = j; } pMesh->UnlockIndexBuffer(); DWORD* pA = NULL; pMesh->LockAttributeBuffer(0, &pA); for (size_t j = 0; j < pMesh->GetNumFaces(); j++){ pA[j] = m_vecASENode[i].nRef; } pMesh->UnlockAttributeBuffer(); std::vector<DWORD> vecAdjBuffer(m_vecASENode[i].vecVertex.size()); pMesh->GenerateAdjacency(0.0f, &vecAdjBuffer[0]); pMesh->OptimizeInplace( D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_COMPACT | D3DXMESHOPT_VERTEXCACHE, &vecAdjBuffer[0], 0, 0, 0); m_vecMeshs.push_back(pMesh); } } m_bMeshed = true; }
void CreateBox( const float &w, const float &h, const float &d, const bool ¢erWidth, const bool ¢erHeight, const bool ¢erDepth, LPD3DXMESH &mesh ) { float offsetX = 0, offsetY = 0, offsetZ = 0; if( centerWidth ) offsetX = -w / 2.f; if( centerHeight ) offsetY = -h / 2.f; if( centerDepth ) offsetZ = -d / 2.f; std::vector<DWORD> vIB; std::vector<VERTEX3> vVB; std::vector<DWORD> vAB; DWORD offset = 0; // fill in the front face index data vIB.push_back( 0 + offset ); vIB.push_back( 1 + offset ); vIB.push_back( 2 + offset ); vIB.push_back( 0 + offset ); vIB.push_back( 2 + offset ); vIB.push_back( 3 + offset ); // fill in the front face vertex data vVB.push_back( VERTEX3( 0.f + offsetX, 0.f + offsetY, 0.f + offsetZ, 0.f, 0.f, -1.f, 0.f, 1.f ) ); vVB.push_back( VERTEX3( 0.f + offsetX, h + offsetY, 0.f + offsetZ, 0.f, 0.f, -1.f, 0.f, 0.f ) ); vVB.push_back( VERTEX3( w + offsetX, h + offsetY, 0.f + offsetZ, 0.f, 0.f, -1.f, 1.f, 0.f ) ); vVB.push_back( VERTEX3( w + offsetX, 0.f + offsetY, 0.f + offsetZ, 0.f, 0.f, -1.f, 1.f, 1.f ) ); vAB.push_back( 0 ); vAB.push_back( 0 ); offset += 4; // fill in the back face index data vIB.push_back( 0 + offset ); vIB.push_back( 1 + offset ); vIB.push_back( 2 + offset ); vIB.push_back( 0 + offset ); vIB.push_back( 2 + offset ); vIB.push_back( 3 + offset ); // fill in the back face vertex data vVB.push_back( VERTEX3( 0.f + offsetX, 0.f + offsetY, d + offsetZ, 0.f, 0.f, 1.f, 1.f, 1.f ) ); vVB.push_back( VERTEX3( w + offsetX, 0.f + offsetY, d + offsetZ, 0.f, 0.f, 1.f, 0.f, 1.f ) ); vVB.push_back( VERTEX3( w + offsetX, h + offsetY, d + offsetZ, 0.f, 0.f, 1.f, 0.f, 0.f ) ); vVB.push_back( VERTEX3( 0.f + offsetX, h + offsetY, d + offsetZ, 0.f, 0.f, 1.f, 1.f, 0.f ) ); vAB.push_back( 1 ); vAB.push_back( 1 ); offset += 4; // fill in the top face index data vIB.push_back( 0 + offset ); vIB.push_back( 1 + offset ); vIB.push_back( 2 + offset ); vIB.push_back( 0 + offset ); vIB.push_back( 2 + offset ); vIB.push_back( 3 + offset ); //fill in the top face vertex data vVB.push_back( VERTEX3( 0.f + offsetX, h + offsetY, 0.f + offsetZ, 0.f, 1.f, 0.f, 0.f, 1.f ) ); vVB.push_back( VERTEX3( 0.f + offsetX, h + offsetY, d + offsetZ, 0.f, 1.f, 0.f, 0.f, 0.f ) ); vVB.push_back( VERTEX3( w + offsetX, h + offsetY, d + offsetZ, 0.f, 1.f, 0.f, 1.f, 0.f ) ); vVB.push_back( VERTEX3( w + offsetX, h + offsetY, 0.f + offsetZ, 0.f, 1.f, 0.f, 1.f, 1.f ) ); vAB.push_back( 2 ); vAB.push_back( 2 ); offset += 4; // fill in the bottom face index data vIB.push_back( 0 + offset ); vIB.push_back( 1 + offset ); vIB.push_back( 2 + offset ); vIB.push_back( 0 + offset ); vIB.push_back( 2 + offset ); vIB.push_back( 3 + offset ); // fill in the bottom face vertex data vVB.push_back( VERTEX3( 0.f + offsetX, 0.f + offsetY, 0.f + offsetZ, 0.f, -1.f, 0.f, 0.f, 1.f ) ); vVB.push_back( VERTEX3( w + offsetX, 0.f + offsetY, 0.f + offsetZ, 0.f, -1.f, 0.f, 0.f, 0.f ) ); vVB.push_back( VERTEX3( w + offsetX, 0.f + offsetY, d + offsetZ, 0.f, -1.f, 0.f, 1.f, 0.f ) ); vVB.push_back( VERTEX3( 0.f + offsetX, 0.f + offsetY, d + offsetZ, 0.f, -1.f, 0.f, 1.f, 1.f ) ); vAB.push_back( 3 ); vAB.push_back( 3 ); offset += 4; // fill in the left face index data vIB.push_back( 0 + offset ); vIB.push_back( 1 + offset ); vIB.push_back( 2 + offset ); vIB.push_back( 0 + offset ); vIB.push_back( 2 + offset ); vIB.push_back( 3 + offset ); // fill in the left face vertex data vVB.push_back( VERTEX3( 0.f + offsetX, 0.f + offsetY, d + offsetZ, -1.f, 0.f, 0.f, 0.f, 1.f ) ); vVB.push_back( VERTEX3( 0.f + offsetX, h + offsetY, d + offsetZ, -1.f, 0.f, 0.f, 0.f, 0.f ) ); vVB.push_back( VERTEX3( 0.f + offsetX, h + offsetY, 0.f + offsetZ, -1.f, 0.f, 0.f, 1.f, 0.f ) ); vVB.push_back( VERTEX3( 0.f + offsetX, 0.f + offsetY, 0.f + offsetZ, -1.f, 0.f, 0.f, 1.f, 1.f ) ); vAB.push_back( 4 ); vAB.push_back( 4 ); offset += 4; // fill in the right face index data vIB.push_back( 0 + offset ); vIB.push_back( 1 + offset ); vIB.push_back( 2 + offset ); vIB.push_back( 0 + offset ); vIB.push_back( 2 + offset ); vIB.push_back( 3 + offset ); // fill in the right face vertex data vVB.push_back( VERTEX3( w + offsetX, 0.f + offsetY, 0.f + offsetZ, 1.f, 0.f, 0.f, 0.f, 1.f ) ); vVB.push_back( VERTEX3( w + offsetX, h + offsetY, 0.f + offsetZ, 1.f, 0.f, 0.f, 0.f, 0.f ) ); vVB.push_back( VERTEX3( w + offsetX, h + offsetY, d + offsetZ, 1.f, 0.f, 0.f, 1.f, 0.f ) ); vVB.push_back( VERTEX3( w + offsetX, 0.f + offsetY, d + offsetZ, 1.f, 0.f, 0.f, 1.f, 1.f ) ); vAB.push_back( 5 ); vAB.push_back( 5 ); offset += 4; D3DXCreateMeshFVF( offset / 2, offset, D3DXMESH_MANAGED | D3DXMESH_32BIT, VERTEX3::FVF, g_pEngine->core->lpd3dd9, &mesh ); VERTEX3 *pVB = nullptr; mesh->LockVertexBuffer( D3DLOCK_DISCARD, reinterpret_cast< void** >( &pVB ) ); copy( vVB.begin(), vVB.end(), pVB ); mesh->UnlockVertexBuffer(); DWORD *pIB = nullptr; mesh->LockIndexBuffer( D3DLOCK_DISCARD, reinterpret_cast< void** >( &pIB ) ); copy( vIB.begin(), vIB.end(), pIB ); mesh->UnlockIndexBuffer(); DWORD *pAB = nullptr; mesh->LockAttributeBuffer( D3DLOCK_DISCARD, &pAB ); copy( vAB.begin(), vAB.end(), pAB ); mesh->UnlockAttributeBuffer(); std::vector<DWORD> adjacencyBuffer( mesh->GetNumFaces() * 3 ); mesh->GenerateAdjacency( 0.f, &adjacencyBuffer[ 0 ] ); mesh->OptimizeInplace( D3DXMESHOPT_COMPACT | D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_VERTEXCACHE, &adjacencyBuffer[ 0 ], nullptr, nullptr, nullptr ); }
void CreateGeometry(const char* sourceFile) { cout << endl << "Reading " << sourceFile << endl; wstring wideSourceFile(sourceFile, sourceFile + strlen(sourceFile)); // Load the mesh from the specified file LPD3DXBUFFER pD3DXMtrlBuffer; LPD3DXBUFFER pD3DXEffectInstances; HRESULT hr = D3DXLoadMeshFromX( wideSourceFile.c_str(), D3DXMESH_SYSTEMMEM, g_pd3dDevice, 0, &pD3DXMtrlBuffer, &pD3DXEffectInstances, &g_dwNumMaterials, &g_pMesh); if (FAILED(hr)) { MessageBox(0, (L"Could not find " + wideSourceFile).c_str(), L"X2CTM", MB_OK); exit(1); } DWORD* adjacencyIn = new DWORD[3 * g_pMesh->GetNumFaces()]; g_pMesh->GenerateAdjacency(0.0001f, adjacencyIn); DWORD* adjacencyOut = new DWORD[3 * g_pMesh->GetNumFaces()]; LPD3DXMESH newMesh = 0; //hr = g_pMesh->Optimize(D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_COMPACT, adjacencyIn, adjacencyOut, 0, 0, &newMesh); //hr = g_pMesh->OptimizeInplace(D3DXMESHOPT_ATTRSORT, adjacencyIn, adjacencyOut, 0, 0); if (FAILED(hr)) { MessageBox(0, L"Unable to build attribute table", L"Whatever", MB_OK); exit(1); } //g_pMesh = newMesh; if (WeldVertices) { DWORD beforeVertCount = g_pMesh->GetNumVertices(); DWORD beforeFaceCount = g_pMesh->GetNumFaces(); hr = D3DXWeldVertices(g_pMesh, D3DXWELDEPSILONS_WELDALL, 0, 0, 0, 0, 0); DWORD afterVertCount = g_pMesh->GetNumVertices(); DWORD afterFaceCount = g_pMesh->GetNumFaces(); } D3DXATTRIBUTERANGE table[256]; DWORD tableSize = sizeof(table) / sizeof(table[0]); g_pMesh->GetAttributeTable(&table[0], &tableSize); D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*) pD3DXMtrlBuffer->GetBufferPointer(); D3DXEFFECTINSTANCE* d3dxEffects = (D3DXEFFECTINSTANCE*) pD3DXEffectInstances->GetBufferPointer(); g_pMeshMaterials = new D3DMATERIAL9[g_dwNumMaterials]; g_pMeshTextures = new LPDIRECT3DTEXTURE9[g_dwNumMaterials]; for (DWORD i = 0; i < g_dwNumMaterials; i++) { g_pMeshMaterials[i] = d3dxMaterials[i].MatD3D; g_pMeshMaterials[i].Ambient = g_pMeshMaterials[i].Diffuse; g_pMeshTextures[i] = 0; if (d3dxMaterials[i].pTextureFilename && lstrlenA(d3dxMaterials[i].pTextureFilename) > 0) { D3DXCreateTextureFromFileA(g_pd3dDevice, d3dxMaterials[i].pTextureFilename, &g_pMeshTextures[i]); } } /* for (DWORD attrib = 0; attrib < tableSize; ++attrib) { // I'm not so sure about material-to-attribute correlation // if (attrib < g_dwNumMaterials) // { LPSTR pTexture = d3dxMaterials[attrib].pTextureFilename; LPSTR pSlash = strchr(pTexture, '\\'); if (pSlash) { pTexture = ++pSlash; } cout << "{Texture='" << pTexture << "',"; // } string subMeshFilename = string("X_") + string("Armature.ctm"); // string(pTexture).substr(0, strlen(pTexture) - 4) + ".ctm"; subMeshFilename[0] = attrib + 'A'; ExportRangeCTM(table[attrib], g_pMesh, subMeshFilename.c_str()); cout //<< table[attrib].AttribId << ' ' << "FaceStart=" << table[attrib].FaceStart << ',' << "FaceCount=" << table[attrib].FaceCount << ',' << "VertexStart=" << table[attrib].VertexStart << ',' << "VertexCount=" << table[attrib].VertexCount << '}' << endl; } */ pD3DXMtrlBuffer->Release(); // Convert the filename from .X to .CTM while preserving the full path. char destFile[_MAX_PATH]; char drive[_MAX_DRIVE]; char dir[_MAX_DIR]; char fname[_MAX_FNAME]; char ext[_MAX_EXT]; _splitpath_s(sourceFile, drive, _MAX_DRIVE, dir, _MAX_DIR, fname, _MAX_FNAME, ext, _MAX_EXT); _makepath_s(destFile, _MAX_PATH, drive, dir, fname, "ctm"); ExportCTM(g_pMesh, destFile); cout << "Exported " << destFile << endl; /* const WORD MISSING_ATTRIBUTE = 0xffff; WORD positionsOffset = MISSING_ATTRIBUTE; WORD normalsOffset = MISSING_ATTRIBUTE; WORD texCoordsOffset = MISSING_ATTRIBUTE; D3DVERTEXELEMENT9 vertexLayout[MAX_FVF_DECL_SIZE]; D3DVERTEXELEMENT9 endMarker = D3DDECL_END(); g_pMesh->GetDeclaration(vertexLayout); D3DVERTEXELEMENT9* pVertexLayout = &vertexLayout[0]; for (int attrib = 0; attrib < MAX_FVF_DECL_SIZE; ++attrib, pVertexLayout++) { if (0 == memcmp(&vertexLayout[attrib], &endMarker, sizeof(endMarker))) { break; } if (pVertexLayout->Stream != 0) { cout << "Nonzero stream: " << pVertexLayout->Stream << endl; continue; } if (pVertexLayout->Usage == D3DDECLUSAGE_POSITION && pVertexLayout->Type == D3DDECLTYPE_FLOAT3) { cout << "Contains positions " << (int) pVertexLayout->UsageIndex << endl; positionsOffset = pVertexLayout->Offset; } else if (pVertexLayout->Usage == D3DDECLUSAGE_NORMAL && pVertexLayout->Type == D3DDECLTYPE_FLOAT3) { cout << "Contains normals " << (int) pVertexLayout->UsageIndex << endl; normalsOffset = pVertexLayout->Offset; } else if (pVertexLayout->Usage == D3DDECLUSAGE_TEXCOORD && pVertexLayout->Type == D3DDECLTYPE_FLOAT2) { cout << "Contains texture coordinates " << (int) pVertexLayout->UsageIndex << endl; texCoordsOffset = pVertexLayout->Offset; } else { cout << "Mysterious attribute" << endl; } } // Check that we support the format of the data. if (positionsOffset == MISSING_ATTRIBUTE) { exit(1); } // Obtain vertex & index counts from the D3D mesh; allocate memory for the CTM mesh. DWORD dwVertexCount = g_pMesh->GetNumVertices(); DWORD dwTriangleCount = g_pMesh->GetNumFaces(); DWORD dwIndexCount = dwTriangleCount * 3; // Lock down the verts and pluck out the positions and normals. { void* pData = 0; if (S_OK != g_pMesh->LockVertexBuffer(0, &pData)) { exit(1); } if (positionsOffset != MISSING_ATTRIBUTE) { unsigned char* pSource = ((unsigned char*) pData) + positionsOffset; DWORD dwSourceStride = g_pMesh->GetNumBytesPerVertex(); DWORD dwDestStride = sizeof(CTMfloat) * 3; for (DWORD dwVertex = 0; dwVertex < dwVertexCount; ++dwVertex) { float* pFloat = (float*) pSource; *pFloat = -*pFloat; //*pFloat = -*pFloat; pSource += dwSourceStride; } } g_pMesh->UnlockVertexBuffer(); } // Lock down the indices and convert them to unsigned 32-bit integers. { void* pData = 0; g_pMesh->LockIndexBuffer(0, &pData); DWORD dwOptions = g_pMesh->GetOptions(); DWORD dwSourceStride = (dwOptions & D3DXMESH_32BIT) ? 4 : 2; unsigned char* pSource = (unsigned char*) pData; for (DWORD dwIndex = 0; dwIndex < dwIndexCount / 3; ++dwIndex) { unsigned short* inds = (unsigned short*) pSource; std::swap(inds[0], inds[1]); pSource += dwSourceStride * 3; } g_pMesh->UnlockIndexBuffer(); } D3DXSaveMeshToX(L"new.x", g_pMesh, 0, d3dxMaterials, d3dxEffects, g_dwNumMaterials, D3DXF_FILEFORMAT_BINARY | D3DXF_FILEFORMAT_COMPRESSED); cout << "Saved." << endl; */ }
void optimizePhysXMesh(int flag, IDirect3DDevice9* D3DDevice, float epsilon, std::vector<physx::PxVec3>& pxVertices, oiram::IndexBuffer& indexBuffer) { assert(D3DDevice); D3DVERTEXELEMENT9 szDecl[] = { {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, {0xFF, 0, D3DDECLTYPE_UNUSED, 0, 0, 0} }; // 创建D3D MESH LPD3DXMESH pMesh = 0; DWORD options = D3DXMESH_SYSTEMMEM | D3DXMESH_DYNAMIC; if (indexBuffer.use32BitIndices) options |= D3DXMESH_32BIT; DWORD numVertices = static_cast<DWORD>(pxVertices.size()), numFaces = numVertices / 3; HRESULT hr = D3DXCreateMesh(numFaces, numVertices, options, szDecl, D3DDevice, &pMesh); if (SUCCEEDED(hr)) { LPVOID pData = nullptr; // 填充Index Buffer if (SUCCEEDED(pMesh->LockIndexBuffer(D3DLOCK_DISCARD, &pData))) { if (indexBuffer.use32BitIndices) memcpy(pData, indexBuffer.uiIndexBuffer.data(), indexBuffer.uiIndexBuffer.size() * sizeof(physx::PxU32)); else memcpy(pData, indexBuffer.usIndexBuffer.data(), indexBuffer.usIndexBuffer.size() * sizeof(physx::PxU16)); pMesh->UnlockIndexBuffer(); } // 填充Vertex Buffer if (SUCCEEDED(pMesh->LockVertexBuffer(D3DLOCK_DISCARD, &pData))) { memcpy(pData, pxVertices.data(), pxVertices.size() * sizeof(physx::PxVec3)); pMesh->UnlockVertexBuffer(); } // 进行Mesh优化 DWORD dwFaces = pMesh->GetNumFaces(); std::vector<DWORD> szAdjacencies(dwFaces * 3); DWORD* pAdjacency = &szAdjacencies[0]; pMesh->GenerateAdjacency(epsilon, pAdjacency); // 清理mesh hr = D3DXCleanMesh(D3DXCLEAN_SIMPLIFICATION, pMesh, pAdjacency, &pMesh, pAdjacency, NULL); if (SUCCEEDED(hr)) { // 去除mesh中重复的顶点 hr = D3DXWeldVertices(pMesh, D3DXWELDEPSILONS_WELDALL, NULL, pAdjacency, pAdjacency, NULL, NULL); if (SUCCEEDED(hr)) { // 将优化后的数据写回mesh data DWORD numIndices = pMesh->GetNumFaces() * 3; indexBuffer.use32BitIndices = numIndices > 65535; if (indexBuffer.use32BitIndices) indexBuffer.uiIndexBuffer.resize(numIndices); else indexBuffer.usIndexBuffer.resize(numIndices); // 取出Index Buffer if (SUCCEEDED(pMesh->LockIndexBuffer(D3DLOCK_READONLY | D3DLOCK_DISCARD, &pData))) { if (indexBuffer.use32BitIndices) memcpy(indexBuffer.uiIndexBuffer.data(), pData, indexBuffer.uiIndexBuffer.size() * sizeof(physx::PxU32)); else memcpy(indexBuffer.usIndexBuffer.data(), pData, indexBuffer.usIndexBuffer.size() * sizeof(physx::PxU16)); pMesh->UnlockIndexBuffer(); } // 取出Vertex Buffer DWORD dwVertices = pMesh->GetNumVertices(); pxVertices.resize(dwVertices); if (SUCCEEDED(pMesh->LockVertexBuffer(D3DLOCK_READONLY | D3DLOCK_DISCARD, &pData))) { memcpy(pxVertices.data(), pData, pxVertices.size() * sizeof(physx::PxVec3)); pMesh->UnlockVertexBuffer(); } } } pMesh->Release(); } }
//------------------------------------------------------------------------------------------------ // Name: XMesh // Desc: Constructs the subset geometry for a D3DXMesh //------------------------------------------------------------------------------------------------ bool XMesh::buildGeometryFromD3DXMesh(LPD3DXMESH d3dxMesh, SubsetGeometry* subsetGeometry, DWORD subsets) { // Check parameters if (APP_ERROR(!d3dxMesh || !subsetGeometry)("Invalid parameter to XMesh::buildGeometryFromD3DXMesh")) return false; // Add a reference to the mesh to counteract freeing it at the end d3dxMesh->AddRef(); // Get the device LPDIRECT3DDEVICE9 pd3dDevice = NULL; d3dxMesh->GetDevice(&pd3dDevice); // If this mesh isn't already in the correct format, have D3D do the grunt work of // converting it. bool generate_normals = false; // Whether or not normals need to be generated for this mesh if ((d3dxMesh->GetFVF() != D3DFVF_GEOMETRYVERTEX) || (D3DFMT_GEOMETRYINDEX == D3DFMT_INDEX32) && ((d3dxMesh->GetOptions() & D3DXMESH_32BIT) == 0)) { // Holds the mesh when its converted to the correct format LPD3DXMESH pTemd3dxMesh = NULL; // Duplicate the loaded mesh into the format if (APP_ERROR(d3dxMesh->CloneMeshFVF( D3DXMESH_SYSTEMMEM | ((D3DFMT_GEOMETRYINDEX == D3DFMT_INDEX32) ? D3DXMESH_32BIT : 0), D3DFVF_GEOMETRYVERTEX, pd3dDevice, &pTemd3dxMesh)) ("XMesh couldn't convert the source geometry format")) { d3dxMesh->Release(); pd3dDevice->Release(); return false; } // Generate normals if they didn't exist generate_normals = ((d3dxMesh->GetFVF()&D3DFVF_NORMAL)!=D3DFVF_NORMAL && (D3DFMT_GEOMETRYINDEX&D3DFVF_NORMAL)!=D3DFVF_NORMAL); // Use this mesh instead d3dxMesh->Release(); d3dxMesh = pTemd3dxMesh; } // The mesh must have its attributes sorted before it can be converted to single strips { // Allocate an adjacency buffer DWORD faces = d3dxMesh->GetNumFaces(); DWORD* pAdjacency = new DWORD[faces * 3]; bool failed = false; if (APP_ERROR(FAILED(d3dxMesh->GenerateAdjacency(ADJACENCY_EPSILON, pAdjacency)))("Unable to generate the mesh adjacency")) failed = true; { // Clean up "bowties" in the mesh that prevent lighting from being calculated correctly LPD3DXMESH cleaned_mesh = NULL; DWORD* cleaned_adjacency = new DWORD[faces * 3]; LPD3DXBUFFER errors_and_warnings = NULL; if (!failed && APP_ERROR(FAILED(D3DXCleanMesh(D3DXCLEAN_BOWTIES, d3dxMesh, pAdjacency, &cleaned_mesh, cleaned_adjacency, &errors_and_warnings))) ("Failed to clean mesh")) { failed = true; if (errors_and_warnings) { DEBUG_ERROR("Mesh cleaning error: %s", (const char*)errors_and_warnings->GetBufferPointer()); } } SAFE_RELEASE(errors_and_warnings); // If we successfully cleaned the mesh, use the new mesh and new set of // adjacencies. Otherwise, just delete anything that was allocated and // keep the original. if (failed) { SAFE_DELETE_ARRAY(cleaned_adjacency); SAFE_RELEASE(cleaned_mesh); } else { SAFE_DELETE_ARRAY(pAdjacency); SAFE_RELEASE(d3dxMesh) pAdjacency = cleaned_adjacency; d3dxMesh = cleaned_mesh; } } // Compute mesh normals, if necessary if (!failed && generate_normals && APP_ERROR(FAILED(D3DXComputeNormals(d3dxMesh, pAdjacency)))("Couldn't generate mesh normals")) { failed = true; } // Optimize the mesh if (!failed && APP_ERROR(FAILED(d3dxMesh->OptimizeInplace(D3DXMESHOPT_ATTRSORT, pAdjacency, NULL, NULL, NULL))) ("Couldn't optimize mesh attributes")) { failed = true; } // Get rid of the temporary adjacency buffer SAFE_DELETE_ARRAY(pAdjacency); // Return if there was an error if (failed) { SAFE_RELEASE(d3dxMesh); SAFE_RELEASE(pd3dDevice); return false; } } // Lock the vertex buffer GeometryVertex* pXVertices = NULL; if (APP_ERROR(d3dxMesh->LockVertexBuffer(D3DLOCK_READONLY, (VOID**)&pXVertices))("Couldn't lock source vertex buffer")) { // Erase this mesh d3dxMesh->Release(); pd3dDevice->Release(); // Failure return false; } // Iterate through all of the materials and copy vertex/index data, and assign material // information for the mesh. for (DWORD subset = 0; subset < subsets; subset++) { // Use D3DX to convert this subset into a nicely indexed form DWORD numStripIndices; LPDIRECT3DINDEXBUFFER9 pSubsetIB; if (APP_ERROR(D3DXConvertMeshSubsetToSingleStrip(d3dxMesh, subset, D3DXMESH_SYSTEMMEM, &pSubsetIB, &numStripIndices))("Couldn't convert mesh subset into indexable strip")) { // Erase any geometry we made DeallocateGeometry(subsetGeometry); // Get rid of the mesh d3dxMesh->UnlockVertexBuffer(); d3dxMesh->Release(); // Free our device pd3dDevice->Release(); // Return the error return false; } D3DINDEXBUFFER_DESC desc; GeometryIndex* pXIndices = NULL; // Check the format of the indices and lock the strip index buffer if (APP_ERROR(pSubsetIB->GetDesc(&desc))("Couldn't get .X mesh IB desc") || (desc.Format != D3DFMT_GEOMETRYINDEX) || APP_ERROR(pSubsetIB->Lock(0, 0, (VOID**)&pXIndices, D3DLOCK_READONLY))("Unable to lock the .X index buffer")) { // Erase any geometry we made DeallocateGeometry(subsetGeometry); // Get rid of the mesh pSubsetIB->Release(); d3dxMesh->UnlockVertexBuffer(); d3dxMesh->Release(); // Free our device pd3dDevice->Release(); // Error! return false; } // This table pairs an index from the .X file to an index in the buffer that // holds the vertices for this subset XIndicesTable xIndicesTable; // For each of the indices in the strip, puts its vertex ID into the indices // table. Use the counter to determine which vertex this is. { GeometryIndex vertexCounter = 0; for (DWORD e = 0; e < numStripIndices; ++e) { // Insert the entry [x-mesh index, subset index] into the table XIndicesTableInsertResult result = xIndicesTable.insert(XIndicesEntry(pXIndices[e], vertexCounter)); // If the result was successful (this isn't a duplicated X-mesh index) increment the vertex counter if (result.second) vertexCounter++; } } // Grab the number of vertices this geometry uses DWORD numVertices = (DWORD)xIndicesTable.size(); // This buffer holds all of the triangles in this subset TriangleList triangles; // This list keeps track of locations in the strip where the winding order changes. This is necessary // because this next part will remove degenerate triangles from the list. std::set<size_t> windingChanges; // Generate the list of triangles from the strip provided for (DWORD t = 0; t < numStripIndices - 2; ++t) { // Build the triangle that will be added to the buffer // CHANGED July 25, 2008: the winding order is wrong here //Triangle tri = { pXIndices[t + 0], pXIndices[t + 1], pXIndices[t + 2] }; Triangle tri = { pXIndices[t + 0], pXIndices[t + 2], pXIndices[t + 1] }; // Convert the triangle into subset-indices by using the lookup table // we generated before. tri.index[0] = xIndicesTable.find(tri.index[0])->second; tri.index[1] = xIndicesTable.find(tri.index[1])->second; tri.index[2] = xIndicesTable.find(tri.index[2])->second; // Check to make sure this triangle isn't degenerate. If it is, we can just skip // this triangle entirely to simplify the geometry. if (tri.index[0] == tri.index[1] || tri.index[1] == tri.index[2] || tri.index[0] == tri.index[2]) { // Try to find the winding in the list std::set<size_t>::iterator currentWinding = windingChanges.find(triangles.size()); // Add this to the winding change list, or remove the change if it's already there if (currentWinding != windingChanges.end()) windingChanges.erase(currentWinding); else windingChanges.insert(triangles.size()); // Don't insert a triangle here continue; } // Add this triangle to the list triangles.push_back(tri); } // Calculate the number of indices we need for the buffer DWORD numGeometryIndices = (DWORD)(triangles.size() * 3); // Allocate the destination geometry Geometry* pGeometry = NULL; if (APP_ERROR(AllocateGeometry(numVertices, numGeometryIndices, &pGeometry))("Couldn't allocate geometry")) { // Erase any geometry we made DeallocateGeometry(subsetGeometry); // Get rid of the mesh pSubsetIB->Unlock(); pSubsetIB->Release(); d3dxMesh->UnlockVertexBuffer(); d3dxMesh->Release(); // Free our device pd3dDevice->Release(); // Error! return false; } // Copy the vertices needed for this subset into the buffer GeometryVertex* pVertices = pGeometry->pVertices; for (XIndicesIterator i = xIndicesTable.begin(); i != xIndicesTable.end(); ++i) { GeometryVertex* pCurrentVertex = &pVertices[i->second]; *pCurrentVertex = pXVertices[i->first]; // Modify the vertex location to make this a unit mesh sitting on the X-Z plane pCurrentVertex->x = pCurrentVertex->x; pCurrentVertex->y = pCurrentVertex->y; pCurrentVertex->z = pCurrentVertex->z; //pVertices[i->second].color = D3DCOLOR_XRGB(255,255,255); // todo: enable color? } // Copy triangles into the indices buffer DWORD index = 0; GeometryIndex* pIndices = pGeometry->pIndices; DWORD windingOrder = 0; for (TriangleIterator t = triangles.begin(); t != triangles.end(); ++t) { // Find this index in the winding list if (windingChanges.find(index / 3) != windingChanges.end()) windingOrder = 1 - windingOrder; // Alternate the winding order so that everything shows up correctly if ((index / 3) % 2 == windingOrder) { pIndices[index + 0] = t->index[0]; pIndices[index + 1] = t->index[1]; pIndices[index + 2] = t->index[2]; } else { pIndices[index + 0] = t->index[1]; pIndices[index + 1] = t->index[0]; pIndices[index + 2] = t->index[2]; } // Increment the index counter index += 3; } // Unlock and delete strip index buffer pSubsetIB->Unlock(); pSubsetIB->Release(); // Store the buffers in the main array std::pair<SubsetGeometry::iterator,bool> result = subsetGeometry->insert(SubsetGeometry::value_type(subset, pGeometry)); if (APP_ERROR(!result.second)("Couldn't insert subset geometry into main array for .X mesh")) { // Get rid of this geometry DeallocateGeometry(pGeometry); DeallocateGeometry(subsetGeometry); // Erase the mesh d3dxMesh->UnlockVertexBuffer(); d3dxMesh->Release(); // Free our device pd3dDevice->Release(); // Return error return false; } //DEBUG_MSG("Subset %i has %i vertices %i indices (%i polygons)\n", subset, numVertices, numGeometryIndices, numGeometryIndices / 3); } // Done with the DirectX mesh. This will not erase the outside mesh. d3dxMesh->UnlockVertexBuffer(); d3dxMesh->Release(); // Free the device reference pd3dDevice->Release(); // Success return true; }
DWORD MeshParameterization::OnGenerateAtlas( DWORD size, void * params ) { VERIFY_MESSAGE_SIZE( size, sizeof( GENERATEATLASMESSAGE ) ); GENERATEATLASMESSAGE * msg = (GENERATEATLASMESSAGE*)params; if( !msg ) { return MSG_ERROR; } bool bUseIncomingTexCoords = msg->useIncomingTexCoords; GenerateBounds(); HRESULT hr; //This should be changed to use a new mesh parameterization technique DWORD numFaces = (DWORD)m_Faces->size(); DWORD numVertices = (DWORD)m_CollapsedMesh->size(); DWORD curError = 0; if( !bUseIncomingTexCoords && numFaces > 0 && numVertices > 0 ) { DWORD fvf = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1 ; DWORD flags = D3DXMESH_SYSTEMMEM ;// | D3DXMESH_MANAGED ;// | D3DXMESH_SOFTWAREPROCESSING | D3DXMESH_SYSTEMMEM |; LPD3DXMESH mesh = NULL; hr = D3DXCreateMeshFVF( numFaces, numVertices, flags, fvf, m_pDevice, &mesh ); if( FAILED( hr ) ) { curError = GetLastError(); EngineGetToolBox()->Log(LOGERROR, _T("MeshParameterization: Error in create mesh fvf\n")); return MSG_ERROR; } //now fill with data BYTE * vertexData; BYTE * indexData; hr = mesh->LockVertexBuffer( 0, (LPVOID*)&vertexData ); hr = mesh->LockIndexBuffer( 0, (LPVOID*)&indexData ); D3DVERTEXELEMENT9 Decl[ MAX_FVF_DECL_SIZE ]; mesh->GetDeclaration( Decl ); paramVertex * pVertOriginal = (paramVertex*)vertexData; for( int i = 0; i < (int)numVertices; i++ ) { paramVertex * pVert = (paramVertex*)vertexData; pVert->x = (*m_CollapsedMesh)[i].originalPosition.x; pVert->y = (*m_CollapsedMesh)[i].originalPosition.y; pVert->z = (*m_CollapsedMesh)[i].originalPosition.z; pVert->nx = -(*m_CollapsedMesh)[i].normal.x; pVert->ny = -(*m_CollapsedMesh)[i].normal.y; pVert->nz = -(*m_CollapsedMesh)[i].normal.z; pVert->u = (*m_CollapsedMesh)[i].generatedU; pVert->v = (*m_CollapsedMesh)[i].generatedV; NormalizeUV( pVert->u ); NormalizeUV( pVert->v ); vertexData += sizeof( paramVertex ); } for( int i = 0; i < (int)numFaces; i++ ) { unsigned short * index = (unsigned short*)indexData; index[0] = ( unsigned short )(*m_Faces)[ i ].index[ 0 ]; index[1] = ( unsigned short )(*m_Faces)[ i ].index[ 1 ]; index[2] = ( unsigned short )(*m_Faces)[ i ].index[ 2 ]; indexData += sizeof( unsigned short )*3;//32 bit indices triangles } LPD3DXBUFFER imt; hr = D3DXComputeIMTFromPerVertexSignal( mesh, (const float*)pVertOriginal + 3*sizeof(float), 3, sizeof(paramVertex), 0L, 0, 0, &imt ); mesh->UnlockIndexBuffer(); mesh->UnlockVertexBuffer(); //tensors float * tensors = new float[ 3*numFaces ]; for( int i = 0; i < 3*(int)numFaces; i += 3 ) { tensors[ i ] = 4.f; tensors[ i + 1 ] = 0.f; tensors[ i + 2 ] = 4.f; } //some checks numVertices = mesh->GetNumVertices(); numFaces = mesh->GetNumFaces(); //create adjacency DWORD * adjacency = new DWORD[ 3*numFaces ]; memset( adjacency, 0, sizeof(DWORD)*3*numFaces ); hr = mesh->GenerateAdjacency( 0.001f, adjacency ); //hr = mesh->ConvertPointRepsToAdjacency( NULL, adjacency ); if( FAILED( hr ) ) { curError = GetLastError(); EngineGetToolBox()->Log(LOGERROR, _T("MeshParameterization: Error in generate adjacency\n")); return MSG_ERROR; } /* save to mesh to check model uvs D3DXMATERIAL mat; mat.MatD3D.Ambient.r = mat.MatD3D.Ambient.a =mat.MatD3D.Ambient.b =mat.MatD3D.Ambient.g = 0; mat.MatD3D.Diffuse.r = mat.MatD3D.Diffuse.a =mat.MatD3D.Diffuse.b =mat.MatD3D.Diffuse.g = 1; mat.pTextureFilename = "tex.dds"; D3DXSaveMeshToX( "mesh.x", mesh, adjacency, &mat, NULL, 0, D3DXF_FILEFORMAT_TEXT ); */ float * imtTensor = tensors;//(float*)imt->GetBufferPointer(); float stretchout; unsigned int charts; LPD3DXMESH meshOut = NULL; LPD3DXBUFFER remappedData = NULL; LPD3DXBUFFER faceData = NULL; D3DXATTRIBUTERANGE Attrib; memset(&Attrib, 0, sizeof(D3DXATTRIBUTERANGE)); Attrib.FaceCount = numFaces; Attrib.VertexCount = numVertices; mesh->SetAttributeTable(&Attrib, 1); int gutter = m_TexSize / 32; gutter = min( gutter, 6 ); hr = D3DXUVAtlasCreate( mesh, 0, .5, m_TexSize, m_TexSize, 6, //gutter 0, adjacency, 0, imtTensor, (LPD3DXUVATLASCB)UVGenCallback, .0001f, 0, //D3DXUVATLAS_GEODESIC_QUALITY , D3DXUVATLAS_GEODESIC_FAST, &meshOut, &faceData, &remappedData, &stretchout, &charts ); if( FAILED( hr ) ) { curError = GetLastError(); EngineGetToolBox()->Log(LOGERROR, _T("MeshParameterization: Error in uv atlas create\n")); return MSG_ERROR; } /* save to mesh to check model uvs hr = meshOut->ConvertPointRepsToAdjacency( NULL, adjacency ); D3DXSaveMeshToX( "mesh2.x", meshOut, adjacency, &mat, NULL, 0, D3DXF_FILEFORMAT_TEXT ); */ delete [] adjacency; delete [] tensors; //Generate our lightmap cache data for passing on and saving GenerateCache( meshOut, remappedData ); GenerateTriangleTexelData(); meshOut->Release(); faceData->Release(); remappedData->Release(); mesh->Release(); } else if( bUseIncomingTexCoords ) { GenerateCache(); GenerateTriangleTexelData(); } return MSG_HANDLED_STOP; }