bool FD3D9MeshUtilities::LayoutUVs( struct FRawMesh& RawMesh, uint32 TextureResolution, uint32 TexCoordIndex, FText& OutError ) { OutError = FText(); if(!IsValid() || !RawMesh.IsValid()) { OutError = LOCTEXT("LayoutUVs_FailedInvalid", "LayoutUVs failed, mesh was invalid."); return false; } int32 NumTexCoords = 0; for (int32 i = 0; i < MAX_MESH_TEXTURE_COORDS; ++i) { if (RawMesh.WedgeTexCoords[i].Num() != RawMesh.WedgeIndices.Num()) { break; } NumTexCoords++; } if (TexCoordIndex > (uint32)NumTexCoords) { OutError = LOCTEXT("LayoutUVs_FailedUVs", "LayoutUVs failed, incorrect number of texcoords."); return false; } // Sort the mesh's triangles by whether they need to be charted, or just to be packed into the atlas. FRawMesh MeshToAtlas = RawMesh; if (TexCoordIndex > 0) { MeshToAtlas.WedgeTexCoords[TexCoordIndex] = MeshToAtlas.WedgeTexCoords[0]; } TRefCountPtr<ID3DXMesh> ChartMesh; TArray<uint32> AtlasAndChartAdjacency; TArray<int32> AtlasAndChartTriangleCharts; TRefCountPtr<ID3DXMesh> MergedMesh; TArray<uint32> MergedAdjacency; TArray<int32> MergedTriangleCharts; TRefCountPtr<ID3DXMesh> AtlasOnlyMesh; TArray<uint32> AtlasOnlyAdjacency; TArray<int32> AtlasOnlyTriangleCharts; { // Create a D3DXMesh for the triangles that only need to be atlassed. const bool bRemoveDegenerateTriangles = true; if (!ConvertRawMeshToD3DXMesh(Device,MeshToAtlas,bRemoveDegenerateTriangles,AtlasOnlyMesh)) { OutError = LOCTEXT("LayoutUVs_FailedConvert", "LayoutUVs failed, couldn't convert to a D3DXMesh."); return false; } // generate mapping orientations info FLayoutUVWindingInfo WindingInfo(AtlasOnlyMesh, TexCoordIndex); // Generate adjacency for the pre-charted triangles based on their input charts. GenerateAdjacency(AtlasOnlyMesh,AtlasOnlyAdjacency,FUVChartAdjacencyFilter(TexCoordIndex), &WindingInfo); ////clean the mesh TRefCountPtr<ID3DXMesh> TempMesh; TArray<uint32> CleanedAdjacency; CleanedAdjacency.AddUninitialized(AtlasOnlyMesh->GetNumFaces() * 3); if( FAILED(D3DXCleanMesh( D3DXCLEAN_SIMPLIFICATION, AtlasOnlyMesh, (::DWORD *)AtlasOnlyAdjacency.GetTypedData(), TempMesh.GetInitReference(), (::DWORD *)CleanedAdjacency.GetTypedData(), NULL ) ) ) { OutError = LOCTEXT("LayoutUVs_FailedClean", "LayoutUVs failed, couldn't clean mesh."); return false; } // Group the pre-charted triangles into indexed charts based on their adjacency in the chart. AssignMinimalAdjacencyGroups(CleanedAdjacency,AtlasOnlyTriangleCharts); MergedMesh = TempMesh; MergedAdjacency = CleanedAdjacency; MergedTriangleCharts = AtlasOnlyTriangleCharts; } if(MergedMesh) { // Create a buffer to hold the triangle chart data. TRefCountPtr<ID3DXBuffer> MergedTriangleChartsBuffer; VERIFYD3D9RESULT(D3DXCreateBuffer( MergedTriangleCharts.Num() * sizeof(int32), MergedTriangleChartsBuffer.GetInitReference() )); uint32* MergedTriangleChartsBufferPointer = (uint32*)MergedTriangleChartsBuffer->GetBufferPointer(); for(int32 TriangleIndex = 0;TriangleIndex < MergedTriangleCharts.Num();TriangleIndex++) { *MergedTriangleChartsBufferPointer++ = MergedTriangleCharts[TriangleIndex]; } const float GutterSize = 2.0f; // Pack the charts into a unified atlas. HRESULT Result = D3DXUVAtlasPack( MergedMesh, TextureResolution, TextureResolution, GutterSize, TexCoordIndex, (::DWORD *)MergedAdjacency.GetTypedData(), NULL, 0, NULL, 0, MergedTriangleChartsBuffer ); if (FAILED(Result)) { UE_LOG(LogD3D9MeshUtils, Warning, TEXT("D3DXUVAtlasPack() returned %u."), Result ); OutError = LOCTEXT("LayoutUVs_FailedPack", "LayoutUVs failed, D3DXUVAtlasPack failed."); return false; } int32 NewNumTexCoords = FMath::Max<int32>(NumTexCoords, TexCoordIndex + 1); FRawMesh FinalMesh; if (!ConvertD3DXMeshToRawMesh(MergedMesh, FinalMesh, NewNumTexCoords)) { OutError = LOCTEXT("LayoutUVs_FailedSimple", "LayoutUVs failed, couldn't convert the simplified D3DXMesh back to a UStaticMesh."); return false; } RawMesh = FinalMesh; } return true; }
bool FD3D9MeshUtilities::GenerateUVs( struct FRawMesh& RawMesh, uint32 TexCoordIndex, float MinChartSpacingPercent, float BorderSpacingPercent, bool bUseMaxStretch, const TArray< int32 >* InFalseEdgeIndices, uint32& MaxCharts, float& MaxDesiredStretch, FText& OutError ) { OutError = FText(); if(!IsValid()) { OutError = LOCTEXT("GenerateUVs_FailedInvalid", "GenerateUVs failed, mesh was invalid."); return false; } int32 NumTexCoords = 0; for (int32 i = 0; i < MAX_MESH_TEXTURE_COORDS; ++i) { if (RawMesh.WedgeTexCoords[i].Num() != RawMesh.WedgeIndices.Num()) { break; } NumTexCoords++; } if (TexCoordIndex > (uint32)NumTexCoords) { OutError = LOCTEXT("GenerateUVs_FailedUVs", "GenerateUVs failed, incorrect number of texcoords."); return false; } TRefCountPtr<ID3DXMesh> ChartMesh; TArray<uint32> AtlasAndChartAdjacency; TArray<int32> AtlasAndChartTriangleCharts; { const bool bUseFalseEdges = InFalseEdgeIndices != NULL; // When using false edges we don't remove degenerates as we want our incoming selected edge list to map // correctly to the D3DXMesh. const bool bRemoveDegenerateTriangles = !bUseFalseEdges; // Create a D3DXMesh for the triangles being charted. TRefCountPtr<ID3DXMesh> SourceMesh; if (!ConvertRawMeshToD3DXMesh(Device, RawMesh,bRemoveDegenerateTriangles,SourceMesh)) { OutError = LOCTEXT("GenerateUVs_FailedConvert", "GenerateUVs failed, couldn't convert to a D3DXMesh."); return false; } //generate adjacency info for the mesh, which is needed later TArray<uint32> Adjacency; GenerateAdjacency(SourceMesh,Adjacency,FFragmentedAdjacencyFilter()); // We don't clean the mesh as this can collapse vertices or delete degenerate triangles, and // we want our incoming selected edge list to map correctly to the D3DXMesh. if( !bUseFalseEdges ) { //clean the mesh TRefCountPtr<ID3DXMesh> TempMesh; TArray<uint32> CleanedAdjacency; CleanedAdjacency.AddUninitialized(SourceMesh->GetNumFaces() * 3); if( FAILED(D3DXCleanMesh( D3DXCLEAN_SIMPLIFICATION, SourceMesh, (::DWORD *)Adjacency.GetTypedData(), TempMesh.GetInitReference(), (::DWORD *)CleanedAdjacency.GetTypedData(), NULL ) ) ) { OutError = LOCTEXT("GenerateUVs_FailedClean", "GenerateUVs failed, couldn't clean mesh."); return false; } SourceMesh = TempMesh; Adjacency = CleanedAdjacency; } // Setup the D3DX "false edge" array. This is three DWORDS per face that define properties of the // face's edges. Values of -1 indicates that the edge may be used as a UV seam in a the chart. Any // other value indicates that the edge should never be a UV seam. This essentially allows us to // provide a precise list of edges to be used as UV seams in the new charts. uint32* FalseEdgeArray = NULL; TArray<uint32> FalseEdges; if( bUseFalseEdges ) { // -1 means "always use this edge as a chart UV seam" to D3DX FalseEdges.AddUninitialized( SourceMesh->GetNumFaces() * 3 ); for( int32 CurFalseEdgeIndex = 0; CurFalseEdgeIndex < (int32)SourceMesh->GetNumFaces() * 3; ++CurFalseEdgeIndex ) { FalseEdges[ CurFalseEdgeIndex ] = -1; } // For each tagged edge for( int32 CurTaggedEdgeIndex = 0; CurTaggedEdgeIndex < InFalseEdgeIndices->Num(); ++CurTaggedEdgeIndex ) { const int32 EdgeIndex = ( *InFalseEdgeIndices )[ CurTaggedEdgeIndex ]; // Mark this as a false edge by setting it to a value other than negative one FalseEdges[ EdgeIndex ] = Adjacency[ CurTaggedEdgeIndex ]; } FalseEdgeArray = (uint32*)FalseEdges.GetTypedData(); } // Partition the mesh's triangles into charts. TRefCountPtr<ID3DXBuffer> PartitionResultAdjacencyBuffer; TRefCountPtr<ID3DXBuffer> FacePartitionBuffer; HRESULT Result = D3DXUVAtlasPartition( SourceMesh, bUseMaxStretch ? 0 : MaxCharts, // Max charts (0 = use max stretch instead) MaxDesiredStretch, TexCoordIndex, (::DWORD *)Adjacency.GetTypedData(), (::DWORD *)FalseEdgeArray, // False edges NULL, // IMT data &GenerateUVsStatusCallback, 0.01f, // Callback frequency NULL, // Callback user data D3DXUVATLAS_GEODESIC_QUALITY, ChartMesh.GetInitReference(), FacePartitionBuffer.GetInitReference(), NULL, PartitionResultAdjacencyBuffer.GetInitReference(), &MaxDesiredStretch, &MaxCharts ); if (FAILED(Result)) { UE_LOG(LogD3D9MeshUtils, Warning, TEXT("D3DXUVAtlasPartition() returned %u with MaxDesiredStretch=%.2f, TexCoordIndex=%u."), Result, MaxDesiredStretch, TexCoordIndex ); OutError = LOCTEXT("GenerateUVs_FailedPartition", "GenerateUVs failed, D3DXUVAtlasPartition failed."); return false; } // Extract the chart adjacency data from the D3DX buffer into an array. for(uint32 TriangleIndex = 0;TriangleIndex < ChartMesh->GetNumFaces();TriangleIndex++) { for(int32 EdgeIndex = 0;EdgeIndex < 3;EdgeIndex++) { AtlasAndChartAdjacency.Add(*((uint32*)PartitionResultAdjacencyBuffer->GetBufferPointer()+TriangleIndex*3+EdgeIndex)); } } // Extract the triangle chart data from the D3DX buffer into an array. uint32* FacePartitionBufferPointer = (uint32*)FacePartitionBuffer->GetBufferPointer(); for(uint32 TriangleIndex = 0;TriangleIndex < ChartMesh->GetNumFaces();TriangleIndex++) { AtlasAndChartTriangleCharts.Add(*FacePartitionBufferPointer++); } // Scale the partitioned UVs down. FUtilVertex* LockedVertices; ChartMesh->LockVertexBuffer(0,(LPVOID*)&LockedVertices); for(uint32 VertexIndex = 0;VertexIndex < ChartMesh->GetNumVertices();VertexIndex++) { LockedVertices[VertexIndex].UVs[TexCoordIndex] /= 2048.0f; } ChartMesh->UnlockVertexBuffer(); } if(ChartMesh) { // Create a buffer to hold the triangle chart data. TRefCountPtr<ID3DXBuffer> MergedTriangleChartsBuffer; VERIFYD3D9RESULT(D3DXCreateBuffer( AtlasAndChartTriangleCharts.Num() * sizeof(int32), MergedTriangleChartsBuffer.GetInitReference() )); uint32* MergedTriangleChartsBufferPointer = (uint32*)MergedTriangleChartsBuffer->GetBufferPointer(); for(int32 TriangleIndex = 0;TriangleIndex < AtlasAndChartTriangleCharts.Num();TriangleIndex++) { *MergedTriangleChartsBufferPointer++ = AtlasAndChartTriangleCharts[TriangleIndex]; } const uint32 FakeTexSize = 1024; const float GutterSize = ( float )FakeTexSize * MinChartSpacingPercent * 0.01f; // Pack the charts into a unified atlas. HRESULT Result = D3DXUVAtlasPack( ChartMesh, FakeTexSize, FakeTexSize, GutterSize, TexCoordIndex, (::DWORD *)AtlasAndChartAdjacency.GetTypedData(), &GenerateUVsStatusCallback, 0.01f, // Callback frequency NULL, 0, MergedTriangleChartsBuffer ); if (FAILED(Result)) { UE_LOG(LogD3D9MeshUtils, Warning, TEXT("D3DXUVAtlasPack() returned %u."), Result ); OutError = LOCTEXT("GenerateUVs_FailedPack", "GenerateUVs failed, D3DXUVAtlasPack failed."); return false; } int32 NewNumTexCoords = FMath::Max<int32>(NumTexCoords, TexCoordIndex + 1); FRawMesh FinalMesh; if (!ConvertD3DXMeshToRawMesh(ChartMesh, FinalMesh, NewNumTexCoords)) { OutError = LOCTEXT("GenerateUVs_FailedSimple", "GenerateUVs failed, couldn't convert the simplified D3DXMesh back to a UStaticMesh."); return false; } // Scale/offset the UVs appropriately to ensure there is empty space around the border { const float BorderSize = BorderSpacingPercent * 0.01f; const float ScaleAmount = 1.0f - BorderSize * 2.0f; for( int32 CurUVIndex = 0; CurUVIndex < MAX_MESH_TEXTURE_COORDS; ++CurUVIndex ) { int32 NumWedges = FinalMesh.WedgeTexCoords[CurUVIndex].Num(); for( int32 WedgeIndex = 0; WedgeIndex < NumWedges; ++WedgeIndex ) { FVector2D& UV = FinalMesh.WedgeTexCoords[CurUVIndex][WedgeIndex]; UV.X = BorderSize + UV.X * ScaleAmount; UV.Y = BorderSize + UV.Y * ScaleAmount; } } } RawMesh = FinalMesh; } return true; }
///////////////////////////////////// // Name: // Purpose: // Output: // Return: ///////////////////////////////////// PUBLIC hMDL MDLGenMap(unsigned int newID, float mapSizeX, float mapSizeZ, float height, float r, unsigned int numIter, hTXT texture, D3DMATERIAL8 *mat) { int size = 1<<numIter; int numVtx = (size+1)*(size+1); //allocate the points float *points; //HACK for now... if(MemAlloc((void**)&points, sizeof(float)*(numVtx+2), M_ZERO) != RETCODE_SUCCESS) { ASSERT_MSG(0, "Unable to allocate points", "Error in MDLGenMap"); return 0; } //generate the points! _MapGeneratePoints(points, height, r, size); hMDL newMdl; if(MemAlloc((void**)&newMdl, sizeof(gfxModel), M_ZERO) != RETCODE_SUCCESS) { ASSERT_MSG(0, "Unable to allocate new model", "Error in ModelGenMap"); return 0; } MemSetPattern(newMdl, "GFXMAP"); //fill 'er up newMdl->ID = newID; newMdl->numMaterial = 1; if(texture) { if(MemAlloc((void**)&newMdl->textures, sizeof(hTXT)*newMdl->numMaterial, M_ZERO) != RETCODE_SUCCESS) { ASSERT_MSG(0, "Unable to allocate model textures", "Error in ModelGenMap"); return 0; } newMdl->textures[0] = texture; TextureAddRef(newMdl->textures[0]); } if(MemAlloc((void**)&newMdl->materials, sizeof(D3DMATERIAL8)*newMdl->numMaterial, M_ZERO) != RETCODE_SUCCESS) { ASSERT_MSG(0, "Unable to allocate materials", "Error in ModelGenMap"); return 0; } if(!mat) { newMdl->materials[0].Diffuse.r = 1.0f; newMdl->materials[0].Diffuse.g = 1.0f; newMdl->materials[0].Diffuse.b = 1.0f; newMdl->materials[0].Diffuse.a = 1.0f; //newMdl->materials[0].Specular = newMdl->materials[0].Emissive = newMdl->materials[0].Ambient = newMdl->materials[0].Diffuse; newMdl->materials[0].Ambient = newMdl->materials[0].Diffuse; //newMdl->materials[0].Power = 1.0f; } else memcpy(newMdl->materials, mat, sizeof(D3DMATERIAL8)); ////////////////////////////////////////////////////////////// //now time to stuff it all in the D3D vertex buffer //create the mesh _GFXCheckError(D3DXCreateMeshFVF( size*size*2, numVtx, D3DXMESH_MANAGED, GFXVERTEXFLAG, g_p3DDevice, &newMdl->mesh), true, "Error in _ModelLoadDataFromFile"); newMdl->indCount = newMdl->mesh->GetNumFaces()*NUMPTFACE; ////////////////////////////////////////////////////////////// ///////////////// //now fill 'er up gfxVtx *ptrVtx, *thisVtx; if(_GFXCheckError( newMdl->mesh->LockVertexBuffer(0, //Flags, nothing special (BYTE**)&ptrVtx //If successful, this will point to the data in the VB ), true, "Error in _ModelLoadDataFromFile")) { return 0; } int maxV = size+1; //fill in data, just go through the lists and fill in stuff for(int rowV = 0; rowV < maxV; rowV++) { for(int colV = 0; colV < maxV; colV++) { thisVtx = &CELL(ptrVtx, rowV, colV, maxV); thisVtx->x = colV*mapSizeX; thisVtx->y = CELL(points, rowV, colV, maxV); thisVtx->z = rowV*mapSizeZ; thisVtx->s = thisVtx->x/TextureGetWidth(texture); thisVtx->t = thisVtx->z/TextureGetHeight(texture); thisVtx->color = 0xffffffff; } } newMdl->mesh->UnlockVertexBuffer(); ///////////////// ///////////////// //now fill the index buffer up unsigned short *ptrInd; if(_GFXCheckError( newMdl->mesh->LockIndexBuffer(0, //Flags, nothing special (BYTE**)&ptrInd //If successful, this will point to the data in the IB ), true, "Error in _ModelLoadDataFromFile")) { return 0; } //fill in data int numCol = size; //number of col int numRow = size; //number of row int max = numCol+1; int numDot = newMdl->mesh->GetNumVertices()-max; //number of dots to iterate (minus last row) int indIter = NUMPTFACE*2; //we are going to make two faces per cel for(int row = 0, ind = 0; row < numRow; row++) { for(int col = 0; col < numCol; col++) { /* 0-----3 |\ | | \ | | \| 1-----2 */ int dot = col+(row*max); //first face ptrInd[ind] = dot; ptrInd[ind+1] = dot+max; ptrInd[ind+2] = ptrInd[ind+1]+1; //second face ptrInd[ind+3] = ptrInd[ind+2]; ptrInd[ind+4] = dot+1; ptrInd[ind+5] = ptrInd[ind]; ind += indIter; } } newMdl->mesh->UnlockIndexBuffer(); ///////////////// //This outta make lighting easy D3DXComputeNormals(newMdl->mesh); ///////////////////////////// //create the adjacency buffer //and do some funky stuff D3DXCreateBuffer(sizeof(DWORD)*newMdl->indCount, &newMdl->adjacencyBuffer); newMdl->mesh->GenerateAdjacency(0.0f, (DWORD*)newMdl->adjacencyBuffer->GetBufferPointer()); D3DXValidMesh(newMdl->mesh, (DWORD*)newMdl->adjacencyBuffer->GetBufferPointer()); ////////////////////////////// //////////////////// //optimize base mesh LPD3DXMESH optMesh=0; _MDLOptimize(newMdl->mesh, newMdl->adjacencyBuffer, newMdl->indCount, &optMesh); if(optMesh) { newMdl->mesh->Release(); newMdl->mesh = optMesh; } newMdl->indCount = newMdl->mesh->GetNumFaces()*NUMPTFACE; //////////////////// //clean up stuff MemFree((void**)&points); //append to list g_MDLLIST.insert(g_MDLLIST.end(), (unsigned int)newMdl); return newMdl; }
//md2 loader PROTECTED RETCODE _ModelLoadDataFromFileMD2(hMDL model, const char *filename) { assert(model); RETCODE ret = RETCODE_SUCCESS; md2Header header; //the md2 header file BYTE *frames=0; //the frames (used later to be typecast) md2Face *faces=0; //3 indices per face long *glCommands=0; //stuff md2SkinFile *skins=0; //skin files associated with this model md2TxtCoord *txtcoords=0; //texture coords in pixel int i; //ready the file FILE *theFile; theFile = fopen(filename, "rb"); if(!theFile) { ASSERT_MSG(0, "Unable to open file", "Error in _ModelLoadDataFromFileMD2"); return RETCODE_FAILURE; } //load up the header fread(&header, sizeof(md2Header), 1, theFile); //confirm format if(header.magic != 844121161) { ASSERT_MSG(0, "Bad MD2 magic number, invalid file!", "Error in _ModelLoadDataFromFileMD2"); ret = RETCODE_FAILURE; goto BADMOJO3; } if(header.version != 8) { ASSERT_MSG(0, "Bad MD2 version number, invalid file!", "Error in _ModelLoadDataFromFileMD2"); ret = RETCODE_FAILURE; goto BADMOJO3; } //////////////// //load up frames if(MemAlloc((void**)&frames, sizeof(BYTE)*header.frameSize*header.numFrames, M_ZERO) != RETCODE_SUCCESS) { ASSERT_MSG(0, "Unable to allocate frames!", "Error in _ModelLoadDataFromFileMD2"); ret = RETCODE_FAILURE; goto BADMOJO3; } fseek(theFile, header.offsetFrames, SEEK_SET); fread(frames, sizeof(BYTE)*header.frameSize*header.numFrames, 1, theFile); //////////////// ///////////////////// //load up gl commands if(MemAlloc((void**)&glCommands, sizeof(long)*header.numGlCommands, M_ZERO) != RETCODE_SUCCESS) { ASSERT_MSG(0, "Unable to allocate gl Commands!", "Error in _ModelLoadDataFromFileMD2"); ret = RETCODE_FAILURE; goto BADMOJO3; } fseek(theFile, header.offsetGlCommands, SEEK_SET); fread(glCommands, header.numGlCommands*sizeof(long), 1, theFile); ///////////////////// /////////////////////////// //load up triangles (faces) if(MemAlloc((void**)&faces, sizeof(md2Face)*header.numTriangles, M_ZERO) != RETCODE_SUCCESS) { ASSERT_MSG(0, "Unable to allocate triangles!", "Error in _ModelLoadDataFromFileMD2"); ret = RETCODE_FAILURE; goto BADMOJO3; } fseek(theFile, header.offsetTriangles, SEEK_SET); fread(faces, sizeof(md2Face)*header.numTriangles, 1, theFile); /////////////////////////// //////////////////////// //load up the skin files if(header.numSkins > 0) { if(MemAlloc((void**)&skins, sizeof(md2SkinFile)*header.numSkins, M_ZERO) != RETCODE_SUCCESS) { ASSERT_MSG(0, "Unable to allocate skin files!", "Error in _ModelLoadDataFromFileMD2"); ret = RETCODE_FAILURE; goto BADMOJO3; } fseek(theFile, header.offsetSkins, SEEK_SET); fread(skins, sizeof(md2SkinFile)*header.numSkins, 1, theFile); } /////////////////////////// /////////////////////////// //load up txtcoords if(MemAlloc((void**)&txtcoords, sizeof(md2TxtCoord)*header.numTexcoords, M_ZERO) != RETCODE_SUCCESS) { ASSERT_MSG(0, "Unable to allocate texture coords!", "Error in _ModelLoadDataFromFileMD2"); ret = RETCODE_FAILURE; goto BADMOJO3; } fseek(theFile, header.offsetTexcoords, SEEK_SET); fread(txtcoords, sizeof(md2TxtCoord)*header.numTexcoords, 1, theFile); /////////////////////////// ///////////////////////// //Get some important info model->numMaterial = 1; //allocate textures if(MemAlloc((void**)&model->textures, sizeof(hTXT)*model->numMaterial, M_ZERO) != RETCODE_SUCCESS) { ASSERT_MSG(0, "Unable to allocate model textures!", "Error in _ModelLoadDataFromFileMD2"); ret = RETCODE_FAILURE; goto BADMOJO3; } MemSetPattern(model->textures, "MDLTXT"); //allocate materials if(MemAlloc((void**)&model->materials, sizeof(GFXMATERIAL)*model->numMaterial, M_ZERO) != RETCODE_SUCCESS) { ASSERT_MSG(0, "Unable to allocate model materials!", "Error in _ModelLoadDataFromFileMD2"); ret = RETCODE_FAILURE; goto BADMOJO3; } MemSetPattern(model->materials, "MDLMTR"); //create mesh for main mesh and insert frame 0 _MD2CreateFrame(&model->mesh, 0, txtcoords, frames, faces, header, 0); model->indCount = model->mesh->GetNumFaces()*NUMPTFACE; ///////////////////////////// //create the adjacency buffer //and do some funky stuff D3DXCreateBuffer(sizeof(DWORD)*model->indCount, &model->adjacencyBuffer); model->mesh->GenerateAdjacency(0.0f, (DWORD*)model->adjacencyBuffer->GetBufferPointer()); D3DXValidMesh(model->mesh, (DWORD*)model->adjacencyBuffer->GetBufferPointer()); ////////////////////////////// //We will only create frames if numframes is greater than 1 if(header.numFrames > 1) { model->numFrames = header.numFrames; //allocate frame meshes if(MemAlloc((void**)&model->frames, sizeof(gfxModelFrame)*model->numFrames, M_ZERO) != RETCODE_SUCCESS) { ASSERT_MSG(0, "Unable to allocate model frames!", "Error in _ModelLoadDataFromFileMD2"); ret = RETCODE_FAILURE; goto BADMOJO3; } MemSetPattern(model->frames, "MDLFRM"); //create mesh for each frame for(i = 0; i < model->numFrames; i++) { _MD2CreateFrame(&model->frames[i].frameMesh, model->frames[i].name, txtcoords, frames, faces, header, i); ///////////////////////////// //create the adjacency buffer //and do some funky stuff D3DXCreateBuffer(sizeof(DWORD)*model->indCount, &model->frames[i].adjacencyBuffer); model->frames[i].frameMesh->GenerateAdjacency(0.0f, (DWORD*)model->frames[i].adjacencyBuffer->GetBufferPointer()); D3DXValidMesh(model->frames[i].frameMesh, (DWORD*)model->adjacencyBuffer->GetBufferPointer()); ////////////////////////////// } } BADMOJO3: if(frames) MemFree((void**)&frames); if(glCommands) MemFree((void**)&glCommands); if(faces) MemFree((void**)&faces); if(skins) MemFree((void**)&skins); if(txtcoords) MemFree((void**)&txtcoords); //set model as CCW backface culling //SETFLAG(model->status, MDL_BACKFACECCW); fclose(theFile); return ret; }
//3ds ascii file textured PROTECTED RETCODE _ModelLoadDataFromFileASE(hMDL model, const char *filename) { assert(model); RETCODE ret = RETCODE_SUCCESS; //data structures gfxVtx *vtxBuff=0; //it's gonna be biG!, bIG!!, BIG!!! txc *txcList=0; //allocated later (numTxc) unsigned short *indList=0; //allocated later (indNum inside model) int numTxc; int vtxInd[NUMPTFACE], txtInd[NUMPTFACE]; int vtxCount, faceCount; //ready the file FILE *theFile; char buff[MAXCHARBUFF]; theFile = fopen(filename, "rt"); //FileOpenFile(filename, FILEREAD | FILETEXT); if(!theFile) { ASSERT_MSG(0,"Unable to open file", "Error in _ModelLoadDataFromFileASE"); return RETCODE_FAILURE; } //now let's parse this baby! if(ParserSkipString(theFile, '*', ' ', "BITMAP")) { //let's get the filename if(ParserReadStringFile(theFile, buff, MAXCHARBUFF, '"', '"') == RETCODE_FAILURE) //we have reached end of file { ASSERT_MSG(0,"Error reading ASE model file, cannot get BITMAP file!", "Error in _ModelLoadDataFromFileASE"); ret = RETCODE_FAILURE; goto BADMOJO2; } //we will only have one texture for now... model->numMaterial = 1; //allocate texture array if(MemAlloc((void**)&model->textures, sizeof(hTXT)*model->numMaterial, M_ZERO) != RETCODE_SUCCESS) { ASSERT_MSG(0,"Unable to allocate textures", "error in _ModelLoadDataFromFileASE"); ret=RETCODE_FAILURE; goto BADMOJO2; } MemSetPattern(model->textures, "MDLTXTS"); model->textures[0] = TextureCreate(MDLTXTID, buff, false, 0); TextureAddRef(model->textures[0]); //D3DXCreateTextureFromFile(g_p3DDevice, buff, &model->texture); if(!model->textures[0]) { ASSERT_MSG(0,"Unable to load texture", "error in _ModelLoadDataFromFileASE"); ret=RETCODE_FAILURE; goto BADMOJO2; } } else { ASSERT_MSG(0,"Error reading ASE model file", "Error in _ModelLoadDataFromFileASE"); ret = RETCODE_FAILURE; goto BADMOJO2; } //now let's find the num vertices if(ParserSkipString(theFile, '*', ' ', "MESH_NUMVERTEX")) { //get the number fscanf(theFile, "%d", &vtxCount); //create the array if(MemAlloc((void**)&vtxBuff, sizeof(gfxVtx)*vtxCount, M_ZERO) != RETCODE_SUCCESS) { ASSERT_MSG(0,"Unable to allocate vertex buffer", "error in _ModelLoadDataFromFileASE"); ret = RETCODE_FAILURE; goto BADMOJO2; } MemSetPattern(vtxBuff, "GFXVTXB"); } else { ASSERT_MSG(0,"Error reading ASE model file", "Error in _ModelLoadDataFromFileASE"); ret = RETCODE_FAILURE; goto BADMOJO2; } //now get the num faces if(ParserSkipString(theFile, '*', ' ', "MESH_NUMFACES")) { //get the number fscanf(theFile, "%d", &faceCount); //create the BIG @$$ array model->indCount = faceCount*NUMPTFACE; if(MemAlloc((void**)&indList, sizeof(unsigned short)*model->indCount, M_ZERO) != RETCODE_SUCCESS) { ASSERT_MSG(0,"Unable to allocate vertex buffer, It's not HUGE!!!", "error in ModelLoadDataFromFileASE"); ret=RETCODE_FAILURE; goto BADMOJO2; } MemSetPattern(indList, "GFXINDB"); } else { ASSERT_MSG(0,"Error reading ASE model file", "Error in ModelLoadDataFromFileASE"); ret=RETCODE_FAILURE; goto BADMOJO2; } int i, j, dummy; //load up the vertex list for(i = 0; i < vtxCount; i++) { //skip "*MESH_VERTEX " if(ParserSkipString(theFile, '*', ' ', "MESH_VERTEX")) { //skip index number if(ParserReadDataFile(theFile, &dummy, dataINT, 9) == RETCODE_FAILURE) //we have reached end of file { ASSERT_MSG(0,"Error reading ASE model file 'dummy'", "Error in ModelLoadDataFromFileASE"); ret=RETCODE_FAILURE; goto BADMOJO2; } //now let's get those that we need if(ParserReadDataFile(theFile, &vtxBuff[i].x, dataFLOAT, 9) == RETCODE_FAILURE) { ASSERT_MSG(0,"Error reading ASE model file 'vtx X'", "Error in ModelLoadDataFromFileASE"); ret=RETCODE_FAILURE; goto BADMOJO2; } if(ParserReadDataFile(theFile, &vtxBuff[i].y, dataFLOAT, 9) == RETCODE_FAILURE) { ASSERT_MSG(0,"Error reading ASE model file 'vtx Y'", "Error in ModelLoadDataFromFileASE"); ret=RETCODE_FAILURE; goto BADMOJO2; } if(ParserReadDataFile(theFile, &vtxBuff[i].z, dataFLOAT, 9) == RETCODE_FAILURE) { ASSERT_MSG(0,"Error reading ASE model file 'vtx Z'", "Error in ModelLoadDataFromFileASE"); ret=RETCODE_FAILURE; goto BADMOJO2; } vtxBuff[i].color = 0xFFFFFFFF; //get the normalized vector and put it as the normal for lighting D3DXVECTOR3 vect(vtxBuff[i].x, vtxBuff[i].y, vtxBuff[i].z); D3DXVec3Normalize(&vect,&vect); float *nV = (float*)vect; vtxBuff[i].nX = -nV[eX]; vtxBuff[i].nY = -nV[eY]; vtxBuff[i].nZ = -nV[eZ]; } else { ASSERT_MSG(0,"Error reading ASE model file '*MESH_VERTEX '", "Error in ModelLoadDataFromFileASE"); ret=RETCODE_FAILURE; goto BADMOJO2; } } //now to fill in the face index for(i = 0, j = 0; i < faceCount; i++, j+=NUMPTFACE) { //skip "*MESH_FACE " if(ParserSkipString(theFile, '*', ' ', "MESH_FACE")) { //skip index number if(ParserReadDataFile(theFile, &dummy, dataINT, ':') == RETCODE_FAILURE) //we have reached end of file { ASSERT_MSG(0,"Error reading ASE model file", "Error in ModelLoadDataFromFileASE"); ret=RETCODE_FAILURE; goto BADMOJO2; } //now let's get those that we need //skip this junk A: if(ParserReadWordFile(theFile, buff, MAXCHARBUFF, ':') == RETCODE_FAILURE) { ASSERT_MSG(0,"Error reading ASE model file", "Error in ModelLoadDataFromFileASE"); ret=RETCODE_FAILURE; goto BADMOJO2; } if(ParserReadDataFile(theFile, &vtxInd[0], dataINT, ' ') == RETCODE_FAILURE) { ASSERT_MSG(0,"Error reading ASE model file", "Error in ModelLoadDataFromFileASE"); ret=RETCODE_FAILURE; goto BADMOJO2; } //skip this junk B: if(ParserReadWordFile(theFile, buff, MAXCHARBUFF, ':') == RETCODE_FAILURE) { ASSERT_MSG(0,"Error reading ASE model file", "Error in ModelLoadDataFromFileASE"); ret=RETCODE_FAILURE; goto BADMOJO2; } if(ParserReadDataFile(theFile, &vtxInd[1], dataINT, ' ') == RETCODE_FAILURE) { ASSERT_MSG(0,"Error reading ASE model file", "Error in ModelLoadDataFromFileASE"); ret=RETCODE_FAILURE; goto BADMOJO2; } //skip this junk C: if(ParserReadWordFile(theFile, buff, MAXCHARBUFF, ':') == RETCODE_FAILURE) { ASSERT_MSG(0,"Error reading ASE model file", "Error in ModelLoadDataFromFileASE"); ret=RETCODE_FAILURE; goto BADMOJO2; } if(ParserReadDataFile(theFile, &vtxInd[2], dataINT, ' ') == RETCODE_FAILURE) { ASSERT_MSG(0,"Error reading ASE model file", "Error in ModelLoadDataFromFileASE"); ret=RETCODE_FAILURE; goto BADMOJO2; } indList[j] = vtxInd[0]; indList[j+1] = vtxInd[1]; indList[j+2] = vtxInd[2]; } else { ASSERT_MSG(0,"Error reading ASE model file", "Error in ModelLoadDataFromFileASE"); ret=RETCODE_FAILURE; goto BADMOJO2; } } //now let's get the number of texture vertices if(ParserSkipString(theFile, '*', ' ', "MESH_NUMTVERTEX")) { //get the number fscanf(theFile, "%d", &numTxc); //create the array if(MemAlloc((void**)&txcList, sizeof(txc)*numTxc, M_ZERO) != RETCODE_SUCCESS) { ASSERT_MSG(0,"Unable to create texture location list", "error in ModelLoadDataFromFileASE"); ret=RETCODE_FAILURE; goto BADMOJO2; } MemSetPattern(txcList, "GFXTXTL"); } else { ASSERT_MSG(0,"Error reading ASE model file", "Error in ModelLoadDataFromFileASE"); ret=RETCODE_FAILURE; goto BADMOJO2; } float junk; //we don't need the depth in texture for now... //let's fill 'er up for(i = 0; i < numTxc; i++) { //skip "*MESH_TVERT " if(ParserSkipString(theFile, '*', ' ', "MESH_TVERT")) { //skip index number if(ParserReadDataFile(theFile, &dummy, dataINT, 9) == RETCODE_FAILURE) //we have reached end of file { ASSERT_MSG(0,"Error reading ASE model file", "Error in ModelLoadDataFromFileASE"); ret=RETCODE_FAILURE; goto BADMOJO2; } //now let's get those that we need if(ParserReadDataFile(theFile, &txcList[i].s, dataFLOAT, 9) == RETCODE_FAILURE) { ASSERT_MSG(0,"Error reading ASE model file", "Error in ModelLoadDataFromFileASE"); ret=RETCODE_FAILURE; goto BADMOJO2; } if(ParserReadDataFile(theFile, &txcList[i].t, dataFLOAT, 9) == RETCODE_FAILURE) { ASSERT_MSG(0,"Error reading ASE model file", "Error in ModelLoadDataFromFileASE"); ret=RETCODE_FAILURE; goto BADMOJO2; } if(ParserReadDataFile(theFile, &junk, dataFLOAT, 9) == RETCODE_FAILURE) { ASSERT_MSG(0,"Error reading ASE model file", "Error in ModelLoadDataFromFileASE"); ret=RETCODE_FAILURE; goto BADMOJO2; } } else { ASSERT_MSG(0,"Error reading ASE model file", "Error in ModelLoadDataFromFileASE"); ret=RETCODE_FAILURE; goto BADMOJO2; } } //let's fill in the face index //number of face to have texture will be the number of faces created...for now... for(i = 0, j = 0; i < faceCount; i++, j+=NUMPTFACE) { //skip "*MESH_TFACE " if(ParserSkipString(theFile, '*', ' ', "MESH_TFACE")) { //skip index number if(ParserReadDataFile(theFile, &dummy, dataINT, 9) == RETCODE_FAILURE) //we have reached end of file { ASSERT_MSG(0,"Error reading ASE model file", "Error in ModelLoadDataFromFileASE"); ret=RETCODE_FAILURE; goto BADMOJO2; } //now let's get those that we need if(ParserReadDataFile(theFile, &txtInd[0], dataINT, 9) == RETCODE_FAILURE) { ASSERT_MSG(0,"Error reading ASE model file", "Error in ModelLoadDataFromFileASE"); ret=RETCODE_FAILURE; goto BADMOJO2; } if(ParserReadDataFile(theFile, &txtInd[1], dataINT, 9) == RETCODE_FAILURE) { ASSERT_MSG(0,"Error reading ASE model file", "Error in ModelLoadDataFromFileASE"); ret=RETCODE_FAILURE; goto BADMOJO2; } if(ParserReadDataFile(theFile, &txtInd[2], dataINT, 9) == RETCODE_FAILURE) { ASSERT_MSG(0,"Error reading ASE model file", "Error in ModelLoadDataFromFileASE"); ret=RETCODE_FAILURE; goto BADMOJO2; } vtxBuff[indList[j]].s = txcList[txtInd[0]].s; vtxBuff[indList[j]].t = txcList[txtInd[0]].t; vtxBuff[indList[j+1]].s = txcList[txtInd[0]].s; vtxBuff[indList[j+1]].t = txcList[txtInd[0]].t; vtxBuff[indList[j+2]].s = txcList[txtInd[2]].s; vtxBuff[indList[j+2]].t = txcList[txtInd[2]].t; } else { ASSERT_MSG(0,"Error reading ASE model file", "Error in ModelLoadDataFromFileASE"); fclose(theFile); return RETCODE_FAILURE; } } ////////////////////////////////////////////////////////////// //now time to stuff it all in the D3D vertex buffer //create the mesh _GFXCheckError(D3DXCreateMeshFVF( faceCount, vtxCount, D3DXMESH_MANAGED, GFXVERTEXFLAG, g_p3DDevice, &model->mesh), true, "Error in ModelLoadDataFromFileASE"); ////////////////////////////////////////////////////////////// ///////////////// //now fill 'er up BYTE *ptrVtx; if(_GFXCheckError( model->mesh->LockVertexBuffer(0, //Flags, nothing special &ptrVtx //If successful, this will point to the data in the VB ), true, "Error in ModelLoadDataFromFileASE")) { ret=RETCODE_FAILURE; goto BADMOJO2; } memcpy(ptrVtx, vtxBuff, sizeof(gfxVtx)*vtxCount); model->mesh->UnlockVertexBuffer(); ///////////////// ///////////////// //now fill the index buffer up BYTE *ptrInd; if(_GFXCheckError( model->mesh->LockIndexBuffer(0, //Flags, nothing special &ptrInd //If successful, this will point to the data in the IB ), true, "Error in ModelLoadDataFromFileASE")) { ret=RETCODE_FAILURE; goto BADMOJO2; } memcpy(ptrInd, indList, sizeof(unsigned short)*model->indCount); model->mesh->UnlockIndexBuffer(); ///////////////// ///////////////////////////// //create the adjacency buffer //and do some funky stuff D3DXCreateBuffer(sizeof(DWORD)*model->indCount, &model->adjacencyBuffer); model->mesh->GenerateAdjacency(0.0f, (DWORD*)model->adjacencyBuffer->GetBufferPointer()); D3DXValidMesh(model->mesh, (DWORD*)model->adjacencyBuffer->GetBufferPointer()); ////////////////////////////// //This outta make lighting easy D3DXComputeNormals(model->mesh); BADMOJO2: if(theFile) fclose(theFile); if(indList) MemFree((void**)&indList); if(vtxBuff) MemFree((void**)&vtxBuff); if(txcList) MemFree((void**)&txcList); return ret; }
//my own model file! PROTECTED RETCODE _ModelLoadDataFromFile(hMDL model, const char *filename) { assert(model); RETCODE ret = RETCODE_SUCCESS; //data structures gfxVtx *vtxBuff=0; //it's gonna be biG!, bIG!!, BIG!!! txc *txcList=0; //allocated later (numTxc) unsigned short *indList=0; //allocated later (indNum inside model) int numTxc; int vtxInd[NUMPTFACE], txtInd[NUMPTFACE]; int vtxCount, faceCount; //ready the file FILE *theFile; char buff[MAXCHARBUFF]; bool bLoading = false; theFile = fopen(filename, "rt"); if(!theFile) { ASSERT_MSG(0, "Unable to open file", "Error in _ModelLoadDataFromFile"); return RETCODE_FAILURE; } do { fscanf(theFile, "%s\n", buff); if(strcmp(buff, "START") == 0) //start loading stuff if we found the START bLoading = true; else if(bLoading) { if(strcmp("[VERTEX]", buff) == 0) { fscanf(theFile, "numvertex=%d\n", &vtxCount); //create the array if(MemAlloc((void**)&vtxBuff, sizeof(gfxVtx)*vtxCount, M_ZERO) != RETCODE_SUCCESS) { ASSERT_MSG(0,"Unable to allocate vertex buffer", "error in _ModelLoadDataFromFile"); ret=RETCODE_FAILURE; goto BADMOJO; } //fill 'em up! int r,g,b,a; for(int i = 0; i < vtxCount; i++) { fscanf(theFile, "vertex=%f,%f,%f color=%d,%d,%d,%d\n", &vtxBuff[i].x,&vtxBuff[i].y,&vtxBuff[i].z, &r,&g,&b,&a); vtxBuff[i].color = D3DCOLOR_RGBA(r,g,b,a); //get the normalized vector and put it as the normal for lighting //D3DXVECTOR3 vect(vtxBuff[i].x, vtxBuff[i].y, vtxBuff[i].z); //D3DXVec3Normalize(&vect,&vect); //float *nV = (float*)vect; //vtxBuff[i].nX = -nV[eX]; vtxBuff[i].nY = -nV[eY]; vtxBuff[i].nZ = -nV[eZ]; } } else if(strcmp("[TEXTURE]", buff) == 0) { fscanf(theFile, "image=%s\n", buff); int filtermode; fscanf(theFile, "filtermode=%d\n", &filtermode); //we will only have one texture for now... model->numMaterial = 1; //allocate texture array if(MemAlloc((void**)&model->textures, sizeof(hTXT)*model->numMaterial, M_ZERO) != RETCODE_SUCCESS) { ASSERT_MSG(0,"Unable to allocate textures", "error in _ModelLoadDataFromFile"); ret=RETCODE_FAILURE; goto BADMOJO; } MemSetPattern(model->textures, "MDLTXTS"); model->textures[0] = TextureCreate(MDLTXTID, buff, false, 0); TextureAddRef(model->textures[0]); //D3DXCreateTextureFromFile(g_p3DDevice, buff, &model->texture); if(!model->textures[0]) { ASSERT_MSG(0,"Unable to load texture", "error in _ModelLoadDataFromFile"); ret=RETCODE_FAILURE; goto BADMOJO; } //now get the texture locations fscanf(theFile, "numtextureloc=%d\n", &numTxc); //create the array if(MemAlloc((void**)&txcList, sizeof(txc)*numTxc, M_ZERO) != RETCODE_SUCCESS) { ASSERT_MSG(0,"Unable to create texture location list", "error in _ModelLoadDataFromFile"); ret=RETCODE_FAILURE; goto BADMOJO; } MemSetPattern(txcList, "GFXTXTL"); //fill 'er up for(int i = 0; i < numTxc; i++) { fscanf(theFile, "texloc=%f,%f\n", &txcList[i].s, &txcList[i].t); } } else if(strcmp("[FACE]", buff) == 0) { fscanf(theFile, "numface=%d\n", &faceCount); //create the BIG @$$ array model->indCount = faceCount*NUMPTFACE; if(MemAlloc((void**)&indList, sizeof(unsigned short)*model->indCount, M_ZERO) != RETCODE_SUCCESS) { ASSERT_MSG(0,"Unable to allocate index buffer, It's not so HUGE!!!", "error in _ModelLoadDataFromFile"); ret=RETCODE_FAILURE; goto BADMOJO; } MemSetPattern(vtxBuff, "GFXINDB"); //fill 'em up for(int i = 0, j = 0; i < faceCount; i++, j+=NUMPTFACE) { fscanf(theFile, "vertexIndex=%d,%d,%d textureIndex=%d,%d,%d\n", &vtxInd[0], &vtxInd[1], &vtxInd[2], &txtInd[0], &txtInd[1], &txtInd[2]); indList[j] = vtxInd[0]; indList[j+1] = vtxInd[1]; indList[j+2] = vtxInd[2]; //do some messed up texture assign vtxBuff[vtxInd[0]].s = txcList[txtInd[0]].s; vtxBuff[vtxInd[0]].t = txcList[txtInd[0]].t; vtxBuff[vtxInd[1]].s = txcList[txtInd[1]].s; vtxBuff[vtxInd[1]].t = txcList[txtInd[1]].t; vtxBuff[vtxInd[2]].s = txcList[txtInd[2]].s; vtxBuff[vtxInd[2]].t = txcList[txtInd[2]].t; } } else if(strcmp("END", buff) == 0) bLoading = false; } }while(bLoading); ////////////////////////////////////////////////////////////// //now time to stuff it all in the D3D vertex buffer //create the mesh _GFXCheckError(D3DXCreateMeshFVF( faceCount, vtxCount, D3DXMESH_MANAGED, GFXVERTEXFLAG, g_p3DDevice, &model->mesh), true, "Error in _ModelLoadDataFromFile"); ////////////////////////////////////////////////////////////// ///////////////// //now fill 'er up BYTE *ptrVtx; if(_GFXCheckError( model->mesh->LockVertexBuffer(0, //Flags, nothing special &ptrVtx //If successful, this will point to the data in the VB ), true, "Error in _ModelLoadDataFromFile")) { ret=RETCODE_FAILURE; goto BADMOJO; } memcpy(ptrVtx, vtxBuff, sizeof(gfxVtx)*vtxCount); model->mesh->UnlockVertexBuffer(); ///////////////// ///////////////// //now fill the index buffer up BYTE *ptrInd; if(_GFXCheckError( model->mesh->LockIndexBuffer(0, //Flags, nothing special &ptrInd //If successful, this will point to the data in the IB ), true, "Error in _ModelLoadDataFromFile")) { ret=RETCODE_FAILURE; goto BADMOJO; } memcpy(ptrInd, indList, sizeof(unsigned short)*model->indCount); model->mesh->UnlockIndexBuffer(); ///////////////// ///////////////////////////// //create the adjacency buffer //and do some funky stuff D3DXCreateBuffer(sizeof(DWORD)*model->indCount, &model->adjacencyBuffer); model->mesh->GenerateAdjacency(0.0f, (DWORD*)model->adjacencyBuffer->GetBufferPointer()); D3DXValidMesh(model->mesh, (DWORD*)model->adjacencyBuffer->GetBufferPointer()); ////////////////////////////// //This outta make lighting easy D3DXComputeNormals(model->mesh); BADMOJO: if(theFile) fclose(theFile); if(indList) MemFree((void**)&indList); if(vtxBuff) MemFree((void**)&vtxBuff); if(txcList) MemFree((void**)&txcList); return ret; }
bool CVertexShader::LoadVariant( IShaderDefines *pDefines, bool bCompile ) { // check for already compiled default version of the shader if (pDefines == NULL && m_VertexShader != NULL) return true; // check for already compiled variant of the shader if (pDefines != NULL) { unsigned long iEncoding = pDefines->GetValuesEncoding().iEncoding; SHADERVARIANTSMAP::iterator itr = m_ShaderVariants.find( iEncoding ); if (itr != m_ShaderVariants.end()) return true; } D3DXMACRO *pMacros = NULL; if (pDefines) { const int iMaxShaderDefineCount = 32; const int iValueCharSize = 64; static char szValues[iMaxShaderDefineCount][iValueCharSize]; static D3DXMACRO vMacros[iMaxShaderDefineCount + 1]; if (iMaxShaderDefineCount < pDefines->GetDefineCount()) { m_ToolBox->Log( LOGFATALERROR, _T("Shader Define Count exceeds the internal buffer!\n") ); return false; } DWORD i; for (i=0; i < pDefines->GetDefineCount(); i++) { vMacros[i].Name = pDefines->GetDefineName(i); vMacros[i].Definition = _itoa(pDefines->GetDefineValue(i), szValues[i], 10); } // null terminate macro list vMacros[i].Name = NULL; vMacros[i].Definition = NULL; pMacros = vMacros; } LPDIRECT3DVERTEXSHADER9 pShader = NULL; LPD3DXBUFFER shaderBuf = NULL; LPD3DXBUFFER pErrorMsgs = NULL; CDX9IncludeManager includeInterface; LPDIRECT3DDEVICE9 pDevice = (LPDIRECT3DDEVICE9)m_Renderer->GetAPIDevice(); if( pDevice ) { int len = _tcslen( (const TCHAR*)m_Code ); LPCSTR profile = D3DXGetVertexShaderProfile( pDevice ); bool bLoadedCompiled = false; HRESULT hr = E_FAIL; const TCHAR *szFile = GetName()->GetString(); TCHAR drive[MAX_PATH]; TCHAR directory[MAX_PATH]; TCHAR filename[MAX_PATH]; TCHAR fileext[MAX_PATH]; TCHAR szDefinesTemp[65] = { '\0' }; _tsplitpath( szFile, drive, directory, filename, fileext ); StdString szCompiledFile; szCompiledFile += drive; szCompiledFile += directory; szCompiledFile += _T("Compiled\\"); szCompiledFile += filename; if (pDefines) { szCompiledFile += _T("_enc"); szCompiledFile += _itot(pDefines->GetValuesEncoding().iEncoding, szDefinesTemp, 10); } szCompiledFile += fileext; #ifdef XBOX szCompiledFile = SetPathDrive( szCompiledFile, EngineGetToolBox()->GetDrive() ); #endif LPVOID pShaderFileData = NULL; UINT shaderLen = 0; struct _stat shaderFilestat; // checking if compiled version exists, if we can load it into a buffer and if the file stats of the shader (not compiled) are readable if (CheckFileExists(szCompiledFile) && ( _tstat( szFile, &shaderFilestat ) == 0) && LoadFileIntoBuffer( szCompiledFile, pShaderFileData, shaderLen, true )) { m_ToolBox->Log( LOGINFORMATION, _T("Reading compiled shader file: %s\n"), szCompiledFile.c_str() ); // create a shader buffer to store the compiled shader hr = D3DXCreateBuffer( shaderLen, &shaderBuf ); if (SUCCEEDED(hr)) { time_t storedMTime = 0; // get the compiled date out of the file memcpy( &storedMTime, pShaderFileData, sizeof(time_t) ); // if the stored modified time in the compiled shader file is the same as the current // modified time of the shader file if( storedMTime == shaderFilestat.st_mtime ) { // reduce the buffer size by the preamble (mod time) shaderLen -= (int)sizeof(time_t); // copy the compiled shader into the shader buffer memcpy( shaderBuf->GetBufferPointer(), ((TCHAR *) pShaderFileData)+ sizeof(time_t), shaderLen); bLoadedCompiled = true; } } SAFE_DELETE_ARRAY( pShaderFileData ); } if (!bLoadedCompiled && bCompile) { if (pDefines) EngineGetToolBox()->Log( LOGINFORMATION, _T("Compiling shader %s:%d\n"), GetName()->GetString(), pDefines->GetValuesEncoding().iEncoding ); else EngineGetToolBox()->Log( LOGINFORMATION, _T("Compiling shader %s\n"), GetName()->GetString() ); hr = D3DXCompileShader( m_Code, len,//length of string in bytes pMacros, //can add that matrix of macros here &includeInterface, //for include directories "main",//? temp profile, //vs_1_1 for example 0, //compiling options? &shaderBuf, &pErrorMsgs, NULL ); } //now actually create the shader if( hr == D3D_OK && shaderBuf ) { if (!bLoadedCompiled) { struct _stat shaderFilestat; // get the shader file's modified time if (_tstat( szFile, &shaderFilestat ) == 0) { m_ToolBox->Log( LOGINFORMATION, _T("Writing compiled shader file: %s\n"), szCompiledFile.c_str() ); // open a compiled shader file for writing FILE *fp = fopen( szCompiledFile, "wb" ); if (fp) { // write shader file's modified time fwrite( &shaderFilestat.st_mtime, sizeof(time_t), 1, fp ); // write compiled shader data fwrite( shaderBuf->GetBufferPointer(), shaderBuf->GetBufferSize(), 1, fp ); fclose(fp); } else { m_ToolBox->Log( LOGWARNING, _T("Failed to write compiled shader file: %s\n"), szCompiledFile.c_str() ); } } } hr = pDevice->CreateVertexShader( (DWORD *) shaderBuf->GetBufferPointer(), &pShader ); assert( SUCCEEDED(hr) ); if (!SUCCEEDED(hr)) { m_ToolBox->Log( LOGWARNING, _T("Failed to create shader : %s\n"), szCompiledFile.c_str() ); } SAFE_RELEASE( shaderBuf ); SAFE_RELEASE( pErrorMsgs ); if (pDefines == NULL) // we are compiling the default shader with no macro defines { assert( m_VertexShader == NULL ); // the default shader should only be compiled on Init when this is NULL m_VertexShader = pShader; } else if (pDefines != NULL) // we are compiling a variant of the shader { unsigned long iEncoding = pDefines->GetValuesEncoding().iEncoding; m_ShaderVariants[iEncoding] = pShader; } return true; } } if( pErrorMsgs ) { IHashString * name = GetName(); TCHAR* debug_errors = (TCHAR*)pErrorMsgs->GetBufferPointer(); m_ToolBox->Log( LOGERROR, _T("Could not create Vertex shader %s\nError message: %s\n"), name->GetString(), debug_errors ); SAFE_RELEASE( pErrorMsgs ); } SAFE_RELEASE( shaderBuf ); return false; }