PROTECTED void _MDLOptimize(LPD3DXMESH mesh, const LPD3DXBUFFER pAdjacencyBuffer, int numInd, LPD3DXMESH *optMesh) { HRESULT hr; DWORD *rgdwAdjacencyTemp = 0; LPD3DXMESH tempMesh; DWORD dw32Bit = mesh->GetOptions() & D3DXMESH_32BIT; // allocate a second adjacency buffer to store post attribute sorted adjacency if(MemAlloc((void**)&rgdwAdjacencyTemp, sizeof(DWORD)*numInd, M_ZERO) != RETCODE_SUCCESS) { ASSERT_MSG(0, "Unable to allocate rgdwAdjacencyTemp", "Error in _MDLOptimize"); goto End; } // attribute sort - the un-optimized mesh option // remember the adjacency for the vertex cache optimization hr = mesh->OptimizeInplace( D3DXMESHOPT_COMPACT|D3DXMESHOPT_ATTRSORT, (DWORD*)pAdjacencyBuffer->GetBufferPointer(), rgdwAdjacencyTemp, NULL, NULL); if( FAILED(hr) ) goto End; // snapshot the attribute sorted mesh, shown as the un-optimized version hr = mesh->CloneMeshFVF( dw32Bit|D3DXMESH_MANAGED, mesh->GetFVF(), g_p3DDevice, &tempMesh ); if( FAILED(hr) ) goto End; // actually do the vertex cache optimization hr = mesh->OptimizeInplace( D3DXMESHOPT_COMPACT|D3DXMESHOPT_ATTRSORT|D3DXMESHOPT_VERTEXCACHE, rgdwAdjacencyTemp, NULL, NULL, NULL); if( FAILED(hr) ) goto End; // snapshot as the optimized mesh hr = mesh->CloneMeshFVF( dw32Bit|D3DXMESH_MANAGED, mesh->GetFVF(), g_p3DDevice, optMesh ); if( FAILED(hr) ) goto End; End: if(rgdwAdjacencyTemp) MemFree((void**)&rgdwAdjacencyTemp); if(tempMesh) tempMesh->Release(); }
HRESULT D3DXMeshTransformation( LPD3DXMESH pMesh, const D3DXMATRIX* pMatrix , VisitorForD3DXVECTOR3* pPointFilter) { KG_PROCESS_ERROR(NULL != pMesh && NULL != pMatrix); { DWORD fvf = pMesh->GetFVF(); KG_PROCESS_ERROR(fvf | D3DFVF_XYZ); DWORD dwNumBytePerVertex = pMesh->GetNumBytesPerVertex(); _ASSERTE(dwNumBytePerVertex >= sizeof(D3DXVECTOR3)); DWORD dwNumVertex = pMesh->GetNumVertices(); BYTE* pBufferStart = NULL; _ASSERTE(sizeof(BYTE) == 1); if(NULL == pPointFilter) { HRESULT hr = pMesh->LockVertexBuffer(0, (LPVOID*)&pBufferStart); KG_COM_PROCESS_ERROR(hr); D3DXVec3TransformCoordArray((D3DXVECTOR3*)(pBufferStart), dwNumBytePerVertex , (D3DXVECTOR3*)pBufferStart, dwNumBytePerVertex, pMatrix, dwNumVertex); pMesh->UnlockVertexBuffer(); } else { //加了Filter之后性能下降是当然的,但是这不是给实时用的,所以没有关系,控制 //调用次数和调用时机就好了 D3DXMeshVertexEnumer vertexEnumer; HRESULT hr = D3DXMeshCreateVertexEnumer(pMesh, vertexEnumer); KG_COM_PROCESS_ERROR(hr); _ASSERTE(vertexEnumer.IsValid()); HRESULT hrForVisitor = E_FAIL; for (UINT i = 0; i < vertexEnumer.GetVertexCount(); ++i) { const D3DXVECTOR3& vTemp = vertexEnumer.GetPos(i); hrForVisitor = pPointFilter->Accept(vTemp); if (FAILED(hr)) { continue; } D3DXVECTOR3 vTransformed; D3DXVec3TransformCoord(&vTransformed, &vTemp, pMatrix); vertexEnumer.SetPos(i, vTransformed); } } } return S_OK; Exit0: return E_FAIL; }
HRESULT D3DXMeshCreateVertexEnumer( LPD3DXMESH pMesh, D3DXMeshVertexEnumer& enumer ) { _ASSERTE(! enumer.IsValid()); ZeroMemory(&enumer, sizeof(D3DXMeshVertexEnumer));//因为外部传入的enumer是可能重用的,这里绝对要重新清空一次 _ASSERTE(NULL != pMesh); KG_PROCESS_ERROR(NULL != pMesh); { BOOL bIsAcceptableMesh = pMesh->GetFVF() & D3DFVF_XYZ; KG_PROCESS_ERROR(bIsAcceptableMesh && _T("不支持没有XYZ标志的Mesh,那样不能保证每个节点开头是顶点")); HRESULT hr = pMesh->LockVertexBuffer(0, reinterpret_cast<LPVOID*>(&enumer.m_pBuffer)); KG_COM_PROCESS_ERROR(hr); _ASSERTE(1 == sizeof(BYTE)); enumer.m_pMesh = pMesh; enumer.m_pMesh->AddRef(); enumer.m_dwNumBytePerVertex = pMesh->GetNumBytesPerVertex(); enumer.m_dwNumVertexCount = pMesh->GetNumVertices(); return S_OK; } Exit0: return E_FAIL; }
HRESULT D3DXMeshClone(LPD3DXMESH pSrc, LPD3DXMESH* pCloned) { LPD3DXMESH pMeshCloned = NULL; DWORD dwOption = pSrc->GetOptions(); DWORD fvf = pSrc->GetFVF(); LPDIRECT3DDEVICE9 pDevice = NULL; KG_PROCESS_ERROR(NULL != pSrc && NULL != pCloned); { HRESULT hr = pSrc->GetDevice(&pDevice); KG_COM_PROCESS_ERROR(hr); hr = pSrc->CloneMeshFVF(dwOption, fvf, pDevice, &pMeshCloned); SAFE_RELEASE(pDevice); *pCloned = pMeshCloned; SAFE_RELEASE(pDevice); return S_OK; } Exit0: SAFE_RELEASE(pMeshCloned); SAFE_RELEASE(pDevice); return E_FAIL; }
//----------------------------------------------------------------------------- // Name: InitDeviceObjects() // Desc: Initialize scene objects. //----------------------------------------------------------------------------- HRESULT CMeshRender::InitDeviceObjects() { DWORD cVerticesPerMesh; // Load mesh LPD3DXBUFFER pAdjacencyBuffer = NULL; LPDIRECT3DVERTEXBUFFER9 pVertexBuffer = NULL; LPD3DXMESH pMesh = NULL; LPD3DXPMESH pPMesh = NULL; LPD3DXMESH pTempMesh; LPD3DXBUFFER pD3DXMtrlBuffer = NULL; void* pVertices; TCHAR strMediaPath[512]; HRESULT hr; DWORD dw32BitFlag; DWORD cVerticesMin; DWORD cVerticesMax; DWORD iPMesh; D3DXWELDEPSILONS Epsilons; DWORD i; D3DXMATERIAL* d3dxMaterials; // Find the path to the mesh if( FAILED( DXUtil_FindMediaFileCb( strMediaPath, sizeof(strMediaPath), m_strMeshFilename ) ) ) return E_FAIL;//D3DAPPERR_MEDIANOTFOUND; // Load the mesh from the specified file if( FAILED( hr = D3DXLoadMeshFromX( strMediaPath, D3DXMESH_MANAGED, m_pd3dDevice, &pAdjacencyBuffer, &pD3DXMtrlBuffer, NULL, &m_dwNumMaterials, &pMesh ) ) ) { // hide error so that device changes will not cause exit, shows blank screen instead goto End; } dw32BitFlag = (pMesh->GetOptions() & D3DXMESH_32BIT); // perform simple cleansing operations on mesh if( FAILED( hr = D3DXCleanMesh( pMesh, (DWORD*)pAdjacencyBuffer->GetBufferPointer(), &pTempMesh, (DWORD*)pAdjacencyBuffer->GetBufferPointer(), NULL ) ) ) { m_dwNumMaterials = 0; goto End; } SAFE_RELEASE(pMesh); pMesh = pTempMesh; // Perform a weld to try and remove excess vertices like the model bigship1.x in the DX9.0 SDK (current model is fixed) // Weld the mesh using all epsilons of 0.0f. A small epsilon like 1e-6 works well too memset(&Epsilons, 0, sizeof(D3DXWELDEPSILONS)); if( FAILED( hr = D3DXWeldVertices( pMesh, 0, &Epsilons, (DWORD*)pAdjacencyBuffer->GetBufferPointer(), (DWORD*)pAdjacencyBuffer->GetBufferPointer(), NULL, NULL ) ) ) { m_dwNumMaterials = 0; goto End; } // verify validity of mesh for simplification if( FAILED( hr = D3DXValidMesh( pMesh, (DWORD*)pAdjacencyBuffer->GetBufferPointer(), NULL ) ) ) { m_dwNumMaterials = 0; goto End; } // Allocate a material/texture arrays d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer(); m_mtrlMeshMaterials = new D3DMATERIAL9[m_dwNumMaterials]; m_pMeshTextures = new LPDIRECT3DTEXTURE9[m_dwNumMaterials]; // Copy the materials and load the textures for( i=0; i<m_dwNumMaterials; i++ ) { m_mtrlMeshMaterials[i] = d3dxMaterials[i].MatD3D; m_mtrlMeshMaterials[i].Ambient = m_mtrlMeshMaterials[i].Diffuse; // Find the path to the texture and create that texture DXUtil_FindMediaFileCb( strMediaPath, sizeof(strMediaPath), d3dxMaterials[i].pTextureFilename ); if( FAILED( D3DXCreateTextureFromFile( m_pd3dDevice, strMediaPath, &m_pMeshTextures[i] ) ) ) m_pMeshTextures[i] = NULL; } pD3DXMtrlBuffer->Release(); pD3DXMtrlBuffer = NULL; // Lock the vertex buffer, to generate a simple bounding sphere hr = pMesh->GetVertexBuffer( &pVertexBuffer ); if( FAILED(hr) ) goto End; hr = pVertexBuffer->Lock( 0, 0, &pVertices, D3DLOCK_NOSYSLOCK ); if( FAILED(hr) ) goto End; hr = D3DXComputeBoundingSphere( (D3DXVECTOR3*)pVertices, pMesh->GetNumVertices(), D3DXGetFVFVertexSize(pMesh->GetFVF()), &m_vObjectCenter, &m_fObjectRadius ); pVertexBuffer->Unlock(); pVertexBuffer->Release(); if( FAILED(hr) || m_dwNumMaterials == 0 ) goto End; if ( !(pMesh->GetFVF() & D3DFVF_NORMAL) ) { hr = pMesh->CloneMeshFVF( dw32BitFlag|D3DXMESH_MANAGED, pMesh->GetFVF() | D3DFVF_NORMAL, m_pd3dDevice, &pTempMesh ); if (FAILED(hr)) goto End; D3DXComputeNormals( pTempMesh, NULL ); pMesh->Release(); pMesh = pTempMesh; } hr = D3DXGeneratePMesh( pMesh, (DWORD*)pAdjacencyBuffer->GetBufferPointer(), NULL, NULL, 1, D3DXMESHSIMP_VERTEX, &pPMesh); if( FAILED(hr) ) goto End; cVerticesMin = pPMesh->GetMinVertices(); cVerticesMax = pPMesh->GetMaxVertices(); cVerticesPerMesh = (cVerticesMax - cVerticesMin) / 10; m_cPMeshes = max(1, (DWORD)ceil((cVerticesMax - cVerticesMin) / (float)cVerticesPerMesh)); m_pPMeshes = new LPD3DXPMESH[m_cPMeshes]; if (m_pPMeshes == NULL) { hr = E_OUTOFMEMORY; goto End; } memset(m_pPMeshes, 0, sizeof(LPD3DXPMESH) * m_cPMeshes); // clone full size pmesh hr = pPMesh->ClonePMeshFVF( D3DXMESH_MANAGED | D3DXMESH_VB_SHARE, pPMesh->GetFVF(), m_pd3dDevice, &m_pPMeshFull ); if (FAILED(hr)) goto End; // clone all the separate pmeshes for (iPMesh = 0; iPMesh < m_cPMeshes; iPMesh++) { hr = pPMesh->ClonePMeshFVF( D3DXMESH_MANAGED | D3DXMESH_VB_SHARE, pPMesh->GetFVF(), m_pd3dDevice, &m_pPMeshes[iPMesh] ); if (FAILED(hr)) goto End; // trim to appropriate space hr = m_pPMeshes[iPMesh]->TrimByVertices(cVerticesMin + cVerticesPerMesh * iPMesh, cVerticesMin + cVerticesPerMesh * (iPMesh+1), NULL, NULL); if (FAILED(hr)) goto End; hr = m_pPMeshes[iPMesh]->OptimizeBaseLOD(D3DXMESHOPT_VERTEXCACHE, NULL); if (FAILED(hr)) goto End; } // set current to be maximum number of vertices m_iPMeshCur = m_cPMeshes - 1; hr = m_pPMeshes[m_iPMeshCur]->SetNumVertices(cVerticesMax); if (FAILED(hr)) goto End; hr = m_pPMeshFull->SetNumVertices(cVerticesMax); if (FAILED(hr)) goto End; End: SAFE_RELEASE( pAdjacencyBuffer ); SAFE_RELEASE( pD3DXMtrlBuffer ); SAFE_RELEASE( pMesh ); SAFE_RELEASE( pPMesh ); if (FAILED(hr)) { for (iPMesh = 0; iPMesh < m_cPMeshes; iPMesh++) { SAFE_RELEASE( m_pPMeshes[iPMesh] ); } delete []m_pPMeshes; m_cPMeshes = 0; m_pPMeshes = NULL; SAFE_RELEASE( m_pPMeshFull ) } return hr; }
HRESULT CMyD3DApplication::LoadMeshData ( LPD3DXMESH *ppMesh, LPD3DXBUFFER *ppAdjacencyBuffer ) { LPDIRECT3DVERTEXBUFFER8 pMeshVB = NULL; LPD3DXBUFFER pD3DXMtrlBuffer = NULL; BYTE* pVertices; TCHAR strMesh[512]; HRESULT hr = S_OK; BOOL bNormalsInFile; LPD3DXMESH pMeshSysMem = NULL; LPD3DXMESH pMeshTemp; DWORD *rgdwAdjacencyTemp = NULL; DWORD i; D3DXMATERIAL* d3dxMaterials; DWORD dw32Bit; // Get a path to the media file DXUtil_FindMediaFile( strMesh, m_strMeshFilename ); // Load the mesh from the specified file hr = D3DXLoadMeshFromX( strMesh, D3DXMESH_SYSTEMMEM, m_pd3dDevice, ppAdjacencyBuffer, &pD3DXMtrlBuffer, &m_dwNumMaterials, &pMeshSysMem ); if( FAILED(hr) ) goto End; // remember if the mesh is 32 or 16 bit, to be added in on the clones dw32Bit = pMeshSysMem->GetOptions() & D3DXMESH_32BIT; // Get the array of materials out of the returned buffer, and allocate a texture array d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer(); m_pMeshMaterials = new D3DMATERIAL8[m_dwNumMaterials]; m_pMeshTextures = new LPDIRECT3DTEXTURE8[m_dwNumMaterials]; for( i=0; i<m_dwNumMaterials; i++ ) { m_pMeshMaterials[i] = d3dxMaterials[i].MatD3D; m_pMeshMaterials[i].Ambient = m_pMeshMaterials[i].Diffuse; m_pMeshTextures[i] = NULL; // Get a path to the texture TCHAR strPath[512]; if (d3dxMaterials[i].pTextureFilename != NULL) { DXUtil_FindMediaFile( strPath, d3dxMaterials[i].pTextureFilename ); // Load the texture D3DXCreateTextureFromFile( m_pd3dDevice, strPath, &m_pMeshTextures[i] ); } } // Done with the material buffer SAFE_RELEASE( pD3DXMtrlBuffer ); // Lock the vertex buffer, to generate a simple bounding sphere hr = pMeshSysMem->GetVertexBuffer( &pMeshVB ); if( SUCCEEDED(hr) ) { hr = pMeshVB->Lock( 0, 0, &pVertices, D3DLOCK_NOSYSLOCK ); if( SUCCEEDED(hr) ) { hr = D3DXComputeBoundingSphere( pVertices, pMeshSysMem->GetNumVertices(), pMeshSysMem->GetFVF(), &m_vObjectCenter, &m_fObjectRadius ); pMeshVB->Unlock(); } pMeshVB->Release(); } if( FAILED(hr) ) goto End; // remember if there were normals in the file, before possible clone operation bNormalsInFile = pMeshSysMem->GetFVF() & D3DFVF_NORMAL; // if using 32byte vertices, check fvf if (m_bForce32ByteFVF) { // force 32 byte vertices if (pMeshSysMem->GetFVF() != (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1)) { hr = pMeshSysMem->CloneMeshFVF( pMeshSysMem->GetOptions(), D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1, m_pd3dDevice, &pMeshTemp ); if( FAILED(hr) ) goto End; pMeshSysMem->Release(); pMeshSysMem = pMeshTemp; } } // otherwise, just make sure that there is a normal mesh else if ( !(pMeshSysMem->GetFVF() & D3DFVF_NORMAL) ) { hr = pMeshSysMem->CloneMeshFVF( pMeshSysMem->GetOptions(), pMeshSysMem->GetFVF() | D3DFVF_NORMAL, m_pd3dDevice, &pMeshTemp ); if (FAILED(hr)) return hr; pMeshSysMem->Release(); pMeshSysMem = pMeshTemp; } // Compute normals for the mesh, if not present if (!bNormalsInFile) { D3DXComputeNormals( pMeshSysMem, NULL ); } *ppMesh = pMeshSysMem; pMeshSysMem = NULL; End: SAFE_RELEASE( pMeshSysMem ); return hr; }
HRESULT InitGeometry() { LPD3DXBUFFER pD3DXMtrlBuffer; if ( FAILED( D3DXLoadMeshFromX( L"./Resource/Tiger.x", D3DXMESH_SYSTEMMEM, g_pd3dDevice, NULL, &pD3DXMtrlBuffer, NULL, &g_dwNumMaterials, &g_pMesh ) ) ) { MessageBox( NULL, L"Could not find tiger.x", L"D3D Tutorial", MB_OK ); return E_FAIL; } D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer(); g_pMeshMaterials = new D3DMATERIAL9[g_dwNumMaterials]; if ( g_pMeshMaterials == NULL ) { return E_OUTOFMEMORY; } g_pMeshTextures = new LPDIRECT3DTEXTURE9[g_dwNumMaterials]; if ( g_pMeshTextures == NULL ) { return E_OUTOFMEMORY; } if ( !( g_pMesh->GetFVF() & D3DFVF_NORMAL ) ) { //가지고 있지 않다면 메쉬를 복제하고 D3DFVF_NORMAL을 추가한다. ID3DXMesh* pTempMesh = 0; g_pMesh->CloneMeshFVF( D3DXMESH_MANAGED, g_pMesh->GetFVF() | D3DFVF_NORMAL, g_pd3dDevice, &pTempMesh ); // 법선을 계산한다. D3DXComputeNormals( pTempMesh, 0 ); g_pMesh->Release(); // 기존메쉬를 제거한다 g_pMesh = pTempMesh; // 기존메쉬를 법선이 계산된 메쉬로 지정한다. } 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] = NULL; if ( d3dxMaterials[i].pTextureFilename != NULL && lstrlenA( d3dxMaterials[i].pTextureFilename ) > 0 ) { if ( FAILED( D3DXCreateTextureFromFileA( g_pd3dDevice, d3dxMaterials[i].pTextureFilename, &g_pMeshTextures[i] ) ) ) { const CHAR* strPrefix = "./Resource/"; CHAR strTexture[MAX_PATH]; strcpy_s( strTexture, MAX_PATH, strPrefix ); strcat_s( strTexture, MAX_PATH, d3dxMaterials[i].pTextureFilename ); if ( FAILED( D3DXCreateTextureFromFileA( g_pd3dDevice, strTexture, &g_pMeshTextures[i] ) ) ) { MessageBox( NULL, L"Could not find texture map", L"D3D Tutorial", MB_OK ); } } } } pD3DXMtrlBuffer->Release(); if ( FAILED( D3DXCreateTextureFromFile( g_pd3dDevice, L"./Resource/earth1.bmp", &g_pTexture1 ) ) ) { MessageBox( NULL, L"Could not find earth1.bmp", L"D3D Tutorial", MB_OK ); return E_FAIL; } if ( FAILED( D3DXCreateTextureFromFile( g_pd3dDevice, L"./Resource/earth2.bmp", &g_pTexture2 ) ) ) { MessageBox( NULL, L"Could not find earth2.bmp", L"D3D Tutorial", MB_OK ); return E_FAIL; } if ( FAILED( g_pd3dDevice->CreateVertexBuffer( 50 * 2 * sizeof( CUSTOMVERTEX ), 0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB1, NULL ) ) ) { return E_FAIL; } if ( FAILED( g_pd3dDevice->CreateVertexBuffer( 50 * 2 * sizeof( CUSTOMVERTEX ), 0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB2, NULL ) ) ) { return E_FAIL; } CUSTOMVERTEX* pVertices1; CUSTOMVERTEX* pVertices2; if ( FAILED( g_pVB1->Lock( 0, 0, (void**)&pVertices1, 0 ) ) ) { return E_FAIL; } for ( DWORD i = 0; i < 50; ++i ) { FLOAT theta = ( 2 * D3DX_PI * i ) / ( 50 - 1 ); pVertices1[2 * i + 0].position = D3DXVECTOR3( sinf( theta ) - 2.0f, -1.0f, cosf( theta ) ); pVertices1[2 * i + 0].normal = D3DXVECTOR3( sinf( theta ) - 2.0f, 0.0f, cosf( theta ) ); pVertices1[2 * i + 0].color = 0xffffffff; #ifndef SHOW_HOW_TO_USE_TCI pVertices1[2 * i + 0].tu = ( (FLOAT)i ) / ( 50 - 1 ); pVertices1[2 * i + 0].tv = 1.0f; #endif pVertices1[2 * i + 1].position = D3DXVECTOR3( sinf( theta ) - 2.0f, 1.0f, cosf( theta ) ); pVertices1[2 * i + 1].normal = D3DXVECTOR3( sinf( theta ) - 2.0f, 0.0f, cosf( theta ) ); pVertices1[2 * i + 1].color = 0xff808080; #ifndef SHOW_HOW_TO_USE_TCI pVertices1[2 * i + 1].tu = ( (FLOAT)i ) / ( 50 - 1 ); pVertices1[2 * i + 1].tv = 0.0f; #endif } g_pVB1->Unlock(); if ( FAILED( g_pVB2->Lock( 0, 0, (void**)&pVertices2, 0 ) ) ) { return E_FAIL; } for ( DWORD i = 0; i < 50; ++i ) { FLOAT theta = ( 2 * D3DX_PI * i ) / ( 50 - 1 ); pVertices2[2 * i + 0].position = D3DXVECTOR3( sinf( theta ) + 2.0f, -1.0f, cosf( theta ) ); pVertices2[2 * i + 0].normal = D3DXVECTOR3( sinf( theta ) + 2.0f, 0.0f, cosf( theta ) ); pVertices2[2 * i + 0].color = 0xffffffff; #ifndef SHOW_HOW_TO_USE_TCI pVertices2[2 * i + 0].tu = ( (FLOAT)i ) / ( 50 - 1 ); pVertices2[2 * i + 0].tv = 1.0f; #endif pVertices2[2 * i + 1].position = D3DXVECTOR3( sinf( theta ) + 2.0f, 1.0f, cosf( theta ) ); pVertices2[2 * i + 1].normal = D3DXVECTOR3( sinf( theta ) + 2.0f, 0.0f, cosf( theta ) ); pVertices2[2 * i + 1].color = 0xff808080; #ifndef SHOW_HOW_TO_USE_TCI pVertices2[2 * i + 1].tu = ( (FLOAT)i ) / ( 50 - 1 ); pVertices2[2 * i + 1].tv = 0.0f; #endif } g_pVB2->Unlock(); return S_OK; }
//----------------------------------------------------------------------------- // Name: InitGeometry() // Desc: Load the mesh and build the material and texture arrays //----------------------------------------------------------------------------- HRESULT InitGeometry() { LPD3DXBUFFER pD3DXMtrlBuffer; // Load the mesh from the specified file if( FAILED( D3DXLoadMeshFromX( L"Tiger.x", D3DXMESH_SYSTEMMEM, g_pd3dDevice, NULL, &pD3DXMtrlBuffer, NULL, &g_dwNumMaterials, &g_pMesh ) ) ) { // If model is not in current folder, try parent folder if( FAILED( D3DXLoadMeshFromX( L"..\\Tiger.x", D3DXMESH_SYSTEMMEM, g_pd3dDevice, NULL, &pD3DXMtrlBuffer, NULL, &g_dwNumMaterials, &g_pMesh ) ) ) { MessageBox( NULL, L"Could not find tiger.x", L"Meshes.exe", MB_OK ); return E_FAIL; } } // 메쉬가 버텍스 포멧으로 D3DFVF_NORMAL을 가지고 있는가? if ( !(g_pMesh->GetFVF() & D3DFVF_NORMAL) ) { //가지고 있지 않다면 메쉬를 복제하고 D3DFVF_NORMAL을 추가한다. ID3DXMesh* pTempMesh = 0; g_pMesh->CloneMeshFVF( D3DXMESH_MANAGED, g_pMesh->GetFVF() | D3DFVF_NORMAL, //이곳에 추가 g_pd3dDevice, &pTempMesh ); // 법선을 계산한다. D3DXComputeNormals( pTempMesh, 0 ); g_pMesh->Release(); // 기존메쉬를 제거한다 g_pMesh = pTempMesh; // 기존메쉬를 법선이 계산된 메쉬로 지정한다. } // We need to extract the material properties and texture names from the // pD3DXMtrlBuffer D3DXMATERIAL* d3dxMaterials = ( D3DXMATERIAL* )pD3DXMtrlBuffer->GetBufferPointer(); g_pMeshMaterials = new D3DMATERIAL9[g_dwNumMaterials]; if( g_pMeshMaterials == NULL ) return E_OUTOFMEMORY; g_pMeshTextures = new LPDIRECT3DTEXTURE9[g_dwNumMaterials]; if( g_pMeshTextures == NULL ) return E_OUTOFMEMORY; for( DWORD i = 0; i < g_dwNumMaterials; i++ ) { // Copy the material g_pMeshMaterials[i] = d3dxMaterials[i].MatD3D; // Set the ambient color for the material (D3DX does not do this) g_pMeshMaterials[i].Ambient = g_pMeshMaterials[i].Diffuse; g_pMeshTextures[i] = NULL; if( d3dxMaterials[i].pTextureFilename != NULL && lstrlenA( d3dxMaterials[i].pTextureFilename ) > 0 ) { // Create the texture if( FAILED( D3DXCreateTextureFromFileA( g_pd3dDevice, d3dxMaterials[i].pTextureFilename, &g_pMeshTextures[i] ) ) ) { // If texture is not in current folder, try parent folder const CHAR* strPrefix = "..\\"; CHAR strTexture[MAX_PATH]; strcpy_s( strTexture, MAX_PATH, strPrefix ); strcat_s( strTexture, MAX_PATH, d3dxMaterials[i].pTextureFilename ); // If texture is not in current folder, try parent folder if( FAILED( D3DXCreateTextureFromFileA( g_pd3dDevice, strTexture, &g_pMeshTextures[i] ) ) ) { MessageBox( NULL, L"Could not find texture map", L"Meshes.exe", MB_OK ); } } } } // Done with the material buffer pD3DXMtrlBuffer->Release(); //#@$%!#$%!@#%%^@%$#@%!^%@#!$@!#$!@#$ LPD3DXBUFFER pD3DXMtrlBuffer2; // Load the mesh from the specified file if( FAILED( D3DXLoadMeshFromX( L"Tiger2.x", D3DXMESH_SYSTEMMEM, g_pd3dDevice, NULL, &pD3DXMtrlBuffer2, NULL, &g_dwNumMaterials2, &g_pMesh2 ) ) ) { // If model is not in current folder, try parent folder if( FAILED( D3DXLoadMeshFromX( L"..\\Tiger2.x", D3DXMESH_SYSTEMMEM, g_pd3dDevice, NULL, &pD3DXMtrlBuffer2, NULL, &g_dwNumMaterials2, &g_pMesh2 ) ) ) { MessageBox( NULL, L"Could not find tiger2.x", L"Meshes.exe", MB_OK ); return E_FAIL; } } // 메쉬가 버텍스 포멧으로 D3DFVF_NORMAL을 가지고 있는가? if ( !(g_pMesh2->GetFVF() & D3DFVF_NORMAL) ) { //가지고 있지 않다면 메쉬를 복제하고 D3DFVF_NORMAL을 추가한다. ID3DXMesh* pTempMesh = 0; g_pMesh2->CloneMeshFVF( D3DXMESH_MANAGED, g_pMesh2->GetFVF() | D3DFVF_NORMAL, //이곳에 추가 g_pd3dDevice, &pTempMesh ); // 법선을 계산한다. D3DXComputeNormals( pTempMesh, 0 ); g_pMesh2->Release(); // 기존메쉬를 제거한다 g_pMesh2 = pTempMesh; // 기존메쉬를 법선이 계산된 메쉬로 지정한다. } // We need to extract the material properties and texture names from the // pD3DXMtrlBuffer2 D3DXMATERIAL* d3dxMaterials2 = ( D3DXMATERIAL* )pD3DXMtrlBuffer2->GetBufferPointer(); g_pMeshMaterials2 = new D3DMATERIAL9[g_dwNumMaterials2]; if( g_pMeshMaterials2 == NULL ) return E_OUTOFMEMORY; g_pMeshTextures2 = new LPDIRECT3DTEXTURE9[g_dwNumMaterials2]; if( g_pMeshTextures2 == NULL ) return E_OUTOFMEMORY; for( DWORD i = 0; i < g_dwNumMaterials2; i++ ) { // Copy the material g_pMeshMaterials2[i] = d3dxMaterials2[i].MatD3D; // Set the ambient color for the material (D3DX does not do this) g_pMeshMaterials2[i].Ambient = g_pMeshMaterials2[i].Diffuse; g_pMeshTextures2[i] = NULL; if( d3dxMaterials2[i].pTextureFilename != NULL && lstrlenA( d3dxMaterials2[i].pTextureFilename ) > 0 ) { // Create the texture if( FAILED( D3DXCreateTextureFromFileA( g_pd3dDevice, d3dxMaterials2[i].pTextureFilename, &g_pMeshTextures2[i] ) ) ) { // If texture is not in current folder, try parent folder const CHAR* strPrefix = "..\\"; CHAR strTexture[MAX_PATH]; strcpy_s( strTexture, MAX_PATH, strPrefix ); strcat_s( strTexture, MAX_PATH, d3dxMaterials2[i].pTextureFilename ); // If texture is not in current folder, try parent folder if( FAILED( D3DXCreateTextureFromFileA( g_pd3dDevice, strTexture, &g_pMeshTextures2[i] ) ) ) { MessageBox( NULL, L"Could not find texture map", L"Meshes.exe", MB_OK ); } } } } // Done with the material buffer pD3DXMtrlBuffer2->Release(); return S_OK; }
//====================================================================== // <<<メッシュ コンテナ オブジェクトの割り当て要求の実装>>> // Name : [in] メッシュの名前 // pMeshData : [in] メッシュデータ構造体へのポインタ // pMaterials : [in] メッシュに使うマテリアルの配列 // pEffectInstances : [in] メッシュに使うエフェクトインスタンスの配列 // NumMaterials : [in] マテリアル配列内のマテリアルの数 // pAdjacency : [in] メッシュの隣接性配列 // pSkinInfo : [in] スキンデータが見つかった場合のスキンメッシュオブジェクトへのポインタ // ppNewMeshContainer : [out, retval] 作成されたメッシュコンテナを返す //====================================================================== HRESULT CAllocateHierarchy::CreateMeshContainer( LPCSTR Name, CONST D3DXMESHDATA *pMeshData, CONST D3DXMATERIAL *pMaterials, CONST D3DXEFFECTINSTANCE *pEffectInstances, DWORD NumMaterials, CONST DWORD *pAdjacency, LPD3DXSKININFO pSkinInfo, LPD3DXMESHCONTAINER *ppNewMeshContainer) { HRESULT hr = S_OK; *ppNewMeshContainer = NULL; // patch meshes を扱う事はできない if( pMeshData->Type != D3DXMESHTYPE_MESH ) { return E_FAIL; } LPD3DXMESH pMesh = pMeshData->pMesh; // FVF で記述されたメッシュ以外は読めぬ if( pMesh->GetFVF() == 0 ) { return E_FAIL; } UINT NumFaces = pMesh->GetNumFaces(); // メッシュ作成 CXMesh *pCXMesh = NULL; try { pCXMesh = new CXMesh; } catch ( std::bad_alloc& ) { // メモリが足りない return E_OUTOFMEMORY; } // 名前設定 pCXMesh->SetName( Name ); // メッシュタイプ設定 pCXMesh->MeshData.Type = D3DXMESHTYPE_MESH; LPDIRECT3DDEVICE9 pD3DDevice = NULL; // デバイスを取得 if( FAILED( pMesh->GetDevice( &pD3DDevice ) ) ) { hr = E_FAIL; goto e_Exit; } // Xファイルに法線が無かったら計算で求める if( !( pMesh->GetFVF() & D3DFVF_NORMAL ) ) { ////FVFに法線を追加した新しいメッシュにする//// hr = pMesh->CloneMeshFVF( pMesh->GetOptions(), pMesh->GetFVF() | D3DFVF_NORMAL, pD3DDevice, &pCXMesh->MeshData.pMesh ); if( FAILED( hr ) ) { goto e_Exit; } // 引数で渡されたメッシュへのポインタに新しいメッシュへのポインタをセット // pMeshへの参照はこの時点で存在しないので、ここではreleaseをかけない pMesh = pCXMesh->MeshData.pMesh; D3DXComputeNormals( pMesh, NULL ); } // 法線があった else { // リファレンスを増やすだけ pCXMesh->MeshData.pMesh = pMesh; pMesh->AddRef(); } // マテリアル用のメモリを確保 pCXMesh->NumMaterials = max( 1, NumMaterials ); try { pCXMesh->pMaterials = new D3DXMATERIAL[pCXMesh->NumMaterials]; pCXMesh->m_ppTextures = new LPDIRECT3DTEXTURE9[pCXMesh->NumMaterials]; pCXMesh->pAdjacency = new DWORD[NumFaces * 3]; } catch ( std::bad_alloc& ) { // メモリが足りない goto e_Exit; } memcpy( pCXMesh->pAdjacency, pAdjacency, sizeof( DWORD ) * NumFaces * 3 ); memset( pCXMesh->m_ppTextures, 0, sizeof( LPDIRECT3DTEXTURE9 ) * pCXMesh->NumMaterials ); // マテリアルのコピー if( NumMaterials > 0 ) { memcpy( pCXMesh->pMaterials, pMaterials, sizeof( D3DXMATERIAL ) * NumMaterials ); for( UINT i=0; i<NumMaterials; i++ ) { if( pCXMesh->pMaterials[i].pTextureFilename != NULL ) { // テクスチャを読み込む if( FAILED( D3DXCreateTextureFromFileEx( pD3DDevice, pCXMesh->pMaterials[i].pTextureFilename, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, D3DUSAGE_RENDERTARGET, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, m_KeyColor, NULL, NULL, &pCXMesh->m_ppTextures[i] ) ) ) { // 読み込み失敗 pCXMesh->m_ppTextures[i] = NULL; } pD3DDevice->SetTexture(0, pCXMesh->m_ppTextures[i]); pD3DDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); pD3DDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); pD3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, true); pD3DDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER); pD3DDevice->SetRenderState(D3DRS_ALPHAREF, 8); } } } // マテリアルが無いので適当にセット else { pCXMesh->pMaterials[0].pTextureFilename = NULL; memset( &pCXMesh->pMaterials[0].MatD3D, 0, sizeof( D3DMATERIAL9 ) ); pCXMesh->pMaterials[0].MatD3D.Diffuse.r = 0.5f; pCXMesh->pMaterials[0].MatD3D.Diffuse.g = 0.5f; pCXMesh->pMaterials[0].MatD3D.Diffuse.b = 0.5f; pCXMesh->pMaterials[0].MatD3D.Specular = pCXMesh->pMaterials[0].MatD3D.Diffuse; } // ワンスキン形式のXファイルだった時の処理 if( pSkinInfo != NULL ) { /* スキンメッシュ用の処理*/ /*pSkinInfo と pMesh をセット*/ pCXMesh->pSkinInfo = pSkinInfo; pSkinInfo->AddRef(); pCXMesh->m_pOrigMesh = pMesh; pMesh->AddRef(); /* Bone Offset Matrices 保存用のメモリを確保*/ UINT NumBones = pSkinInfo->GetNumBones(); try { pCXMesh->m_pBoneOffsetMatrices = new D3DXMATRIX[NumBones]; } catch ( std::bad_alloc& ) { // メモリが足りない goto e_Exit; } /*Bone Offset Matrices 読み込み*/ for( UINT i = 0; i < NumBones; i++ ) { //memcpy(&pCXMesh->m_pBoneOffsetMatrices[i], pCXMesh->pSkinInfo->GetBoneOffsetMatrix(i), sizeof(D3DMATRIX) ); pCXMesh->m_pBoneOffsetMatrices[i] = *(pCXMesh->pSkinInfo->GetBoneOffsetMatrix( i ) ); } // ジェネレート処理 hr = m_pModel->GenerateSkinnedMesh( m_pD3DX9, pCXMesh, m_MaxBlend ); if( FAILED( hr ) ) { goto e_Exit; } } // メッシュコンテナの割り当て。 // CXMeshクラスは D3DXMESHCONTAINER を継承している *ppNewMeshContainer = pCXMesh; pCXMesh = NULL; e_Exit: // 開放処理 F_RELEASE( pD3DDevice ); if( pCXMesh != NULL ) { DestroyMeshContainer( pCXMesh ); } return hr; }
HRESULT LoadMesh() { LPD3DXBUFFER pD3DXMtrlBuffer; if ( FAILED( D3DXLoadMeshFromX( L"Tiger.x", D3DXMESH_SYSTEMMEM, g_pd3dDevice, NULL, &pD3DXMtrlBuffer, NULL, &g_dwNumMaterials, &g_pMesh ) ) ) { if ( FAILED( D3DXLoadMeshFromX( L"..\Tiger.x", D3DXMESH_SYSTEMMEM, g_pd3dDevice, NULL, &pD3DXMtrlBuffer, NULL, &g_dwNumMaterials, &g_pMesh ) ) ) { MessageBox( NULL, L"Could not find tiger.x", L"Meshes.exe", MB_OK ); return E_FAIL; } } D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer(); g_pMeshMaterials = new D3DMATERIAL9[g_dwNumMaterials]; if ( NULL == g_pMeshMaterials ) return E_OUTOFMEMORY; g_pMeshTextures = new LPDIRECT3DTEXTURE9[g_dwNumMaterials]; if ( NULL == g_pMeshTextures ) return E_OUTOFMEMORY; 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] = NULL; if ( d3dxMaterials[i].pTextureFilename != NULL && lstrlenA( d3dxMaterials[i].pTextureFilename ) > 0 ) { if ( FAILED( D3DXCreateTextureFromFileA( g_pd3dDevice, d3dxMaterials[i].pTextureFilename, &g_pMeshTextures[i] ) ) ) { const CHAR* strPrefix = "..\\"; CHAR strTexture[MAX_PATH]; strcpy_s( strTexture, MAX_PATH, strPrefix ); strcat_s( strTexture, MAX_PATH, d3dxMaterials[i].pTextureFilename ); if ( FAILED( D3DXCreateTextureFromFileA( g_pd3dDevice, strTexture, &g_pMeshTextures[i] ) ) ) { MessageBox( NULL, L"Could not find texture map", L"Meshes.exe", MB_OK ); return E_FAIL; } } } } pD3DXMtrlBuffer->Release(); // 법선 벡터를 만들어준다 if ( !( g_pMesh->GetFVF() & D3DFVF_NORMAL ) ) { ID3DXMesh* pTempMesh = 0; g_pMesh->CloneMeshFVF( D3DXMESH_MANAGED, g_pMesh->GetFVF() | D3DFVF_NORMAL, g_pd3dDevice, &pTempMesh ); D3DXComputeNormals( pTempMesh, 0 ); g_pMesh->Release(); g_pMesh = pTempMesh; } return S_OK; }
//------------------------------------------------------------------------------------------------ // 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; }
HRESULT InitGeometry() { //mesh LPD3DXBUFFER pD3DXMtrlBuffer0; if ( FAILED( D3DXLoadMeshFromX( L"test_1.x", D3DXMESH_SYSTEMMEM, g_pD3DDevice, NULL, &pD3DXMtrlBuffer0, NULL, &g_dwNumMaterials, &g_pMesh0 ) ) ) { MessageBox( NULL, L"Could not find test_1.x", L"Meshes.exe", MB_OK ); return E_FAIL; } if ( !( g_pMesh0->GetFVF()&D3DFVF_NORMAL ) ) { ID3DXMesh* pTempMesh = 0; g_pMesh0->CloneMeshFVF( D3DXMESH_MANAGED, g_pMesh0->GetFVF() | D3DFVF_NORMAL, g_pD3DDevice, &pTempMesh ); D3DXComputeNormals( pTempMesh, 0 ); g_pMesh0->Release(); g_pMesh0 = pTempMesh; } //texture D3DXMATERIAL* d3dxMarteials = (D3DXMATERIAL*) pD3DXMtrlBuffer0->GetBufferPointer(); g_pMeshMaterials0 = new D3DMATERIAL9[g_dwNumMaterials]; if ( NULL == g_pMeshMaterials0 ) { return E_OUTOFMEMORY; } g_pMeshTextures0 = new LPDIRECT3DTEXTURE9[g_dwNumMaterials]; if ( NULL == g_pMeshTextures0 ) { return E_OUTOFMEMORY; } for ( DWORD i = 0; i < g_dwNumMaterials; ++i ) { g_pMeshMaterials0[i] = d3dxMarteials[i].MatD3D; g_pMeshMaterials0[i].Ambient = g_pMeshMaterials0[i].Diffuse; g_pMeshTextures0[i] = NULL; if ( ( NULL != d3dxMarteials[i].pTextureFilename ) && lstrlenA( d3dxMarteials[i].pTextureFilename )>0 ) { if ( FAILED( D3DXCreateTextureFromFileA( g_pD3DDevice, d3dxMarteials[i].pTextureFilename, &g_pMeshTextures0[i] ) ) ) { const CHAR* strPrefix = "..\\"; CHAR strTexture[MAX_PATH]; strcpy_s( strTexture, MAX_PATH, strPrefix ); strcat_s( strTexture, MAX_PATH, d3dxMarteials[i].pTextureFilename ); if ( FAILED( D3DXCreateTextureFromFileA( g_pD3DDevice, strTexture, &g_pMeshTextures0[i] ) ) ) { MessageBox( NULL, L"Could not find texture map", L"Meshes.exe", MB_OK ); } } } } pD3DXMtrlBuffer0->Release(); return S_OK; }
int main(int argc, char* argv[]) { if (argc < 3) { puts("Usage: MeshConv meshfile rdffile"); return 1; } // Initialize DirectDraw pD3D = Direct3DCreate9(D3D_SDK_VERSION); if (pD3D == NULL) { puts("Cannot init D3D"); return 1; } MeshMender mender; std::vector<MeshMender::Vertex> MendVerts; std::vector<unsigned int> MendIndices; std::vector<unsigned int> mappingNewToOld; HRESULT hr; D3DDISPLAYMODE dispMode; D3DPRESENT_PARAMETERS presentParams; pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &dispMode); ZeroMemory(&presentParams, sizeof(presentParams)); presentParams.Windowed = TRUE; presentParams.hDeviceWindow = GetConsoleWindow(); presentParams.SwapEffect = D3DSWAPEFFECT_COPY; presentParams.BackBufferWidth = 8; presentParams.BackBufferHeight = 8; presentParams.BackBufferFormat = dispMode.Format; hr = pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, NULL, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentParams, &pD3DDevice); if (FAILED(hr)) { printf("Cannot init D3D device: %08x\n", hr); pD3D->Release(); return 1; } printf("Loading mesh %s: ", argv[1]); LPD3DXBUFFER pAdjacency, pMaterials, pEffects; DWORD n; LPD3DXMESH pLoadMesh; hr = D3DXLoadMeshFromX(argv[1], D3DXMESH_SYSTEMMEM, pD3DDevice, &pAdjacency, &pMaterials, &pEffects, &n, &pLoadMesh); if (FAILED(hr)) { printf("ERROR: %08x\n", hr); goto mesherror; } pEffects->Release(); pMaterials->Release(); printf("%d faces, %d verts\n", pLoadMesh->GetNumFaces(), pLoadMesh->GetNumVertices()); LPD3DXMESH pMesh; if (pLoadMesh->GetFVF() != MESHFVF) { hr = pLoadMesh->CloneMeshFVF(D3DXMESH_SYSTEMMEM, MESHFVF, pD3DDevice, &pMesh); pLoadMesh->Release(); if (FAILED(hr)) { printf("CloneMesh error: %08x\n", hr); goto mesherror; } } else pMesh = pLoadMesh; printf("Welding verts: "); DWORD* pAdj = new DWORD[pAdjacency->GetBufferSize() / 4]; D3DXWELDEPSILONS Eps; memset(&Eps, 0, sizeof(Eps)); hr = D3DXWeldVertices(pMesh, D3DXWELDEPSILONS_WELDPARTIALMATCHES, &Eps, (DWORD*)pAdjacency->GetBufferPointer(), pAdj, NULL, NULL); if (FAILED(hr)) { printf("ERROR: %08x\n", hr); goto mesherror; } hr = pMesh->OptimizeInplace(D3DXMESHOPT_VERTEXCACHE, pAdj, (DWORD*)pAdjacency->GetBufferPointer(), NULL, NULL); if (FAILED(hr)) { printf("ERROR: %08x\n", hr); goto mesherror; } pAdjacency->Release(); delete [] pAdj; printf("%d faces, %d verts\n", pMesh->GetNumFaces(), pMesh->GetNumVertices()); printf("Mending mesh: "); DWORD NumVerts = pMesh->GetNumVertices(); DWORD NumFaces = pMesh->GetNumFaces(); MESHVERT* MeshVert; pMesh->LockVertexBuffer(0, (LPVOID*)&MeshVert); //fill up Mend vectors with your mesh's data MendVerts.reserve(NumVerts); for(DWORD i = 0; i < NumVerts; ++i) { MeshMender::Vertex v; v.pos = MeshVert[i].pos; v.s = MeshVert[i].s; v.t = MeshVert[i].t; v.normal = MeshVert[i].norm; MendVerts.push_back(v); } pMesh->UnlockVertexBuffer(); WORD* MeshIdx; pMesh->LockIndexBuffer(0, (LPVOID*)&MeshIdx); MendIndices.reserve(NumFaces * 3); for(DWORD i = 0; i < NumFaces * 3; ++i) { MendIndices.push_back(MeshIdx[i]); } pMesh->UnlockIndexBuffer(); pMesh->Release(); pMesh = 0; //pass it in to Mend mender to do it's stuff mender.Mend(MendVerts, MendIndices, mappingNewToOld, 0.9f, 0.9f, 0.9f, 1.0f, MeshMender::DONT_CALCULATE_NORMALS, MeshMender::RESPECT_SPLITS); mappingNewToOld.clear(); printf("%d faces, %d verts\n", MendIndices.size() / 3, MendVerts.size()); printf("Saving data: "); FILE* fp = fopen("meshdata.bin", "wb"); n = MendIndices.size() / 3; fwrite(&n, 4, 1, fp); n = MendVerts.size(); fwrite(&n, 4, 1, fp); fclose(fp); // Load existing file HANDLE hFile = CreateFile(argv[2], GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0); if (hFile == INVALID_HANDLE_VALUE) { printf("ERROR: %08x\n", GetLastError()); goto mesherror; } DWORD Size = GetFileSize(hFile, 0); char* FileData = (char*)VirtualAlloc(0, 64*1024*1024, MEM_RESERVE, PAGE_NOACCESS); VirtualAlloc(FileData, Size, MEM_COMMIT, PAGE_READWRITE); ReadFile(hFile, FileData, Size, &n, 0); FileData[n] = 0; Size = n; char *p, *q; // Find vertex data p = strstr(FileData, "VertexBuffer"); if (!p) { printf("ERROR: Invalid output file\n"); goto mesherror; } p = strchr(p, '{'); q = p+1; int depth = 1; do { if (*q == '}') --depth; else if (*q == '{') ++depth; ++q; } while (depth > 0); // move post-vertex data to temp buffer Size = (FileData + Size) - q; char* TempData = (char*)VirtualAlloc(0, Size, MEM_COMMIT, PAGE_READWRITE); memcpy(TempData, q, Size); // write vertex data strcpy(p, "{\r\n VertexFormat {D3DVSDT_FLOAT3 D3DVSDT_NORMPACKED3 D3DVSDT_FLOAT2 D3DVSDT_NORMPACKED3 D3DVSDT_NORMPACKED3}\r\n VertexData\r\n {\r\n"); p += strlen(p); for (std::vector<MeshMender::Vertex>::iterator i = MendVerts.begin(); i != MendVerts.end(); ++i) { VirtualAlloc(p, 500, MEM_COMMIT, PAGE_READWRITE); p += sprintf(p, " %12f %12f %12f %12f %12f %12f %12f %12f %12f %12f %12f %12f %12f %12f\r\n", i->pos.x, i->pos.y, i->pos.z, i->normal.x, i->normal.y, i->normal.z, i->s, i->t, i->tangent.x, i->tangent.y, i->tangent.z, i->binormal.x, i->binormal.y, i->binormal.z); } strcpy(p, " }\r\n}"); p += strlen(p); VirtualAlloc(p, Size, MEM_COMMIT, PAGE_READWRITE); memcpy(p, TempData, Size); Size += p - FileData; VirtualFree(TempData, 0, MEM_RELEASE); // Find index data p = strstr(FileData, "IndexBuffer"); if (!p) { printf("ERROR: Invalid output file\n"); goto mesherror; } p = strchr(p, '{'); q = p+1; depth = 1; do { if (*q == '}') --depth; else if (*q == '{') ++depth; ++q; } while (depth > 0); // move post-index data to temp buffer Size = (FileData + Size) - q; TempData = (char*)VirtualAlloc(0, Size, MEM_COMMIT, PAGE_READWRITE); memcpy(TempData, q, Size); // write index data strcpy(p, "{\r\n IndexData\r\n {\r\n "); p += strlen(p); n = 0; for (std::vector<unsigned>::iterator i = MendIndices.begin(); i != MendIndices.end(); ++i) { VirtualAlloc(p, 20, MEM_COMMIT, PAGE_READWRITE); p += sprintf(p, " %5hu", *i); if (n++ == 2) { p += sprintf(p, "\r\n "); n = 0; } } strcpy(p-3, "}\r\n}"); p += strlen(p); VirtualAlloc(p, Size, MEM_COMMIT, PAGE_READWRITE); memcpy(p, TempData, Size); Size += p - FileData; VirtualFree(TempData, 0, MEM_RELEASE); SetFilePointer(hFile, 0, 0, FILE_BEGIN); WriteFile(hFile, FileData, Size, &n, 0); SetEndOfFile(hFile); CloseHandle(hFile); VirtualFree(FileData, 0, MEM_RELEASE); printf("Done\n"); pD3D->Release(); pD3DDevice->Release(); return 0; mesherror: pD3D->Release(); pD3DDevice->Release(); return 1; }
//メッシュコンテナの生成 HRESULT Dx_Hierarchy::CreateMeshContainer( LPCTSTR Name, CONST D3DXMESHDATA *pMeshData, CONST D3DXMATERIAL *pMaterials, CONST D3DXEFFECTINSTANCE *pEffectInstances, DWORD NumMaterials, CONST DWORD *pAdjacency, LPD3DXSKININFO pSkinInfo, LPD3DXMESHCONTAINER *ppMeshContainer ) { HRESULT hr = S_OK; //生成用オブジェクトの宣言 DxMeshContainer *pMeshContainer = NULL; //生成したオブジェクトの登録先を初期化 *ppMeshContainer = NULL; int iFacesAmount; unsigned iMaterial; LPDIRECT3DDEVICE9 pDevice = NULL; LPD3DXMESH pMesh = NULL; // patch meshes を扱う事はできない //if( pMeshData->Type != D3DXMESHTYPE_MESH ) return E_FAIL; // FVF で記述されたメッシュ以外は読めない //if( pMesh->GetFVF() == 0 ) return E_FAIL; //DWORD dwBoneAmt=0; //メッシュデータの持つメッシュポインタを取得 pMesh = pMeshData->pMesh; //オブジェクトの生成 pMeshContainer = new DxMeshContainer; //変数がNULLだった場合 if (pMeshContainer == NULL) { //エラーの意味 : Direct3D が呼び出しを完了するための十分なメモリを割り当てることができませんでした。 return E_OUTOFMEMORY; } // ZeroMemory(pMeshContainer, sizeof(DxMeshContainer)); //メッシュコンテナ名の領域確保 pMeshContainer->Name=new TCHAR[lstrlen(Name) + 1]; //領域が確保されなかった場合 if (!pMeshContainer->Name) { //エラーの意味 : Direct3D サブシステム内で原因不明のエラーが発生しました。 return E_FAIL; } //名前をコピーする strcpy(pMeshContainer->Name,Name); //メッシュに関連付けられているデバイスを取得 if(FAILED(pMesh->GetDevice(&pDevice))) { /*hr = E_FAIL; SAFE_RELEASE( pDevice ); if( pMeshContainer ) DestroyMeshContainer( pMeshContainer ); return hr;*/ } //メッシュに含まれる面の数を取得 iFacesAmount = pMesh->GetNumFaces(); // 当該メッシュが法線を持たない場合は法線を追加する if (!(pMesh->GetFVF() & D3DFVF_NORMAL)) { //メッシュデータの種類を「メッシュ」に変更 pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH; //FVFコードを使ってメッシュのコピーを生成 hr = pMesh->CloneMeshFVF( pMesh->GetOptions(), pMesh->GetFVF() | D3DFVF_NORMAL, pDevice, &pMeshContainer->MeshData.pMesh ); //処理が失敗した場合 if (FAILED(hr)) { //エラーの意味 : Direct3D サブシステム内で原因不明のエラーが発生しました。 return E_FAIL; } pMesh = pMeshContainer->MeshData.pMesh; //pMeshに含まれる各頂点の法線を計算して出力 D3DXComputeNormals( pMesh, NULL ); } else{ //メッシュコンテナ内のメッシュデータにメッシュポインタを設定 pMeshContainer->MeshData.pMesh = pMesh; //メッシュデータの種類を「メッシュ」に設定 pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH; //??? pMesh->AddRef(); } //メッシュのマテリアル設定 //マテリアル数を設定 pMeshContainer->NumMaterials = max(1, NumMaterials); //マテリアルの数だけマテリアルの領域を確保 pMeshContainer->pMaterials = new D3DXMATERIAL[pMeshContainer->NumMaterials]; //マテリアルの数だけテクスチャの領域確保 pMeshContainer->ppTextures = new LPDIRECT3DTEXTURE9[pMeshContainer->NumMaterials]; //面の数だけ領域を確保 pMeshContainer->pAdjacency = new DWORD[iFacesAmount*3]; //それぞれの領域確保に失敗した場合 if ((pMeshContainer->pAdjacency == NULL) || (pMeshContainer->pMaterials == NULL)) { //エラーの意味 : Direct3D が呼び出しを完了するための十分なメモリを割り当てることができませんでした。 return E_OUTOFMEMORY; } //配列に0を設定 memset(pMeshContainer->ppTextures, 0, sizeof(LPDIRECT3DTEXTURE9) * pMeshContainer->NumMaterials); //配列にpAbjacencyを設定 memcpy(pMeshContainer->pAdjacency, pAdjacency, sizeof(DWORD) * iFacesAmount*3); //マテリアルが存在する時 if (NumMaterials > 0) { // memcpy(pMeshContainer->pMaterials, pMaterials, sizeof(D3DXMATERIAL) * NumMaterials); // for (iMaterial = 0; iMaterial < NumMaterials; iMaterial++) { //テクスチャのファイル名が存在する場合 if( pMeshContainer->pMaterials[iMaterial].pTextureFilename != NULL) { //ファイルまでの相対パスを設定 char path[256] ="res/x/"; //ファイル名を取得 LPSTR fName = pMeshContainer->pMaterials[iMaterial].pTextureFilename; //テクスチャ情報の生成 pMeshContainer->ppTextures[iMaterial] = this->t_manager->LoadTextureFromFile(fName,path); //テクスチャ名の破棄 pMeshContainer->pMaterials[iMaterial].pTextureFilename = NULL; } } } else { //テクスチャ名の破棄 pMeshContainer->pMaterials[0].pTextureFilename = NULL; //マテリアルに0を設定 memset(&pMeshContainer->pMaterials[0].MatD3D, 0, sizeof(D3DMATERIAL9)); // pMeshContainer->pMaterials[0].MatD3D.Diffuse.r = 0.5f; pMeshContainer->pMaterials[0].MatD3D.Diffuse.g = 0.5f; pMeshContainer->pMaterials[0].MatD3D.Diffuse.b = 0.5f; pMeshContainer->pMaterials[0].MatD3D.Specular = pMeshContainer->pMaterials[0].MatD3D.Diffuse; } //スキニング情報が存在する場合、ボーンを生成 if(pSkinInfo!=NULL) { //メッシュコンテナ内のスキニング情報を設定 pMeshContainer->pSkinInfo = pSkinInfo; //??? pSkinInfo->AddRef(); //スキニング情報からボーンを生成 this->CreateBone(pMeshContainer,pDevice); } //ローカルに生成したメッシュコンテナを呼び出し側にコピーする *ppMeshContainer = pMeshContainer; //処理が無事に終了 return hr; }
HRESULT AllocateHierarchy::CreateMeshContainer( LPCSTR Name, CONST D3DXMESHDATA *pMeshData, CONST D3DXMATERIAL *pMaterials, CONST D3DXEFFECTINSTANCE *pEffectInstances, DWORD NumMaterials, CONST DWORD *pAdjacency, LPD3DXSKININFO pSkinInfo, LPD3DXMESHCONTAINER *ppNewMeshContainer) { HRESULT hr; D3DXMESHCONTAINER_DERIVED *pMeshContainer = NULL; UINT NumFaces; UINT iMaterial; UINT iBone, cBones; LPDIRECT3DDEVICE9 pd3dDevice = NULL; LPD3DXMESH pMesh = NULL; *ppNewMeshContainer = NULL; // this sample does not handle patch meshes, so fail when one is found if (pMeshData->Type != D3DXMESHTYPE_MESH) { hr = E_FAIL; goto e_Exit; } // get the pMesh interface pointer out of the mesh data structure pMesh = pMeshData->pMesh; // this sample does not FVF compatible meshes, so fail when one is found if (pMesh->GetFVF() == 0) { hr = E_FAIL; goto e_Exit; } // allocate the overloaded structure to return as a D3DXMESHCONTAINER pMeshContainer = new D3DXMESHCONTAINER_DERIVED; if (pMeshContainer == NULL) { hr = E_OUTOFMEMORY; goto e_Exit; } memset(pMeshContainer, 0, sizeof(D3DXMESHCONTAINER_DERIVED)); // make sure and copy the name. All memory as input belongs to caller, interfaces can be addref'd though hr = AllocateName(Name, &pMeshContainer->Name); if (FAILED(hr)) goto e_Exit; pMesh->GetDevice(&pd3dDevice); NumFaces = pMesh->GetNumFaces(); // if no normals are in the mesh, add them if (!(pMesh->GetFVF() & D3DFVF_NORMAL)) { pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH; // clone the mesh to make room for the normals hr = pMesh->CloneMeshFVF( pMesh->GetOptions(), pMesh->GetFVF() | D3DFVF_NORMAL, pd3dDevice, &pMeshContainer->MeshData.pMesh ); if (FAILED(hr)) goto e_Exit; // get the new pMesh pointer back out of the mesh container to use // NOTE: we do not release pMesh because we do not have a reference to it yet pMesh = pMeshContainer->MeshData.pMesh; // now generate the normals for the pmesh D3DXComputeNormals( pMesh, NULL ); } else // if no normals, just add a reference to the mesh for the mesh container { pMeshContainer->MeshData.pMesh = pMesh; pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH; pMesh->AddRef(); } // allocate memory to contain the material information. This sample uses // the D3D9 materials and texture names instead of the EffectInstance style materials pMeshContainer->NumMaterials = max(1, NumMaterials); pMeshContainer->pMaterials = new D3DXMATERIAL[pMeshContainer->NumMaterials]; pMeshContainer->ppTextures = new LPDIRECT3DTEXTURE9[pMeshContainer->NumMaterials]; pMeshContainer->pAdjacency = new DWORD[NumFaces*3]; if ((pMeshContainer->pAdjacency == NULL) || (pMeshContainer->pMaterials == NULL)) { hr = E_OUTOFMEMORY; goto e_Exit; } memcpy(pMeshContainer->pAdjacency, pAdjacency, sizeof(DWORD) * NumFaces*3); memset(pMeshContainer->ppTextures, 0, sizeof(LPDIRECT3DTEXTURE9) * pMeshContainer->NumMaterials); // if materials provided, copy them if (NumMaterials > 0) { memcpy(pMeshContainer->pMaterials, pMaterials, sizeof(D3DXMATERIAL) * NumMaterials); for (iMaterial = 0; iMaterial < NumMaterials; iMaterial++) { if (pMeshContainer->pMaterials[iMaterial].pTextureFilename != NULL) { string strTexturePath; string strFilename = _pSkinmesh->GetMeshname(); strFilename = strFilename + "\\" + pMeshContainer->pMaterials[iMaterial].pTextureFilename; strTexturePath = MODEL_DIR(strFilename.c_str()); if( FAILED( Moon_CreateTexture( pd3dDevice, const_cast<char*>(strTexturePath.c_str()), &pMeshContainer->ppTextures[iMaterial] ) ) ) pMeshContainer->ppTextures[iMaterial] = NULL; // don't remember a pointer into the dynamic memory, just forget the name after loading pMeshContainer->pMaterials[iMaterial].pTextureFilename = NULL; } } } else // if no materials provided, use a default one { pMeshContainer->pMaterials[0].pTextureFilename = NULL; memset(&pMeshContainer->pMaterials[0].MatD3D, 0, sizeof(D3DMATERIAL9)); pMeshContainer->pMaterials[0].MatD3D.Diffuse.r = 0.5f; pMeshContainer->pMaterials[0].MatD3D.Diffuse.g = 0.5f; pMeshContainer->pMaterials[0].MatD3D.Diffuse.b = 0.5f; pMeshContainer->pMaterials[0].MatD3D.Specular = pMeshContainer->pMaterials[0].MatD3D.Diffuse; } // if there is skinning information, save off the required data and then setup for HW skinning if (pSkinInfo != NULL) { // first save off the SkinInfo and original mesh data pMeshContainer->pSkinInfo = pSkinInfo; pSkinInfo->AddRef(); pMeshContainer->pOrigMesh = pMesh; pMesh->AddRef(); // Will need an array of offset matrices to move the vertices from the figure space to the bone's space cBones = pSkinInfo->GetNumBones(); pMeshContainer->pBoneOffsetMatrices = new D3DXMATRIX[cBones]; if (pMeshContainer->pBoneOffsetMatrices == NULL) { hr = E_OUTOFMEMORY; goto e_Exit; } // get each of the bone offset matrices so that we don't need to get them later for (iBone = 0; iBone < cBones; iBone++) { pMeshContainer->pBoneOffsetMatrices[iBone] = *(pMeshContainer->pSkinInfo->GetBoneOffsetMatrix(iBone)); } // GenerateSkinnedMesh will take the general skinning information and transform it to a HW friendly version hr = _pSkinmesh->GenerateSkinmesh(pMeshContainer); if (FAILED(hr)) goto e_Exit; } *ppNewMeshContainer = pMeshContainer; pMeshContainer = NULL; e_Exit: SAFE_RELEASE(pd3dDevice); // call Destroy function to properly clean up the memory allocated if (pMeshContainer != NULL) { DestroyMeshContainer(pMeshContainer); } return hr; }
HRESULT InitGeometry() { LPD3DXBUFFER pD3DXMtrlBuffer; if ( FAILED( D3DXLoadMeshFromX( L"./Resource/girl.x", D3DXMESH_SYSTEMMEM, g_pd3dDevice, NULL, &pD3DXMtrlBuffer, NULL, &g_dwNumMaterials, &g_pMesh ) ) ) { MessageBox( NULL, L"Could not find girl.x", L"D3D Tutorial", MB_OK ); return E_FAIL; } D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer(); g_pMeshMaterials = new D3DMATERIAL9[g_dwNumMaterials]; if ( g_pMeshMaterials == NULL ) { return E_OUTOFMEMORY; } g_pMeshTextures = new LPDIRECT3DTEXTURE9[g_dwNumMaterials]; if ( g_pMeshTextures == NULL ) { return E_OUTOFMEMORY; } if ( !( g_pMesh->GetFVF() & D3DFVF_NORMAL ) ) { //가지고 있지 않다면 메쉬를 복제하고 D3DFVF_NORMAL을 추가한다. ID3DXMesh* pTempMesh = 0; g_pMesh->CloneMeshFVF( D3DXMESH_MANAGED, g_pMesh->GetFVF() | D3DFVF_NORMAL, g_pd3dDevice, &pTempMesh ); // 법선을 계산한다. D3DXComputeNormals( pTempMesh, 0 ); g_pMesh->Release(); // 기존메쉬를 제거한다 g_pMesh = pTempMesh; // 기존메쉬를 법선이 계산된 메쉬로 지정한다. } 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] = NULL; if ( d3dxMaterials[i].pTextureFilename != NULL && lstrlenA( d3dxMaterials[i].pTextureFilename ) > 0 ) { if ( FAILED( D3DXCreateTextureFromFileA( g_pd3dDevice, d3dxMaterials[i].pTextureFilename, &g_pMeshTextures[i] ) ) ) { const CHAR* strPrefix = "./Resource/"; CHAR strTexture[MAX_PATH]; strcpy_s( strTexture, MAX_PATH, strPrefix ); strcat_s( strTexture, MAX_PATH, d3dxMaterials[i].pTextureFilename ); if ( FAILED( D3DXCreateTextureFromFileA( g_pd3dDevice, strTexture, &g_pMeshTextures[i] ) ) ) { MessageBox( NULL, L"Could not find texture map", L"D3D Tutorial", MB_OK ); } } } } pD3DXMtrlBuffer->Release(); return S_OK; }
//----------------------------------------------------------------------------- // Desc: 在这里是调用了成员函数 GenerateGameSkinMesh(pMeshContainer); // 是在这里加载了蒙皮信息 //----------------------------------------------------------------------------- HRESULT DexAllocateHierarchy::CreateMeshContainer(LPCSTR Name, CONST D3DXMESHDATA *pMeshData, CONST D3DXMATERIAL *pMaterials, CONST D3DXEFFECTINSTANCE *pEffectInstances, DWORD NumMaterials, CONST DWORD *pAdjacency, LPD3DXSKININFO pSkinInfo, LPD3DXMESHCONTAINER *ppNewMeshContainer) { HRESULT hr; stDexMeshContainerEx *pMeshContainer = NULL; LPDIRECT3DDEVICE9 device = NULL; UINT NumFaces; UINT iMaterial; UINT iBone, cBones; LPD3DXMESH pMesh = NULL; *ppNewMeshContainer = NULL; // this sample does not handle patch meshes, so fail when one is found if (pMeshData->Type != D3DXMESHTYPE_MESH) { hr = E_FAIL; return hr; } // get the pMesh interface pointer out of the mesh data structure pMesh = pMeshData->pMesh; pMesh->GetDevice( &device ); // this sample does not FVF compatible meshes, so fail when one is found if (pMesh->GetFVF() == 0) { hr = E_FAIL; return hr; } // allocate the overloaded structure to return as a D3DXMESHCONTAINER pMeshContainer = new stDexMeshContainerEx; if (pMeshContainer == NULL) { hr = E_OUTOFMEMORY; return hr; } memset(pMeshContainer, 0, sizeof(stDexMeshContainerEx)); // make sure and copy the name. All memory as input belongs to caller, interfaces can be addref'd though hr = AllocateName(Name, &pMeshContainer->Name); if (FAILED(hr)) { if (pMeshContainer != NULL) { DestroyMeshContainer(pMeshContainer); } return hr; } NumFaces = pMesh->GetNumFaces(); // if no normals are in the mesh, add them if (!(pMesh->GetFVF() & D3DFVF_NORMAL)) { pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH; // clone the mesh to make room for the normals hr = pMesh->CloneMeshFVF( pMesh->GetOptions(), pMesh->GetFVF() | D3DFVF_NORMAL, device, &pMeshContainer->MeshData.pMesh ); if (FAILED(hr)) { if (pMeshContainer != NULL) { DestroyMeshContainer(pMeshContainer); } return hr; } // get the new pMesh pointer back out of the mesh container to use // NOTE: we do not release pMesh because we do not have a reference to it yet pMesh = pMeshContainer->MeshData.pMesh; // now generate the normals for the pmesh D3DXComputeNormals( pMesh, NULL ); } else // if no normals, just add a reference to the mesh for the mesh container { pMeshContainer->MeshData.pMesh = pMesh; pMeshContainer->MeshData.Type = D3DXMESHTYPE_MESH; pMesh->AddRef(); } // allocate memory to contain the material information. This sample uses // the D3D9 materials and texture names instead of the EffectInstance style materials pMeshContainer->NumMaterials = max(1, NumMaterials); pMeshContainer->pMaterials = new D3DXMATERIAL[pMeshContainer->NumMaterials]; pMeshContainer->ppTextures = new LPDIRECT3DTEXTURE9[pMeshContainer->NumMaterials]; pMeshContainer->pAdjacency = new DWORD[NumFaces*3]; if ((pMeshContainer->pAdjacency == NULL) || (pMeshContainer->pMaterials == NULL)) { hr = E_OUTOFMEMORY; if (pMeshContainer != NULL) { DestroyMeshContainer(pMeshContainer); } return hr; } memcpy(pMeshContainer->pAdjacency, pAdjacency, sizeof(DWORD) * NumFaces*3); memset(pMeshContainer->ppTextures, 0, sizeof(LPDIRECT3DTEXTURE9) * pMeshContainer->NumMaterials); // if materials provided, copy them if (NumMaterials > 0) { memcpy(pMeshContainer->pMaterials, pMaterials, sizeof(D3DXMATERIAL) * NumMaterials); for (iMaterial = 0; iMaterial < NumMaterials; iMaterial++) { if (pMeshContainer->pMaterials[iMaterial].pTextureFilename != NULL) { //TCHAR file[1000]; //FindMediaFile(file,pMeshContainer->pMaterials[iMaterial].pTextureFilename); // 根据纹理的文件名创建纹理资源,如果创建失败,纹理指针必须赋成NULL // MessageNULL(file); //D3DXCreateTextureFromFileEx(device, file, // D3DX_DEFAULT_NONPOW2, // D3DX_DEFAULT_NONPOW2, // D3DX_FROM_FILE, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, // D3DX_FILTER_NONE, D3DX_FILTER_NONE, D3DCOLOR_XRGB(0,0,0), NULL, NULL, // &pMeshContainer->ppTextures[iMaterial]); string texname = "model/"; //轉到model文件夾中去找紋理 texname += pMeshContainer->pMaterials[iMaterial].pTextureFilename; if( FAILED( D3DXCreateTextureFromFile( device, texname.c_str(), &pMeshContainer->ppTextures[iMaterial] ) ) ) { getLog()->BeginLog(); getLog()->Log(log_allert, "load model texture %s failed! \n", texname.c_str()); pMeshContainer->ppTextures[iMaterial] = NULL; getLog()->EndLog(); } // don't remember a pointer into the dynamic memory, just forget the name after loading pMeshContainer->pMaterials[iMaterial].pTextureFilename = NULL; } } } else // if no materials provided, use a default one { pMeshContainer->pMaterials[0].pTextureFilename = NULL; memset(&pMeshContainer->pMaterials[0].MatD3D, 0, sizeof(D3DMATERIAL9)); pMeshContainer->pMaterials[0].MatD3D.Diffuse.r = 0.5f; pMeshContainer->pMaterials[0].MatD3D.Diffuse.g = 0.5f; pMeshContainer->pMaterials[0].MatD3D.Diffuse.b = 0.5f; pMeshContainer->pMaterials[0].MatD3D.Specular = pMeshContainer->pMaterials[0].MatD3D.Diffuse; } // if there is skinning information, save off the required data and then setup for HW skinning if (pSkinInfo != NULL) { // first save off the SkinInfo and original mesh data pMeshContainer->pSkinInfo = pSkinInfo; pSkinInfo->AddRef(); pMeshContainer->pOrigMesh = pMesh; pMesh->AddRef(); // Will need an array of offset matrices to move the vertices from the figure space to the bone's space cBones = pSkinInfo->GetNumBones(); pMeshContainer->pBoneOffsetMatrices = new D3DXMATRIX[cBones]; if (pMeshContainer->pBoneOffsetMatrices == NULL) { hr = E_OUTOFMEMORY; if (pMeshContainer != NULL) { DestroyMeshContainer(pMeshContainer); } return hr; } // get each of the bone offset matrices so that we don't need to get them later for (iBone = 0; iBone < cBones; iBone++) { pMeshContainer->pBoneOffsetMatrices[iBone] = *(pMeshContainer->pSkinInfo->GetBoneOffsetMatrix(iBone)); } // GenerateGameSkinMesh will take the general skinning information and transform it to a HW friendly version hr = GenerateGameSkinMesh(device, pMeshContainer ); if (FAILED(hr)) { if (pMeshContainer != NULL) { DestroyMeshContainer(pMeshContainer); } return hr; } } *ppNewMeshContainer = pMeshContainer; pMeshContainer = NULL; // call Destroy function to properly clean up the memory allocated if (pMeshContainer != NULL) { DestroyMeshContainer(pMeshContainer); } return hr; }
HRESULT InitGeometry() { //mesh LPD3DXBUFFER pD3DXMtrlBuffer0; if (FAILED(D3DXLoadMeshFromX(L"Tiger.x", D3DXMESH_SYSTEMMEM, g_pD3DDevice, NULL, &pD3DXMtrlBuffer0, NULL, &g_dwNumMaterials, &g_pMesh0))) { MessageBox(NULL, L"Could not find tiger.x", L"Meshes.exe", MB_OK); return E_FAIL; } if ( !(g_pMesh0->GetFVF()&D3DFVF_NORMAL) ) { ID3DXMesh* pTempMesh = 0; g_pMesh0->CloneMeshFVF(D3DXMESH_MANAGED, g_pMesh0->GetFVF() | D3DFVF_NORMAL, g_pD3DDevice, &pTempMesh); D3DXComputeNormals( pTempMesh,0 ); g_pMesh0->Release(); g_pMesh0 = pTempMesh; } //1번 D3DXMATERIAL* d3dxMarteials = (D3DXMATERIAL*) pD3DXMtrlBuffer0->GetBufferPointer(); g_pMeshMaterials0 = new D3DMATERIAL9[g_dwNumMaterials]; if (NULL == g_pMeshMaterials0) { return E_OUTOFMEMORY; } g_pMeshTextures0 = new LPDIRECT3DTEXTURE9[g_dwNumMaterials]; if (NULL == g_pMeshTextures0) { return E_OUTOFMEMORY; } for (DWORD i = 0; i < g_dwNumMaterials; ++i) { g_pMeshMaterials0[i] = d3dxMarteials[i].MatD3D; g_pMeshMaterials0[i].Ambient = g_pMeshMaterials0[i].Diffuse; g_pMeshTextures0[i] = NULL; if ((NULL != d3dxMarteials[i].pTextureFilename) && lstrlenA(d3dxMarteials[i].pTextureFilename)>0) { if (FAILED(D3DXCreateTextureFromFileA(g_pD3DDevice, d3dxMarteials[i].pTextureFilename, &g_pMeshTextures0[i]))) { const CHAR* strPrefix = "..\\"; CHAR strTexture[MAX_PATH]; strcpy_s(strTexture, MAX_PATH, strPrefix); strcat_s(strTexture, MAX_PATH, d3dxMarteials[i].pTextureFilename); if (FAILED(D3DXCreateTextureFromFileA(g_pD3DDevice, strTexture, &g_pMeshTextures0[i]))) { MessageBox(NULL, L"Could not find texture map", L"Meshes.exe", MB_OK); } } } } pD3DXMtrlBuffer0->Release(); //silinder if (FAILED(D3DXCreateTextureFromFile(g_pD3DDevice, L"gom.bmp", &g_pTexture0))) { MessageBox(NULL, L"Could not find gom.bmp", L"*.exe", MB_OK); return E_FAIL; } if (FAILED(D3DXCreateTextureFromFile(g_pD3DDevice, L"sun.bmp", &g_pTexture1))) { MessageBox(NULL, L"Could not find sun.bmp", L"*.exe", MB_OK); return E_FAIL; } //buffer0 if (FAILED(g_pD3DDevice->CreateVertexBuffer(50*2*sizeof(CUSTOMVERTEX), 0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVertexBuffer0, NULL))) { return E_FAIL; } CUSTOMVERTEX* pVertieces; if (FAILED(g_pVertexBuffer0->Lock(0, 0, (void**)&pVertieces, 0))) { return E_FAIL; } for (DWORD i = 0; i < 50; ++i) { FLOAT theta = (2 * D3DX_PI*i) / (50 - 1); pVertieces[2 * i + 0].position = D3DXVECTOR3(sinf(theta)-0.7f, 1.5f, cosf(theta)); pVertieces[2 * i + 0].normal = D3DXVECTOR3(sinf(theta), 0.f, cosf(theta)); pVertieces[2 * i + 0].color = 0xffffffff; pVertieces[2 * i + 0].tu = ((FLOAT) i) / (50 - 1); pVertieces[2 * i + 0].tv = 1.f; pVertieces[2 * i + 1].position = D3DXVECTOR3(sinf(theta)-0.7f, 3.5f, cosf(theta)); pVertieces[2 * i + 1].normal = D3DXVECTOR3(sinf(theta), 0.f, cosf(theta)); pVertieces[2 * i + 1].color = 0xffffffff; pVertieces[2 * i + 1].tu = ((FLOAT) i) / (50 - 1); pVertieces[2 * i + 1].tv = 0.f; } g_pVertexBuffer0->Unlock(); //buffer1 if (FAILED(g_pD3DDevice->CreateVertexBuffer(50 * 2 * sizeof(CUSTOMVERTEX), 0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVertexBuffer1, NULL))) { return E_FAIL; } CUSTOMVERTEX* pVertieces1; if (FAILED(g_pVertexBuffer1->Lock(0, 0, (void**) &pVertieces1, 0))) { return E_FAIL; } for (DWORD i = 0; i < 50; ++i) { FLOAT theta = (2 * D3DX_PI*i) / (50 - 1); pVertieces1[2 * i + 0].position = D3DXVECTOR3(sinf(theta)+.7f, 1.5f, cosf(theta)); pVertieces1[2 * i + 0].normal = D3DXVECTOR3(sinf(theta), 0.f, cosf(theta)); pVertieces1[2 * i + 0].color = 0xffffffff; pVertieces1[2 * i + 0].tu = ((FLOAT) i) / (50 - 1); pVertieces1[2 * i + 0].tv = 1.f; pVertieces1[2 * i + 1].position = D3DXVECTOR3(sinf(theta)+.7f, 3.5f, cosf(theta)); pVertieces1[2 * i + 1].normal = D3DXVECTOR3(sinf(theta), 0.f, cosf(theta)); pVertieces1[2 * i + 1].color = 0xffffffff; pVertieces1[2 * i + 1].tu = ((FLOAT) i) / (50 - 1); pVertieces1[2 * i + 1].tv = 0.f; } g_pVertexBuffer1->Unlock(); return S_OK; }