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; 
}
Example #3
0
/////////////////////////////////////
// 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;
}
Example #4
0
//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;
}
Example #5
0
//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;
}
Example #6
0
//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;
}