Sign in to follow this  

D3DXCreateMeshFVF & D3DXCreateMesh

This topic is 4309 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I am making a Terrain engine which is currently using the "Brute Force" method to create and render a terrain from a height map. However i would like to make the terrain as an ID3DXMesh rather than just polygons so that i can use it with my NodeTree class. I believe you use eigther D3DXCreateMeshFVF or D3DXCreateMesh to create the mesh, but using this code:
			

if(!D3DXCreateMeshFVF(numPolys,numVertices,D3DXMESH_WRITEONLY,m_FVF_XYZ_DIFFUSE ,base->D3dDevice,&mesh))
	{
		MessageBox(NULL,"failed to create terrain Mesh",NULL,NULL);
	}


I dont get the messagebox, so it passes, but the mesh parameter remains on 0xcdcdcd which means its not initialised. Here is the rest of the class if its helps:

//HEADER FILE

#include "Entity.h"

#ifndef TERRAIN_H
#define TERRAIN_H

class Terrain: public Entity
{
public:
	
	Terrain::Terrain();
	Terrain::Terrain(char* HeightMapFile, char* TextureMapFile,
					 float TriangleWidth, float TriangleLength, float HeightScale,
					 int numCols, int numRows);

	Terrain::~Terrain();

	bool Initialise(char* HeightMapFile,
			  char* TextureMapFile,
			  float TriangleWidth,			// Width and Height of each triangle step
			  float TriangleLength,			// Scale factors!
			  float HeightScale,
			  int numCols, 
			  int numRows);

	void Release();


	bool Render();

	float GetHeight(D3DXVECTOR3 v){ return GetHeight(v.x, v.z); }
	float GetHeight(float XPos, float ZPos);

protected:

	//IDirect3DDevice9* m_pD3DDevice;

	IDirect3DIndexBuffer9*  m_pIndexBuffer;
	IDirect3DVertexBuffer9* m_pVertexBuffer;

	IDirect3DTexture9* m_pTexture;
	LPD3DXMESH mesh;

	struct stVertex
	{
		FLOAT x, y, z;  // D3DFVF_XYZ
		DWORD colour;   // D3DFVF_DIFFUSE
		FLOAT tu, tv;   // D3DFVF_TEX1
	};

	// This is set to (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1) in the Create(..) method
	UINT m_FVF_XYZ_DIFFUSE; 

	int numPolys;
	int numVertices;

	float triangleWidth;
	float triangleLength;
	float heightScale;

	int   Columns;
	int   Rows;
	BITMAP bitmap ;
	char* texturemapfile;

};// End of CXTerrain

#endif


//CPP FILE

#include "Base.h"
#include "Terrain.h"

struct stBITMAP_FILE
{
	BITMAPFILEHEADER bitmapfileheader;  // this contains the bitmapfile header
	BITMAPINFOHEADER bitmapinfoheader;  // this is all the info including the palette
	PALETTEENTRY     palette[256];      // we will store the palette here
	UCHAR            *buffer;           // this is a pointer to the data
};


static bool Load_Bitmap_File(stBITMAP_FILE* pBitmap, char *szFileName)
{
	memset(pBitmap, 0, sizeof(stBITMAP_FILE));

	FILE* fp = fopen(szFileName, "rb");

	fread(&pBitmap->bitmapfileheader, 1, sizeof(BITMAPFILEHEADER), fp);
	fread(&pBitmap->bitmapinfoheader, 1, sizeof(BITMAPINFOHEADER), fp);


	// now load the color palette if there is one
	if (pBitmap->bitmapinfoheader.biBitCount == 8)
	{
		int iMaxColours = 256;
		fread(&pBitmap->palette, 1, iMaxColours*sizeof(PALETTEENTRY), fp );

		// now set all the flags in the palette correctly and fix the reversed 
		// BGR RGBQUAD data format
		for (int index=0; index < iMaxColours; index++)
		{
			// reverse the red and green fields
			int temp_color                 = pBitmap->palette[index].peRed;
			pBitmap->palette[index].peRed  = pBitmap->palette[index].peBlue;
			pBitmap->palette[index].peBlue = temp_color;

			// always set the flags word to this
			pBitmap->palette[index].peFlags = PC_NOCOLLAPSE;
		} // end for index

	} // end if

	// finally the image data itself
	fseek(fp, -(int)(pBitmap->bitmapinfoheader.biSizeImage), SEEK_END );

	// now read in the image
	if (pBitmap->bitmapinfoheader.biBitCount==8 || pBitmap->bitmapinfoheader.biBitCount==16) 
	{
		// allocate the memory for the image
		pBitmap->buffer = new unsigned char[pBitmap->bitmapinfoheader.biSizeImage];

		// now read it in
		fread( pBitmap->buffer, 1,  pBitmap->bitmapinfoheader.biSizeImage,  fp);

	} // end if


	fclose(fp);

	// return success
	return true;

}

