//-------------------------------------------------------------------------------------- HRESULT CLoaderXFile::Load( WCHAR* szFileName, FRAME_TRANSFORM_TYPE requestedBHT ) { HRESULT hr = E_FAIL; ID3DXBuffer *pMat = NULL; ID3DXMesh *pRawMesh = NULL; ID3DXMesh *pMesh = NULL; DWORD cMat; IDirect3DDevice9* pDev9 = NULL; DWORD* pAdjBuffer = NULL; // Create a d3d9 object IDirect3D9* pD3D9 = Direct3DCreate9( D3D_SDK_VERSION ); if( pD3D9 == NULL ) return E_FAIL; D3DPRESENT_PARAMETERS pp; pp.BackBufferWidth = 320; pp.BackBufferHeight = 240; pp.BackBufferFormat = D3DFMT_X8R8G8B8; pp.BackBufferCount = 1; pp.MultiSampleType = D3DMULTISAMPLE_NONE; pp.MultiSampleQuality = 0; pp.SwapEffect = D3DSWAPEFFECT_DISCARD; pp.hDeviceWindow = GetShellWindow(); pp.Windowed = true; pp.Flags = 0; pp.FullScreen_RefreshRateInHz = 0; pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; pp.EnableAutoDepthStencil = false; hr = pD3D9->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_NULLREF, NULL, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &pp, &pDev9 ); if(FAILED(hr)) goto Error; if( szFileName ) { hr = D3DXLoadMeshFromX( szFileName, 0, pDev9, NULL, &pMat, NULL, &cMat, &pRawMesh ); if(FAILED(hr)) goto Error; } D3DVERTEXELEMENT9 declTanBi[] = { { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, { 0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 }, { 0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 }, { 0, 32, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT, 0 }, { 0, 44, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BINORMAL, 0 }, D3DDECL_END() }; D3DVERTEXELEMENT9* pdecl = declTanBi; // Make a clone with the desired vertex format. if( SUCCEEDED( pRawMesh->CloneMesh( D3DXMESH_32BIT | D3DXMESH_DYNAMIC, pdecl, pDev9, &m_pMesh ) ) ) { // Optimize pAdjBuffer = new DWORD[ 3*m_pMesh->GetNumFaces() ]; if( !pAdjBuffer ) { hr = E_OUTOFMEMORY; goto Error; } m_pMesh->GenerateAdjacency( 0.001f, pAdjBuffer ); m_pMesh->OptimizeInplace( D3DXMESHOPT_ATTRSORT, pAdjBuffer, NULL, NULL, NULL ); // Attributes m_pMesh->GetAttributeTable( NULL, &m_dwNumAttr ); if( m_dwNumAttr > 0 ) { m_pAttr = new D3DXATTRIBUTERANGE[m_dwNumAttr]; m_pMesh->GetAttributeTable( m_pAttr, &m_dwNumAttr ); } // Materials m_dwNumMaterials = cMat; if( m_dwNumMaterials > 0 ) { D3DXMATERIAL* pMaterialBuffer = (D3DXMATERIAL*)pMat->GetBufferPointer(); m_pMats = new D3DXMATERIAL[ m_dwNumMaterials ]; if( !m_pMats ) { hr = E_OUTOFMEMORY; goto Error; } for( DWORD m=0; m<m_dwNumMaterials; m++ ) { CopyMemory( &m_pMats[m], &pMaterialBuffer[m], sizeof(D3DXMATERIAL) ); } } // Create the intermediate mesh hr = CreateIntermediateMesh( declTanBi, 6 ); if(FAILED(hr)) goto Error; } hr = S_OK; Error: SAFE_RELEASE( pMat ); SAFE_RELEASE( pRawMesh ); SAFE_RELEASE( pMesh ); SAFE_RELEASE( pDev9 ); SAFE_RELEASE( pD3D9 ); SAFE_DELETE_ARRAY( pAdjBuffer ); return hr; }
void SkinnedMesh::buildSkinnedMesh(ID3DXMesh* mesh) { //==================================================================== // First add a normal component and 2D texture coordinates component. D3DVERTEXELEMENT9 elements[64]; UINT numElements = 0; VertexPNT::Decl->GetDeclaration(elements, &numElements); ID3DXMesh* tempMesh = 0; HR(mesh->CloneMesh(D3DXMESH_SYSTEMMEM, elements, gd3dDevice, &tempMesh)); if( !hasNormals(tempMesh) ) HR(D3DXComputeNormals(tempMesh, 0)); //==================================================================== // Optimize the mesh; in particular, the vertex cache. DWORD* adj = new DWORD[tempMesh->GetNumFaces()*3]; ID3DXBuffer* remap = 0; HR(tempMesh->GenerateAdjacency(EPSILON, adj)); ID3DXMesh* optimizedTempMesh = 0; HR(tempMesh->Optimize(D3DXMESH_SYSTEMMEM | D3DXMESHOPT_VERTEXCACHE | D3DXMESHOPT_ATTRSORT, adj, 0, 0, &remap, &optimizedTempMesh)); ReleaseCOM(tempMesh); // Done w/ this mesh. delete[] adj; // Done with buffer. // In the .X file (specifically the array DWORD vertexIndices[nWeights] // data member of the SkinWeights template) each bone has an array of // indices which identify the vertices of the mesh that the bone influences. // Because we have just rearranged the vertices (from optimizing), the vertex // indices of a bone are obviously incorrect (i.e., they index to vertices the bone // does not influence since we moved vertices around). In order to update a bone's // vertex indices to the vertices the bone _does_ influence, we simply need to specify // where we remapped the vertices to, so that the vertex indices can be updated to // match. This is done with the ID3DXSkinInfo::Remap method. HR(mSkinInfo->Remap(optimizedTempMesh->GetNumVertices(), (DWORD*)remap->GetBufferPointer())); ReleaseCOM(remap); // Done with remap info. //==================================================================== // The vertex format of the source mesh does not include vertex weights // nor bone index data, which are both needed for vertex blending. // Therefore, we must convert the source mesh to an "indexed-blended-mesh," // which does have the necessary data. DWORD numBoneComboEntries = 0; ID3DXBuffer* boneComboTable = 0; HR(mSkinInfo->ConvertToIndexedBlendedMesh(optimizedTempMesh, D3DXMESH_MANAGED | D3DXMESH_WRITEONLY, MAX_NUM_BONES_SUPPORTED, 0, 0, 0, 0, &mMaxVertInfluences, &numBoneComboEntries, &boneComboTable, &mSkinnedMesh)); ReleaseCOM(optimizedTempMesh); // Done with tempMesh. ReleaseCOM(boneComboTable); // Don't need bone table. #if defined(DEBUG) | defined(_DEBUG) // Output to the debug output the vertex declaration of the mesh at this point. // This is for insight only to see what exactly ConvertToIndexedBlendedMesh // does to the vertex declaration. D3DVERTEXELEMENT9 elems[MAX_FVF_DECL_SIZE]; HR(mSkinnedMesh->GetDeclaration(elems)); OutputDebugString("\nVertex Format After ConvertToIndexedBlendedMesh\n"); int i = 0; while( elems[i].Stream != 0xff ) // While not D3DDECL_END() { if( elems[i].Type == D3DDECLTYPE_FLOAT1) OutputDebugString("Type = D3DDECLTYPE_FLOAT1; "); if( elems[i].Type == D3DDECLTYPE_FLOAT2) OutputDebugString("Type = D3DDECLTYPE_FLOAT2; "); if( elems[i].Type == D3DDECLTYPE_FLOAT3) OutputDebugString("Type = D3DDECLTYPE_FLOAT3; "); if( elems[i].Type == D3DDECLTYPE_UBYTE4) OutputDebugString("Type = D3DDECLTYPE_UBYTE4; "); if( elems[i].Usage == D3DDECLUSAGE_POSITION) OutputDebugString("Usage = D3DDECLUSAGE_POSITION\n"); if( elems[i].Usage == D3DDECLUSAGE_BLENDWEIGHT) OutputDebugString("Usage = D3DDECLUSAGE_BLENDWEIGHT\n"); if( elems[i].Usage == D3DDECLUSAGE_BLENDINDICES) OutputDebugString("Usage = D3DDECLUSAGE_BLENDINDICES\n"); if( elems[i].Usage == D3DDECLUSAGE_NORMAL) OutputDebugString("Usage = D3DDECLUSAGE_NORMAL\n"); if( elems[i].Usage == D3DDECLUSAGE_TEXCOORD) OutputDebugString("Usage = D3DDECLUSAGE_TEXCOORD\n"); ++i; } #endif }
/** Merges a set of D3DXMeshes. */ static void MergeD3DXMeshes( IDirect3DDevice9* Device, TRefCountPtr<ID3DXMesh>& OutMesh,TArray<int32>& OutBaseFaceIndex,const TArray<ID3DXMesh*>& Meshes) { TArray<D3DVERTEXELEMENT9> VertexElements; GetD3D9MeshVertexDeclarations(VertexElements); // Count the number of faces and vertices in the input meshes. int32 NumFaces = 0; int32 NumVertices = 0; for(int32 MeshIndex = 0;MeshIndex < Meshes.Num();MeshIndex++) { NumFaces += Meshes[MeshIndex]->GetNumFaces(); NumVertices += Meshes[MeshIndex]->GetNumVertices(); } // Create mesh for source data VERIFYD3D9RESULT(D3DXCreateMesh( NumFaces, NumVertices, D3DXMESH_SYSTEMMEM, (D3DVERTEXELEMENT9*)VertexElements.GetData(), Device, OutMesh.GetInitReference() ) ); // Fill D3DXMesh FUtilVertex* ResultVertices; uint16* ResultIndices; ::DWORD * ResultAttributes; OutMesh->LockVertexBuffer(0,(LPVOID*)&ResultVertices); OutMesh->LockIndexBuffer(0,(LPVOID*)&ResultIndices); OutMesh->LockAttributeBuffer(0, &ResultAttributes); int32 BaseVertexIndex = 0; int32 BaseFaceIndex = 0; for(int32 MeshIndex = 0;MeshIndex < Meshes.Num();MeshIndex++) { ID3DXMesh* Mesh = Meshes[MeshIndex]; FUtilVertex* Vertices; uint16* Indices; ::DWORD * Attributes; Mesh->LockVertexBuffer(0,(LPVOID*)&Vertices); Mesh->LockIndexBuffer(0,(LPVOID*)&Indices); Mesh->LockAttributeBuffer(0, &Attributes); for(uint32 FaceIndex = 0;FaceIndex < Mesh->GetNumFaces();FaceIndex++) { for(uint32 VertexIndex = 0;VertexIndex < 3;VertexIndex++) { *ResultIndices++ = BaseVertexIndex + *Indices++; } } OutBaseFaceIndex.Add(BaseFaceIndex); BaseFaceIndex += Mesh->GetNumFaces(); FMemory::Memcpy(ResultVertices,Vertices,Mesh->GetNumVertices() * sizeof(FUtilVertex)); ResultVertices += Mesh->GetNumVertices(); BaseVertexIndex += Mesh->GetNumVertices(); FMemory::Memcpy(ResultAttributes,Attributes,Mesh->GetNumFaces() * sizeof(uint32)); ResultAttributes += Mesh->GetNumFaces(); Mesh->UnlockIndexBuffer(); Mesh->UnlockVertexBuffer(); Mesh->UnlockAttributeBuffer(); } OutMesh->UnlockIndexBuffer(); OutMesh->UnlockVertexBuffer(); OutMesh->UnlockAttributeBuffer(); }
// This functions creates a sphere of "radius" and vertex color "color" bool CreateSphere(float radius, int color, ID3DXMesh **mesh) { assert(g3D->mDevice != NULL); assert(mesh != NULL); // This is the number of divisions the sphere will have vertically and // horizontally const unsigned int kSlices = 16; // Vertical divisions const unsigned int kStacks = 16; // Horizontal divisions ID3DXMesh *temp = NULL; // Temp D3D mesh object // Create the sphere // By parameter: // g3D->mDevice -- Pointer to the Direct3D device to be associated with the sphere // radius -- Radius of the sphere // kSlices -- Number of vertical divisions in the sphere // kStacks -- Number of horizontal divisions in the sphere // &temp -- A pointer to a ID3DXMesh*, it will get filled with the // the created mesh // NULL -- Optional pointer to a ID3DXBuffer, if a valid pointer was passed // it would be filled with the adjacency information for each face in // the mesh. By passing NULL, we say we don't want this information if(D3DXCreateSphere(g3D->mDevice, radius, kSlices, kStacks, &temp, NULL) != D3D_OK) return false; // Next we clone the mesh. This does two things. First, it allows us to // specify the vertex format we want on the cloned mesh. Second, it copies the // current mesh data into the ID3DXMesh we passed to this function. // By parameter: // D3DXMESH_VB_MANAGED | D3DXMESH_IB_MANAGED -- Flags specifying how we want the mesh to be // cloned. This particular flag combo says // "Have the vertex buffer and index buffer // associated with this mesh be in pooled memory // that DirectX manages for us." // SVertexType -- Flexible vertex format that we want the cloned mesh to be converted to // g3D->mDevice -- IDirect3DDevice9 to associate this mesh with // mesh -- A pointer to a ID3DXMesh* that will get filled with the cloned mesh if(temp->CloneMeshFVF(D3DXMESH_VB_MANAGED | D3DXMESH_IB_MANAGED, SVertexType, g3D->mDevice, mesh) != D3D_OK) { return false; } // Okay so up to this point we've created a stock D3D sphere, then converted // it a sphere with the FVF that we want. Now were going to // loop through each vertex and set it to the color that we want it to be SVertex *v; // Lock the vertex buffer if((*mesh)->LockVertexBuffer(0, (void**)&v) != D3D_OK) { (*mesh)->Release(); return false; } // Loop through all the verts in the mesh, setting each one's // color to the color passed into the function for(unsigned int i = 0; i < (*mesh)->GetNumVertices(); ++i) v[i].color = color; // Don't be stingy, unlock the vertex buffer so others can use it (*mesh)->UnlockVertexBuffer(); temp->Release(); // Last but not least, free up the temporary mesh return true; }
void Terrain::buildGeometry() { //=============================================================== // Create one large mesh for the grid in system memory. DWORD numTris = (mVertRows-1)*(mVertCols-1)*2; DWORD numVerts = mVertRows*mVertCols; ID3DXMesh* mesh = 0; D3DVERTEXELEMENT9 elems[MAX_FVF_DECL_SIZE]; UINT numElems = 0; HR(VertexPNT::Decl->GetDeclaration(elems, &numElems)); HR(D3DXCreateMesh(numTris, numVerts, D3DXMESH_SYSTEMMEM|D3DXMESH_32BIT, elems, gd3dDevice, &mesh)); //=============================================================== // Write the grid vertices and triangles to the mesh. VertexPNT* v = 0; HR(mesh->LockVertexBuffer(0, (void**)&v)); std::vector<D3DXVECTOR3> verts; std::vector<DWORD> indices; GenTriGrid(mVertRows, mVertCols, mDX, mDZ, D3DXVECTOR3(0.0f, 0.0f, 0.0f), verts, indices); float w = mWidth; float d = mDepth; for(UINT i = 0; i < mesh->GetNumVertices(); ++i) { // We store the grid vertices in a linear array, but we can // convert the linear array index to an (r, c) matrix index. int r = i / mVertCols; int c = i % mVertCols; v[i].pos = verts[i]; v[i].pos.y = mHeightmap(r, c); v[i].tex0.x = (v[i].pos.x + (0.5f*w)) / w; v[i].tex0.y = (v[i].pos.z - (0.5f*d)) / -d; } // Write triangle data so we can compute normals. DWORD* indexBuffPtr = 0; HR(mesh->LockIndexBuffer(0, (void**)&indexBuffPtr)); for(UINT i = 0; i < mesh->GetNumFaces(); ++i) { indexBuffPtr[i*3+0] = indices[i*3+0]; indexBuffPtr[i*3+1] = indices[i*3+1]; indexBuffPtr[i*3+2] = indices[i*3+2]; } HR(mesh->UnlockIndexBuffer()); // Compute Vertex Normals. HR(D3DXComputeNormals(mesh, 0)); //=============================================================== // Now break the grid up into subgrid meshes. // Find out the number of subgrids we'll have. For example, if // m = 513, n = 257, SUBGRID_VERT_ROWS = SUBGRID_VERT_COLS = 33, // then subGridRows = 512/32 = 16 and sibGridCols = 256/32 = 8. int subGridRows = (mVertRows-1) / (SubGrid::NUM_ROWS-1); int subGridCols = (mVertCols-1) / (SubGrid::NUM_COLS-1); for(int r = 0; r < subGridRows; ++r) { for(int c = 0; c < subGridCols; ++c) { // Rectangle that indicates (via matrix indices ij) the // portion of global grid vertices to use for this subgrid. RECT R = { c * (SubGrid::NUM_COLS-1), r * (SubGrid::NUM_ROWS-1), (c+1) * (SubGrid::NUM_COLS-1), (r+1) * (SubGrid::NUM_ROWS-1) }; buildSubGridMesh(R, v); } } HR(mesh->UnlockVertexBuffer()); ReleaseCOM(mesh); // Done with global mesh. }
void LoadXFile(const std::string & filename, ID3DXMesh** meshOut, std::vector<Mtrl> & mtrls, std::vector<IDirect3DTexture9*> & texs) { ID3DXMesh* meshSys = 0; ID3DXBuffer * adjBuffer = 0; ID3DXBuffer * mtrlBuffer = 0; DWORD numMtrls = 0; //step 1. Load the x file into system memory HR(D3DXLoadMeshFromX(filename.c_str(), D3DXMESH_SYSTEMMEM, gd3dDevice, &adjBuffer, &mtrlBuffer, 0, &numMtrls, &meshSys)); //step 2. look into MAX_FVF_DECL_SIZE D3DVERTEXELEMENT9 elems[MAX_FVF_DECL_SIZE]; HR(meshSys->GetDeclaration(elems)); bool hasNormals = false; D3DVERTEXELEMENT9 term = D3DDECL_END(); for(int i = 0; i < MAX_FVF_DECL_SIZE; ++i) { //did we reach end? if(elems[i].Stream == 0xff) break; if(elems[i].Type == D3DDECLTYPE_FLOAT3 && elems[i].Usage == D3DDECLUSAGE_NORMAL && elems[i].UsageIndex == 0) { hasNormals = true; break; } } //step 3. D3DVERTEXELEMENT9 elements[64]; UINT numElements = 0; VertexPNT::Decl->GetDeclaration(elements, &numElements); ID3DXMesh * temp = 0; //HR(meshSys->CloneMesh(D3DXMESH_SYSTEMMEM, elements, gd3dDevice, &temp)); HR(meshSys->CloneMesh(D3DXMESH_32BIT, elements, gd3dDevice, &temp)); ReleaseCOM(meshSys); meshSys = temp; //step 4 if( hasNormals == false ) HR(D3DXComputeNormals(meshSys, 0)); //step 5 HR(meshSys->Optimize(D3DXMESH_MANAGED | D3DXMESHOPT_COMPACT | D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_VERTEXCACHE, (DWORD*)adjBuffer->GetBufferPointer(), 0, 0, 0, meshOut)); ReleaseCOM(meshSys); //Done w/ system mesh ReleaseCOM(adjBuffer); //done with buffer //step 6: get the materials and load the textures if(mtrlBuffer != 0 && numMtrls != 0) { D3DXMATERIAL *d3dxMtrls = (D3DXMATERIAL*)mtrlBuffer->GetBufferPointer(); for(DWORD i = 0; i < numMtrls; ++i) { //save the ith material. MatD3D ambient //doesnt have a default value, so I'm setting //it to be the same as the diffuse Mtrl m; m.ambient = d3dxMtrls[i].MatD3D.Diffuse; m.diffuse = d3dxMtrls[i].MatD3D.Diffuse; m.spec = d3dxMtrls[i].MatD3D.Specular; m.specPower = d3dxMtrls[i].MatD3D.Power; mtrls.push_back(m); //check if the ith material has an associative texture if(d3dxMtrls[i].pTextureFilename != 0) { //yes, load the texture for the ith subset IDirect3DTexture9* tex = 0; char *texFN = d3dxMtrls[i].pTextureFilename; HR(D3DXCreateTextureFromFile(gd3dDevice, texFN, &tex)); //save the loaded texure texs.push_back(tex); } else { //no texture texs.push_back( 0 ); } } } ReleaseCOM(mtrlBuffer); // done with the buffer }
//-------------------------------------------------------------------------------------- HRESULT CMeshLoader::Create( IDirect3DDevice9* pd3dDevice, const WCHAR* strFilename ) { HRESULT hr; WCHAR str[ MAX_PATH ] = {0}; // Start clean Destroy(); // Store the device pointer m_pd3dDevice = pd3dDevice; // Load the vertex buffer, index buffer, and subset information from a file. In this case, // an .obj file was chosen for simplicity, but it's meant to illustrate that ID3DXMesh objects // can be filled from any mesh file format once the necessary data is extracted from file. //V_RETURN( LoadGeometryFromOBJ( strFilename ) ); V_RETURN( LoadGeometryFromOBJ_Fast( strFilename ) ); // Set the current directory based on where the mesh was found WCHAR wstrOldDir[MAX_PATH] = {0}; GetCurrentDirectory( MAX_PATH, wstrOldDir ); SetCurrentDirectory( m_strMediaDir ); // Load material textures for( int iMaterial = 0; iMaterial < m_Materials.GetSize(); iMaterial++ ) { Material* pMaterial = m_Materials.GetAt( iMaterial ); if( pMaterial->strTexture[0] ) { // Avoid loading the same texture twice bool bFound = false; for( int x = 0; x < iMaterial; x++ ) { Material* pCur = m_Materials.GetAt( x ); if( 0 == wcscmp( pCur->strTexture, pMaterial->strTexture ) ) { bFound = true; pMaterial->pTexture = pCur->pTexture; break; } } // Not found, load the texture if( !bFound ) { V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, pMaterial->strTexture ) ); V_RETURN( D3DXCreateTextureFromFile( pd3dDevice, pMaterial->strTexture, &( pMaterial->pTexture ) ) ); int a = 0; } } } // Restore the original current directory SetCurrentDirectory( wstrOldDir ); // Create the encapsulated mesh ID3DXMesh* pMesh = NULL; V_RETURN( D3DXCreateMesh( m_Indices.GetSize() / 3, m_Vertices.GetSize(), D3DXMESH_MANAGED | D3DXMESH_32BIT, VERTEX_DECL, pd3dDevice, &pMesh ) ); // Copy the vertex data VERTEX* pVertex; V_RETURN( pMesh->LockVertexBuffer( 0, ( void** )&pVertex ) ); memcpy( pVertex, m_Vertices.GetData(), m_Vertices.GetSize() * sizeof( VERTEX ) ); pMesh->UnlockVertexBuffer(); m_Vertices.RemoveAll(); // Copy the index data DWORD* pIndex; V_RETURN( pMesh->LockIndexBuffer( 0, ( void** )&pIndex ) ); memcpy( pIndex, m_Indices.GetData(), m_Indices.GetSize() * sizeof( DWORD ) ); pMesh->UnlockIndexBuffer(); m_Indices.RemoveAll(); // Copy the attribute data DWORD* pSubset; V_RETURN( pMesh->LockAttributeBuffer( 0, &pSubset ) ); memcpy( pSubset, m_Attributes.GetData(), m_Attributes.GetSize() * sizeof( DWORD ) ); pMesh->UnlockAttributeBuffer(); m_Attributes.RemoveAll(); // Reorder the vertices according to subset and optimize the mesh for this graphics // card's vertex cache. When rendering the mesh's triangle list the vertices will // cache hit more often so it won't have to re-execute the vertex shader. DWORD* aAdjacency = new DWORD[pMesh->GetNumFaces() * 3]; if( aAdjacency == NULL ) return E_OUTOFMEMORY; V( pMesh->GenerateAdjacency( 1e-6f, aAdjacency ) ); V( pMesh->OptimizeInplace( D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_VERTEXCACHE, aAdjacency, NULL, NULL, NULL ) ); SAFE_DELETE_ARRAY( aAdjacency ); m_pMesh = pMesh; return S_OK; }
WaterDemo::WaterDemo(HINSTANCE hInstance, std::string winCaption, D3DDEVTYPE devType, DWORD requestedVP) : D3DApp(hInstance, winCaption, devType, requestedVP) { if(!checkDeviceCaps()) { MessageBox(0, "checkDeviceCaps() Failed", 0, 0); PostQuitMessage(0); } InitAllVertexDeclarations(); mLight.dirW = D3DXVECTOR3(0.0f, -2.0f, -1.0f); D3DXVec3Normalize(&mLight.dirW, &mLight.dirW); mLight.ambient = D3DXCOLOR(0.3f, 0.3f, 0.3f, 1.0f); mLight.diffuse = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f); mLight.spec = D3DXCOLOR(0.7f, 0.7f, 0.7f, 1.0f); mGfxStats = new GfxStats(); mSky = new Sky("grassenvmap1024.dds", 10000.0f); D3DXMATRIX waterWorld; D3DXMatrixTranslation(&waterWorld, 0.0f, 2.0f, 0.0f); Mtrl waterMtrl; waterMtrl.ambient = D3DXCOLOR(0.26f, 0.23f, 0.3f, 0.90f); waterMtrl.diffuse = D3DXCOLOR(0.26f, 0.23f, 0.3f, 0.90f); waterMtrl.spec = 1.0f*WHITE; waterMtrl.specPower = 64.0f; Water::InitInfo waterInitInfo; waterInitInfo.dirLight = mLight; waterInitInfo.mtrl = waterMtrl; waterInitInfo.vertRows = 128; waterInitInfo.vertCols = 128; waterInitInfo.dx = 1.0f; waterInitInfo.dz = 1.0f; waterInitInfo.waveMapFilename0 = "wave0.dds"; waterInitInfo.waveMapFilename1 = "wave1.dds"; waterInitInfo.waveMapVelocity0 = D3DXVECTOR2(0.05f, 0.08f); waterInitInfo.waveMapVelocity1 = D3DXVECTOR2(-0.02f, 0.1f); waterInitInfo.texScale = 16.0f; waterInitInfo.toWorld = waterWorld; mWater = new Water(waterInitInfo); mWater->setEnvMap(mSky->getEnvMap()); ID3DXMesh* tempMesh = 0; LoadXFile("BasicColumnScene.x", &tempMesh, mSceneMtrls, mSceneTextures); // Get the vertex declaration for the NMapVertex. D3DVERTEXELEMENT9 elems[MAX_FVF_DECL_SIZE]; UINT numElems = 0; HR(NMapVertex::Decl->GetDeclaration(elems, &numElems)); // Clone the mesh to the NMapVertex format. ID3DXMesh* clonedTempMesh = 0; HR(tempMesh->CloneMesh(D3DXMESH_MANAGED, elems, gd3dDevice, &clonedTempMesh)); // Now use D3DXComputeTangentFrameEx to build the TNB-basis for each vertex // in the mesh. HR(D3DXComputeTangentFrameEx( clonedTempMesh, // Input mesh D3DDECLUSAGE_TEXCOORD, 0, // Vertex element of input tex-coords. D3DDECLUSAGE_BINORMAL, 0, // Vertex element to output binormal. D3DDECLUSAGE_TANGENT, 0, // Vertex element to output tangent. D3DDECLUSAGE_NORMAL, 0, // Vertex element to output normal. 0, // Options 0, // Adjacency 0.01f, 0.25f, 0.01f, // Thresholds for handling errors &mSceneMesh, // Output mesh 0)); // Vertex Remapping // Done with temps. ReleaseCOM(tempMesh); ReleaseCOM(clonedTempMesh); D3DXMatrixIdentity(&mSceneWorld); D3DXMatrixIdentity(&mSceneWorldInv); HR(D3DXCreateTextureFromFile(gd3dDevice, "floor_nmap.bmp", &mSceneNormalMaps[0])); HR(D3DXCreateTextureFromFile(gd3dDevice, "bricks_nmap.bmp", &mSceneNormalMaps[1])); HR(D3DXCreateTextureFromFile(gd3dDevice, "whitetex.dds", &mWhiteTex)); // Initialize camera. gCamera->pos().y = 7.0f; gCamera->pos().z = -30.0f; gCamera->setSpeed(10.0f); mGfxStats->addVertices(mSceneMesh->GetNumVertices()); mGfxStats->addTriangles(mSceneMesh->GetNumFaces()); mGfxStats->addVertices(mWater->getNumVertices()); mGfxStats->addTriangles(mWater->getNumTriangles()); mGfxStats->addVertices(mSky->getNumVertices()); mGfxStats->addTriangles(mSky->getNumTriangles()); buildFX(); onResetDevice(); }
void PropsDemo::drawScene() { // Clear the backbuffer and depth buffer. HR(gd3dDevice->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xff888888, 1.0f, 0)); HR(gd3dDevice->BeginScene()); HR(mFX->SetValue(mhEyePosW, &gCamera->pos(), sizeof(D3DXVECTOR3))); HR(mFX->SetTechnique(mhTech)); UINT numPasses = 0; HR(mFX->Begin(&numPasses, 0)); HR(mFX->BeginPass(0)); drawObject(mCastle, mCastleWorld); // Use alpha test to block non leaf pixels from being rendered in the // trees (i.e., use alpha mask). HR(gd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, true)); HR(gd3dDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL)); HR(gd3dDevice->SetRenderState(D3DRS_ALPHAREF, 200)); // Draw the trees: NUM_TREES/4 of each of the four types. for(int i = 0; i < NUM_TREES; ++i) { if( i < NUM_TREES/4 ) drawObject(mTrees[0], mTreeWorlds[i]); else if( i < 2*NUM_TREES/4 ) drawObject(mTrees[1], mTreeWorlds[i]); else if( i < 3*NUM_TREES/4 ) drawObject(mTrees[2], mTreeWorlds[i]); else drawObject(mTrees[3], mTreeWorlds[i]); } HR(gd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, false)); HR(mFX->EndPass()); HR(mFX->End()); HR(mGrassFX->SetValue(mhGrassEyePosW, &gCamera->pos(), sizeof(D3DXVECTOR3))); HR(mGrassFX->SetMatrix(mhGrassViewProj, &(gCamera->viewProj()))); HR(mGrassFX->SetFloat(mhGrassTime, mTime)); HR(mGrassFX->Begin(&numPasses, 0)); HR(mGrassFX->BeginPass(0)); // Draw to depth buffer only. HR(mGrassMesh->DrawSubset(0)); HR(mGrassFX->EndPass()); HR(mGrassFX->End()); mTerrain->draw(); mWater->draw(); // draw alpha blended objects last. mGfxStats->display(); HR(gd3dDevice->EndScene()); // Present the backbuffer. HR(gd3dDevice->Present(0, 0, 0, 0)); }
void PropsDemo::buildGrass() { D3DVERTEXELEMENT9 elems[MAX_FVF_DECL_SIZE]; UINT numElems = 0; HR(GrassVertex::Decl->GetDeclaration(elems, &numElems)); HR(D3DXCreateMesh(NUM_GRASS_BLOCKS*2, NUM_GRASS_BLOCKS*4, D3DXMESH_MANAGED, elems, gd3dDevice, &mGrassMesh)); GrassVertex* v = 0; WORD* k = 0; HR(mGrassMesh->LockVertexBuffer(0, (void**)&v)); HR(mGrassMesh->LockIndexBuffer(0, (void**)&k)); int indexOffset = 0; // Scale down the region in which we generate grass. int w = (int)(mTerrain->getWidth() * 0.15f); int d = (int)(mTerrain->getDepth() * 0.15f); // Randomly generate a grass block (three intersecting quads) around the // terrain in the height range [35, 50] (similar to the trees). for(int i = 0; i < NUM_GRASS_BLOCKS; ++i) { //============================================ // Construct vertices. // Generate random position in region. Note that we also shift // this region to place it in the world. float x = (float)((rand() % w) - (w*0.5f)) - 30.0f; float z = (float)((rand() % d) - (d*0.5f)) - 20.0f; float y = mTerrain->getHeight(x, z); // Only generate grass blocks in this height range. If the height // is outside this range, generate a new random position and // try again. if(y < 37.0f || y > 40.0f) { --i; // We are trying again, so decrement back the index. continue; } float sx = GetRandomFloat(0.75f, 1.25f); float sy = GetRandomFloat(0.75f, 1.25f); float sz = GetRandomFloat(0.75f, 1.25f); D3DXVECTOR3 pos(x, y, z); D3DXVECTOR3 scale(sx, sy, sz); buildGrassFin(v, k, indexOffset, pos, scale); v += 4; k += 6; } HR(mGrassMesh->UnlockVertexBuffer()); HR(mGrassMesh->UnlockIndexBuffer()); // Fill in the attribute buffer (everything in subset 0) DWORD* attributeBufferPtr = 0; HR(mGrassMesh->LockAttributeBuffer(0, &attributeBufferPtr)); for(UINT i = 0; i < mGrassMesh->GetNumFaces(); ++i) attributeBufferPtr[i] = 0; HR(mGrassMesh->UnlockAttributeBuffer()); DWORD* adj = new DWORD[mGrassMesh->GetNumFaces()*3]; HR(mGrassMesh->GenerateAdjacency(EPSILON, adj)); HR(mGrassMesh->OptimizeInplace(D3DXMESHOPT_ATTRSORT|D3DXMESHOPT_VERTEXCACHE, adj, 0, 0, 0)); delete [] adj; }
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASS wc; wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; wc.lpfnWndProc = (WNDPROC) MainWindowProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW)); wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = "xtocmod"; if (RegisterClass(&wc) == 0) { MessageBox(NULL, "Failed to register the window class.", "Fatal Error", MB_OK | MB_ICONERROR); return NULL; } DWORD windowStyle = (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX); g_mainWindow = CreateWindow("xtocmod", "xtocmod", windowStyle, CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, NULL, NULL, hInstance, NULL); if (g_mainWindow == NULL) { MessageBox(NULL, "Error creating application window.", "Fatal Error", MB_OK | MB_ICONERROR); } //ShowWindow(g_mainWindow, SW_SHOW); SetForegroundWindow(g_mainWindow); SetFocus(g_mainWindow); // Initialize D3D g_d3d = Direct3DCreate9(D3D_SDK_VERSION); if (g_d3d == NULL) { ShowD3DErrorMessage("Initializing D3D", 0); return 1; } D3DPRESENT_PARAMETERS presentParams; ZeroMemory(&presentParams, sizeof(presentParams)); presentParams.Windowed = TRUE; presentParams.SwapEffect = D3DSWAPEFFECT_COPY; #if 0 presentParams.BackBufferWidth = 300; presentParams.BackBufferHeight = 300; presentParams.BackBufferCount = 1; presentParams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; presentParams.Windowed = TRUE; #endif HRESULT hr = g_d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_mainWindow, D3DCREATE_HARDWARE_VERTEXPROCESSING, &presentParams, &g_d3dDev); if (FAILED(hr)) { ShowD3DErrorMessage("Creating D3D device", hr); //return 1; } string inputFilename(lpCmdLine); string outputFilename(inputFilename, 0, inputFilename.rfind('.')); outputFilename += ".cmod"; ID3DXMesh* mesh = NULL; ID3DXBuffer* adjacency = NULL; ID3DXBuffer* materialBuf = NULL; ID3DXBuffer* effects = NULL; DWORD numMaterials; hr = D3DXLoadMeshFromX(inputFilename.c_str(), 0, g_d3dDev, &adjacency, &materialBuf, &effects, &numMaterials, &mesh); if (FAILED(hr)) { ShowD3DErrorMessage("Loading mesh from X file", hr); return 1; } DWORD numVertices = mesh->GetNumVertices(); DWORD numFaces = mesh->GetNumFaces(); cout << "vertices: " << numVertices << '\n'; cout << "faces: " << numFaces << '\n'; cout << "adjacency buffer size: " << adjacency->GetBufferSize() << '\n'; ofstream meshfile(outputFilename.c_str()); // Output the header meshfile << "#celmodel__ascii\n\n"; cout << "numMaterials=" << numMaterials << '\n'; D3DXMATERIAL* materials = reinterpret_cast<D3DXMATERIAL*>(materialBuf->GetBufferPointer()); for (DWORD mat = 0; mat < numMaterials; mat++) { meshfile << "material\n"; meshfile << "diffuse " << materials[mat].MatD3D.Diffuse << '\n'; //meshfile << "emissive " << materials[mat].MatD3D.Emissive << '\n'; meshfile << "specular " << materials[mat].MatD3D.Specular << '\n'; meshfile << "specpower " << materials[mat].MatD3D.Power << '\n'; meshfile << "opacity " << materials[mat].MatD3D.Diffuse.a << '\n'; meshfile << "end_material\n\n"; } // Vertex format D3DVERTEXELEMENT9 declElements[MAX_FVF_DECL_SIZE]; hr = mesh->GetDeclaration(declElements); if (FAILED(hr)) { ShowD3DErrorMessage("Checking vertex declaration", hr); return 1; } DWORD stride = D3DXGetDeclVertexSize(declElements, 0); VertexAttribute vertexMap[VertexAttribute::MaxAttribute]; CreateVertexAttributeMap(declElements, vertexMap); meshfile << "mesh\n\n"; DumpVertexDescription(vertexMap, meshfile); ID3DXMesh* optMesh = NULL; ID3DXBuffer* vertexRemap = NULL; DWORD* faceRemap = new DWORD[numFaces]; DWORD* optAdjacency = new DWORD[numFaces * 3]; hr = mesh->Optimize(D3DXMESHOPT_COMPACT | D3DXMESHOPT_STRIPREORDER, //D3DXMESHOPT_VERTEXCACHE | reinterpret_cast<DWORD*>(adjacency->GetBufferPointer()), optAdjacency, faceRemap, &vertexRemap, &optMesh); if (FAILED(hr)) { ShowD3DErrorMessage("Optimize failed: ", hr); return 1; } // Attribute table DWORD attribTableSize = 0; hr = optMesh->GetAttributeTable(NULL, &attribTableSize); if (FAILED(hr)) { ShowD3DErrorMessage("Querying attribute table size", hr); return 1; } D3DXATTRIBUTERANGE* attribTable = NULL; if (attribTableSize > 0) { attribTable = new D3DXATTRIBUTERANGE[attribTableSize]; hr = optMesh->GetAttributeTable(attribTable, &attribTableSize); if (FAILED(hr)) { ShowD3DErrorMessage("Getting attribute table", hr); return 1; } } cout << "Attribute table size: " << attribTableSize << '\n'; if (attribTableSize == 1) { cout << "Attribute id: " << attribTable[0].AttribId << '\n'; } if (!DumpMeshVertices(optMesh, vertexMap, stride, meshfile)) return 1; // output the indices for (DWORD attr = 0; attr < attribTableSize; attr++) { StripifyMeshSubset(optMesh, attr, meshfile); } meshfile << "\nend_mesh\n"; #if 0 IDirect3DIndexBuffer9* indices = NULL; hr = mesh->GetIndexBuffer(&indices); #endif #if 0 // No message loop required for this app MSG msg; GetMessage(&msg, NULL, 0u, 0u); while (msg.message != WM_QUIT) { GetMessage(&msg, NULL, 0u, 0u); TranslateMessage(&msg); DispatchMessage(&msg); } #endif return 0; }
void World::editTerrain() { BOOL hit = false; DWORD faceIndex, hitCount; float u, v, dist; LPD3DXBUFFER allHits; ID3DXMesh* mesh = mTerrain->getMesh()->getMesh(); if(gInput->keyDown(VK_LBUTTON) || gInput->keyDown(VK_RBUTTON)) { float strength = 300.0f; if(gInput->keyDown(VK_RBUTTON)) strength *= -1; D3DXVECTOR3 origin, dir; gInput->getWorldPickingRay(origin, dir); D3DXIntersect(mesh, &origin, &dir, &hit, &faceIndex, &u, &v, &dist, &allHits, &hitCount); if(hit) { DWORD* k = 0; mesh->LockIndexBuffer(0, (void**)&k); int pressed = k[faceIndex*3]; mesh->UnlockIndexBuffer(); VertexPNT* v = 0; mesh->LockVertexBuffer(0, (void**)&v); int size = 10; int x = pressed % mTerrain->getColums(); int z = pressed / mTerrain->getColums(); for(int i = z - size/2; i < z + size/2; i++) for(int j = x - size/2; j < x + size/2; j++) { if(i < 0 || j < 0 || i >= mTerrain->getRows() || j >= mTerrain->getColums()) continue; float dist = sqrt((float)(z-i)*(z-i) + (float)(x-j)*(x-j)); dist = max(dist, 3.0f); if(strength > 0) v[i*mTerrain->getColums() + j].pos.y += min(strength / dist, strength)/100; else v[i*mTerrain->getColums() + j].pos.y += max(strength / dist, strength)/100; } mesh->UnlockVertexBuffer(); //mTerrain->smothOut(x, z, 10); } } if(gInput->keyPressed(VK_MBUTTON)) { D3DXIntersect(mesh, &gCamera->getPosition(), &gCamera->getDirection(), &hit, &faceIndex, &u, &v, &dist, &allHits, &hitCount); if(hit) { DWORD* k = 0; mesh->LockIndexBuffer(0, (void**)&k); int pressed = k[faceIndex*3]; mesh->UnlockIndexBuffer(); VertexPNT* v = 0; mesh->LockVertexBuffer(0, (void**)&v); int size = 10; int x = pressed % mTerrain->getColums(); int z = pressed / mTerrain->getColums(); mTerrain->smothOut(x, z, 5); } } }
bool CMeshBundle::loadMesh( const CResourceId& id, const CResourceId& fullName, CMesh& mesh ) const { // try to load with D3DX // obsolete case: .X files if( CStringHelper::endsWith( fullName.getUniqueName(), ".x" ) || CStringHelper::endsWith( fullName.getUniqueName(), ".X" ) ) { ID3DXBuffer* adjancency = NULL; ID3DXBuffer* material = NULL; ID3DXBuffer* effects = NULL; DWORD matCount; ID3DXMesh* dxmesh = NULL; HRESULT hres = D3DXLoadMeshFromX( fullName.getUniqueName().c_str(), D3DXMESH_SYSTEMMEM, &CD3DDevice::getInstance().getDevice(), &adjancency, &material, &effects, &matCount, &dxmesh ); if( !SUCCEEDED( hres ) ) return false; assert( dxmesh ); if( adjancency ) adjancency->Release(); if( material ) material->Release(); if( effects ) effects->Release(); // // init our mesh assert( !mesh.isCreated() ); // HACK - very limited int formatFlags = 0; DWORD dxFormat = dxmesh->GetFVF(); if( dxFormat & D3DFVF_XYZ ) formatFlags |= CVertexFormat::V_POSITION; if( dxFormat & D3DFVF_NORMAL ) formatFlags |= CVertexFormat::V_NORMAL; if( dxFormat & D3DFVF_TEX1 ) formatFlags |= CVertexFormat::V_UV0_2D; CVertexFormat vertFormat( formatFlags ); // HACK int indexStride = 2; CD3DVertexDecl* vertDecl = RGET_VDECL( CVertexDesc( vertFormat ) ); mesh.createResource( dxmesh->GetNumVertices(), dxmesh->GetNumFaces()*3, vertFormat, indexStride, *vertDecl, CMesh::BUF_STATIC ); // // now, copy data into our mesh void *dxvb, *dxib; dxmesh->LockVertexBuffer( 0, &dxvb ); dxmesh->LockIndexBuffer( 0, &dxib ); void* myvb = mesh.lockVBWrite(); void* myib = mesh.lockIBWrite(); memcpy( myvb, dxvb, mesh.getVertexCount() * mesh.getVertexStride() ); memcpy( myib, dxib, mesh.getIndexCount() * mesh.getIndexStride() ); dxmesh->UnlockVertexBuffer(); dxmesh->UnlockIndexBuffer(); mesh.unlockVBWrite(); mesh.unlockIBWrite(); // // create groups int ngroups; dxmesh->GetAttributeTable( 0, (DWORD*)&ngroups ); D3DXATTRIBUTERANGE *attrs = new D3DXATTRIBUTERANGE[ngroups]; dxmesh->GetAttributeTable( attrs, (DWORD*)&ngroups ); for( int i = 0; i < ngroups; ++i ) { const D3DXATTRIBUTERANGE& a = attrs[i]; mesh.addGroup( CMesh::CGroup( a.VertexStart, a.VertexCount, a.FaceStart, a.FaceCount ) ); } delete[] attrs; // release d3dx mesh dxmesh->Release(); } else { // our own format assert( !mesh.isCreated() ); bool ok = CMeshSerializer::loadMeshFromFile( fullName.getUniqueName().c_str(), mesh ); if( !ok ) return false; } mesh.computeAABBs(); CONSOLE.write( "mesh loaded '" + id.getUniqueName() + "'" ); return true; }
ID3DXMesh* GenerateSphere(IDirect3DDevice9* device, float radius, UINT rings, UINT sectors) { if (!device) { return 0; } const DWORD numVertexes = rings * sectors; const DWORD numFaces = (rings - 1) * (sectors - 1) * 2; ID3DXMesh* mesh = 0; HRESULT hr = D3DXCreateMeshFVF(numFaces, numVertexes, D3DXMESH_32BIT | D3DXMESH_VB_WRITEONLY | D3DXMESH_IB_WRITEONLY, D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1, device, &mesh); if (FAILED(hr)) { MessageBox(0, L"Unable to generate sphere", L"Application error", MB_ICONSTOP); return 0; } SphereVertex* vertexes = 0; DWORD* indexes = 0; mesh->LockVertexBuffer(0, (void**)&vertexes); mesh->LockIndexBuffer(0, (void**)&indexes); float const R = 1.f / (float)(rings - 1); float const S = 1.f / (float)(sectors - 1); // for (UINT ring = 0; ring < rings; ring++) { for (UINT sector = 0; sector < sectors; sector++) { float const y = sin(D3DX_PI * 0.5f + D3DX_PI * ring * R ); float const x = cos(2 * D3DX_PI * sector * S) * sin( D3DX_PI * ring * R ); float const z = sin(2 * D3DX_PI * sector * S) * sin( D3DX_PI * ring * R ); SphereVertex* vertex = vertexes++; vertex->pos = Vec3(x, y, z) * radius; // D3DXVec3Normalize(&vertex->normal, &vertex->pos); vertex->tex = Vec2(sector / (float)(sectors - 1.0f), ring / (float)(rings - 1.0f)); } } // for (UINT ring = 0; ring < rings - 1; ++ring) { for (UINT sector = 0; sector < sectors - 1; ++sector) { DWORD v0 = ring * sectors + sector; DWORD v1 = ring * sectors + sector + 1; DWORD v2 = (ring + 1) * sectors + sector; DWORD v3 = (ring + 1) * sectors + sector + 1; *indexes++ = v0; *indexes++ = v1; *indexes++ = v2; *indexes++ = v2; *indexes++ = v1; *indexes++ = v3; } } mesh->UnlockIndexBuffer(); mesh->UnlockVertexBuffer(); return mesh; }
ID3DXMesh* CMesh::createD3DXMesh() const { HRESULT hr; ID3DXMesh* dxMesh = 0; DWORD meshOpts = D3DXMESH_MANAGED; if( getIndexStride() == 4 ) meshOpts |= D3DXMESH_32BIT; // get declaration D3DVERTEXELEMENT9 decl[MAX_FVF_DECL_SIZE]; UINT numElements; getVertexDecl().getObject()->GetDeclaration( decl, &numElements ); // create mesh hr = D3DXCreateMesh( getIndexCount()/3, getVertexCount(), meshOpts, decl, &CD3DDevice::getInstance().getDevice(), &dxMesh ); if( FAILED(hr) ) return NULL; // copy VB { const void* srcVB = lockVBRead(); void* dxVB = 0; hr = dxMesh->LockVertexBuffer( 0, &dxVB ); if( FAILED(hr) ) { dxMesh->Release(); return NULL; } memcpy( dxVB, srcVB, getVertexCount() * getVertexStride() ); hr = dxMesh->UnlockVertexBuffer(); unlockVBRead(); } // copy IB { const void* srcIB = lockIBRead(); void* dxIB = 0; hr = dxMesh->LockIndexBuffer( 0, &dxIB ); if( FAILED(hr) ) { dxMesh->Release(); return NULL; } memcpy( dxIB, srcIB, getIndexCount() * getIndexStride() ); hr = dxMesh->UnlockIndexBuffer(); unlockIBRead(); } // copy groups { int ngroups = getGroupCount(); D3DXATTRIBUTERANGE* attrs = new D3DXATTRIBUTERANGE[ngroups]; DWORD* attrBuf = 0; hr = dxMesh->LockAttributeBuffer( 0, &attrBuf ); if( FAILED(hr) ) { dxMesh->Release(); return NULL; } for( int g = 0; g < ngroups; ++g ) { attrs[g].AttribId = g; const CMesh::CGroup& group = getGroup(g); attrs[g].VertexStart = group.getFirstVertex(); attrs[g].VertexCount = group.getVertexCount(); attrs[g].FaceStart = group.getFirstPrim(); attrs[g].FaceCount = group.getPrimCount(); for( int f = 0; f < group.getPrimCount(); ++f ) *attrBuf++ = g; } dxMesh->UnlockAttributeBuffer(); hr = dxMesh->SetAttributeTable( attrs, ngroups ); delete[] attrs; } return dxMesh; }
Mesh* GenerateCylinder(IDirect3DDevice9* device, float radius, float height, UINT sectors) { if (!device) { return 0; } const DWORD numVertexes = 2 * (sectors + 1); const DWORD numFaces = 2 * sectors; ID3DXMesh* mesh = 0; HRESULT hr = D3DXCreateMeshFVF(numFaces, numVertexes, D3DXMESH_32BIT | D3DXMESH_VB_WRITEONLY | D3DXMESH_IB_WRITEONLY, D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1, device, &mesh); if (FAILED(hr)) { MessageBox(0, L"Unable to generate sphere", L"Application error", MB_ICONSTOP); return 0; } SphereVertex* vertexes = 0; DWORD* indexes = 0; mesh->LockVertexBuffer(0, (void**)&vertexes); mesh->LockIndexBuffer(0, (void**)&indexes); const UINT rings = 1; // for (UINT ring = 0; ring < rings + 1; ring++) { for (UINT sector = 0; sector < sectors + 1; sector++) { const float z = sinf(sector * D3DX_PI * 2.f / sectors) * radius; const float x = cosf(sector * D3DX_PI * 2.f / sectors) * radius ; const float y = height * (1.0f - (ring / rings)); SphereVertex* vertex = vertexes++; vertex->pos = Vec3(x, y, z); vertex->normal = Vec3(x, 0, z); vertex->tex = Vec2((FLOAT)sector / (sectors - 1), (FLOAT)ring / rings ); } } // for (UINT ring = 0; ring < rings; ++ring) { for (UINT sector = 0; sector < sectors; ++sector) { DWORD v0 = (ring * (sectors + 1) + sector); DWORD v1 = (ring * (sectors + 1) + sector + 1); DWORD v2 = ((ring + 1) * (sectors + 1) + sector); DWORD v3 = ((ring + 1) * (sectors + 1) + sector + 1); *indexes++ = v0; *indexes++ = v1; *indexes++ = v2; *indexes++ = v2; *indexes++ = v1; *indexes++ = v3; } } mesh->UnlockIndexBuffer(); mesh->UnlockVertexBuffer(); return mesh; }
void Scene::LoadFromXFile(string file, IDirect3DDevice9 *device) { assert(device); ID3DXBuffer *material = nullptr; DWORD num_material = 0; ID3DXMesh *mesh = nullptr; HRESULT res = D3DXLoadMeshFromX(file.c_str(), // pFilename D3DXMESH_DYNAMIC, // Options device, // pD3DDevice nullptr, // ppAdjacency &material, // ppMaterials nullptr, // ppEffectInstances &num_material, // pNumMaterials &mesh); // ppMesh if (FAILED(res)) { Logger::GtLogError("load mesh from X file failed:%s", file.c_str()); return; } assert(num_material == 1); D3DXMATERIAL *mat = static_cast<D3DXMATERIAL *>(material->GetBufferPointer()); material_.ambient.r = mat->MatD3D.Ambient.r; material_.ambient.g = mat->MatD3D.Ambient.g; material_.ambient.b = mat->MatD3D.Ambient.b; material_.ambient.a = mat->MatD3D.Ambient.a; material_.diffuse.r = mat->MatD3D.Diffuse.r; material_.diffuse.g = mat->MatD3D.Diffuse.g; material_.diffuse.b = mat->MatD3D.Diffuse.b; material_.diffuse.a = mat->MatD3D.Diffuse.a; material_.specular.r = mat->MatD3D.Specular.r; material_.specular.g = mat->MatD3D.Specular.g; material_.specular.b = mat->MatD3D.Specular.b; material_.specular.a = mat->MatD3D.Specular.a; material_.emissive.r = mat->MatD3D.Emissive.r; material_.emissive.g = mat->MatD3D.Emissive.g; material_.emissive.b = mat->MatD3D.Emissive.b; material_.emissive.a = mat->MatD3D.Emissive.a; material_.power = mat->MatD3D.Power; bool ret = texture_.Load(mat->pTextureFilename, device); assert(ret); material->Release(); DWORD num_vertex = mesh->GetNumVertices(); IDirect3DVertexBuffer9 *vertex_buffer = nullptr; res = mesh->GetVertexBuffer(&vertex_buffer); assert(SUCCEEDED(res)); uint8 *vertex_data = nullptr; res = vertex_buffer->Lock(0, 0, reinterpret_cast<void **>(&vertex_data), D3DLOCK_READONLY); assert(SUCCEEDED(res)); D3DVERTEXELEMENT9 vertex_elements[MAX_FVF_DECL_SIZE] = {0}; res = mesh->GetDeclaration(vertex_elements); assert(SUCCEEDED(res)); int offset_pos = 0; int offset_nor = 0; int offset_tex = 0; int vertex_size = mesh->GetNumBytesPerVertex(); for (int i = 0; i < MAX_FVF_DECL_SIZE; ++i) { if (vertex_elements[i].Type == D3DDECLTYPE_UNUSED) break; if (vertex_elements[i].Usage == D3DDECLUSAGE_POSITION) { offset_pos = vertex_elements[i].Offset; } if (vertex_elements[i].Usage == D3DDECLUSAGE_NORMAL) { offset_nor = vertex_elements[i].Offset; } if (vertex_elements[i].Usage == D3DDECLUSAGE_TEXCOORD) { offset_tex = vertex_elements[i].Offset; } } Primitive verteies(num_vertex, nullptr, nullptr); for (int i = 0; i < num_vertex; ++i) { verteies.positions[i] = *reinterpret_cast<Vector3 *>(vertex_data + vertex_size * i + offset_pos); verteies.positions[i].Display(); verteies.normals[i] = *reinterpret_cast<Vector3 *>(vertex_data + vertex_size * i + offset_nor); verteies.normals[i].Display(); verteies.uvs[i] = *reinterpret_cast<Vector2 *>(vertex_data + vertex_size * i + offset_tex); verteies.uvs[i].Display(); } primitive_ = verteies; vertex_buffer->Unlock(); vertex_buffer->Release(); }
void LoadXFile( const std::string& filename, ID3DXMesh** meshOut, std::vector<Mtrl>& mtrls, std::vector<IDirect3DTexture9*>& texs) { // Step 1: Load the .x file from file into a system memory mesh. ID3DXMesh* meshSys = 0; ID3DXBuffer* adjBuffer = 0; ID3DXBuffer* mtrlBuffer = 0; DWORD numMtrls = 0; HR(D3DXLoadMeshFromX(filename.c_str(), D3DXMESH_SYSTEMMEM, gd3dDevice, &adjBuffer, &mtrlBuffer, 0, &numMtrls, &meshSys)); // Step 2: Find out if the mesh already has normal info? D3DVERTEXELEMENT9 elems[MAX_FVF_DECL_SIZE]; HR(meshSys->GetDeclaration(elems)); bool hasNormals = false; D3DVERTEXELEMENT9 term = D3DDECL_END(); for(int i = 0; i < MAX_FVF_DECL_SIZE; ++i) { // Did we reach D3DDECL_END() {0xFF,0,D3DDECLTYPE_UNUSED, 0,0,0}? if(elems[i].Stream == 0xff ) break; if( elems[i].Type == D3DDECLTYPE_FLOAT3 && elems[i].Usage == D3DDECLUSAGE_NORMAL && elems[i].UsageIndex == 0 ) { hasNormals = true; break; } } // Step 3: Change vertex format to VertexPNT. D3DVERTEXELEMENT9 elements[64]; UINT numElements = 0; VertexPNT::Decl->GetDeclaration(elements, &numElements); ID3DXMesh* temp = 0; HR(meshSys->CloneMesh(D3DXMESH_SYSTEMMEM, elements, gd3dDevice, &temp)); ReleaseCOM(meshSys); meshSys = temp; // Step 4: If the mesh did not have normals, generate them. if( hasNormals == false) HR(D3DXComputeNormals(meshSys, 0)); // Step 5: Optimize the mesh. HR(meshSys->Optimize(D3DXMESH_MANAGED | D3DXMESHOPT_COMPACT | D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_VERTEXCACHE, (DWORD*)adjBuffer->GetBufferPointer(), 0, 0, 0, meshOut)); ReleaseCOM(meshSys); // Done w/ system mesh. ReleaseCOM(adjBuffer); // Done with buffer. // Step 6: Extract the materials and load the textures. if( mtrlBuffer != 0 && numMtrls != 0 ) { D3DXMATERIAL* d3dxmtrls = (D3DXMATERIAL*)mtrlBuffer->GetBufferPointer(); for(DWORD i = 0; i < numMtrls; ++i) { // Save the ith material. Note that the MatD3D property does not have an ambient // value set when its loaded, so just set it to the diffuse value. Mtrl m; m.ambient = d3dxmtrls[i].MatD3D.Diffuse; m.diffuse = d3dxmtrls[i].MatD3D.Diffuse; m.spec = d3dxmtrls[i].MatD3D.Specular; m.specPower = d3dxmtrls[i].MatD3D.Power; mtrls.push_back( m ); // Check if the ith material has an associative texture if( d3dxmtrls[i].pTextureFilename != 0 ) { // Yes, load the texture for the ith subset IDirect3DTexture9* tex = 0; char* texFN = d3dxmtrls[i].pTextureFilename; HR(D3DXCreateTextureFromFile(gd3dDevice, texFN, &tex)); // Save the loaded texture texs.push_back( tex ); } else { // No texture for the ith subset texs.push_back( 0 ); } } } ReleaseCOM(mtrlBuffer); // done w/ buffer }
void XManager::loadXFile(IDirect3DDevice9* dev, const std::string& filename, ID3DXMesh** meshOut, std::vector<Material>* mtrls, std::vector<IDirect3DTexture9*>* texs) { // Step 1: Load the .x file from file into a system memory mesh. ID3DXMesh* meshSys = 0; ID3DXBuffer* adjBuffer = 0; ID3DXBuffer* mtrlBuffer = 0; DWORD numMtrls = 0; HR(D3DXLoadMeshFromX(filename.c_str(), D3DXMESH_SYSTEMMEM, dev, &adjBuffer, &mtrlBuffer, 0, &numMtrls, &meshSys)); // Step 2: Find out if the mesh already has normal info? D3DVERTEXELEMENT9 elems[MAX_FVF_DECL_SIZE]; HR(meshSys->GetDeclaration(elems)); bool hasNormals = false; D3DVERTEXELEMENT9 term = D3DDECL_END(); for(int i = 0; i < MAX_FVF_DECL_SIZE; ++i) { // Did we reach D3DDECL_END() {0xFF,0,D3DDECLTYPE_UNUSED, 0,0,0}? if(elems[i].Stream == 0xff ) break; if( elems[i].Type == D3DDECLTYPE_FLOAT3 && elems[i].Usage == D3DDECLUSAGE_NORMAL && elems[i].UsageIndex == 0 ) { hasNormals = true; break; } } // Step 3: Change vertex format to CustomVertex3NormalUV D3DVERTEXELEMENT9 elements[64]; UINT numElements = 0; CustomVertex3NormalUV::decl->GetDeclaration(elements, &numElements); ID3DXMesh* temp = 0; HR(meshSys->CloneMesh(D3DXMESH_SYSTEMMEM, elements, dev, &temp)); SAFERELEASECOM(meshSys); meshSys = temp; // Step 4: If the mesh did not have normals, generate them. if( hasNormals == false) HR(D3DXComputeNormals(meshSys, 0)); // Step 5: Optimize the mesh. HR(meshSys->Optimize(D3DXMESH_MANAGED | D3DXMESHOPT_COMPACT | D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_VERTEXCACHE, (DWORD*)adjBuffer->GetBufferPointer(), 0, 0, 0, meshOut)); SAFERELEASECOM(meshSys); // Done w/ system mesh. SAFERELEASECOM(adjBuffer); // Done with buffer. // Step 6: Extract the materials and load the textures. if( mtrlBuffer != 0 && numMtrls != 0 ) { D3DXMATERIAL* d3dxmtrls = (D3DXMATERIAL*)mtrlBuffer->GetBufferPointer(); for(DWORD i = 0; i < numMtrls; ++i) { // Save the ith material. Note that the MatD3D property does not have an ambient // value set when its loaded, so just set it to the diffuse value. Material m; m.ambient = d3dxmtrls[i].MatD3D.Diffuse; m.diffuse = d3dxmtrls[i].MatD3D.Diffuse; m.spec = d3dxmtrls[i].MatD3D.Specular; m.specPower = d3dxmtrls[i].MatD3D.Power; mtrls->push_back( m ); // Check if the ith material has an associative texture if( d3dxmtrls[i].pTextureFilename != 0 ) { IDirect3DTexture9* tex = 0; std::string s(d3dxmtrls[i].pTextureFilename); const char folder[] = "./texture/"; unsigned int pos = s.find_last_of('\/'); std::string newFileName(folder); // std::string::npos gets returned if no / was found if(pos != std::string::npos) { //std::string sub = s.substr(pos,s.size()); if(strcmp(s.substr(pos+1,s.size()).c_str(),"Watcher.tga") == 0) { newFileName.append("Watcher_Black.tga"); } else { newFileName.append(s.substr(pos+1,s.size())); } } else { newFileName.append(s); } // Save the loaded texture HR(D3DXCreateTextureFromFile(dev, newFileName.c_str(), &tex)); texs->push_back( tex ); } else {
void Terrain::buildSubGridMesh(RECT& R, VertexPNT* gridVerts) { //=============================================================== // Create the subgrid mesh. ID3DXMesh* subMesh = 0; D3DVERTEXELEMENT9 elems[MAX_FVF_DECL_SIZE]; UINT numElems = 0; HR(VertexPNT::Decl->GetDeclaration(elems, &numElems)); HR(D3DXCreateMesh(SubGrid::NUM_TRIS, SubGrid::NUM_VERTS, D3DXMESH_MANAGED, elems, gd3dDevice, &subMesh)); //=============================================================== // Build Vertex Buffer. Copy rectangle of vertices from the // grid into the subgrid structure. VertexPNT* v = 0; HR(subMesh->LockVertexBuffer(0, (void**)&v)); int k = 0; for(int i = R.top; i <= R.bottom; ++i) { for(int j = R.left; j <= R.right; ++j) { v[k++] = gridVerts[i*mVertCols+j]; } } //=============================================================== // Compute the bounding box before unlocking the vertex buffer. AABB bndBox; HR(D3DXComputeBoundingBox((D3DXVECTOR3*)v, subMesh->GetNumVertices(), sizeof(VertexPNT), &bndBox.minPt, &bndBox.maxPt)); HR(subMesh->UnlockVertexBuffer()); //=============================================================== // Build Index and Attribute Buffer. // Get indices for subgrid (we don't use the verts here--the verts // are given by the parameter gridVerts). std::vector<D3DXVECTOR3> tempVerts; std::vector<DWORD> tempIndices; GenTriGrid(SubGrid::NUM_ROWS, SubGrid::NUM_COLS, mDX, mDZ, D3DXVECTOR3(0.0f, 0.0f, 0.0f), tempVerts, tempIndices); WORD* indices = 0; DWORD* attBuff = 0; HR(subMesh->LockIndexBuffer(0, (void**)&indices)); HR(subMesh->LockAttributeBuffer(0, &attBuff)); for(int i = 0; i < SubGrid::NUM_TRIS; ++i) { indices[i*3+0] = (WORD)tempIndices[i*3+0]; indices[i*3+1] = (WORD)tempIndices[i*3+1]; indices[i*3+2] = (WORD)tempIndices[i*3+2]; attBuff[i] = 0; // All in subset 0. } HR(subMesh->UnlockIndexBuffer()); HR(subMesh->UnlockAttributeBuffer()); //=============================================================== // Optimize for the vertex cache and build attribute table. DWORD* adj = new DWORD[subMesh->GetNumFaces()*3]; HR(subMesh->GenerateAdjacency(EPSILON, adj)); HR(subMesh->OptimizeInplace(D3DXMESHOPT_VERTEXCACHE|D3DXMESHOPT_ATTRSORT, adj, 0, 0, 0)); delete[] adj; //=============================================================== // Save the mesh and bounding box. mSubGridMeshes.push_back(subMesh); mSubGridBndBoxes.push_back(bndBox); }
void CMeshConverter::OptimiseGraphicsObject(void) { int i; int j; ID3DXMesh* pXMesh; CGraphicsPrimitive* pcPrimitive; CVertexBufferExtended* psVertexBuffer; void* pvDestIndexBuffer; void* pvDestVertexBuffer; void* pvSrcIndexBuffer; void* pvSrcVertexBuffer; int iVertSize; DWORD* pvAdjacency; int iPrimitiveStart; int iOldVertSize; int iNumIndices; int iOldVertexBufferIndex; int iNumTriangles; void* pvDestBaseIndexBuffer; SIndexBuffer* psIndexBuffer; DWORD iMeshOptions; mpcGraphicsObject->SortPrimitives(); mpcGraphicsObject->Lock(); psIndexBuffer = mpcGraphicsObject->GetIndexBuffer(); iVertSize = 0; iNumIndices = 0; iOldVertexBufferIndex = 0; iNumTriangles = 0; iOldVertSize = 0; iMeshOptions = D3DXMESH_SYSTEMMEM; SetFlag((int*)&iMeshOptions, D3DXMESH_32BIT, psIndexBuffer->iIndexSize == 4); for (i = 0; i < mpcGraphicsObject->GetNumPrimitives(); i++) { pcPrimitive = mpcGraphicsObject->GetPrimitive(i); psVertexBuffer = mpcGraphicsObject->GetVertexBufferForIndex(pcPrimitive->miVertexBufferIndex); if (iOldVertSize != psVertexBuffer->iVertexSize) { if (iNumIndices != 0) { gcD3D.CreateMesh(iNumTriangles, iNumIndices, iMeshOptions, psVertexBuffer->iVertexFormat, &pXMesh); iVertSize = pXMesh->GetNumBytesPerVertex(); pXMesh->LockIndexBuffer(D3DLOCK_NO_DIRTY_UPDATE, &pvDestBaseIndexBuffer); pXMesh->LockVertexBuffer(D3DLOCK_NO_DIRTY_UPDATE, &pvDestVertexBuffer); psVertexBuffer = mpcGraphicsObject->GetVertexBufferForIndex(iOldVertexBufferIndex); pvSrcVertexBuffer = psVertexBuffer->pvLockedBuffer; if (iVertSize != psVertexBuffer->iVertexSize) { gcLogger.Error("D3DX vertex size differs from expected size"); break; } memcpy(pvDestVertexBuffer, pvSrcVertexBuffer, psVertexBuffer->iVertexSize * psVertexBuffer->iNumVerticies); pvDestIndexBuffer = pvDestBaseIndexBuffer; for (j = iPrimitiveStart; j < i; j++) { pcPrimitive = mpcGraphicsObject->GetPrimitive(j); pvSrcIndexBuffer = RemapSinglePointer(psIndexBuffer->pvLockedBuffer, 2 * pcPrimitive->miStartIndex); memcpy(pvDestIndexBuffer, pvSrcIndexBuffer, psIndexBuffer->iIndexSize * pcPrimitive->miNumVertices); pvDestIndexBuffer = RemapSinglePointer(pvDestIndexBuffer, pcPrimitive->miNumVertices); } pvAdjacency = (DWORD*)malloc(pcPrimitive->miNumPrimitives * 3 * sizeof(DWORD)); pXMesh->GenerateAdjacency(0.0f, pvAdjacency); pXMesh->OptimizeInplace(D3DXMESHOPT_VERTEXCACHE | D3DXMESHOPT_DONOTSPLIT, pvAdjacency, NULL, NULL, NULL); free(pvAdjacency); pvDestIndexBuffer = pvDestBaseIndexBuffer; for (j = iPrimitiveStart; j < i; j++) { pcPrimitive = mpcGraphicsObject->GetPrimitive(j); pvSrcIndexBuffer = RemapSinglePointer(psIndexBuffer->pvLockedBuffer, 2 * pcPrimitive->miStartIndex); memcpy(pvSrcIndexBuffer, pvDestIndexBuffer, psIndexBuffer->iIndexSize * pcPrimitive->miNumVertices); pvDestIndexBuffer = RemapSinglePointer(pvDestIndexBuffer, pcPrimitive->miNumVertices); } memcpy(pvSrcVertexBuffer, pvDestVertexBuffer, psVertexBuffer->iVertexSize * psVertexBuffer->iNumVerticies); pXMesh->UnlockIndexBuffer(); pXMesh->UnlockVertexBuffer(); pXMesh->Release(); } iPrimitiveStart = i; iNumIndices = 0; iOldVertexBufferIndex = pcPrimitive->miVertexBufferIndex; } else { iNumIndices += pcPrimitive->miNumVertices; iNumTriangles += pcPrimitive->miNumPrimitives; if (iOldVertexBufferIndex != pcPrimitive->miVertexBufferIndex) { gcUserError.Set("Primitive vertex buffer index is F****D!"); break; } } } mpcGraphicsObject->Unlock(); }
HRESULT HelloShadowVolume::RestoreDeviceObjects() { HRESULT hr; IDirect3DDevice8* device; hr = m_spD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &m_dpps, &device); if (FAILED(hr)) { MessageBox(0, L"CreateDevice failed", 0, 0); return E_FAIL; } m_spDevice.reset(device, [](IDirect3DDevice8* device) { device->Release(); }); m_spDevice->SetRenderState(D3DRS_ZENABLE, TRUE); m_spDevice->SetRenderState(D3DRS_LIGHTING, FALSE); m_spDevice->SetRenderState(D3DRS_DITHERENABLE, TRUE); D3DVIEWPORT8 viewport = { 0, 0, m_iWidth, m_iHeight }; m_spDevice->SetViewport(&viewport); D3DXVECTOR3 eye(0.0f, 0.0f, 30.0f); D3DXVECTOR3 target(0.0f, 0.0f, 0.0f); D3DXVECTOR3 up(0.0f, 1.0f, 0.0f); D3DXMatrixLookAtLH(&m_mtView, &eye, &target, &up); D3DXMatrixPerspectiveFovLH(&m_mtProj, 0.2*D3DX_PI, (float)m_iWidth / (float)m_iHeight, 1.0f, 100.f); m_cPlaneTint = { 0.7f, 0.6f, 0.4f, 1.0f }; ID3DXMesh* plane; //D3DXCreatePolygon(m_spDevice.get(), 2.0f, 4, &plane, NULL); CreatePlane(m_spDevice.get(), 15.0f, 10, &plane); //D3DXCreateSphere(m_spDevice.get(), 1.0f,20,20, &plane, NULL); IDirect3DVertexBuffer8* vb; IDirect3DIndexBuffer8* ib; plane->GetVertexBuffer(&vb); plane->GetIndexBuffer(&ib); m_spPlaneVB.reset(vb, [](IDirect3DVertexBuffer8* vb) { vb->Release(); }); m_spPlaneIB.reset(ib, [](IDirect3DIndexBuffer8* ib) { ib->Release(); }); m_dwPlaneNumVertices = plane->GetNumVertices(); m_dwPlaneNumFaces = plane->GetNumFaces(); plane->Release(); DWORD decl[] = { D3DVSD_STREAM(0), D3DVSD_REG(0, D3DVSDT_FLOAT3), D3DVSD_REG(3, D3DVSDT_FLOAT3), D3DVSD_END() }; hr = CreateVSFromBinFile(m_spDevice.get(), decl, L"plane.vso", &m_dwPlaneVSH); if (FAILED(hr)) { MessageBox(0, 0, L"CreateVSFromBinFile failed", 0); return E_FAIL; } hr = CreatePSFromBinFile(m_spDevice.get(), L"plane.pso", &m_dwPlanePSH); if (FAILED(hr)) { MessageBox(0, 0, L"CreatePSFromBinFile failed", 0); return E_FAIL; } D3DXMATRIX Rx, Tz; D3DXMatrixRotationX(&Rx, D3DX_PI*0.5f); D3DXMatrixTranslation(&Tz, 0.0f, -3.0f, 0.0f); m_mtPlaneWorld = Rx * Tz; ID3DXMesh* occluder; CreateOccluder(m_spDevice.get(), &occluder); IDirect3DVertexBuffer8* vbOccluder; IDirect3DIndexBuffer8* ibOccluder; occluder->GetVertexBuffer(&vbOccluder); occluder->GetIndexBuffer(&ibOccluder); m_spOccluderVB.reset(vbOccluder, [](IDirect3DVertexBuffer8* vb) { vb->Release(); }); m_spOccluderIB.reset(ibOccluder, [](IDirect3DIndexBuffer8* ib) { ib->Release(); }); m_dwOccluderNumVertices = occluder->GetNumVertices(); m_dwOccluderNumFaces = occluder->GetNumFaces(); occluder->Release(); hr = CreateVSFromBinFile(m_spDevice.get(), decl, L"occluder.vso", &m_dwOccluderVSH); if (FAILED(hr)) { MessageBox(0, 0, L"CreateVSFromBinFile failed", 0); return E_FAIL; } hr = CreatePSFromBinFile(m_spDevice.get(), L"occluder.pso", &m_dwOccluderPSH); if (FAILED(hr)) { MessageBox(0, 0, L"CreatePSFromBinFile failed", 0); return E_FAIL; } m_cOccluderTint = { 0.3f, 0.0f, 0.8f, 1.0f }; D3DXMATRIX Rz, T; D3DXMatrixTranslation(&T, 5.1f * cosf(0.5), 0.0f, 5.1f * sinf(0.5)); D3DXMatrixIdentity(&m_mtVolumeWorld); D3DXMatrixRotationZ(&Rz, 0.5f); m_mtOccluderWorld = T * Rz; ID3DXMesh* volume; CreateVolume(m_spDevice.get(), &volume); IDirect3DVertexBuffer8* vbVolume; IDirect3DIndexBuffer8* ibVolume; volume->GetVertexBuffer(&vbVolume); volume->GetIndexBuffer(&ibVolume); m_spVolumeVB.reset(vbVolume, [](IDirect3DVertexBuffer8* vb) { vb->Release(); }); m_spVolumeIB.reset(ibVolume, [](IDirect3DIndexBuffer8* ib) { ib->Release(); }); m_dwVolumeNumVertices = volume->GetNumVertices(); m_dwVolumeNumFaces = volume->GetNumFaces(); volume->Release(); hr = CreateVSFromBinFile(m_spDevice.get(), decl, L"volume.vso", &m_dwVolumeVSH); if (FAILED(hr)) { MessageBox(0, 0, L"CreateVSFromBinFile failed", 0); return E_FAIL; } hr = CreatePSFromBinFile(m_spDevice.get(), L"volume.pso", &m_dwVolumePSH); if (FAILED(hr)) { MessageBox(0, 0, L"CreatePSFromBinFile failed", 0); return E_FAIL; } m_cVolumeTint = { 0.7f, 0.0f, 0.0f, 1.0f }; D3DXMATRIX Sx; D3DXMatrixIdentity(&m_mtVolumeWorld); D3DXMatrixScaling(&Sx, 6.0f, 1.0f, 1.0f); D3DXMatrixRotationZ(&Rz, 0.5f); m_mtVolumeWorld = Sx * Rz; return S_OK; }
VCNNode* D3DConverter::ConvertMesh(const std::wstring& name, LPD3DXMESHCONTAINER baseMeshContainer, D3DXFRAME* frameRoot, ID3DXAnimationController* animController, LPDIRECT3DDEVICE9 device) { MultiAnimMC* meshContainer = static_cast<MultiAnimMC*>(baseMeshContainer); ID3DXMesh* systemMesh = meshContainer->MeshData.pMesh; // Load vertex caches // DWORD meshFVF = systemMesh->GetFVF(); size_t vertexCount = systemMesh->GetNumVertices(); const DWORD stride = D3DXGetFVFVertexSize( meshFVF ); const DWORD normalStride = D3DXGetFVFVertexSize( D3DFVF_NORMAL ); const DWORD diffuseStride = D3DXGetFVFVertexSize( D3DFVF_DIFFUSE ); const DWORD textureStride = D3DXGetFVFVertexSize( D3DFVF_TEX1 ); std::vector<VCNFloat> vtPositionBuffer( vertexCount * kCacheStrides[VT_POSITION] ); std::vector<VCNFloat> vtBlendWeights( vertexCount * kCacheStrides[VT_BLENDWEIGHTS] ); //TODO Verify the size of this shit std::vector<DWORD> vtBlendIndices( vertexCount * kCacheStrides[VT_BLENDINDICES] ); //TODO Verify the size of this shit std::vector<VCNFloat> vtNormalBuffer( vertexCount * kCacheStrides[VT_LIGHTING] ); std::vector<VCNFloat> vtTextureBuffer( vertexCount * kCacheStrides[VT_DIFFUSE_TEX_COORDS] ); VCNFloat* vtPositionBuf = &vtPositionBuffer[0]; VCNFloat* vtBlendWeightBuf = &vtBlendWeights[0]; DWORD* vtBlendIndicesBuf = &vtBlendIndices[0]; VCNFloat* vtNormalBuf = &vtNormalBuffer[0]; VCNFloat* vtTextureBuf = &vtTextureBuffer[0]; BYTE* vbptr = NULL; BYTE* vblineptr = NULL; systemMesh->LockVertexBuffer(D3DLOCK_READONLY, (LPVOID*)&vblineptr); DWORD positionBlendAndIndicesStride = GetPositionStride(meshFVF); for(VCNUInt i = 0; i < vertexCount; ++i) { vbptr = vblineptr; if ( ContainsPositionInformation(meshFVF) ) { // Read position float* posData = (float*)vbptr; *vtPositionBuf = posData[0]; vtPositionBuf++; *vtPositionBuf = posData[1]; vtPositionBuf++; *vtPositionBuf = posData[2]; vtPositionBuf++; if (ContainsBlending(meshFVF)) { // Get blend weights size_t blendCount = (positionBlendAndIndicesStride / 4) - 3 - 1; // -3 to remove xyz, -1 to remove indices which come after for(size_t i = 0; i < blendCount; ++i) { *vtBlendWeightBuf = posData[3 + i]; vtBlendWeightBuf++; } vtBlendWeightBuf += 4 - blendCount; //each item is an array of 4 floats // Get blend indices // TODO SKIN Check the format we have to send this data as. if ( ContainsFlag(meshFVF, D3DFVF_LASTBETA_UBYTE4) ) { *vtBlendIndicesBuf = ((DWORD*)vbptr)[3 + blendCount]; vtBlendIndicesBuf++; } } vbptr += positionBlendAndIndicesStride; } else { VCN_ASSERT_FAIL( VCNTXT("Mesh FVF not supported (no vertex position) [FVF = %d, stride = %d]"), meshFVF, stride ); } // Read normal if ( ContainsFlag(meshFVF, D3DFVF_NORMAL) ) { D3DXVECTOR3* normal = (D3DXVECTOR3*)(vbptr); *vtNormalBuf = normal->x; vtNormalBuf++; *vtNormalBuf = normal->y; vtNormalBuf++; *vtNormalBuf = normal->z; vtNormalBuf++; // Set default diffuse color std::fill(vtNormalBuf, vtNormalBuf+3, 1.0f); vtNormalBuf += 3; vbptr += normalStride; } else { VCN_ASSERT_FAIL( VCNTXT("Mesh FVF not supported (no normals) [FVF = %d, stride = %d]"), meshFVF, stride ); } if ( ContainsFlag(meshFVF, D3DFVF_DIFFUSE) ) vbptr += diffuseStride; // Read texcoords // the check with D3DFVF_TEX0 is pretty useless as it's always true... the flag value is 0... if ( ContainsFlag(meshFVF, D3DFVF_TEX0) || ContainsFlag(meshFVF, D3DFVF_TEX1) ) { float* texCoords = (float*)(vbptr); *vtTextureBuf = texCoords[0]; vtTextureBuf++; *vtTextureBuf = texCoords[1]; vtTextureBuf++; vbptr += textureStride; } else { VCN_ASSERT_FAIL( VCNTXT("Mesh FVF not supported (no texture coordinates) [FVF = %d, stride = %d]"), meshFVF, stride ); } vblineptr += stride; } systemMesh->UnlockVertexBuffer(); VCND3D9* renderer = VCNRenderCore::GetInstance()->Cast<VCND3D9>(); // Generate cache resources that will be bind to Vicuna's meshes VCNResID positionCache = renderer->CreateCache(VT_POSITION, &vtPositionBuffer[0], vertexCount * kCacheStrides[VT_POSITION]); VCNResID lightingCache = renderer->CreateCache(VT_LIGHTING, &vtNormalBuffer[0], vertexCount * kCacheStrides[VT_LIGHTING]); VCNResID textureCache = renderer->CreateCache(VT_DIFFUSE_TEX_COORDS, &vtTextureBuffer[0], vertexCount * kCacheStrides[VT_DIFFUSE_TEX_COORDS]); VCNResID blendWeightCache = renderer->CreateCache(VT_BLENDWEIGHTS, &vtBlendWeights[0], vertexCount * kCacheStrides[VT_BLENDWEIGHTS]); VCNResID blendIndiceCache = renderer->CreateCache(VT_BLENDINDICES, &vtBlendIndices[0], vertexCount * kCacheStrides[VT_BLENDINDICES]); // Get model faces // VCNUShort* ibptr = 0; std::vector<VCNUShort> indices( systemMesh->GetNumFaces() * 3 ); systemMesh->LockIndexBuffer(D3DLOCK_READONLY, (LPVOID*)&ibptr); for(VCNUInt i = 0; i < systemMesh->GetNumFaces(); i++) { indices[(i * 3) + 0] = *(ibptr++); indices[(i * 3) + 1] = *(ibptr++); indices[(i * 3) + 2] = *(ibptr++); } systemMesh->UnlockIndexBuffer(); // Load materials // std::vector<VCNResID> materialIDS; D3DXMATERIAL* d3dxMaterials = meshContainer->pMaterials; for (DWORD i = 0; i < meshContainer->NumMaterials; ++i) { VCNResID materialID = kInvalidResID; // Create the texture if it exists - it may not if ( d3dxMaterials[i].pTextureFilename ) { VCNResID textureID = kInvalidResID; VCNString texturePath = VCNTXT("Textures/"); texturePath += VCN_A2W(d3dxMaterials[i].pTextureFilename); // Check if the texture is already loaded VCND3D9Texture* resTexture = VCNResourceCore::GetInstance()->GetResource<VCND3D9Texture>(texturePath); if ( !resTexture ) { textureID = VCNMaterialCore::GetInstance()->CreateTexture(texturePath); VCN_ASSERT_MSG( textureID != kInvalidResID, VCNTXT("Can't load texture %s"), texturePath.c_str() ); } else { textureID = resTexture->GetResourceID(); } VCNMaterial* material = new VCNMaterial(); const VCNString materialName = StringBuilder() << name << VCNTXT("_material_") << i; material->SetName( materialName ); VCNColor ambient = VCNColor((const VCNFloat*)&d3dxMaterials[i].MatD3D.Ambient); ambient.a = 1.0f; ambient += VCNColor(0.5f, 0.5f, 0.5f, 0); material->SetAmbientColor( ambient ); material->SetDiffuseColor( VCNColor((const VCNFloat*)&d3dxMaterials[i].MatD3D.Diffuse) ); material->SetSpecularColor( VCNColor((const VCNFloat*)&d3dxMaterials[i].MatD3D.Specular) ); material->SetSpecularPower( d3dxMaterials[i].MatD3D.Power ); VCNEffectParamSet& params = material->GetEffectParamSet(); params.SetEffectID( eidSkinned ); params.AddResource( VCNTXT("DiffuseTexture"), textureID ); // Add material as a resource. materialID = VCNResourceCore::GetInstance()->AddResource( material->GetName(), material ); } materialIDS.push_back( materialID ); } // Get the model attribute table with which we will instantiate has many mesh. // DWORD attribTableSize; std::vector<D3DXATTRIBUTERANGE> attribTable; HRESULT hr = systemMesh->GetAttributeTable( 0, &attribTableSize ); if ( FAILED(hr) ) return 0; attribTable.resize( attribTableSize ); hr = systemMesh->GetAttributeTable( &attribTable[0], &attribTableSize ); if ( FAILED(hr) ) return 0; // Set the root node VCNNode* rootNode = attribTableSize > 1 ? VCNNodeCore::GetInstance()->CreateNode<VCNNode>() : VCNNodeCore::GetInstance()->CreateNode<VCNRenderNode>(); rootNode->SetTag( StringBuilder() << name << VCNTXT("_Root") ); // For each attribute, we get the material texture for (DWORD i = 0; i < attribTableSize; ++i) { VCNRenderNode* partNode = attribTableSize == 1 ? safe_pointer_cast<VCNRenderNode*>( rootNode ) : VCNNodeCore::GetInstance()->CreateNode<VCNRenderNode>(); const VCNString partNodeName = StringBuilder() << name << VCNTXT("_Part_") << i; partNode->SetTag( partNodeName ); VCNMesh* partMesh = new VCNMesh(); partMesh->SetCacheID(VT_POSITION, positionCache); //SKIN do this for blend weights and blend indices partMesh->SetCacheID(VT_LIGHTING, lightingCache); partMesh->SetCacheID(VT_DIFFUSE_TEX_COORDS, textureCache); partMesh->SetCacheID(VT_BLENDWEIGHTS, blendWeightCache); partMesh->SetCacheID(VT_BLENDINDICES, blendIndiceCache); partMesh->SetPrimitiveType(PT_TRIANGLELIST); partMesh->SetBoneInfluenceCount( meshContainer->m_dwMaxNumFaceInfls ); size_t numBones = meshContainer->pSkinInfo == nullptr ? 0 : meshContainer->pSkinInfo->GetNumBones(); if (numBones > 0) { auto offsets = std::vector<Matrix4>(numBones); std::transform( std::begin(meshContainer->m_amxBoneOffsets), std::end(meshContainer->m_amxBoneOffsets), std::begin(offsets), [](const D3DXMATRIX& mat) { return Matrix4( (VCNFloat*)mat.m ); }); partMesh->SetBoneOffsets( std::move(offsets) ); LPD3DXBONECOMBINATION boneCombination = reinterpret_cast<LPD3DXBONECOMBINATION>( meshContainer->m_pBufBoneCombos->GetBufferPointer() ); size_t numPaletteEntries = meshContainer->m_dwNumPaletteEntries; std::vector<size_t> matriceIndexes; for(size_t paletteIndex = 0; paletteIndex < numPaletteEntries; ++paletteIndex) { size_t matIndex = boneCombination[i].BoneId[paletteIndex]; if ( matIndex == std::numeric_limits<size_t>::max()) continue; matriceIndexes.push_back(matIndex); } partMesh->SetMatrixPaletteIndexes(matriceIndexes); } const DWORD partFaceCount = attribTable[i].FaceCount; const void* partFaceBufferStart = &indices[attribTable[i].FaceStart * 3]; const VCNResID indexCacheID = renderer->CreateCache(VT_INDEX, partFaceBufferStart, partFaceCount * 3 * kCacheStrides[VT_INDEX]); partMesh->SetFaceCount( attribTable[i].FaceCount ); partMesh->SetFaceCache( indexCacheID ); // Compute bounding sphere float radius; D3DXVECTOR3 center; D3DXComputeBoundingSphere( (D3DXVECTOR3*)(&vtPositionBuffer[0] + attribTable[i].VertexStart * 3), attribTable[i].VertexCount, stride, ¢er, &radius ); VCNSphere modelBoundSphere( radius, V2V<Vector3>(center) ); partMesh->SetBoundingSphere( modelBoundSphere ); // Add mesh resource const VCNString partMeshName = StringBuilder() << name << VCNTXT("_part_") << i; const VCNResID partMeshID = VCNResourceCore::GetInstance()->AddResource( partMeshName, partMesh ); // Set model part node attributes partNode->SetMeshID( partMeshID ); if (animController && numBones > 0) { partNode->AddComponent( new VCND3DAnimator(partMeshID, animController, frameRoot, meshContainer->m_apmxBonePointers) ); } size_t index = attribTable[i].AttribId; index = index >= materialIDS.size() ? materialIDS.size() - 1 : index; partNode->SetMaterialID( materialIDS[index] ); // Add children to root if ( attribTableSize > 1 ) { rootNode->AttachChild( partNode->GetNodeID() ); } } return rootNode; }
void RobotArmDemo::drawScene() { // Clear the backbuffer and depth buffer. HR(gd3dDevice->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0)); HR(gd3dDevice->BeginScene()); HR(mFX->SetValue(mhLight, &mLight, sizeof(DirLight))); HR(mFX->SetTechnique(mhTech)); UINT numPasses = 0; HR(mFX->Begin(&numPasses, 0)); HR(mFX->BeginPass(0)); // Build the world transforms for each bone, then render them. buildBoneWorldTransforms(); D3DXMATRIX T; D3DXMatrixTranslation(&T, -NUM_BONES, 0.0f, 0.0f); for(int i = 0; i < NUM_BONES; ++i) { // Append the transformation with a slight translation to better // center the skeleton at the center of the scene. mWorld = mBones[i].toWorldXForm * T; HR(mFX->SetMatrix(mhWorld, &mWorld)); HR(mFX->SetMatrix(mhWVP, &(mWorld*mView*mProj))); D3DXMATRIX worldInvTrans; //! ÄæÏò D3DXMatrixInverse(&worldInvTrans, 0, &mWorld); //! תÖà D3DXMatrixTranspose(&worldInvTrans, &worldInvTrans); HR(mFX->SetMatrix(mhWorldInvTrans, &worldInvTrans)); for(int j = 0; j < mMtrl.size(); ++j) { HR(mFX->SetValue(mhMtrl, &mMtrl[j], sizeof(Mtrl))); // If there is a texture, then use. if(mTex[j] != 0) { HR(mFX->SetTexture(mhTex, mTex[j])); } // But if not, then set a pure white texture. When the texture color // is multiplied by the color from lighting, it is like multiplying by // 1 and won't change the color from lighting. else { HR(mFX->SetTexture(mhTex, mWhiteTex)); } HR(mFX->CommitChanges()); HR(mBoneMesh->DrawSubset(j)); } } HR(mFX->EndPass()); HR(mFX->End()); mGfxStats->display(); HR(gd3dDevice->EndScene()); // Present the backbuffer. HR(gd3dDevice->Present(0, 0, 0, 0)); }
void LODManager::Render(IDirect3DDevice9 *D3DDevice) { const char *meshpath = (lod == GRID_FARNEAR ? "landscape\\lod\\farnear\\" : (lod == GRID_FARFAR ? "landscape\\lod\\farfar\\" : "landscape\\lod\\farinf\\")); const char *textpath = (lod == GRID_FARNEAR ? "landscapelod\\generated\\farnear\\" : (lod == GRID_FARFAR ? "landscapelod\\generated\\farfar\\" : "landscapelod\\generated\\farinf\\")); int nativeminx = (GRID_SIZE * 32) + (Constants.Coordinates.x - GridDistantCount.Get()); int nativeminy = (GRID_SIZE * 32) + (Constants.Coordinates.y - GridDistantCount.Get()); int nativemaxx = (GRID_SIZE * 32) + (Constants.Coordinates.x + GridDistantCount.Get()); int nativemaxy = (GRID_SIZE * 32) + (Constants.Coordinates.y + GridDistantCount.Get()); /* y-axis has flipped rounding */ nativeminx = (nativeminx / 32) - GRID_SIZE; nativeminy = (nativeminy / 32) - GRID_SIZE + 0; nativemaxx = (nativemaxx / 32) - GRID_SIZE; nativemaxy = (nativemaxy / 32) - GRID_SIZE + 0; int gridx = Constants.Coordinates.x / 32; int gridy = Constants.Coordinates.y / 32; for (int x = (gridx - extend); x <= (gridx + extend); x++) for (int y = (gridy - extend); y <= (gridy + extend); y++) { /* TODO: try radius, seems it's not a box */ /* leave out Oblivion's native tiles */ if ((x >= nativeminx) && (x <= nativemaxx) && (y >= nativeminy) && (y <= nativemaxy)) continue; /* leave out other LOD's inner tiles */ if ((abs(gridx - x) <= inner) && (abs(gridy - y) <= inner)) continue; /* where are we? */ const float TileOffset[4] = {x * TILE_DIM, y * TILE_DIM, 0, 0}; /* filter outside-array coordinates */ if (((GRID_OFFSET + y) >= 0) && ((GRID_OFFSET + y) < GRID_SIZE) && ((GRID_OFFSET + x) >= 0) && ((GRID_OFFSET + x) < GRID_SIZE)) { /* never seen, never attempted */ if (MeshIDs[lod][GRID_OFFSET + y][GRID_OFFSET + x] < -1) { /* TODO: 32 means 32x32 cells, in theory that can be different as well */ char buf[256]; sprintf(buf, "%02d.%02d.%02d.32", WorldSpace, x * 32, y * 32); char pth[256]; strcpy(pth, meshpath); strcat(pth, buf); strcat(pth, ".x"); /* no textures without mesh, but we can render texture-free */ if ((MeshIDs[lod][GRID_OFFSET + y][GRID_OFFSET + x] = MeshManager::GetSingleton()->LoadPrivateMesh(pth, MR_REGULAR)) != -1) { if (ColrIDs[lod][GRID_OFFSET + y][GRID_OFFSET + x] < -1) { strcpy(pth, textpath); strcat(pth, buf); strcat(pth, ".dds"); ColrIDs[lod][GRID_OFFSET + y][GRID_OFFSET + x] = TextureManager::GetSingleton()->LoadPrivateTexture(pth, TR_PLANAR); } if (NormIDs[lod][GRID_OFFSET + y][GRID_OFFSET + x] < -1) { strcpy(pth, textpath); strcat(pth, buf); strcat(pth, "_fn.dds"); NormIDs[lod][GRID_OFFSET + y][GRID_OFFSET + x] = TextureManager::GetSingleton()->LoadPrivateTexture(pth, TR_PLANAR); } /* put the addresses */ ManagedMeshRecord *mesh = Meshes [lod][GRID_OFFSET + y][GRID_OFFSET + x] = MeshManager::GetSingleton()->GetMesh (MeshIDs[lod][GRID_OFFSET + y][GRID_OFFSET + x]); ManagedTextureRecord *colr = Colors [lod][GRID_OFFSET + y][GRID_OFFSET + x] = TextureManager::GetSingleton()->GetTexture(ColrIDs[lod][GRID_OFFSET + y][GRID_OFFSET + x]); ManagedTextureRecord *norm = Normals[lod][GRID_OFFSET + y][GRID_OFFSET + x] = TextureManager::GetSingleton()->GetTexture(NormIDs[lod][GRID_OFFSET + y][GRID_OFFSET + x]); /* failure to load all resources */ if (!mesh || !colr || !norm) { if (mesh) mesh->Release(); if (colr) colr->Release(); if (norm) norm->Release(); MeshIDs[lod][GRID_OFFSET + y][GRID_OFFSET + x] = -1; ColrIDs[lod][GRID_OFFSET + y][GRID_OFFSET + x] = -1; NormIDs[lod][GRID_OFFSET + y][GRID_OFFSET + x] = -1; continue; } #if defined(OBGE_GAMMACORRECTION) /* remember DeGamma for this kind of texture */ static const bool PotDeGamma = true; colr->GetTexture()->SetPrivateData(GammaGUID, &PotDeGamma, sizeof(PotDeGamma), 0); #endif } } /* get the addresses */ ManagedMeshRecord *mesh = Meshes [lod][GRID_OFFSET + y][GRID_OFFSET + x]; ManagedTextureRecord *colr = Colors [lod][GRID_OFFSET + y][GRID_OFFSET + x]; ManagedTextureRecord *norm = Normals[lod][GRID_OFFSET + y][GRID_OFFSET + x]; ID3DXMesh *m; if (mesh && (m = (ID3DXMesh *)mesh->GetMesh())) { #if 0 DWORD FVF = m->GetFVF(); DWORD size = m->GetNumBytesPerVertex(); DWORD numf = m->GetNumFaces(); DWORD numv = m->GetNumVertices(); IDirect3DIndexBuffer9 *pIB; m->GetIndexBuffer(&pIB); IDirect3DVertexBuffer9 *pVB; m->GetVertexBuffer(&pVB); D3DDevice->SetStreamSource(0, pVB, 0, size); D3DDevice->SetFVF(FVF); D3DDevice->SetTexture(0, colr->GetTexture()); D3DDevice->SetTexture(1, norm->GetTexture()); D3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, numv, 0, numf); #endif D3DDevice->SetTexture(0, colr ? colr->GetTexture() : NULL); D3DDevice->SetTexture(1, norm ? norm->GetTexture() : NULL); D3DDevice->SetVertexShader(vShader[lod]); D3DDevice->SetPixelShader (pShader[lod]); D3DDevice->SetVertexShaderConstantF(32, TileOffset, 1); m->DrawSubset(0); } } /* water-planes */ D3DDevice->SetVertexShader(vShaderW); D3DDevice->SetPixelShader (pShaderW); D3DDevice->SetVertexShaderConstantF(32, TileOffset, 1); D3DDevice->SetStreamSource(0, WaterVertex, 0, sizeof(WaterTile)); D3DDevice->SetFVF(WATERTILEFORMAT); D3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); } const float TileOffset[4] = {0, 0, 0, 1}; /* infini-plane */ D3DDevice->SetVertexShader(vShaderW); D3DDevice->SetPixelShader (pShaderW); D3DDevice->SetVertexShaderConstantF(32, TileOffset, 1); D3DDevice->SetStreamSource(0, InfiniteVertex, 0, sizeof(WaterTile)); D3DDevice->SetFVF(WATERTILEFORMAT); D3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); }
// Create a torus with the parameters specified // Returns true for success, false otherwise bool CreateTorus(float innerRad, float outerRad, int color, ID3DXMesh **mesh) { assert(g3D->mDevice != NULL); assert(mesh != NULL); const unsigned int kSides = 16; // Number of divisions looking at the torus form the side const unsigned int kRings = 16; // Number of divisions looking at the torus from the top // so you can see the hole in the middle ID3DXMesh *temp = NULL; // Temp D3D mesh object // Create the torus // By paramter: // g3D->mDevice -- Pointer to the Direct3D device to be associated with the torus // innerRad -- Inner radius of the torus // outerRad -- Outside radius of the torus // kSides -- Number of sides in a cross-section of the torus // kRings -- Number of rings in a cross-section of the torus // &temp -- A pointer to a ID3DXMesh*, it will get filled with the // the created mesh // NULL -- Optional pointer to a ID3DXBuffer, if a valid pointer was passed // it would be filled with the adjacency information for each face in // the mesh. By passing NULL, we say we don't want this information if(D3DXCreateTorus(g3D->mDevice, innerRad, outerRad, kSides, kRings, &temp, NULL) != D3D_OK) return false; // Next we clone the mesh. This does two things. First, it allows us to // specify the vertex format we want on the cloned mesh. Second, it copies the // current mesh data into the ID3DXMesh we passed to this function. // By parameter: // D3DXMESH_VB_MANAGED | D3DXMESH_IB_MANAGED -- Flags specifying how we want the mesh to be // cloned. This particular flag combo says // "Have the vertex buffer and index buffer // associated with this mesh be in pooled memory // that DirectX manages for us." // SVertexType -- Flexible vertex format that we want the cloned mesh to be converted to // g3D->mDevice -- IDirect3DDevice9 to associate this mesh with // mesh -- A pointer to a ID3DXMesh* that will get filled with the cloned mesh if(temp->CloneMeshFVF(D3DXMESH_VB_MANAGED | D3DXMESH_IB_MANAGED, SVertexType, g3D->mDevice, mesh) != D3D_OK) { return false; } // Okay so up to this point we've created a stock D3D torus, then converted // it a torus with the FVF that we want. Now were going to loop through each // vertex and set it to the color that we want it to be. SVertex *v; // Lock the vertex buffer if((*mesh)->LockVertexBuffer(0, (void**)&v) != D3D_OK) { (*mesh)->Release(); return false; } // Loop through all the verts in the mesh, setting each one's // color to the color passed into the function for(unsigned int i = 0; i < (*mesh)->GetNumVertices(); ++i) v[i].color = color; // We're done with the vertex buffer, so unlock it so it may be used // by others (*mesh)->UnlockVertexBuffer(); temp->Release(); // Last but not least, free up the temporary mesh return true; }
void SphereCylDemo::genCylTexCoords(AXIS axis) { // D3DXCreate* functions generate vertices with position // and normal data. But for texturing, we also need // tex-coords. So clone the mesh to change the vertex // format to a format with tex-coords. D3DVERTEXELEMENT9 elements[64]; UINT numElements = 0; VertexPNT::Decl->GetDeclaration(elements, &numElements); ID3DXMesh* temp = 0; HR(mCylinder->CloneMesh(D3DXMESH_SYSTEMMEM, elements, gd3dDevice, &temp)); ReleaseCOM(mCylinder); // Now generate texture coordinates for each vertex. VertexPNT* vertices = 0; HR(temp->LockVertexBuffer(0, (void**)&vertices)); // We need to get the height of the cylinder we are projecting the // vertices onto. That height depends on which axis the client has // specified that the cylinder lies on. The height is determined by // finding the height of the bounding cylinder on the specified axis. D3DXVECTOR3 maxPoint(-FLT_MAX, -FLT_MAX, -FLT_MAX); D3DXVECTOR3 minPoint(FLT_MAX, FLT_MAX, FLT_MAX); for(UINT i = 0; i < temp->GetNumVertices(); ++i) { D3DXVec3Maximize(&maxPoint, &maxPoint, &vertices[i].pos); D3DXVec3Minimize(&minPoint, &minPoint, &vertices[i].pos); } float a = 0.0f; float b = 0.0f; float h = 0.0f; switch( axis ) { case X_AXIS: a = minPoint.x; b = maxPoint.x; h = b-a; break; case Y_AXIS: a = minPoint.y; b = maxPoint.y; h = b-a; break; case Z_AXIS: a = minPoint.z; b = maxPoint.z; h = b-a; break; } // Iterate over each vertex and compute its texture coordinate. for(UINT i = 0; i < temp->GetNumVertices(); ++i) { // Get the coordinates along the axes orthogonal to the // axis the cylinder is aligned with. float x = 0.0f; float y = 0.0f; float z = 0.0f; switch( axis ) { case X_AXIS: x = vertices[i].pos.y; z = vertices[i].pos.z; y = vertices[i].pos.x; break; case Y_AXIS: x = vertices[i].pos.x; z = vertices[i].pos.z; y = vertices[i].pos.y; break; case Z_AXIS: x = vertices[i].pos.x; z = vertices[i].pos.y; y = vertices[i].pos.z; break; } // Convert to cylindrical coordinates. float theta = atan2f(z, x); float y2 = y - b; // Transform [a, b]-->[-h, 0] // Transform theta from [0, 2*pi] to [0, 1] range and // transform y2 from [-h, 0] to [0, 1]. float u = theta / (2.0f*D3DX_PI); float v = y2 / -h; // Save texture coordinates. vertices[i].tex0.x = u; vertices[i].tex0.y = v; } HR(temp->UnlockVertexBuffer()); // Clone back to a hardware mesh. HR(temp->CloneMesh(D3DXMESH_MANAGED | D3DXMESH_WRITEONLY, elements, gd3dDevice, &mCylinder)); ReleaseCOM(temp); }