Difference between revisions of "Code Snippets"

From Horde3D Wiki
Jump to: navigation, search
m (More procedurally generated content code)
m (More procedurally generated content code)
Line 9: Line 9:
 
The following is similar but different to the [[Procedurally generated geometry tutorial]]
 
The following is similar but different to the [[Procedurally generated geometry tutorial]]
 
{{CppSourceCode|
 
{{CppSourceCode|
description=Building a 2D grid of points|  
+
description=Building a 2D grid of quads|  
 
code=
 
code=
 
<source lang="cpp" line="1">
 
<source lang="cpp" line="1">
Line 226: Line 226:
 
int dataSize = 0;
 
int dataSize = 0;
 
char* data = 0;
 
char* data = 0;
BuildLensBlurMesh( data, dataSize, batchStart, batchCount, vertRStart, vertREnd );
+
ScreenGridMesh( data, dataSize, batchStart, batchCount, vertRStart, vertREnd );
 
bool loadedData = h3dLoadResource( gridGeo, data, dataSize );
 
bool loadedData = h3dLoadResource( gridGeo, data, dataSize );
 
delete [] lensBlurData;
 
delete [] lensBlurData;

Revision as of 16:05, 10 August 2010

What is this page?

This page of the wiki is a sharing zone for rough Horde example code.




More procedurally generated content code

The following is similar but different to the Procedurally generated geometry tutorial

Building a 2D grid of quads
void ScreenGridMesh( char*& data, int& fileSize, int& batchStart, int& batchCount, int& vertRStart, int& vertREnd )
{
	extern int appWidth;
	extern int appHeight;

	//This example splits the screen up into groups of 16 pixels, and create a quad for each group.
	int quadSize = 16;
	int quadsH = (appWidth +quadSize-1) / quadSize;//divide by 16, rounding up
	int quadsV = (appHeight+quadSize-1) / quadSize;
	int quads = quadsH*quadsV;


	int version = 5;//This is the current version of the GEO format (at the time of writing).

	int numJoints = 0;//I don't have code below for writing joints...
	int numMorphTargets = 0;//...or morph targets

//The lines that begin with //! or /*! could be used if you want a more complete vertex format (i.e. normal/binormal/tangent/joints/etc)
//!	int numVertexStreams = 8;
	int numVertexStreams = 2;//I'm just using position + tex-coord

	int numVertices = quads * 4;// I'm making 4 verts per quad
	int numTriangleIndices = quads * 6;//Each quad is 2 triangles. Each triangle is made up of 3 verts, so I need 6 indices to describe each quad.

	//These are all "magic numbers" that horde uses to interpret the data streams
	int vertPositionID = 0;
	int vertNormalID = 1;
	int vertTangentID = 2;
	int vertBiTangentID = 3;
	int vertJointIndexID = 4;
	int vertJointWeightID = 5;
	int vertTexCoordID = 6;
	int vertTexCoord2ID = 7;
	int positionElementSize = sizeof(float)*3;
	int normalElementSize   = sizeof(short)*3;
	int tangentElementSize  = sizeof(short)*3;
	int biTangentElementSize= sizeof(short)*3;
	int jointIndexElementSize = sizeof(char)*4;
	int jointWeightElementSize = sizeof(char)*4;
	int texCoordElementSize = sizeof(float)*2;
	int texCoord2ElementSize = sizeof(float)*2;

	batchStart = 0;
	batchCount = numTriangleIndices;
	vertRStart = 0;
	vertREnd = numVertices-1;
	
//!	int vertDataSize = positionElementSize+normalElementSize+
//!	                   tangentElementSize+biTangentElementSize+
//!	                   jointIndexElementSize+jointWeightElementSize+
//!	                   texCoordElementSize+texCoord2ElementSize;
	int vertDataSize = positionElementSize+texCoordElementSize;

	int quadDataSize = vertDataSize*4 + sizeof(int)*6;
//!	fileSize = sizeof(char)*4 + sizeof(int)*22 + quadDataSize*quads;
	fileSize = sizeof(char)*4 + sizeof(int)*10 + quadDataSize*quads;

	data = new char[fileSize];
	int written = 0;
	
#define ASSERT( c )	\
	if( !(c) ) { printf( "ASSERTION FAILED: %s\n", #c ); breakPlz(); }
#define WRITE_DATA( d, size )	\
	memcpy( &data[written], d, size ); written += size; ASSERT( written <= fileSize );

	//First write the header
	WRITE_DATA( "H3DG", sizeof(char)*4 );
	WRITE_DATA( &version, sizeof(int) );

	//Joint data would go here, if I had any
	WRITE_DATA( &numJoints, sizeof(int) );

	//Then write the vertex-stream header
	WRITE_DATA( &numVertexStreams, sizeof(int) );
	WRITE_DATA( &numVertices, sizeof(int) );

	//I'm making quads in this example, so all my loops are going to create 4 pieces of each data.

	//To begin with I write the positions:
	WRITE_DATA( &vertPositionID, sizeof(int) );
	WRITE_DATA( &positionElementSize, sizeof(int) );
	for( int y=0; y<quadsV; ++y )
	{
		for( int x=0; x<quadsH; ++x )
		{
			float positionA[3] = { ((x+0.0f)/(float)quadsH)*2.0f-1.0f, ((y+0.0f)/(float)quadsV)*2.0f-1.0f, 0.0f };
			float positionB[3] = { ((x+1.0f)/(float)quadsH)*2.0f-1.0f, ((y+0.0f)/(float)quadsV)*2.0f-1.0f, 0.0f };
			float positionC[3] = { ((x+1.0f)/(float)quadsH)*2.0f-1.0f, ((y+1.0f)/(float)quadsV)*2.0f-1.0f, 0.0f };
			float positionD[3] = { ((x+0.0f)/(float)quadsH)*2.0f-1.0f, ((y+1.0f)/(float)quadsV)*2.0f-1.0f, 0.0f };
			WRITE_DATA( positionA, sizeof(float)*3 );
			WRITE_DATA( positionB, sizeof(float)*3 );
			WRITE_DATA( positionC, sizeof(float)*3 );
			WRITE_DATA( positionD, sizeof(float)*3 );
		}
	}
	/*!
	//Normals/binormals/tangents should be floats in the 0-1 range, and then multiplied by 32767 and cast to 'short'. This is a form of compression.
	WRITE_DATA( &vertNormalID, sizeof(int) );
	WRITE_DATA( &normalElementSize, sizeof(int) );
	for( int i=0; i!=quads; ++i )
	{
		short n[] = { 0, 0, 32767 };
		WRITE_DATA( n, sizeof(short)*3 );
		WRITE_DATA( n, sizeof(short)*3 );
		WRITE_DATA( n, sizeof(short)*3 );
		WRITE_DATA( n, sizeof(short)*3 );
	}
	WRITE_DATA( &vertTangentID, sizeof(int) );
	WRITE_DATA( &tangentElementSize, sizeof(int) );
	for( int i=0; i!=quads; ++i )
	{
		short n[] = { 0, 32767, 0 };
		WRITE_DATA( n, sizeof(short)*3 );
		WRITE_DATA( n, sizeof(short)*3 );
		WRITE_DATA( n, sizeof(short)*3 );
		WRITE_DATA( n, sizeof(short)*3 );
	}
	WRITE_DATA( &vertBiTangentID, sizeof(int) );
	WRITE_DATA( &biTangentElementSize, sizeof(int) );
	for( int i=0; i!=quads; ++i )
	{
		short n[] = { 32767, 0, 0 };
		WRITE_DATA( n, sizeof(short)*3 );
		WRITE_DATA( n, sizeof(short)*3 );
		WRITE_DATA( n, sizeof(short)*3 );
		WRITE_DATA( n, sizeof(short)*3 );
	}

	//Each vertex can be influenced by 4 joints - the joint IDs are written here
	WRITE_DATA( &vertJointIndexID, sizeof(int) );
	WRITE_DATA( &jointIndexElementSize, sizeof(int) );
	for( int i=0; i!=quads; ++i )
	{
		char j[] = { 0, 0, 0, 0 };
		WRITE_DATA( j, sizeof(char)*4 );
		WRITE_DATA( j, sizeof(char)*4 );
		WRITE_DATA( j, sizeof(char)*4 );
		WRITE_DATA( j, sizeof(char)*4 );
	}

	//The 'percent' (out of 255, not out of 100) that each of the above joints influences the vertex:
	WRITE_DATA( &vertJointWeightID, sizeof(int) );
	WRITE_DATA( &jointWeightElementSize, sizeof(int) );
	for( int i=0; i!=quads; ++i )
	{
		ASSERT( sizeof(char) == 1 )
		char j[] = { 255, 0, 0, 0 };
		WRITE_DATA( j, sizeof(char)*4 );
		WRITE_DATA( j, sizeof(char)*4 );
		WRITE_DATA( j, sizeof(char)*4 );
		WRITE_DATA( j, sizeof(char)*4 );
	}
	*/
	//Tex-coords are pairs of floats
	WRITE_DATA( &vertTexCoordID, sizeof(int) );
	WRITE_DATA( &texCoordElementSize, sizeof(int) );
	for( int i=0; i!=quads; ++i )
	{
		float uvTl[] = { 0.0f, 1.0f };
		float uvBl[] = { 0.0f, 0.0f };
		float uvBr[] = { 1.0f, 0.0f };
		float uvTr[] = { 1.0f, 1.0f };
		WRITE_DATA( uvTl, sizeof(float)*2 );
		WRITE_DATA( uvBl, sizeof(float)*2 );
		WRITE_DATA( uvBr, sizeof(float)*2 );
		WRITE_DATA( uvTr, sizeof(float)*2 );
	}
	/*!
	//You can have a second set of tex-coords if you want
	WRITE_DATA( &vertTexCoord2ID, sizeof(int) );
	WRITE_DATA( &texCoord2ElementSize, sizeof(int) );
	for( int i=0; i!=quads; ++i )
	{
		float uvTl[] = { 0.0f, 1.0f };
		float uvBl[] = { 0.0f, 0.0f };
		float uvBr[] = { 1.0f, 0.0f };
		float uvTr[] = { 1.0f, 1.0f };
		WRITE_DATA( uvTl, sizeof(float)*2 );
		WRITE_DATA( uvBl, sizeof(float)*2 );
		WRITE_DATA( uvBr, sizeof(float)*2 );
		WRITE_DATA( uvTr, sizeof(float)*2 );
	}*/

	//Finally, time for the index buffer
	WRITE_DATA( &numTriangleIndices, sizeof(int) );
	for( int i=0; i!=quads; ++i )
	{
		int base = i * 4;
		int a = base, b = base+1, c = base+2, d=base+2, e=base+3, f=base;
		WRITE_DATA( &a, sizeof(int) );
		WRITE_DATA( &b, sizeof(int) );
		WRITE_DATA( &c, sizeof(int) );
		WRITE_DATA( &d, sizeof(int) );
		WRITE_DATA( &e, sizeof(int) );
		WRITE_DATA( &f, sizeof(int) );
	}

	//Morph targets would go here, if I had any
	WRITE_DATA( &numMorphTargets, sizeof(int) );

	ASSERT( written == fileSize );//ensure we didn't over/under-use the buffer
}
Example Usage
	// Build a geo
	H3DRes gridGeo = h3dAddResource( H3DResTypes::Geometry, "runtime/blahBlah.geo", H3DResFlags::NoQuery );
	int batchStart = 0, batchCount = 0, vertRStart = 0, vertREnd = 0;
	{
		int dataSize = 0;
		char* data = 0;
		ScreenGridMesh( data, dataSize, batchStart, batchCount, vertRStart, vertREnd );
		bool loadedData = h3dLoadResource( gridGeo, data, dataSize );
		delete [] lensBlurData;
	}
	
	// Load a material
	H3DRes material = h3dAddResource( H3DResTypes::Material, "materials/grid.material.xml", 0 );
	h3dutLoadResourcesFromDisk( _contentDir.c_str() );

	// Create a model/mesh from the procedural geo
	H3DNode model = h3dAddModelNode( H3DRootNode, "MyModel", gridGeo );
	H3DNode mesh = h3dAddMeshNode( model, "MyMesh", material, batchStart, batchCount, vertRStart, vertREnd );