Terrain::Terrain()
{
}

Terrain::Terrain(char* HeightMapFile, char* TextureMapFile,
				 float TriangleWidth, float TriangleLength, float HeightScale, int numCols, int numRows)
{

	texturemapfile = TextureMapFile;
	Initialise(HeightMapFile,TextureMapFile,TriangleWidth,TriangleLength,HeightScale, numCols, numRows);

}
Terrain::~Terrain()
{
	Release();
}

bool Terrain::Initialise(char* HeightMapFile, char* TextureMapFile, float TriangleWidth,
				   float TriangleLength, float HeightScale, int numCols, int numRows)
{
	//----------------------------------------//
	//------Save passed screen object---------//

	// Simple Error Checking
	if( !base->D3dDevice)
		return false;

	triangleWidth   = TriangleWidth;
	triangleLength  = TriangleLength;
	heightScale = HeightScale;

	Position = D3DXVECTOR3(0,0,0);

	//--------Load our Texture----------------//

	if(TextureMapFile != NULL && HeightMapFile != NULL)
	{
				D3DXCreateTextureFromFile(base->D3dDevice, TextureMapFile, &m_pTexture);

			//---------Get Bitmap Details-------------//
			HBITMAP b = ( HBITMAP ) LoadImage (NULL , HeightMapFile, IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE|LR_LOADFROMFILE ) ;

			if( b==NULL)
			{
				MessageBox(0, "Error Loading Bitmap in Terrain Class", "Error Loading Bitmap", 0);
				return false;
			}

			
			GetObject ( b,  sizeof ( BITMAP ),  &bitmap ) ;
			Columns = bitmap.bmWidth ;
			Rows    = bitmap.bmHeight ;
	}
	else
	{
		Columns = numCols;
		Rows = numRows;
	}
			//---------Mesh Details-------------//

			numVertices = Columns*Rows;
			numPolys = ((Columns-1)*(Rows-1)*2);

			if(!D3DXCreateMeshFVF(numPolys,numVertices,D3DXMESH_WRITEONLY,m_FVF_XYZ_DIFFUSE ,base->D3dDevice,&mesh))
			{
				MessageBox(NULL,"failed to create terrain Mesh",NULL,NULL);
			}

	//---------Create Index Buffer-------//
	base->D3dDevice->CreateIndexBuffer(3*numPolys*sizeof(WORD), D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &m_pIndexBuffer,NULL);


	//---------Create Vertex Buffer------//
	m_FVF_XYZ_DIFFUSE = D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1;

	base->D3dDevice->CreateVertexBuffer(numVertices*sizeof(stVertex), 0, m_FVF_XYZ_DIFFUSE, D3DPOOL_MANAGED, &m_pVertexBuffer, NULL);

	//-------If texture load here--------//


	//----Genereate the vertex list------//
	stVertex *pVertexList;
	m_pVertexBuffer->Lock(0,0, (void**)&pVertexList, 0);

stBITMAP_FILE HeightMap;
	if(HeightMapFile != NULL)
	{
		Load_Bitmap_File(&HeightMap, HeightMapFile);
	}

	volatile int indx=0;
	for( int iCurrRow=0; iCurrRow< Rows; iCurrRow++ )
	{
		for( int iCurrCol=0; iCurrCol< Columns; iCurrCol++ )
		{
			indx = (iCurrRow* (Columns)) + iCurrCol;

			pVertexList[indx].x = (float)iCurrCol * TriangleWidth;
			pVertexList[indx].z = (float)iCurrRow * TriangleLength;
			
				if(HeightMapFile != NULL)
				{			
					float fColourValue = (float)HeightMap.buffer[iCurrCol + (iCurrRow*Columns)]/255.0f;
					pVertexList[indx].y = fColourValue * HeightScale;

					int iIndex = HeightMap.buffer[indx];

					UCHAR r = HeightMap.palette[iIndex].peRed;
					UCHAR g = HeightMap.palette[iIndex].peGreen;
					UCHAR b = HeightMap.palette[iIndex].peBlue;
					
					pVertexList[indx].colour = D3DCOLOR_XRGB(r,g,b);
				}
				else
				{
					float fColourValue = 0.0f;
					pVertexList[indx].y = fColourValue; //* HeightScale;

					int iIndex = indx;

					UCHAR r = 255;
					UCHAR g = 255;
					UCHAR b = 255;

					pVertexList[indx].colour = D3DCOLOR_XRGB(r,g,b);

				}

			

			// If we have a texture map texture coordinates:
			{
				// I manually loaded in the texture...and the y is inverted,
				// as I didn't invert it in the loader...I've done it here
				pVertexList[indx].tu = (float)iCurrCol/(float)Columns;
				pVertexList[indx].tv = 1 - (float)iCurrRow/(float)Rows;

			}//end if

		}// end inner for loop
	}// end outer for loop

	if(HeightMapFile != NULL)
	{
		delete[] HeightMap.buffer;
	}

	m_pVertexBuffer->Unlock();

	//---------Compute the Max and Mins---------//

	//------Genererate Polygon List-------------//

	WORD *pPolyList;
	m_pIndexBuffer->Lock(0,0, (void**)&pPolyList, 0);

	indx = 0;

	for( int iCurrRow=0; iCurrRow< Rows-1; iCurrRow++ )
	{
		for( int iCurrCol=0; iCurrCol< Columns-1; iCurrCol++ )
		{
			int iBasePolyIndex = ( iCurrRow* (Columns)) + iCurrCol;

			pPolyList[indx] = iBasePolyIndex;
			indx++;
			pPolyList[indx] = iBasePolyIndex+Columns;
			indx++;
			pPolyList[indx] = iBasePolyIndex+Columns+1;
			indx++;

			pPolyList[indx] = iBasePolyIndex;
			indx++;
			pPolyList[indx] = iBasePolyIndex+Columns+1;
			indx++;
			pPolyList[indx] = iBasePolyIndex+1;
			indx++;
		}
	}

	m_pIndexBuffer->Unlock();

	DeleteObject(&bitmap);

	return true;
}




