public WaterMesh( String meshName, float planeSize, int cmplx )
{ // najak R-F
// Assign Fields to the Initializer values
this.meshName = meshName;
this.size = planeSize;
this.cmplx = cmplx; // Number of Rows/Columns in the Water Grid representation
cmplxAdj = (float)System.Math.Pow( ( cmplx / 64f ), 1.4f ) * 2;
numFaces = 2 * (int)System.Math.Pow( cmplx, 2 ); // Each square is split into 2 triangles.
numVertices = (int)System.Math.Pow( ( cmplx + 1 ), 2 ); // Vertex grid is (Complexity+1) squared
// Allocate and initialize space for calculated Normals
vNorms = new Vector3[ cmplx + 1, cmplx + 1 ]; // vertex Normals for each grid point
fNorms = new Vector3[ cmplx, cmplx, 2 ]; // face Normals for each triangle
// Create mesh and submesh to represent the Water
mesh = (Mesh)MeshManager.Instance.CreateManual( meshName, ResourceGroupManager.DefaultResourceGroupName, null );
subMesh = mesh.CreateSubMesh();
subMesh.useSharedVertices = false;
// Construct metadata to describe the buffers associated with the water submesh
subMesh.vertexData = new VertexData();
subMesh.vertexData.vertexStart = 0;
subMesh.vertexData.vertexCount = numVertices;
// Define local variables to point to the VertexData Properties
VertexDeclaration vdecl = subMesh.vertexData.vertexDeclaration; // najak: seems like metadata
VertexBufferBinding vbind = subMesh.vertexData.vertexBufferBinding; // najak: pointer to actual buffer
//najak: Set metadata to describe the three vertex buffers that will be accessed.
vdecl.AddElement( 0, 0, VertexElementType.Float3, VertexElementSemantic.Position );
vdecl.AddElement( 1, 0, VertexElementType.Float3, VertexElementSemantic.Normal );
vdecl.AddElement( 2, 0, VertexElementType.Float2, VertexElementSemantic.TexCoords );
// Prepare buffer for positions - todo: first attempt, slow
// Create the Position Vertex Buffer and Bind it index 0 - Write Only
posVBuf = HwBufMgr.CreateVertexBuffer( vdecl.Clone(0), numVertices, BufferUsage.DynamicWriteOnly );
vbind.SetBinding( 0, posVBuf );
// Prepare buffer for normals - write only
// Create the Normals Buffer and Bind it to index 1 - Write only
normVBuf = HwBufMgr.CreateVertexBuffer( vdecl.Clone(1), numVertices, BufferUsage.DynamicWriteOnly );
vbind.SetBinding( 1, normVBuf );
// Prepare Texture Coordinates buffer (static, written only once)
// Creates a 2D buffer of 2D coordinates: (Complexity X Complexity), pairs.
// Each pair indicates the normalized coordinates of the texture to map to.
// (0,1.00), (0.02, 1.00), (0.04, 1.00), ... (1.00,1.00)
// (0,0.98), (0.02, 0.98), (0.04, 1.00), ... (1.00,0.98)
// ...
// (0,0.00), (0.02, 0.00), (0.04, 0.00), ... (1.00,0.00)
// This construct is simple and is used to calculate the Texture map.
// Todo: Write directly to the buffer, when Axiom supports this in safe manner
float[ , , ] tcBufDat = new float[ cmplx + 1, cmplx + 1, 2 ];
for ( int i = 0; i <= cmplx; i++ )
{
// 2D column iterator for texture map
for ( int j = 0; j <= cmplx; j++ )
{
// 2D row iterator for texture map
// Define the normalized(0..1) X/Y-coordinates for this element of the 2D grid
tcBufDat[ i, j, 0 ] = (float)i / cmplx;
tcBufDat[ i, j, 1 ] = 1.0f - ( (float)j / ( cmplx ) );
}
}
// Now Create the actual hardware buffer to contain the Texture Coordinate 2d map.
// and Bind it to buffer index 2
tcVBuf = HwBufMgr.CreateVertexBuffer( vdecl.Clone(2), numVertices, BufferUsage.StaticWriteOnly );
tcVBuf.WriteData( 0, tcVBuf.Size, tcBufDat, true );
vbind.SetBinding( 2, tcVBuf );
// Create a Graphics Buffer on non-shared vertex indices (3 points for each triangle).
// Since the water grid consist of [Complexity x Complexity] squares, each square is
// split into 2 right triangles 45-90-45. That is how the water mesh is constructed.
// Therefore the number of faces = 2 * Complexity * Complexity
ushort[ , , ] idxBuf = new ushort[ cmplx, cmplx, 6 ];
for ( int i = 0; i < cmplx; i++ )
{ // iterate the rows
for ( int j = 0; j < cmplx; j++ )
{ // iterate the columns
// Define 4 corners of each grid
ushort p0 = (ushort)( i * ( cmplx + 1 ) + j ); // top left point on square
ushort p1 = (ushort)( i * ( cmplx + 1 ) + j + 1 ); // top right
ushort p2 = (ushort)( ( i + 1 ) * ( cmplx + 1 ) + j ); // bottom left
ushort p3 = (ushort)( ( i + 1 ) * ( cmplx + 1 ) + j + 1 ); // bottom right
// Split Square Grid element into 2 adjacent triangles.
idxBuf[ i, j, 0 ] = p2;
idxBuf[ i, j, 1 ] = p1;
idxBuf[ i, j, 2 ] = p0; // top-left triangle
idxBuf[ i, j, 3 ] = p2;
idxBuf[ i, j, 4 ] = p3;
idxBuf[ i, j, 5 ] = p1; // bottom-right triangle
}
}
// Copy Index Buffer to the Hardware Index Buffer
HardwareIndexBuffer hdwrIdxBuf = HwBufMgr.CreateIndexBuffer( IndexType.Size16, 3 * numFaces, BufferUsage.StaticWriteOnly, true );
hdwrIdxBuf.WriteData( 0, numFaces * 3 * 2, idxBuf, true );
// Set index buffer for this submesh
subMesh.indexData.indexBuffer = hdwrIdxBuf;
subMesh.indexData.indexStart = 0;
subMesh.indexData.indexCount = 3 * numFaces;
//Prepare Vertex Position Buffers (Note: make 3, since each frame is function of previous two)
vBufs = new Vector3[ 3 ][ , ];
for ( int b = 0; b < 3; b++ )
{
vBufs[ b ] = new Vector3[ cmplx + 1, cmplx + 1 ];
for ( int y = 0; y <= cmplx; y++ )
{
for ( int x = 0; x <= cmplx; x++ )
{
vBufs[ b ][ y, x ].x = (float)( x ) / (float)( cmplx ) * (float)size;
vBufs[ b ][ y, x ].y = 0;
vBufs[ b ][ y, x ].z = (float)( y ) / (float)( cmplx ) * (float)size;
}
}
}
curBufNum = 0;
vBuf = vBufs[ curBufNum ];
posVBuf.WriteData( 0, posVBuf.Size, vBufs[ 0 ], true );
AxisAlignedBox meshBounds = new AxisAlignedBox( new Vector3( 0, 0, 0 ), new Vector3( size, 0, size ) );
mesh.BoundingBox = meshBounds; // mesh->_setBounds(meshBounds); // najak: can't find _setBounds()
mesh.Load();
mesh.Touch();
} // end WaterMesh Constructor