MeshContainer* XFileLoader::CreateMeshContainer() { HRESULT hr; MeshContainer* meshContainer = NULL; Graphics* graphics = Graphics::GetInstance(); IDirect3DDevice9Ptr pD3DDevice = graphics->GetDirect3DDevice(); if( !(m_pD3DMesh->GetFVF() & D3DFVF_NORMAL) ) { LPD3DXMESH tmpMesh = NULL; // 柔軟な頂点フォーマット (FVF) コードを使ってメッシュのコピーを作成する hr = m_pD3DMesh->CloneMeshFVF( m_pD3DMesh->GetOptions(), m_pD3DMesh->GetFVF() | D3DFVF_NORMAL, pD3DDevice, &tmpMesh); // ←ここにコピー if(FAILED(hr)) { goto exit; } // メッシュに含まれる各頂点の法線を計算して、設定する //D3DXComputeNormals( tmpMesh, reinterpret_cast<DWORD*>(pAdjacencyBuf->GetBufferPointer()) ); D3DXComputeNormals( tmpMesh, NULL ); m_pD3DMesh->Release(); m_pD3DMesh = tmpMesh; } D3DVERTEXELEMENT9 pDecl[MAX_FVF_DECL_SIZE]; hr = m_pD3DMesh->GetDeclaration(pDecl); if( FAILED(hr) ) { goto exit; } DWORD vertexNum = m_pD3DMesh->GetNumVertices(); DWORD faceNum = m_pD3DMesh->GetNumFaces(); DWORD attrNum = 0; m_pD3DMesh->GetAttributeTable(NULL, &attrNum); DWORD size = m_pD3DMesh->GetNumBytesPerVertex(); BYTE* pD3DVertice = NULL; m_pD3DMesh->LockVertexBuffer( 0,(LPVOID*)&pD3DVertice ); sVertex* vertices = new sVertex[vertexNum]; for( DWORD vertIdx = 0;vertIdx<vertexNum;vertIdx++ ) { sVertex* vertex = &vertices[vertIdx]; vertex->uv = D3DXVECTOR2(0.0f,0.0f); vertex->color = 0xFFFFFFFF; for( DWORD i=0;i<MAX_FVF_DECL_SIZE;i++ ) { D3DVERTEXELEMENT9& decl = pDecl[i]; if( decl.Stream==0xFF ) { break; } switch( decl.Usage ) { case D3DDECLUSAGE_POSITION: vertex->position = *(D3DXVECTOR3*)(pD3DVertice+vertIdx*size+decl.Offset); vertex->position = vertex->position * m_scale; break; case D3DDECLUSAGE_NORMAL: vertex->normal = *(D3DXVECTOR3*)(pD3DVertice+vertIdx*size+decl.Offset); break; case D3DDECLUSAGE_TEXCOORD: vertex->uv = *(D3DXVECTOR2*)(pD3DVertice+vertIdx*size+decl.Offset); break; case D3DDECLUSAGE_COLOR: vertex->color = *(DWORD*)(pD3DVertice+vertIdx*size+decl.Offset); break; } } } m_pD3DMesh->UnlockVertexBuffer(); LPDIRECT3DINDEXBUFFER9 pIndexBuffer = NULL; m_pD3DMesh->GetIndexBuffer( &pIndexBuffer ); D3DINDEXBUFFER_DESC desc; pIndexBuffer->GetDesc( &desc ); pIndexBuffer->Release(); DWORD* indices = new DWORD[faceNum*3]; if( desc.Format==D3DFMT_INDEX16 ) { WORD* pD3DIndices = NULL; m_pD3DMesh->LockIndexBuffer(0,(LPVOID*)&pD3DIndices ); for( DWORD i=0;i<faceNum*3;i++ ) { indices[i] = pD3DIndices[i]; } m_pD3DMesh->UnlockIndexBuffer(); } else { DWORD* pD3DIndices =NULL; m_pD3DMesh->LockIndexBuffer(0,(LPVOID*)&pD3DIndices ); memcpy( indices,pD3DIndices,sizeof(DWORD)*faceNum*3 ); m_pD3DMesh->UnlockIndexBuffer(); } D3DXATTRIBUTERANGE *attrList = new D3DXATTRIBUTERANGE[attrNum]; m_pD3DMesh->GetAttributeTable(attrList, &attrNum); meshContainer = new MeshContainer; meshContainer->pMesh = new Mesh; meshContainer->pMesh->Create( vertexNum,faceNum,attrNum ); meshContainer->pMesh->SetVertices( vertices ); meshContainer->pMesh->SetIndices( indices ); meshContainer->pMesh->SetAttributeRanges( attrList ); delete[] vertices; delete[] indices; delete[] attrList; meshContainer->materialNum = m_Materials; meshContainer->pMaterials = new sMaterial[m_Materials]; D3DXMATERIAL* pD3DMaterials = (D3DXMATERIAL*)m_pMaterialBuf->GetBufferPointer(); for( DWORD i=0;i<m_Materials;i++ ) { sMaterial* pMaterial = &meshContainer->pMaterials[i]; D3DXMATERIAL* pD3DMaterial = &pD3DMaterials[i]; pMaterial->colorDiffuse = pD3DMaterial->MatD3D.Diffuse; pMaterial->colorSpecular.r = pD3DMaterial->MatD3D.Specular.r; pMaterial->colorSpecular.g = pD3DMaterial->MatD3D.Specular.g; pMaterial->colorSpecular.b = pD3DMaterial->MatD3D.Specular.b; pMaterial->colorSpecular.a = 0.0f; pMaterial->colorAmbient.r = pD3DMaterial->MatD3D.Diffuse.r; pMaterial->colorAmbient.g = pD3DMaterial->MatD3D.Diffuse.g; pMaterial->colorAmbient.b = pD3DMaterial->MatD3D.Diffuse.b; pMaterial->colorAmbient.a = 0.0f; pMaterial->colorEmissive.r = pD3DMaterial->MatD3D.Emissive.r; pMaterial->colorEmissive.g = pD3DMaterial->MatD3D.Emissive.g; pMaterial->colorEmissive.b = pD3DMaterial->MatD3D.Emissive.b; pMaterial->colorEmissive.a = 0.0f; pMaterial->specularPower = pD3DMaterial->MatD3D.Power; TCHAR path[MAX_PATH]; _tcscpy_s( path,m_path.c_str() ); tstring texFileName; tstring sphereFileName; if( pD3DMaterial->pTextureFilename && strlen(pD3DMaterial->pTextureFilename)>0 ) { tstring filename = to_tstring(pD3DMaterial->pTextureFilename); tstring::size_type index = filename.find( _T("*") ); if( index != tstring::npos ) { sphereFileName = filename.substr( index+1 ); PathAppend( path,sphereFileName.c_str() ); sphereFileName = path; PathRemoveFileSpec( path ); texFileName = filename.erase( index ); PathAppend( path,texFileName.c_str() ); texFileName = path; PathRemoveFileSpec( path ); } else { texFileName = filename; PathAppend( path,texFileName.c_str() ); texFileName = path; PathRemoveFileSpec( path ); } tstring ext = PathFindExtension( texFileName.c_str() ); if( ext == _T(".sph" ) || ext == _T(".spa") ) { sphereFileName = texFileName; texFileName = _T(""); } } if( !texFileName.empty() ) { TexturePtr pTex = ResourceManager::GetInstance().GetResource<Texture>( texFileName ); if( !pTex ) { pTex = TexturePtr(new Texture); if( pTex->CreateFromFile( texFileName ) ) { ResourceManager::GetInstance().AddResource( texFileName,pTex ); } else { pTex.reset(); } } if( pTex ) { pMaterial->textureDiffuse = pTex; } } if( !sphereFileName.empty() ) { TexturePtr pTex = ResourceManager::GetInstance().GetResource<Texture>( sphereFileName ); if( !pTex ) { pTex = TexturePtr(new Texture); if( pTex->CreateFromFile( sphereFileName ) ) { ResourceManager::GetInstance().AddResource( sphereFileName,pTex ); } else { pTex.reset(); } } if( pTex ) { pMaterial->textureSphere = pTex; } tstring ext = PathFindExtension( sphereFileName.c_str() ); if( ext == _T(".sph" ) ) { pMaterial->spheremap = eSPHEREMAP_MUL; } else if( ext == _T(".spa") ) { pMaterial->spheremap = eSPHEREMAP_ADD; } } } exit: if( m_pMaterialBuf ) { m_pMaterialBuf->Release(); m_pMaterialBuf = NULL; } if( m_pEffectInstancesBuf ) { m_pEffectInstancesBuf->Release(); m_pEffectInstancesBuf = NULL; } if( m_pAdjacencyBuf ) { m_pAdjacencyBuf->Release(); m_pAdjacencyBuf = NULL; } if( m_pD3DMesh ) { m_pD3DMesh->Release(); m_pD3DMesh = NULL; } return meshContainer; }
bool GStillEntity::checkIntersect ( const D3DXVECTOR4& vPos, /*世界坐标系中的点 */ const D3DXVECTOR4& vDir, /*世界坐标系中的向量 */ bool bInsectInfo /*是 裥枰鲎残畔?*/ ) { HRESULT hr = S_FALSE; //将Pos和Dir转换到物体本地坐标系中 D3DXMATRIX matWorld = getTrans()->getLocalD3D(); D3DXMatrixInverse ( &matWorld, NULL, &matWorld ); D3DXVec4Transform ( ( D3DXVECTOR4 * ) &vDir, ( D3DXVECTOR4 * ) &vDir, &matWorld ); D3DXVec3Normalize ( ( D3DXVECTOR3* ) &vDir, ( D3DXVECTOR3* ) &vDir ); D3DXVec4Transform ( ( D3DXVECTOR4 * ) &vPos, ( D3DXVECTOR4 * ) &vPos, &matWorld ); if ( mMeshForInsect == NULL ) { recreateInsectMesh(); } BOOL bHit = FALSE; hr = D3DXIntersect ( mMeshForInsect, ( D3DXVECTOR3* ) &vPos, ( D3DXVECTOR3* ) &vDir, &bHit, &m_InsectInfo.dwFaceIndex, &m_InsectInfo.u, &m_InsectInfo.v, &m_InsectInfo.fDist, NULL, NULL ); mNodeState.setBit ( eObjState_Picked, ( bool ) bHit ); dDebugMsgBox ( hr, "碰撞失败!" ); if ( FAILED ( hr ) ) { return false; } if ( bInsectInfo && mNodeState[eObjState_Picked] ) { D3DXVECTOR3 v[3]; DWORD dwIndex[3]; //先要获取索引缓冲区格式 LPDIRECT3DINDEXBUFFER9 pI = NULL; mMeshForInsect->GetIndexBuffer ( &pI ); D3DINDEXBUFFER_DESC indexDesc; dMemoryZero ( &indexDesc, sizeof ( D3DINDEXBUFFER_DESC ) ); if ( pI != NULL ) { pI->GetDesc ( &indexDesc ); } if ( indexDesc.Format== D3DFMT_INDEX16 ) { WORD *pIndexData16; hr = mMeshForInsect->LockIndexBuffer ( D3DLOCK_READONLY, ( void** ) &pIndexData16 ); dwIndex[0] = pIndexData16[m_InsectInfo.dwFaceIndex * 3 + 0]; dwIndex[1] = pIndexData16[m_InsectInfo.dwFaceIndex * 3 + 1]; dwIndex[2] = pIndexData16[m_InsectInfo.dwFaceIndex * 3 + 2]; } else { DWORD *pIndexData32; hr = mMeshForInsect->LockIndexBuffer ( D3DLOCK_READONLY, ( void** ) &pIndexData32 ); dwIndex[0] = pIndexData32[m_InsectInfo.dwFaceIndex * 3 + 0]; dwIndex[1] = pIndexData32[m_InsectInfo.dwFaceIndex * 3 + 1]; dwIndex[2] = pIndexData32[m_InsectInfo.dwFaceIndex * 3 + 2]; } mMeshForInsect->UnlockIndexBuffer(); D3DXVECTOR3 *pVertexData; hr = mMeshForInsect->LockVertexBuffer ( D3DLOCK_READONLY, ( void** ) &pVertexData ); v[0] = pVertexData[dwIndex[0]]; v[1] = pVertexData[dwIndex[1]]; v[2] = pVertexData[dwIndex[2]]; mMeshForInsect->UnlockVertexBuffer(); D3DXVECTOR4 vNormal ( ZEROFLOAT, ZEROFLOAT, ZEROFLOAT, ZEROFLOAT ); D3DXVECTOR4 vHitPos ( ZEROFLOAT, ZEROFLOAT, ZEROFLOAT, ZEROFLOAT ); D3DXVECTOR3 vTmp1, vTmp2; vTmp1 = v[1] - v[0]; vTmp2 = v[2] - v[0]; vHitPos = ( D3DXVECTOR4 ) v[0] + m_InsectInfo.u * ( D3DXVECTOR4 ) vTmp1 + m_InsectInfo.v * ( D3DXVECTOR4 ) vTmp2; vHitPos.w = 1; updateWorld (); D3DXVec4Transform ( &vHitPos, &vHitPos, &getTrans()->getLocalD3D() ); m_InsectInfo.vHitPos = D3DXVECTOR3 ( vHitPos.x, vHitPos.y, vHitPos.z ); D3DXVec3Cross ( ( D3DXVECTOR3* ) &vNormal, &vTmp1, &vTmp2 ); vNormal.w = 0; D3DXVec4Transform ( &vNormal, &vNormal, &matWorld ); D3DXVec3Normalize ( ( D3DXVECTOR3* ) &vNormal, ( D3DXVECTOR3* ) &vNormal ); m_InsectInfo.vNormal = D3DXVECTOR3 ( vNormal.x, vNormal.y, vNormal.z ); } return mNodeState[eObjState_Picked]; }
void CSampleRigidParticlesAndTerrain::InititialisePhysics() { neV3 gravity; gravity.Set(0.0f, -8.0f, 0.0f); neSimulatorSizeInfo sizeInfo; sizeInfo.rigidParticleCount = NUMBER_OF_PARTICLES; sizeInfo.animatedBodiesCount = WALL_NUMBER; sizeInfo.geometriesCount = NUMBER_OF_PARTICLES * GEOMETRY_PER_BODY + WALL_NUMBER; { //dont need any of these sizeInfo.rigidBodiesCount = 0; sizeInfo.constraintsCount = 0; } s32 totalBody = NUMBER_OF_PARTICLES + WALL_NUMBER; sizeInfo.overlappedPairsCount = totalBody * (totalBody - 1) / 2; sim = neSimulator::CreateSimulator(sizeInfo, &all, &gravity); neV3 position; position.SetZero(); for (s32 j = 0; j < NUMBER_OF_PARTICLES; j++) { position.Set(0.0f, 2.0f * j + 20.0f, 0.0f); //position.Set(13.5f, 20.0f, 1.5f); MakeParticle(position, j); } //SetUpTerrain terrainRender.SetGraphicMesh(L"model\\landscape2.x"); terrainRender.SetDiffuseColor(D3DXCOLOR(0.1f,0.5f,0.1f,1.0f)); LPD3DXMESH lpterrainD3Dmesh = terrainRender.mMesh.GetMesh(); neTriangleMesh triMesh; triMesh.vertexCount = lpterrainD3Dmesh->GetNumVertices(); triMesh.triangleCount = lpterrainD3Dmesh->GetNumFaces(); neV3 * verts = new neV3[triMesh.vertexCount]; // DWORD dwFVF = lpterrainD3Dmesh->GetFVF(); DWORD dwOptions = lpterrainD3Dmesh->GetOptions(); DWORD dwNumFaces = lpterrainD3Dmesh->GetNumFaces(); DWORD dwNumVertices = lpterrainD3Dmesh->GetNumVertices(); DWORD dwBytes = lpterrainD3Dmesh->GetNumBytesPerVertex(); LPDIRECT3DVERTEXBUFFER9 pVB; lpterrainD3Dmesh->GetVertexBuffer(&pVB); byte* pBuffer; pVB->Lock(0, 0, (void**)&pBuffer, 0); byte* pPointer = pBuffer; for (int i = 0;i< triMesh.vertexCount;i++) { if (dwFVF & D3DFVF_XYZ) { D3DVECTOR *d3dvector; d3dvector = (D3DVECTOR*)pPointer; verts[i].Set(d3dvector->x,d3dvector->y,d3dvector->z); pPointer += sizeof(D3DVECTOR); } //if (dwFVF & D3DFVF_NORMAL) //{ // //don't care the NORMAL data // pPointer += sizeof(D3DVECTOR); //} //if (dwFVF & D3DFVF_TEX1) //{ // pPointer += 8; //} pPointer += dwBytes - sizeof(D3DVECTOR); } pVB->Unlock(); pVB->Release(); // triMesh.vertices = verts; neTriangle * tri = new neTriangle[triMesh.triangleCount]; s32 * triindex = new s32[triMesh.triangleCount * 3]; // LPDIRECT3DINDEXBUFFER9 pIB; lpterrainD3Dmesh->GetIndexBuffer(&pIB); D3DINDEXBUFFER_DESC kDesc; pIB->GetDesc(&kDesc); dwBytes = 0; if (kDesc.Format & D3DFMT_INDEX16) { dwBytes = 2 * sizeof(byte); } else if (kDesc.Format & D3DFMT_INDEX32) { dwBytes = 4 * sizeof(byte); } pIB->Lock(0, 0, (void**)&pBuffer, 0); pPointer = pBuffer; while ((pPointer - pBuffer) < kDesc.Size) { if (dwBytes == 2*sizeof(byte)) { //16bit triindex[(pPointer-pBuffer)/dwBytes] = *((s16*)pPointer); } else if (dwBytes == 4*sizeof(byte)) { //32bit triindex[(pPointer-pBuffer)/dwBytes] = *((s32*)pPointer); } pPointer += dwBytes; } pIB->Unlock(); pIB->Release(); // for (s32 i = 0; i < triMesh.triangleCount; i++) { tri[i].indices[0] = triindex[i * 3]; tri[i].indices[1] = triindex[i * 3 + 1]; tri[i].indices[2] = triindex[i * 3 + 2]; tri[i].materialID = 0; tri[i].flag = neTriangle::NE_TRI_TRIANGLE; //tri[i].flag = neTriangle::NE_TRI_HEIGHT_MAP; } triMesh.triangles = tri; sim->SetTerrainMesh(&triMesh); //SetUpRoom ground = sim->CreateAnimatedBody(); neGeometry * geom = ground->AddGeometry(); geom->SetBoxSize(gFloor.boxSize); ground->UpdateBoundingInfo(); ground->SetPos(gFloor.pos); groundRender.SetGraphicBox(gFloor.boxSize[0], gFloor.boxSize[1], gFloor.boxSize[2]); }
//------------------------------------------------------------------------------------------------ // 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; }