void Terrain::Release()
{
	m_pIndexBuffer->Release();
	m_pVertexBuffer->Release();

	m_pTexture->Release();
}



bool Terrain::Render()
{
	D3DXMATRIX matPos;
	D3DXMatrixTranslation(&matPos, Position.x, Position.y, Position.z);
	D3DXMATRIX matWorld = matPos;
	base->D3dDevice->SetTransform( D3DTS_WORLD, &matWorld );

	base->D3dDevice->SetStreamSource(0, m_pVertexBuffer, 0, sizeof(stVertex));
	base->D3dDevice->SetFVF(m_FVF_XYZ_DIFFUSE);
	base->D3dDevice->SetIndices(m_pIndexBuffer);


	// Debug - Display map using wireframe instead of solid fill.
	//base->D3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);

	// if we have texturing
	if(texturemapfile != NULL)
	{
		base->D3dDevice->SetTexture(0,m_pTexture);
		base->D3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
		base->D3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
		
		mesh->DrawSubset(0);

	}
	//else
	//{
	//	base->D3dDevice->SetTexture(0,NULL);
	//	base->D3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
	//	base->D3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_DIFFUSE);
	//}

	//base->D3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, numVertices , 0, numPolys);

	
	return true;
}


float Terrain::GetHeight(float XPos, float ZPos)
{
	//[1] Originally 0,0 is the bottom left of the grid
	//[2] But we scaled x,z by TriangleWidth and TriangleLength

	XPos = XPos - Position.x;
	ZPos = ZPos - Position.z;

	XPos = XPos/triangleWidth;
	ZPos = ZPos/triangleLength;

	XPos=XPos-0.5f;
	ZPos=ZPos-0.5f;

	XPos = ceilf(XPos);
	ZPos = ceilf(ZPos);

	if( (ZPos >= Columns) || (ZPos<= 0 ) )
		return 0.0f;

	if( (XPos >= Rows) || (XPos<= 0 ) )
		return 0.0f;

	int v0 = (int)(XPos + ZPos*Columns);
	int v1 = (int)(v0 + 1);

	int v2 = (int)(v0 + Columns);
	int v3 = (int)(v1 + Columns);

	// Alternative to the average method, which is to take the heighest
	// value instead of the average.
	//int vHeighest = v0;
	//if( v1 > vHeighest ) vHeighest = v1;
	//if( v2 > vHeighest ) vHeighest = v2;
	//if( v3 > vHeighest ) vHeighest = v3;
	//float fAveHeight = pVertexList[vHeighest].y;

	stVertex *pVertexList;
	m_pVertexBuffer->Lock(0,0, (void**)&pVertexList, 0);

	float fAveHeight = 0.25f * (pVertexList[v0].y +
		pVertexList[v1].y +
		pVertexList[v2].y +
		pVertexList[v3].y );

	// Debug to display where on the grid our point is being taken from
	/*
	pVertexList[v0].colour = 0xffff0000;
	pVertexList[v1].colour = 0xffff0000;
	pVertexList[v2].colour = 0xffff0000;
	pVertexList[v3].colour = 0xffff0000;
	*/

	m_pVertexBuffer->Unlock();

	return fAveHeight;
}


Thanks!!

Share this post


Link to post
Share on other sites
use FAILED() or SUCCEEDED() to check if a DX method failed or not. D3D has many different return codes, and these macros would handle it for you.

Should be:

if(FAILED(D3DXCreateMeshFVF(numPolys,numVertices,D3DXMESH_WRITEONLY,m_FVF_XYZ_DIFFUSE ,base->D3dDevice,&mesh)))
{
MessageBox(NULL,"failed to create terrain Mesh",NULL,NULL);
}


Hope this helps :).

Share this post


Link to post
Share on other sites
Hi, I am not sure if I am right.. but the way I define a custom FVF is as such..

// Our custom FVF, which describes our custom vertex structure
#define D3DFVF_CUSTOMVERTEX ( D3DFVF_XYZ | D3DFVF_NORMAL)

Share this post


Link to post
Share on other sites
Quote:
Does anyone know why it would fail in the first place?
Have you checked the debug output? D3DX will often elaborate on return codes with full descriptions via the debug output window. See the link in my signiture if you're not familiar with DirectX debugging...

At a guess it'll be your parameters. Output those (or find them via the debugger) immediately before you make the call. It's quite possible that you're somehow introducing unexpected values that are confusing D3DX!

Quote:
Original post by eudora
Hi, I am not sure if I am right.. but the way I define a custom FVF is as such..

// Our custom FVF, which describes our custom vertex structure
#define D3DFVF_CUSTOMVERTEX ( D3DFVF_XYZ | D3DFVF_NORMAL)
You can use the C preprocessor for this sort of thing (many people do), but if you're coding in a C++ style then you'll get evils from more experienced coders [wink] However, I would definitely advise against using the 'D3D' prefix on your identifier - in this case it shouldn't hurt you, but using names similar to those that might appear in the standard headers is a perfect place to get collisions. Combine that with the damage a preprocessor directive can do and you're going to have a bad day [grin]

Personally, I prefer a mix of the two methods shown in this thread. const DWORD FVF_Vertex = D3DFVF_XYZ | D3DFVF_TEX1; for example. Making it a DWORD matches what SetFVF() is expecting (and also gives you type safety) and making it constant avoids the possibility of it getting trampled on by other pieces of code.

hth
Jack

Share this post


Link to post
Share on other sites

This topic is 4309 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this