/// <summary>
        ///		Updates the face normals for this edge list based on (changed)
        ///		position information, useful for animated objects.
        /// </summary>
        /// <param name="vertexSet">The vertex set we are updating.</param>
        /// <param name="positionBuffer">The updated position buffer, must contain ONLY xyz.</param>
        public void UpdateFaceNormals(int vertexSet, HardwareVertexBuffer positionBuffer)
        {
            unsafe {
                Debug.Assert(positionBuffer.VertexSize == sizeof(float) * 3, "Position buffer should contain only positions!");

                // Lock buffer for reading
                IntPtr posPtr = positionBuffer.Lock(BufferLocking.ReadOnly);
                float *pVert  = (float *)posPtr.ToPointer();

                // Iterate over the triangles
                for (int i = 0; i < triangles.Count; i++)
                {
                    Triangle t = (Triangle)triangles[i];

                    // Only update tris which are using this vertex set
                    if (t.vertexSet == vertexSet)
                    {
                        int     offset = t.vertIndex[0] * 3;
                        Vector3 v1     = new Vector3(pVert[offset], pVert[offset + 1], pVert[offset + 2]);

                        offset = t.vertIndex[1] * 3;
                        Vector3 v2 = new Vector3(pVert[offset], pVert[offset + 1], pVert[offset + 2]);

                        offset = t.vertIndex[2] * 3;
                        Vector3 v3 = new Vector3(pVert[offset], pVert[offset + 1], pVert[offset + 2]);

                        t.normal = MathUtil.CalculateFaceNormal(v1, v2, v3);
                    }
                }
            }

            // unlock the buffer
            positionBuffer.Unlock();
        }
        /// <summary>
        ///   Utility method to pull a bunch of floats out of a vertex buffer.
        /// </summary>
        /// <param name="data"></param>
        /// <param name="vBuffer"></param>
        /// <param name="elem"></param>
        public static void ReadBuffer( float[ , ] data, HardwareVertexBuffer vBuffer, VertexElement elem )
        {
            int count = data.GetLength( 1 );
            IntPtr bufData = vBuffer.Lock( BufferLocking.ReadOnly );

            Debug.Assert( vBuffer.VertexSize % sizeof( float ) == 0 );
            Debug.Assert( elem.Offset % sizeof( float ) == 0 );
            int vertexCount = vBuffer.VertexCount;
            int vertexSpan = vBuffer.VertexSize / sizeof( float );
            int offset = elem.Offset / sizeof( float );
            unsafe
            {
                float* pFloats = (float*) bufData.ToPointer();
                for( int i = 0; i < vertexCount; ++i )
                {
                    for( int j = 0; j < count; ++j )
                    {
                        Debug.Assert( ((offset + i * vertexSpan + j) * sizeof( float )) < (vertexCount * vBuffer.VertexSize),
                                     "Read off end of vertex buffer" );
                        data[ i, j ] = pFloats[ offset + i * vertexSpan + j ];
                    }
                }
            }

            // unlock the buffer
            vBuffer.Unlock();
        }
Exemple #3
0
        /// <summary>
        ///		Utility method for extruding vertices based on a light.
        /// </summary>
        /// <remarks>
        ///		Unfortunately, because D3D cannot handle homogenous (4D) position
        ///		coordinates in the fixed-function pipeline (GL can, but we have to
        ///		be cross-API), when we extrude in software we cannot extrude to
        ///		infinity the way we do in the vertex program (by setting w to
        ///		0.0f). Therefore we extrude by a fixed distance, which may cause
        ///		some problems with larger scenes. Luckily better hardware (ie
        ///		vertex programs) can fix this.
        /// </remarks>
        /// <param name="vertexBuffer">The vertex buffer containing ONLY xyz position
        /// values, which must be originalVertexCount * 2 * 3 floats long.</param>
        /// <param name="originalVertexCount">The count of the original number of
        /// vertices, ie the number in the mesh, not counting the doubling
        /// which has already been done (by <see cref="VertexData.PrepareForShadowVolume"/>)
        /// to provide the extruded area of the buffer.</param>
        /// <param name="lightPosition"> 4D light position in object space, when w=0.0f this
        /// represents a directional light</param>
        /// <param name="extrudeDistance">The distance to extrude.</param>
        public static void ExtrudeVertices(HardwareVertexBuffer vertexBuffer, int originalVertexCount, Vector4 lightPosition,
                                           float extrudeDistance)
        {
#if !AXIOM_SAFE_ONLY
            unsafe
#endif
            {
                Debug.Assert(vertexBuffer.VertexSize == sizeof(float) * 3, "Position buffer should contain only positions!");

                // Extrude the first area of the buffer into the second area
                // Lock the entire buffer for writing, even though we'll only be
                // updating the latter because you can't have 2 locks on the same
                // buffer
                var srcPtr  = vertexBuffer.Lock(BufferLocking.Normal);
                var destPtr = srcPtr + (originalVertexCount * 3 * 4);
                var pSrc    = srcPtr.ToFloatPointer();
                var pDest   = destPtr.ToFloatPointer();

                int destCount = 0, srcCount = 0;

                // Assume directional light, extrusion is along light direction
                var extrusionDir = new Vector3(-lightPosition.x, -lightPosition.y, -lightPosition.z);
                extrusionDir.Normalize();
                extrusionDir *= extrudeDistance;

                for (var vert = 0; vert < originalVertexCount; vert++)
                {
                    if (lightPosition.w != 0.0f)
                    {
                        // Point light, adjust extrusionDir
                        extrusionDir.x = pSrc[srcCount + 0] - lightPosition.x;
                        extrusionDir.y = pSrc[srcCount + 1] - lightPosition.y;
                        extrusionDir.z = pSrc[srcCount + 2] - lightPosition.z;
                        extrusionDir.Normalize();
                        extrusionDir *= extrudeDistance;
                    }

                    pDest[destCount++] = pSrc[srcCount++] + extrusionDir.x;
                    pDest[destCount++] = pSrc[srcCount++] + extrusionDir.y;
                    pDest[destCount++] = pSrc[srcCount++] + extrusionDir.z;
                }
            }

            vertexBuffer.Unlock();
        }
        private static void ReadBuffer(HardwareVertexBuffer vBuffer, int vertexCount, int vertexSize,
								ref Vector3[] data)
        {
            IntPtr bufData = vBuffer.Lock(BufferLocking.ReadOnly);

            unsafe {
                float* pFloats = (float*)bufData.ToPointer();
                for (int i = 0; i < vertexCount; ++i)
                    for (int j = 0; j < 3; ++j) {
                        Debug.Assert(sizeof(float) * (i * 3 + j) < vertexCount * vertexSize,
                            "Read off end of vertex buffer");
                        data[i][j] = pFloats[i * 3 + j];
                    }
            }

            // unlock the buffer
            vBuffer.Unlock();
        }
Exemple #5
0
        /// <summary>
        ///		Updates the face normals for this edge list based on (changed)
        ///		position information, useful for animated objects.
        /// </summary>
        /// <param name="vertexSet">The vertex set we are updating.</param>
        /// <param name="positionBuffer">The updated position buffer, must contain ONLY xyz.</param>
        public void UpdateFaceNormals(int vertexSet, HardwareVertexBuffer positionBuffer)
        {
#if !AXIOM_SAFE_ONLY
            unsafe
#endif
            {
                Debug.Assert(positionBuffer.VertexSize == sizeof(float) * 3, "Position buffer should contain only positions!");

                // Lock buffer for reading
                var posPtr = positionBuffer.Lock(BufferLocking.ReadOnly);
                var pVert  = posPtr.ToFloatPointer();

                // Iterate over the triangles
                for (var i = 0; i < this.triangles.Count; i++)
                {
                    var t = (Triangle)this.triangles[i];

                    // Only update tris which are using this vertex set
                    if (t.vertexSet == vertexSet)
                    {
                        var offset = t.vertIndex[0] * 3;
                        var v1     = new Vector3(pVert[offset], pVert[offset + 1], pVert[offset + 2]);

                        offset = t.vertIndex[1] * 3;
                        var v2 = new Vector3(pVert[offset], pVert[offset + 1], pVert[offset + 2]);

                        offset = t.vertIndex[2] * 3;
                        var v3 = new Vector3(pVert[offset], pVert[offset + 1], pVert[offset + 2]);

                        t.normal = CalculateFaceNormal(v1, v2, v3);
                    }
                }
            }

            // unlock the buffer
            positionBuffer.Unlock();
        }
		protected void UpdateVertexBuffer( HardwareVertexBuffer posBuf, HardwareVertexBuffer deltaBuf, Rectangle rect )
		{
			Debug.Assert( rect.Left >= this.mOffsetX && rect.Right <= this.mBoundaryX && rect.Top >= this.mOffsetY &&
			              rect.Bottom <= this.mBoundaryY );

			// potentially reset our bounds depending on coverage of the update
			ResetBounds( rect );

			//main data
			var inc = (ushort)( ( this.mTerrain.Size - 1 )/( this.mVertexDataRecord.Resolution - 1 ) );
			long destOffsetX = rect.Left <= this.mOffsetX ? 0 : ( rect.Left - this.mOffsetX )/inc;
			long destOffsetY = rect.Top <= this.mOffsetY ? 0 : ( rect.Top - this.mOffsetY )/inc;
			// Fill the buffers

			BufferLocking lockmode;
			if ( destOffsetX != 0 || destOffsetY != 0 || rect.Width < this.mSize || rect.Height < this.mSize )
			{
				lockmode = BufferLocking.Normal;
			}
			else
			{
				lockmode = BufferLocking.Discard;
			}
			Real uvScale = 1.0f/( this.mTerrain.Size - 1 );
			var pBaseHeight = this.mTerrain.GetHeightData( rect.Left, rect.Top );
			var pBaseDelta = this.mTerrain.GetDeltaData( rect.Left, rect.Top );
			var rowskip = (ushort)( this.mTerrain.Size*inc );
			ushort destPosRowSkip = 0, destDeltaRowSkip = 0;
			BufferBase pRootPosBuf = null;
			BufferBase pRootDeltaBuf = null;
			BufferBase pRowPosBuf = null;
			BufferBase pRowDeltaBuf = null;

			if ( posBuf != null )
			{
				destPosRowSkip = (ushort)( this.mVertexDataRecord.Size*posBuf.VertexSize );
				pRootPosBuf = posBuf.Lock( lockmode );
				pRowPosBuf = pRootPosBuf;
				// skip dest buffer in by left/top
				pRowPosBuf += destOffsetY*destPosRowSkip + destOffsetX*posBuf.VertexSize;
			}
			if ( deltaBuf != null )
			{
				destDeltaRowSkip = (ushort)( this.mVertexDataRecord.Size*deltaBuf.VertexSize );
				pRootDeltaBuf = deltaBuf.Lock( lockmode );
				pRowDeltaBuf = pRootDeltaBuf;
				// skip dest buffer in by left/top
				pRowDeltaBuf += destOffsetY*destDeltaRowSkip + destOffsetX*deltaBuf.VertexSize;
			}
			Vector3 pos = Vector3.Zero;

			for ( var y = (ushort)rect.Top; y < rect.Bottom; y += inc )
			{
#if !AXIOM_SAFE_ONLY
				unsafe
#endif
				{
					var pHeight = pBaseHeight.ToFloatPointer();
					var pHIdx = 0;
					var pDelta = pBaseDelta.ToFloatPointer();
					var pDeltaIdx = 0;
					var pPosBuf = pRowPosBuf != null ? pRowPosBuf.ToFloatPointer() : null;
					var pPosBufIdx = 0;
					var pDeltaBuf = pRowDeltaBuf != null ? pRowDeltaBuf.ToFloatPointer() : null;
					var pDeltaBufIdx = 0;
					for ( var x = (ushort)rect.Left; x < rect.Right; x += inc )
					{
						if ( pPosBuf != null )
						{
							this.mTerrain.GetPoint( x, y, pHeight[ pHIdx ], ref pos );
							// Update bounds *before* making relative
							MergeIntoBounds( x, y, pos );
							// relative to local centre
							pos -= this.mLocalCentre;
							pHIdx += inc;

							pPosBuf[ pPosBufIdx++ ] = pos.x;
							pPosBuf[ pPosBufIdx++ ] = pos.y;
							pPosBuf[ pPosBufIdx++ ] = pos.z;

							// UVs - base UVs vary from 0 to 1, all other values
							// will be derived using scalings
							pPosBuf[ pPosBufIdx++ ] = x*uvScale;
							pPosBuf[ pPosBufIdx++ ] = 1.0f - ( y*uvScale );
						}

						if ( pDeltaBuf != null )
						{
							//delta
							pDeltaBuf[ pDeltaBufIdx++ ] = pDelta[ pDeltaIdx ];
							pDeltaIdx += inc;
							// delta LOD threshold
							// we want delta to apply to LODs no higher than this value
							// at runtime this will be combined with a per-renderable parameter
							// to ensure we only apply morph to the correct LOD
							pDeltaBuf[ pDeltaBufIdx++ ] = (float)this.mTerrain.GetLODLevelWhenVertexEliminated( x, y ) - 1.0f;
						}
					} // end unsafe
				} //end for

				pBaseHeight += rowskip;
				pBaseDelta += rowskip;
				if ( pRowPosBuf != null )
				{
					pRowPosBuf += destPosRowSkip;
				}
				if ( pRowDeltaBuf != null )
				{
					pRowDeltaBuf += destDeltaRowSkip;
				}
			} //end for

			// Skirts now
			// skirt spacing based on top-level resolution (* inc to cope with resolution which is not the max)
			var skirtSpacing = (ushort)( this.mVertexDataRecord.SkirtRowColSkip*inc );
			var skirtOffset = Vector3.Zero;
			this.mTerrain.GetVector( 0, 0, -this.mTerrain.SkirtSize, ref skirtOffset );

			// skirt rows
			// clamp rows to skirt spacing (round up)
			var skirtStartX = rect.Left;
			var skirtStartY = rect.Top;
			// for rows, clamp Y to skirt frequency, X to inc (LOD resolution vs top)
			if ( skirtStartY%skirtSpacing != 0 )
			{
				skirtStartY += skirtSpacing - ( skirtStartY%skirtSpacing );
			}
			if ( skirtStartX%inc != 0 )
			{
				skirtStartX += inc - ( skirtStartX%inc );
			}

			skirtStartY = System.Math.Max( skirtStartY, (long)this.mOffsetY );
			pBaseHeight = this.mTerrain.GetHeightData( skirtStartX, skirtStartY );
			if ( posBuf != null )
			{
				// position dest buffer just after the main vertex data
				pRowPosBuf = pRootPosBuf + posBuf.VertexSize*this.mVertexDataRecord.Size*this.mVertexDataRecord.Size;
				// move it onwards to skip the skirts we don't need to update
				pRowPosBuf += destPosRowSkip*( ( skirtStartY - this.mOffsetY )/skirtSpacing );
				pRowPosBuf += posBuf.VertexSize*( skirtStartX - this.mOffsetX )/inc;
			}
			if ( deltaBuf != null )
			{
				// position dest buffer just after the main vertex data
				pRowDeltaBuf = pRootDeltaBuf + deltaBuf.VertexSize*this.mVertexDataRecord.Size*this.mVertexDataRecord.Size;
				// move it onwards to skip the skirts we don't need to update
				pRowDeltaBuf += destDeltaRowSkip*( skirtStartY - this.mOffsetY )/skirtSpacing;
				pRowDeltaBuf += deltaBuf.VertexSize*( skirtStartX - this.mOffsetX )/inc;
			}

			for ( var y = (ushort)skirtStartY; y < (ushort)rect.Bottom; y += skirtSpacing )
			{
#if !AXIOM_SAFE_ONLY
				unsafe
#endif
				{
					var pHeight = pBaseHeight.ToFloatPointer();
					var pHIdx = 0;
					var pPosBuf = pRowPosBuf != null ? pRowPosBuf.ToFloatPointer() : null;
					var pPosIdx = 0;
					var pDeltaBuf = pRowDeltaBuf != null ? pRowDeltaBuf.ToFloatPointer() : null;
					var pDeltaIdx = 0;
					for ( var x = (ushort)skirtStartX; x < (ushort)rect.Right; x += inc )
					{
						if ( pPosBuf != null )
						{
							this.mTerrain.GetPoint( x, y, pHeight[ pHIdx ], ref pos );
							// relative to local centre
							pos -= this.mLocalCentre;
							pHIdx += inc;
							pos += skirtOffset;
							pPosBuf[ pPosIdx++ ] = pos.x;
							pPosBuf[ pPosIdx++ ] = pos.y;
							pPosBuf[ pPosIdx++ ] = pos.z;

							// UVs - same as base
							pPosBuf[ pPosIdx++ ] = x*uvScale;
							pPosBuf[ pPosIdx++ ] = 1.0f - ( y*uvScale );
						}
						if ( pDeltaBuf != null )
						{
							// delta (none)
							pDeltaBuf[ pDeltaIdx++ ] = 0;
							// delta threshold (irrelevant)
							pDeltaBuf[ pDeltaIdx++ ] = 99;
						}
					} //end for
					pBaseHeight += this.mTerrain.Size*skirtSpacing;
					if ( pRowPosBuf != null )
					{
						pRowPosBuf += destPosRowSkip;
					}
					if ( pRowDeltaBuf != null )
					{
						pRowDeltaBuf += destDeltaRowSkip;
					}
				} // end unsafe
			} //end for

			// skirt cols
			// clamp cols to skirt spacing (round up)
			skirtStartX = rect.Left;
			if ( skirtStartX%skirtSpacing != 0 )
			{
				skirtStartX += skirtSpacing - ( skirtStartX%skirtSpacing );
			}
			// clamp Y to inc (LOD resolution vs top)
			skirtStartY = rect.Top;
			if ( skirtStartY%inc != 0 )
			{
				skirtStartY += inc - ( skirtStartY%inc );
			}
			skirtStartX = System.Math.Max( skirtStartX, (long)this.mOffsetX );

			if ( posBuf != null )
			{
				// position dest buffer just after the main vertex data and skirt rows
				pRowPosBuf = pRootPosBuf + posBuf.VertexSize*this.mVertexDataRecord.Size*this.mVertexDataRecord.Size;
				// skip the row skirts
				pRowPosBuf += this.mVertexDataRecord.NumSkirtRowsCols*this.mVertexDataRecord.Size*posBuf.VertexSize;
				// move it onwards to skip the skirts we don't need to update
				pRowPosBuf += destPosRowSkip*( skirtStartX - this.mOffsetX )/skirtSpacing;
				pRowPosBuf += posBuf.VertexSize*( skirtStartY - this.mOffsetY )/inc;
			}
			if ( deltaBuf != null )
			{
				// Deltaition dest buffer just after the main vertex data and skirt rows
				pRowDeltaBuf = pRootDeltaBuf + deltaBuf.VertexSize*this.mVertexDataRecord.Size*this.mVertexDataRecord.Size;

				// skip the row skirts
				pRowDeltaBuf += this.mVertexDataRecord.NumSkirtRowsCols*this.mVertexDataRecord.Size*deltaBuf.VertexSize;
				// move it onwards to skip the skirts we don't need to update
				pRowDeltaBuf += destDeltaRowSkip*( skirtStartX - this.mOffsetX )/skirtSpacing;
				pRowDeltaBuf += deltaBuf.VertexSize*( skirtStartY - this.mOffsetY )/inc;
			}

			for ( var x = (ushort)skirtStartX; x < (ushort)rect.Right; x += skirtSpacing )
			{
#if !AXIOM_SAFE_ONLY
				unsafe
#endif
				{
					var pPosBuf = pRowPosBuf != null ? pRowPosBuf.ToFloatPointer() : null;
					var pPosIdx = 0;
					var pDeltaBuf = pRowDeltaBuf != null ? pRowDeltaBuf.ToFloatPointer() : null;
					var pDeltaIdx = 0;
					for ( var y = (ushort)skirtStartY; y < (ushort)rect.Bottom; y += inc )
					{
						if ( pPosBuf != null )
						{
							this.mTerrain.GetPoint( x, y, this.mTerrain.GetHeightAtPoint( x, y ), ref pos );
							// relative to local centre
							pos -= this.mLocalCentre;
							pos += skirtOffset;

							pPosBuf[ pPosIdx++ ] = pos.x;
							pPosBuf[ pPosIdx++ ] = pos.y;
							pPosBuf[ pPosIdx++ ] = pos.z;

							// UVs - same as base
							pPosBuf[ pPosIdx++ ] = x*uvScale;
							pPosBuf[ pPosIdx++ ] = 1.0f - ( y*uvScale );
						}
						if ( pDeltaBuf != null )
						{
							// delta (none)
							pDeltaBuf[ pDeltaIdx++ ] = 0;
							// delta threshold (irrelevant)
							pDeltaBuf[ pDeltaIdx++ ] = 99;
						}
					} //end for
					if ( pRowPosBuf != null )
					{
						pRowPosBuf += destPosRowSkip;
					}
					if ( pRowDeltaBuf != null )
					{
						pRowDeltaBuf += destDeltaRowSkip;
					}
				} // end unsafe
			} //end for

			if ( posBuf != null )
			{
				posBuf.Unlock();
			}
			if ( deltaBuf != null )
			{
				deltaBuf.Unlock();
			}
		}
		public unsafe void Initialize( int startx, int startz, Real[] pageHeightData )
		{

			if ( mOptions.maxGeoMipMapLevel != 0 )
			{
				int i = (int)1 << ( mOptions.maxGeoMipMapLevel - 1 );

				if ( ( i + 1 ) > mOptions.tileSize )
				{
					LogManager.Instance.Write( "Invalid maximum mipmap specifed, must be n, such that 2^(n-1)+1 < tileSize \n" );
					return;
				}
			}

			DeleteGeometry();

			//calculate min and max heights;
			Real min = 256000, max = 0;

			mTerrain = new VertexData();
			mTerrain.vertexStart = 0;
			mTerrain.vertexCount = mOptions.tileSize * mOptions.tileSize;

			renderOperation.useIndices = true;
			renderOperation.operationType = mOptions.useTriStrips ? OperationType.TriangleStrip : OperationType.TriangleList;
			renderOperation.vertexData = mTerrain;
			renderOperation.indexData = GetIndexData();

			VertexDeclaration decl = mTerrain.vertexDeclaration;
			VertexBufferBinding bind = mTerrain.vertexBufferBinding;

			// positions
			int offset = 0;
			decl.AddElement( MAIN_BINDING, offset, VertexElementType.Float3, VertexElementSemantic.Position );
			offset += VertexElement.GetTypeSize( VertexElementType.Float3 );
			if ( mOptions.lit )
			{
				decl.AddElement( MAIN_BINDING, offset, VertexElementType.Float3, VertexElementSemantic.Position );
				offset += VertexElement.GetTypeSize( VertexElementType.Float3 );
			}
			// texture coord sets
			decl.AddElement( MAIN_BINDING, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 0 );
			offset += VertexElement.GetTypeSize( VertexElementType.Float2 );
			decl.AddElement( MAIN_BINDING, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 1 );
			offset += VertexElement.GetTypeSize( VertexElementType.Float2 );
			if ( mOptions.coloured )
			{
				decl.AddElement( MAIN_BINDING, offset, VertexElementType.Color, VertexElementSemantic.Diffuse );
				offset += VertexElement.GetTypeSize( VertexElementType.Color );
			}

			// Create shared vertex buffer
			mMainBuffer =
				HardwareBufferManager.Instance.CreateVertexBuffer( decl.Clone( MAIN_BINDING ), mTerrain.vertexCount, BufferUsage.StaticWriteOnly );
			// Create system memory copy with just positions in it, for use in simple reads
			//mPositionBuffer = OGRE_ALLOC_T(float, mTerrain.vertexCount * 3, MEMCATEGORY_GEOMETRY);
			mPositionBuffer = new float[ mTerrain.vertexCount * 3 ];

			bind.SetBinding( MAIN_BINDING, mMainBuffer );

			if ( mOptions.lodMorph )
			{
				// Create additional element for delta
				decl.AddElement( DELTA_BINDING, 0, VertexElementType.Float1, VertexElementSemantic.BlendWeights );
				// NB binding is not set here, it is set when deriving the LOD
			}


			mInit = true;

			mRenderLevel = 0;

			mMinLevelDistSqr = new Real[ mOptions.maxGeoMipMapLevel ];

			int endx = startx + mOptions.tileSize;

			int endz = startz + mOptions.tileSize;

			Vector3 left, down, here;

			VertexElement poselem = decl.FindElementBySemantic( VertexElementSemantic.Position );
			VertexElement texelem0 = decl.FindElementBySemantic( VertexElementSemantic.TexCoords, 0 );
			VertexElement texelem1 = decl.FindElementBySemantic( VertexElementSemantic.TexCoords, 1 );
			//fixed ( float* pSysPos = mPositionBuffer )
			{
				int pos = 0;
				byte* pBase = (byte*)mMainBuffer.Lock( BufferLocking.Discard );

				for ( int j = startz; j < endz; j++ )
				{
					for ( int i = startx; i < endx; i++ )
					{
						float* pPos = (float*)( pBase + poselem.Offset );
						float* pTex0 = (float*)( pBase + texelem0.Offset );
						float* pTex1 = (float*)( pBase + texelem1.Offset );
						//poselem.baseVertexPointerToElement(pBase, &pPos);

						//texelem0.baseVertexPointerToElement(pBase, &pTex0);
						//texelem1.baseVertexPointerToElement(pBase, &pTex1);

						Real height = pageHeightData[ j * mOptions.pageSize + i ];
						height = height * mOptions.scale.y; // scale height

						//*pSysPos++ = *pPos++ = (float) i*mOptions.scale.x; //x
						//*pSysPos++ = *pPos++ = height; // y
						//*pSysPos++ = *pPos++ = (float) j*mOptions.scale.z; //z

						mPositionBuffer[ pos++ ] = *pPos++ = (float)i * mOptions.scale.x; //x
						mPositionBuffer[ pos++ ] = *pPos++ = height; // y
						mPositionBuffer[ pos++ ] = *pPos++ = (float)j * mOptions.scale.z; //z

						*pTex0++ = (float)i / (float)( mOptions.pageSize - 1 );
						*pTex0++ = (float)j / (float)( mOptions.pageSize - 1 );

						*pTex1++ = ( (float)i / (float)( mOptions.tileSize - 1 ) ) * mOptions.detailTile;
						*pTex1++ = ( (float)j / (float)( mOptions.tileSize - 1 ) ) * mOptions.detailTile;

						if ( height < min )
							min = (Real)height;

						if ( height > max )
							max = (Real)height;

						pBase += mMainBuffer.VertexSize;
					}
				}

				mMainBuffer.Unlock();
				mBounds = new AxisAlignedBox();
				mBounds.SetExtents( new Vector3( (Real)startx * mOptions.scale.x, min, (Real)startz * mOptions.scale.z ),
									new Vector3( (Real)( endx - 1 ) * mOptions.scale.x, max,
												 (Real)( endz - 1 ) * mOptions.scale.z ) );

				mCenter = new Vector3( ( startx * mOptions.scale.x + ( endx - 1 ) * mOptions.scale.x ) / 2,
									   ( min + max ) / 2,
									   ( startz * mOptions.scale.z + ( endz - 1 ) * mOptions.scale.z ) / 2 );
				boundingRadius = Math.Sqrt(
									  Utility.Sqr( max - min ) +
									  Utility.Sqr( ( endx - 1 - startx ) * mOptions.scale.x ) +
									  Utility.Sqr( ( endz - 1 - startz ) * mOptions.scale.z ) ) / 2;

				// Create delta buffer list if required to morph
				if ( mOptions.lodMorph )
				{
					// Create delta buffer for all except the lowest mip
					mDeltaBuffers = new AxiomSortedCollection<int, HardwareVertexBuffer>( mOptions.maxGeoMipMapLevel - 1 );
				}

				Real C = CalculateCFactor();

				CalculateMinLevelDist2( C );
			}
		}
        /// <summary>
        ///   Fill a vertex buffer with the contents of a one dimensional 
        ///   integer array
        /// </summary>
        /// <param name="vBuffer">HardwareVertexBuffer to populate</param>
        /// <param name="vertexCount">the number of vertices</param>
        /// <param name="vertexSize">the size of each vertex</param>
        /// <param name="data">the array of data to put in the buffer</param>
        internal static void FillBuffer( HardwareVertexBuffer vBuffer, int vertexCount, int vertexSize, int[] data )
        {
            IntPtr bufData = vBuffer.Lock( BufferLocking.Discard );

            unsafe
            {
                int* pInts = (int*) bufData.ToPointer();
                for( int i = 0; i < vertexCount; ++i )
                {
                    Debug.Assert( sizeof( int ) * i < vertexCount * vertexSize,
                        "Wrote off end of vertex buffer" );
                    pInts[ i ] = data[ i ];
                }
            }

            // unlock the buffer
            vBuffer.Unlock();
        }
        /// <summary>
        ///   Hacked old version to add a transform
        /// </summary>
        /// <param name="vBuffer"></param>
        /// <param name="vertexOffset"></param>
        /// <param name="vertexStride"></param>
        /// <param name="vertexCount"></param>
        /// <param name="vertexSize"></param>
        /// <param name="data"></param>
        /// <param name="transform"></param>
        private void ReadBuffer(HardwareVertexBuffer vBuffer, int vertexOffset, int vertexStride, int vertexCount, int vertexSize, float[,] data, Matrix4 transform)
        {
            int count = data.GetLength(1);
            IntPtr bufData = vBuffer.Lock(BufferLocking.ReadOnly);
            Debug.Assert(count == 3);
            int floatOffset = vertexOffset / sizeof(float);
            int floatStride = vertexStride / sizeof(float);
            Debug.Assert(vertexOffset % sizeof(float) == 0);

            unsafe {
                float* pFloats = (float*)bufData.ToPointer();
                for (int i = 0; i < vertexCount; ++i) {
                    Vector3 tmpVec = Vector3.Zero;
                    for (int j = 0; j < count; ++j) {
                        int k = i * floatStride + floatOffset + j;
                        Debug.Assert(sizeof(float) * k < vertexCount * vertexStride,
                            "Read off end of vertex buffer");
                        tmpVec[j] = pFloats[k];
                    }
                    tmpVec = transform * tmpVec;
                    for (int j = 0; j < count; ++j)
                        data[i, j] = tmpVec[j];
                }
            }

            // unlock the buffer
            vBuffer.Unlock();
        }
        /// <summary>
        ///     Tells the system to build the mesh relating to the surface into externally created buffers.
        /// </summary>
        /// <remarks>
        ///     The VertexDeclaration of the vertex buffer must be identical to the one passed into
        ///     <see cref="DefineSurface"/>.  In addition, there must be enough space in the buffer to 
        ///     accommodate the patch at full detail level; you should check <see cref="RequiredVertexCount"/>
        ///     and <see cref="RequiredIndexCount"/> to determine this. This method does not create an internal
        ///     mesh for this patch and so GetMesh will return null if you call it after building the
        ///     patch this way.
        /// </remarks>
        /// <param name="destVertexBuffer">The destination vertex buffer in which to build the patch.</param>
        /// <param name="vertexStart">The offset at which to start writing vertices for this patch.</param>
        /// <param name="destIndexBuffer">The destination index buffer in which to build the patch.</param>
        /// <param name="indexStart">The offset at which to start writing indexes for this patch.</param>
        public void Build(HardwareVertexBuffer destVertexBuffer, int vertexStart, HardwareIndexBuffer destIndexBuffer, int indexStart)
        {
            if(controlPoints.Count == 0) {
                return;
            }

            vertexBuffer = destVertexBuffer;
            vertexOffset = vertexStart;
            indexBuffer = destIndexBuffer;
            indexOffset = indexStart;

            // lock just the region we are interested in
            IntPtr lockedBuffer = vertexBuffer.Lock(
                vertexOffset * declaration.GetVertexSize(0),
                requiredVertexCount * declaration.GetVertexSize(0),
                BufferLocking.NoOverwrite);

            DistributeControlPoints(lockedBuffer);

            // subdivide the curves to the max
            // Do u direction first, so need to step over v levels not done yet
            int vStep = 1 << maxVLevel;
            int uStep = 1 << maxULevel;

            // subdivide this row in u
            for(int v = 0; v < meshHeight; v += vStep) {
                SubdivideCurve(lockedBuffer, v * meshWidth, uStep, meshWidth / uStep, uLevel);
            }

            // Now subdivide in v direction, this time all the u direction points are there so no step
            for(int u = 0; u < meshWidth; u++) {
                SubdivideCurve(lockedBuffer, u, vStep * meshWidth, meshHeight / vStep, vLevel);
            }

            // don't forget to unlock!
            vertexBuffer.Unlock();

            // Make triangles from mesh at this current level of detail
            MakeTriangles();
        }
Exemple #11
0
		private void _generatePlaneVertexData( HardwareVertexBuffer vbuf, int ySegments, int xSegments, float xSpace, float halfWidth, float ySpace, float halfHeight, Matrix4 transform, bool firstTime, bool normals, Matrix4 rotation, int numTexCoordSets, float xTexCoord, float yTexCoord, SubMesh subMesh, ref Vector3 min, ref Vector3 max, ref float maxSquaredLength )
		{
			Vector3 vec;
			unsafe
			{
				// lock the vertex buffer
				IntPtr data = vbuf.Lock( BufferLocking.Discard );

				float* pData = (float*)data.ToPointer();

				for ( int y = 0; y <= ySegments; y++ )
				{
					for ( int x = 0; x <= xSegments; x++ )
					{
						// centered on origin
						vec.x = ( x * xSpace ) - halfWidth;
						vec.y = ( y * ySpace ) - halfHeight;
						vec.z = 0.0f;

						vec = transform.TransformAffine( vec );

						*pData++ = vec.x;
						*pData++ = vec.y;
						*pData++ = vec.z;

						// Build bounds as we go
						if ( firstTime )
						{
							min = vec;
							max = vec;
							maxSquaredLength = vec.LengthSquared;
							firstTime = false;
						}
						else
						{
							min.Floor( vec );
							max.Ceil( vec );
							maxSquaredLength = Utility.Max( maxSquaredLength, vec.LengthSquared );
						}

						if ( normals )
						{
							vec = Vector3.UnitZ;
							vec = rotation.TransformAffine( vec );

							*pData++ = vec.x;
							*pData++ = vec.y;
							*pData++ = vec.z;
						}

						for ( int i = 0; i < numTexCoordSets; i++ )
						{
							*pData++ = x * xTexCoord;
							*pData++ = 1 - ( y * yTexCoord );
						} // for texCoords
					} // for x
				} // for y

				// unlock the buffer
				vbuf.Unlock();

				subMesh.useSharedVertices = true;

			} // unsafe
		}
Exemple #12
0
        /// <summary>
        ///		Modifies the vertex data to be suitable for use for rendering shadow geometry.
        /// </summary>
        /// <remarks>
        ///		<para>
        ///			Preparing vertex data to generate a shadow volume involves firstly ensuring that the
        ///			vertex buffer containing the positions is a standalone vertex buffer,
        ///			with no other components in it. This method will therefore break apart any existing
        ///			vertex buffers if position is sharing a vertex buffer.
        ///			Secondly, it will double the size of this vertex buffer so that there are 2 copies of
        ///			the position data for the mesh. The first half is used for the original, and the second
        ///			half is used for the 'extruded' version. The vertex count used to render will remain
        ///			the same though, so as not to add any overhead to regular rendering of the object.
        ///			Both copies of the position are required in one buffer because shadow volumes stretch
        ///			from the original mesh to the extruded version.
        ///		</para>
        ///		<para>
        ///			It's important to appreciate that this method can fundamentally change the structure of your
        ///			vertex buffers, although in reality they will be new buffers. As it happens, if other
        ///			objects are using the original buffers then they will be unaffected because the reference
        ///			counting will keep them intact. However, if you have made any assumptions about the
        ///			structure of the vertex data in the buffers of this object, you may have to rethink them.
        ///		</para>
        /// </remarks>
        public void PrepareForShadowVolume()
        {
            /* NOTE
             *          Sinbad would dearly, dearly love to just use a 4D position buffer in order to
             *          store the extra 'w' value I need to differentiate between extruded and
             *          non-extruded sections of the buffer, so that vertex programs could use that.
             *          Hey, it works fine for GL. However, D3D9 in it's infinite stupidity, does not
             *          support 4d position vertices in the fixed-function pipeline. If you use them,
             *          you just see nothing. Since we can't know whether the application is going to use
             *          fixed function or vertex programs, we have to stick to 3d position vertices and
             *          store the 'w' in a separate 1D texture coordinate buffer, which is only used
             *          when rendering the shadow.
             */

            // Upfront, lets check whether we have vertex program capability
            var renderSystem      = Root.Instance.RenderSystem;
            var useVertexPrograms = false;

            if (renderSystem != null && renderSystem.Capabilities.HasCapability(Capabilities.VertexPrograms))
            {
                useVertexPrograms = true;
            }

            // Look for a position element
            var posElem = this.vertexDeclaration.FindElementBySemantic(VertexElementSemantic.Position);

            if (posElem != null)
            {
                var posOldSource = posElem.Source;

                var vbuf = this.vertexBufferBinding.GetBuffer(posOldSource);

                var wasSharedBuffer = false;

                // Are there other elements in the buffer except for the position?
                if (vbuf.VertexSize > posElem.Size)
                {
                    // We need to create another buffer to contain the remaining elements
                    // Most drivers don't like gaps in the declaration, and in any case it's waste
                    wasSharedBuffer = true;
                }

                HardwareVertexBuffer newPosBuffer = null, newRemainderBuffer = null;
                var newRemainderDeclaration = (VertexDeclaration)this.vertexDeclaration.Clone();

                if (wasSharedBuffer)
                {
                    var found = false;
                    var index = 0;
                    do
                    {
                        if (newRemainderDeclaration.GetElement(index).Semantic == VertexElementSemantic.Position)
                        {
                            newRemainderDeclaration.RemoveElement(index);
                            found = true;
                        }
                        index++;
                    }while (!found);

                    newRemainderBuffer = HardwareBufferManager.Instance.CreateVertexBuffer(newRemainderDeclaration, vbuf.VertexCount,
                                                                                           vbuf.Usage, vbuf.HasShadowBuffer);
                }

                // Allocate new position buffer, will be FLOAT3 and 2x the size
                var oldVertexCount = vbuf.VertexCount;
                var newVertexCount = oldVertexCount * 2;

                var newPosDecl = HardwareBufferManager.Instance.CreateVertexDeclaration();
                newPosDecl.AddElement(0, 0, VertexElementType.Float3, VertexElementSemantic.Position);
                newPosBuffer = HardwareBufferManager.Instance.CreateVertexBuffer(newPosDecl, newVertexCount, vbuf.Usage,
                                                                                 vbuf.HasShadowBuffer);

                // Iterate over the old buffer, copying the appropriate elements and initializing the rest
                var baseSrcPtr = vbuf.Lock(BufferLocking.ReadOnly);

                // Point first destination pointer at the start of the new position buffer,
                // the other one half way along
                var destPtr = newPosBuffer.Lock(BufferLocking.Discard);
                // oldVertexCount * 3 * 4, since we are dealing with byte offsets here
                var dest2Ptr = destPtr + (oldVertexCount * 12);

                var prePosVertexSize    = 0;
                var postPosVertexSize   = 0;
                var postPosVertexOffset = 0;

                if (wasSharedBuffer)
                {
                    // Precalculate any dimensions of vertex areas outside the position
                    prePosVertexSize    = posElem.Offset;
                    postPosVertexOffset = prePosVertexSize + posElem.Size;
                    postPosVertexSize   = vbuf.VertexSize - postPosVertexOffset;

                    // the 2 separate bits together should be the same size as the remainder buffer vertex
                    Debug.Assert(newRemainderBuffer.VertexSize == (prePosVertexSize + postPosVertexSize));

                    var baseDestRemPtr = newRemainderBuffer.Lock(BufferLocking.Discard);

                    var baseSrcOffset     = 0;
                    var baseDestRemOffset = 0;

#if !AXIOM_SAFE_ONLY
                    unsafe
#endif
                    {
                        var pDest  = destPtr.ToFloatPointer();
                        var pDest2 = dest2Ptr.ToFloatPointer();

                        int destCount = 0, dest2Count = 0;

                        // Iterate over the vertices
                        for (var v = 0; v < oldVertexCount; v++)
                        {
                            var pSrc = (baseSrcPtr + (posElem.Offset + baseSrcOffset)).ToFloatPointer();

                            // Copy position, into both buffers
                            pDest[destCount++] = pDest2[dest2Count++] = pSrc[0];
                            pDest[destCount++] = pDest2[dest2Count++] = pSrc[1];
                            pDest[destCount++] = pDest2[dest2Count++] = pSrc[2];

                            // now deal with any other elements
                            // Basically we just memcpy the vertex excluding the position
                            if (prePosVertexSize > 0)
                            {
                                Memory.Copy(baseSrcPtr, baseDestRemPtr, baseSrcOffset, baseDestRemOffset, prePosVertexSize);
                            }

                            if (postPosVertexSize > 0)
                            {
                                Memory.Copy(baseSrcPtr, baseDestRemPtr, baseSrcOffset + postPosVertexOffset,
                                            baseDestRemOffset + prePosVertexSize, postPosVertexSize);
                            }

                            // increment the pointer offsets
                            baseDestRemOffset += newRemainderBuffer.VertexSize;
                            baseSrcOffset     += vbuf.VertexSize;
                        } // next vertex
                    }     // unsafe
                }
                else
                {
                    // copy the data directly
                    Memory.Copy(baseSrcPtr, destPtr, vbuf.Size);
                    Memory.Copy(baseSrcPtr, dest2Ptr, vbuf.Size);
                }

                vbuf.Unlock();
                newPosBuffer.Unlock();

                if (wasSharedBuffer)
                {
                    newRemainderBuffer.Unlock();
                }

                // At this stage, he original vertex buffer is going to be destroyed
                // So we should force the deallocation of any temporary copies
                HardwareBufferManager.Instance.ForceReleaseBufferCopies(vbuf);

                if (useVertexPrograms)
                {
#if !AXIOM_SAFE_ONLY
                    unsafe
#endif
                    {
                        var decl = HardwareBufferManager.Instance.CreateVertexDeclaration();
                        decl.AddElement(0, 0, VertexElementType.Float1, VertexElementSemantic.Position);

                        // Now it's time to set up the w buffer
                        this.hardwareShadowVolWBuffer = HardwareBufferManager.Instance.CreateVertexBuffer(decl, newVertexCount,
                                                                                                          BufferUsage.StaticWriteOnly,
                                                                                                          false);

                        // Fill the first half with 1.0, second half with 0.0
                        var wPtr      = this.hardwareShadowVolWBuffer.Lock(BufferLocking.Discard);
                        var pDest     = wPtr.ToFloatPointer();
                        var destCount = 0;

                        for (var v = 0; v < oldVertexCount; v++)
                        {
                            pDest[destCount++] = 1.0f;
                        }
                        for (var v = 0; v < oldVertexCount; v++)
                        {
                            pDest[destCount++] = 0.0f;
                        }
                    } // unsafe

                    this.hardwareShadowVolWBuffer.Unlock();
                } // if vertexPrograms

                short newPosBufferSource = 0;

                if (wasSharedBuffer)
                {
                    // Get the a new buffer binding index
                    newPosBufferSource = this.vertexBufferBinding.NextIndex;

                    // Re-bind the old index to the remainder buffer
                    this.vertexBufferBinding.SetBinding(posOldSource, newRemainderBuffer);
                }
                else
                {
                    // We can just re-use the same source idex for the new position buffer
                    newPosBufferSource = posOldSource;
                }

                // Bind the new position buffer
                this.vertexBufferBinding.SetBinding(newPosBufferSource, newPosBuffer);

                // Now, alter the vertex declaration to change the position source
                // and the offsets of elements using the same buffer
                for (var i = 0; i < this.vertexDeclaration.ElementCount; i++)
                {
                    var element = this.vertexDeclaration.GetElement(i);

                    if (element.Semantic == VertexElementSemantic.Position)
                    {
                        // Modify position to point at new position buffer
                        this.vertexDeclaration.ModifyElement(i, newPosBufferSource /* new source buffer */, 0 /* no offset now */,
                                                             VertexElementType.Float3, VertexElementSemantic.Position);
                    }
                    else if (wasSharedBuffer && element.Source == posOldSource && element.Offset > prePosVertexSize)
                    {
                        // This element came after position, remove the position's size
                        this.vertexDeclaration.ModifyElement(i, posOldSource /* same old source */, element.Offset - posElem.Size
                                                             /* less offset now */, element.Type, element.Semantic, element.Index);
                    }
                }
            } // if posElem != null
        }
Exemple #13
0
		/// <summary>
		///		Utility method for extruding vertices based on a light.
		/// </summary>
		/// <remarks>
		///		Unfortunately, because D3D cannot handle homogenous (4D) position
		///		coordinates in the fixed-function pipeline (GL can, but we have to
		///		be cross-API), when we extrude in software we cannot extrude to
		///		infinity the way we do in the vertex program (by setting w to
		///		0.0f). Therefore we extrude by a fixed distance, which may cause
		///		some problems with larger scenes. Luckily better hardware (ie
		///		vertex programs) can fix this.
		/// </remarks>
		/// <param name="vertexBuffer">The vertex buffer containing ONLY xyz position
		/// values, which must be originalVertexCount * 2 * 3 floats long.</param>
		/// <param name="originalVertexCount">The count of the original number of
		/// vertices, ie the number in the mesh, not counting the doubling
		/// which has already been done (by <see cref="VertexData.PrepareForShadowVolume"/>)
		/// to provide the extruded area of the buffer.</param>
		/// <param name="lightPosition"> 4D light position in object space, when w=0.0f this
		/// represents a directional light</param>
		/// <param name="extrudeDistance">The distance to extrude.</param>
		public static void ExtrudeVertices( HardwareVertexBuffer vertexBuffer, int originalVertexCount, Vector4 lightPosition, float extrudeDistance )
		{
			unsafe
			{
				Debug.Assert( vertexBuffer.VertexSize == sizeof( float ) * 3, "Position buffer should contain only positions!" );

				// Extrude the first area of the buffer into the second area
				// Lock the entire buffer for writing, even though we'll only be
				// updating the latter because you can't have 2 locks on the same
				// buffer
				IntPtr srcPtr = vertexBuffer.Lock( BufferLocking.Normal );
				IntPtr destPtr = new IntPtr( srcPtr.ToInt64() + ( originalVertexCount * 3 * 4 ) );
				float* pSrc = (float*)srcPtr.ToPointer();
				float* pDest = (float*)destPtr.ToPointer();

				int destCount = 0, srcCount = 0;

				// Assume directional light, extrusion is along light direction
				Vector3 extrusionDir = new Vector3( -lightPosition.x, -lightPosition.y, -lightPosition.z );
				extrusionDir.Normalize();
				extrusionDir *= extrudeDistance;

				for ( int vert = 0; vert < originalVertexCount; vert++ )
				{
					if ( lightPosition.w != 0.0f )
					{
						// Point light, adjust extrusionDir
						extrusionDir.x = pSrc[ srcCount + 0 ] - lightPosition.x;
						extrusionDir.y = pSrc[ srcCount + 1 ] - lightPosition.y;
						extrusionDir.z = pSrc[ srcCount + 2 ] - lightPosition.z;
						extrusionDir.Normalize();
						extrusionDir *= extrudeDistance;
					}

					pDest[ destCount++ ] = pSrc[ srcCount++ ] + extrusionDir.x;
					pDest[ destCount++ ] = pSrc[ srcCount++ ] + extrusionDir.y;
					pDest[ destCount++ ] = pSrc[ srcCount++ ] + extrusionDir.z;
				}
			}

			vertexBuffer.Unlock();
		}
        public unsafe void DebugLog(Log log)
        {
            log.Write("EdgeListBuilder Log");
            log.Write("-------------------");
            log.Write("Number of vertex sets: {0}", vertexDataList.Count);
            log.Write("Number of index sets: {0}", indexDataList.Count);

            int i, j;

            // Log original vertex data
            for (i = 0; i < vertexDataList.Count; i++)
            {
                VertexData vData = (VertexData)vertexDataList[i];
                log.Write(".");
                log.Write("Original vertex set {0} - vertex count {1}", i, vData.vertexCount);

                VertexElement posElem =
                    vData.vertexDeclaration.FindElementBySemantic(VertexElementSemantic.Position);
                HardwareVertexBuffer vbuf =
                    vData.vertexBufferBinding.GetBuffer(posElem.Source);

                // lock the buffer for reading
                IntPtr basePtr = vbuf.Lock(BufferLocking.ReadOnly);

                byte *pBaseVertex = (byte *)basePtr.ToPointer();

                float *pReal;

                for (j = 0; j < vData.vertexCount; j++)
                {
                    pReal = (float *)(pBaseVertex + posElem.Offset);

                    log.Write("Vertex {0}: ({1}, {2}, {3})", j, pReal[0], pReal[1], pReal[2]);

                    pBaseVertex += vbuf.VertexSize;
                }

                vbuf.Unlock();
            }

            // Log original index data
            for (i = 0; i < indexDataList.Count; i += 3)
            {
                IndexData iData = (IndexData)indexDataList[i];
                log.Write(".");
                log.Write("Original triangle set {0} - index count {1} - vertex set {2})",
                          i, iData.indexCount, indexDataVertexDataSetList[i]);

                // Get the indexes ready for reading
                short *p16Idx = null;
                int *  p32Idx = null;

                IntPtr idxPtr = iData.indexBuffer.Lock(BufferLocking.ReadOnly);

                if (iData.indexBuffer.Type == IndexType.Size32)
                {
                    p32Idx = (int *)idxPtr.ToPointer();
                }
                else
                {
                    p16Idx = (short *)idxPtr.ToPointer();
                }

                for (j = 0; j < iData.indexCount / 3; j++)
                {
                    if (iData.indexBuffer.Type == IndexType.Size32)
                    {
                        log.Write("Triangle {0}: ({1}, {2}, {3})", j, *p32Idx++, *p32Idx++, *p32Idx++);
                    }
                    else
                    {
                        log.Write("Triangle {0}: ({1}, {2}, {3})", j, *p16Idx++, *p16Idx++, *p16Idx++);
                    }
                }

                iData.indexBuffer.Unlock();

                // Log common vertex list
                log.Write(".");
                log.Write("Common vertex list - vertex count {0}", vertices.Count);

                for (i = 0; i < vertices.Count; i++)
                {
                    CommonVertex c = (CommonVertex)vertices[i];

                    log.Write("Common vertex {0}: (vertexSet={1}, originalIndex={2}, position={3}",
                              i, c.vertexSet, c.index, c.position);
                }
            }
        }
Exemple #15
0
			protected int CopyVertices( HardwareVertexBuffer srcBuf, BufferBase pDst, List<VertexElement> elems,
			                            QueuedGeometry geom, Vector3 regionCenter )
			{
#if !AXIOM_SAFE_ONLY
				unsafe
#endif
				{
					// lock source
					var src = srcBuf.Lock( BufferLocking.ReadOnly );
					var bufInc = srcBuf.VertexSize;

					var temp = Vector3.Zero;

					// Calculate elem sizes outside the loop
					var elemSizes = new int[elems.Count];
					for ( var i = 0; i < elems.Count; i++ )
					{
						elemSizes[ i ] = VertexElement.GetTypeSize( elems[ i ].Type );
					}

					// Move the position offset calculation outside the loop
					var positionDelta = geom.position - regionCenter;

					for ( var v = 0; v < geom.geometry.vertexData.vertexCount; ++v )
					{
						// iterate over vertex elements
						for ( var i = 0; i < elems.Count; i++ )
						{
							var elem = elems[ i ];
							var pSrcReal = ( src + elem.Offset ).ToFloatPointer();
							var pDstReal = ( pDst + elem.Offset ).ToFloatPointer();

							switch ( elem.Semantic )
							{
								case VertexElementSemantic.Position:
									temp.x = pSrcReal[ 0 ];
									temp.y = pSrcReal[ 1 ];
									temp.z = pSrcReal[ 2 ];
									// transform
									temp = ( geom.orientation*( temp*geom.scale ) );
									pDstReal[ 0 ] = temp.x + positionDelta.x;
									pDstReal[ 1 ] = temp.y + positionDelta.y;
									pDstReal[ 2 ] = temp.z + positionDelta.z;
									break;
								case VertexElementSemantic.Normal:
								case VertexElementSemantic.Tangent:
								case VertexElementSemantic.Binormal:
									temp.x = pSrcReal[ 0 ];
									temp.y = pSrcReal[ 1 ];
									temp.z = pSrcReal[ 2 ];
									// rotation only
									temp = geom.orientation*temp;
									pDstReal[ 0 ] = temp.x;
									pDstReal[ 1 ] = temp.y;
									pDstReal[ 2 ] = temp.z;
									break;
								default:
									// just raw copy
									var size = elemSizes[ i ];
									// Optimize the loop for the case that
									// these things are in units of 4
									if ( ( size & 0x3 ) == 0x3 )
									{
										var cnt = size/4;
										while ( cnt-- > 0 )
										{
											pDstReal[ cnt ] = pSrcReal[ cnt ];
										}
									}
									else
									{
										// Fall back to the byte-by-byte copy
										var pbSrc = ( src + elem.Offset ).ToBytePointer();
										var pbDst = ( pDst + elem.Offset ).ToBytePointer();
										while ( size-- > 0 )
										{
											pbDst[ size ] = pbSrc[ size ];
										}
									}
									break;
							}
						}

						// Increment both pointers
						pDst.Ptr += bufInc;
						src.Ptr += bufInc;
					}

					srcBuf.Unlock();
					return pDst.Ptr;
				}
			}
        /// <summary>
        ///
        /// </summary>
        /// <param name="indexSet"></param>
        /// <param name="vertexSet"></param>
        protected void BuildTrianglesEdges(int indexSet, int vertexSet)
        {
            IndexData     indexData = (IndexData)indexDataList[indexSet];
            OperationType opType    = operationTypes[indexSet];

            int iterations = 0;

            switch (opType)
            {
            case OperationType.TriangleList:
                iterations = indexData.indexCount / 3;
                break;

            case OperationType.TriangleFan:
            case OperationType.TriangleStrip:
                iterations = indexData.indexCount - 2;
                break;
            }

            // locate postion element & the buffer to go with it
            VertexData    vertexData = (VertexData)vertexDataList[vertexSet];
            VertexElement posElem    =
                vertexData.vertexDeclaration.FindElementBySemantic(VertexElementSemantic.Position);

            HardwareVertexBuffer posBuffer = vertexData.vertexBufferBinding.GetBuffer(posElem.Source);
            IntPtr posPtr = posBuffer.Lock(BufferLocking.ReadOnly);
            IntPtr idxPtr = indexData.indexBuffer.Lock(BufferLocking.ReadOnly);

            unsafe {
                byte *pBaseVertex = (byte *)posPtr.ToPointer();

                short *p16Idx = null;
                int *  p32Idx = null;

                // counters used for pointer indexing
                int count16 = 0;
                int count32 = 0;

                if (indexData.indexBuffer.Type == IndexType.Size16)
                {
                    p16Idx = (short *)idxPtr.ToPointer();
                }
                else
                {
                    p32Idx = (int *)idxPtr.ToPointer();
                }

                float *pReal = null;

                int triStart = edgeData.triangles.Count;

                // iterate over all the groups of 3 indices
                edgeData.triangles.Capacity = triStart + iterations;

                for (int t = 0; t < iterations; t++)
                {
                    EdgeData.Triangle tri = new EdgeData.Triangle();
                    tri.indexSet  = indexSet;
                    tri.vertexSet = vertexSet;

                    int[]     index = new int[3];
                    Vector3[] v     = new Vector3[3];

                    for (int i = 0; i < 3; i++)
                    {
                        // Standard 3-index read for tri list or first tri in strip / fan
                        if (opType == OperationType.TriangleList || t == 0)
                        {
                            if (indexData.indexBuffer.Type == IndexType.Size32)
                            {
                                index[i] = p32Idx[count32++];
                            }
                            else
                            {
                                index[i] = p16Idx[count16++];
                            }
                        }
                        else
                        {
                            // Strips and fans are formed from last 2 indexes plus the
                            // current one for triangles after the first
                            if (indexData.indexBuffer.Type == IndexType.Size32)
                            {
                                index[i] = p32Idx[i - 2];
                            }
                            else
                            {
                                index[i] = p16Idx[i - 2];
                            }

                            // Perform single-index increment at the last tri index
                            if (i == 2)
                            {
                                if (indexData.indexBuffer.Type == IndexType.Size32)
                                {
                                    count32++;
                                }
                                else
                                {
                                    count16++;
                                }
                            }
                        }

                        // populate tri original vertex index
                        tri.vertIndex[i] = index[i];

                        // Retrieve the vertex position
                        byte *pVertex = pBaseVertex + (index[i] * posBuffer.VertexSize);
                        pReal  = (float *)(pVertex + posElem.Offset);
                        v[i].x = *pReal++;
                        v[i].y = *pReal++;
                        v[i].z = *pReal++;
                        // find this vertex in the existing vertex map, or create it
                        tri.sharedVertIndex[i] = FindOrCreateCommonVertex(v[i], vertexSet, indexSet, index[i]);
                    }

                    // Calculate triangle normal (NB will require recalculation for
                    // skeletally animated meshes)
                    tri.normal = MathUtil.CalculateFaceNormal(v[0], v[1], v[2]);

                    // Add triangle to list
                    edgeData.triangles.Add(tri);

                    try {
                        // create edges from common list
                        if (tri.sharedVertIndex[0] < tri.sharedVertIndex[1])
                        {
                            CreateEdge(vertexSet, triStart + t,
                                       tri.vertIndex[0], tri.vertIndex[1],
                                       tri.sharedVertIndex[0], tri.sharedVertIndex[1]);
                        }
                        if (tri.sharedVertIndex[1] < tri.sharedVertIndex[2])
                        {
                            CreateEdge(vertexSet, triStart + t,
                                       tri.vertIndex[1], tri.vertIndex[2],
                                       tri.sharedVertIndex[1], tri.sharedVertIndex[2]);
                        }
                        if (tri.sharedVertIndex[2] < tri.sharedVertIndex[0])
                        {
                            CreateEdge(vertexSet, triStart + t,
                                       tri.vertIndex[2], tri.vertIndex[0],
                                       tri.sharedVertIndex[2], tri.sharedVertIndex[0]);
                        }
                    }
                    catch (Exception ex) {
                        //Debug.WriteLine(ex.ToString());
                        //Debug.WriteLine(ex.StackTrace);
                        // unlock those buffers!
                        indexData.indexBuffer.Unlock();
                        posBuffer.Unlock();

                        throw ex;
                    }
                } // for iterations
            }     // unsafe

            // unlock those buffers!
            indexData.indexBuffer.Unlock();
            posBuffer.Unlock();
        }
        unsafe void UpdateVertexBufferr(HardwareVertexBuffer posbuf, HardwareVertexBuffer deltabuf, Rectangle rect)
        {
            // potentially reset our bounds depending on coverage of the update
		ResetBounds(rect);

		// Main data
		ushort inc = (ushort)((mTerrain.Size-1) / (mVertexDataRecord.Resolution-1));
		long destOffsetX = rect.Left <= mOffsetX ? 0 : (rect.Left - mOffsetX) / inc;
		long destOffsetY = rect.Top <= mOffsetY ? 0 : (rect.Top - mOffsetY) / inc;
		// Fill the buffers
		
		BufferLocking lockMode;
		if (destOffsetX != 0 || destOffsetY != 0|| rect.Right - rect.Left < mSize
			|| rect.Bottom - rect.Top < mSize)
		{
			lockMode = BufferLocking.Normal;
		}
		else
		{
			lockMode = BufferLocking.Discard;
		}

		Real uvScale = 1.0 / (mTerrain.Size - 1);
		float* pBaseHeight = (float*)mTerrain.GetHeightData(rect.Left, rect.Top);
		float* pBaseDelta = (float*)mTerrain.GetDeltaData(rect.Left, rect.Top);
		ushort rowskip = (ushort)(mTerrain.Size * inc);
		ushort destPosRowSkip = 0, destDeltaRowSkip = 0;
		byte* pRootPosBuf = (byte*)IntPtr.Zero;
		byte* pRootDeltaBuf = (byte*)IntPtr.Zero;
		byte* pRowPosBuf = (byte*)IntPtr.Zero;
		byte* pRowDeltaBuf = (byte*)IntPtr.Zero;

		if (posbuf != null)
		{
			destPosRowSkip = (ushort)(mVertexDataRecord.Size * posbuf.VertexSize);
			pRootPosBuf = (byte*)(posbuf.Lock(lockMode));
			pRowPosBuf = pRootPosBuf;
			// skip dest buffer in by left/top
			pRowPosBuf += destOffsetY * destPosRowSkip + destOffsetX * posbuf.VertexSize;
		}
		if (deltabuf != null)
		{
			destDeltaRowSkip = (ushort)(mVertexDataRecord.Size * deltabuf.VertexSize);
			pRootDeltaBuf = (byte*)(deltabuf.Lock(lockMode));
			pRowDeltaBuf = pRootDeltaBuf;
			// skip dest buffer in by left/top
			pRowDeltaBuf += destOffsetY * destDeltaRowSkip + destOffsetX * deltabuf.VertexSize;
		}
		Vector3 pos = Vector3.Zero;

        int posIndex = 0;
        for (ushort y = (ushort)rect.Top; y < rect.Bottom; y += inc)
		{
			float* pHeight = pBaseHeight;
			float* pDelta = pBaseDelta;
			float* pPosBuf = (float*)(pRowPosBuf);
			float* pDeltaBuf = (float*)(pRowDeltaBuf);
            for (ushort x = (ushort)rect.Left; x < rect.Right; x += inc)
			{
				if (pPosBuf != (float*)IntPtr.Zero)
				{
					mTerrain.GetPoint(x, y, pBaseHeight[posIndex], ref pos);
					// Update bounds *before* making relative
					MergeIntoBounds(x, y, pos);
					// relative to local centre
					pos -= mLocalCentre;

					//pHeight += inc;
                    posIndex += inc;

					*pPosBuf++ = pos.x;
					*pPosBuf++ = pos.y;
					*pPosBuf++ = pos.z;

					// UVs - base UVs vary from 0 to 1, all other values
					// will be derived using scalings
					*pPosBuf++ = x * uvScale;
					*pPosBuf++ = 1.0 - (y * uvScale);

				}

				if (pDeltaBuf != (float*)IntPtr.Zero)
				{
					// delta
					*pDeltaBuf++ = *pDelta;
					pDelta += inc;
					// delta LOD threshold
					// we want delta to apply to LODs no higher than this value
					// at runtime this will be combined with a per-renderable parameter
					// to ensure we only apply morph to the correct LOD
					*pDeltaBuf++ = (float)mTerrain.GetLODLevelWhenVertexEliminated(x, y) - 1.0f;

				}

				
			}
			//pBaseHeight += rowskip;
            posIndex += rowskip;
			pBaseDelta += rowskip;
			if (pRowPosBuf != (float*)IntPtr.Zero)
				pRowPosBuf += destPosRowSkip;
			if (pRowDeltaBuf!= (float*)IntPtr.Zero)
				pRowDeltaBuf += destDeltaRowSkip;

		}


		// Skirts now
		// skirt spacing based on top-level resolution (* inc to cope with resolution which is not the max)
        ushort skirtSpacing = (ushort)(mVertexDataRecord.SkirtRowColSkip * inc);
		Vector3 skirtOffset = Vector3.Zero;
		mTerrain.GetVector(0, 0, -mTerrain.SkirtSize, ref skirtOffset);

		// skirt rows
		// clamp rows to skirt spacing (round up)
		long skirtStartX = rect.Left;
		long skirtStartY = rect.Top;
		if (skirtStartY % skirtSpacing != 0)
			skirtStartY += skirtSpacing - (skirtStartY % skirtSpacing);
		skirtStartY = System.Math.Max(skirtStartY, (long)mOffsetY);
		pBaseHeight = (float*)mTerrain.GetHeightData(skirtStartX, skirtStartY);
		if (posbuf != null)
		{
			// position dest buffer just after the main vertex data
			pRowPosBuf = pRootPosBuf + posbuf.VertexSize 
				* mVertexDataRecord.Size * mVertexDataRecord.Size;
			// move it onwards to skip the skirts we don't need to update
			pRowPosBuf += destPosRowSkip * (skirtStartY - mOffsetY) / skirtSpacing;
			pRowPosBuf += posbuf.VertexSize * (skirtStartX - mOffsetX);
		}
		if (deltabuf != null)
		{
			// position dest buffer just after the main vertex data
			pRowDeltaBuf = pRootDeltaBuf + deltabuf.VertexSize 
				* mVertexDataRecord.Size * mVertexDataRecord.Size;
			// move it onwards to skip the skirts we don't need to update
			pRowDeltaBuf += destDeltaRowSkip * (skirtStartY - mOffsetY) / skirtSpacing;
			pRowDeltaBuf += deltabuf.VertexSize * (skirtStartX - mOffsetX);
		}
        for (ushort y = (ushort)skirtStartY; y < rect.Bottom; y += skirtSpacing)
		{
			float* pHeight = pBaseHeight;
			float* pPosBuf = (float*)(pRowPosBuf);
			float* pDeltaBuf = (float*)(pRowDeltaBuf);
            for (ushort x = (ushort)skirtStartX; x < rect.Right; x += inc)
			{
				if (pPosBuf != (float*)IntPtr.Zero)
				{
					mTerrain.GetPoint(x, y, *pHeight, ref pos);
					// relative to local centre
					pos -= mLocalCentre;
					pHeight += inc;

					pos += skirtOffset;

					*pPosBuf++ = pos.x;
					*pPosBuf++ = pos.y;
					*pPosBuf++ = pos.z;

					// UVs - same as base
					*pPosBuf++ = x * uvScale;
					*pPosBuf++ = 1.0 - (y * uvScale);

				}

				if (pDeltaBuf != (float*)IntPtr.Zero)
				{
					// delta (none)
					*pDeltaBuf++ = 0; 
					// delta threshold (irrelevant)
					*pDeltaBuf++ = 99;
				}
			}
			pBaseHeight += mTerrain.Size * skirtSpacing;
			if (pRowPosBuf != (byte*)IntPtr.Zero)
				pRowPosBuf += destPosRowSkip;
			if (pRowDeltaBuf != (byte*)IntPtr.Zero)
				pRowDeltaBuf += destDeltaRowSkip;
		}
		// skirt cols
		// clamp cols to skirt spacing (round up)
		skirtStartX = rect.Left;
		if (skirtStartX % skirtSpacing != 0)
			skirtStartX += skirtSpacing - (skirtStartX % skirtSpacing);
		skirtStartY = rect.Top;
		skirtStartX = System.Math.Max(skirtStartX, (long)mOffsetX);
		if (posbuf != null)
		{
			// position dest buffer just after the main vertex data and skirt rows
			pRowPosBuf = pRootPosBuf + posbuf.VertexSize 
				* mVertexDataRecord.Size * mVertexDataRecord.Size;
			// skip the row skirts
			pRowPosBuf += mVertexDataRecord.NumSkirtRowsCols * mVertexDataRecord.Size * posbuf.VertexSize;
			// move it onwards to skip the skirts we don't need to update
			pRowPosBuf += destPosRowSkip * (skirtStartX - mOffsetX) / skirtSpacing;
			pRowPosBuf += posbuf.VertexSize * (skirtStartY - mOffsetY);
		}
		if (deltabuf != null)
		{
			// Deltaition dest buffer just after the main vertex data and skirt rows
			pRowDeltaBuf = pRootDeltaBuf + deltabuf.VertexSize 
				* mVertexDataRecord.Size * mVertexDataRecord.Size;
			// skip the row skirts
			pRowDeltaBuf += mVertexDataRecord.NumSkirtRowsCols * mVertexDataRecord.Size * deltabuf.VertexSize;
			// move it onwards to skip the skirts we don't need to update
			pRowDeltaBuf += destDeltaRowSkip * (skirtStartX - mOffsetX) / skirtSpacing;
			pRowDeltaBuf += deltabuf.VertexSize * (skirtStartY - mOffsetY);
		}

        for (ushort x = (ushort)skirtStartX; x < rect.Right; x += skirtSpacing)
		{
			float* pPosBuf = (float*)(pRowPosBuf);
			float* pDeltaBuf = (float*)(pRowDeltaBuf);
            for (ushort y = (ushort)skirtStartY; y < rect.Bottom; y += inc)
			{
				if (pPosBuf != (float*)IntPtr.Zero)
				{
					mTerrain.GetPoint(x, y, mTerrain.GetHeightAtPoint(x, y), ref pos);
					// relative to local centre
					pos -= mLocalCentre;
					pos += skirtOffset;

					*pPosBuf++ = pos.x;
					*pPosBuf++ = pos.y;
					*pPosBuf++ = pos.z;

					// UVs - same as base
					*pPosBuf++ = x * uvScale;
					*pPosBuf++ = 1.0 - (y * uvScale);
				}
				if (pDeltaBuf != (float*)IntPtr.Zero)
				{
					// delta (none)
					*pDeltaBuf++ = 0; 
					// delta threshold (irrelevant)
					*pDeltaBuf++ = 99;
				}
			}
			if (pRowPosBuf != (byte*)IntPtr.Zero)
				pRowPosBuf += destPosRowSkip;
			if (pRowDeltaBuf != (byte*)IntPtr.Zero)
				pRowDeltaBuf += destDeltaRowSkip;
		}

		if (posbuf != null)
			posbuf.Unlock();
		if (deltabuf != null)
			deltabuf.Unlock();
        }
        /// <summary>
        ///    Fetch the data from the vBuffer into the data array
        /// </summary>
        /// <remarks>the data field that will be populated by this call should 
        ///          already have the correct dimensions</remarks>
        /// <param name="vBuffer">the vertex buffer with the data</param>
        /// <param name="vertexCount">the number of vertices</param>
        /// <param name="vertexSize">the size of each vertex</param>
        /// <param name="data">the array to fill</param>
        internal void GetBuffer(HardwareVertexBuffer vBuffer, int vertexCount, int vertexSize, float[,] data)
        {
            int count = data.GetLength(1);
            IntPtr bufData = vBuffer.Lock(BufferLocking.Discard);

            unsafe {
                float* pFloats = (float*)bufData.ToPointer();
                for (int i = 0; i < vertexCount; ++i)
                    for (int j = 0; j < count; ++j) {
                        Debug.Assert(sizeof(float) * (i * count + j) < vertexCount * vertexSize,
                            "Read off end of index buffer");
                        data[i, j] = pFloats[i * count + j];
                    }
            }

            // unlock the buffer
            vBuffer.Unlock();
        }
Exemple #19
0
		/// <summary>Get a hardware vertex buffer version of the vertex offsets.</summary>
		public HardwareVertexBuffer GetHardwareVertexBuffer( int numVertices )
		{
			if ( vertexBuffer == null )
			{
				// Create buffer
                VertexDeclaration decl = HardwareBufferManager.Instance.CreateVertexDeclaration();
                decl.AddElement(0, 0, VertexElementType.Float3, VertexElementSemantic.Position);

				vertexBuffer = HardwareBufferManager.Instance.CreateVertexBuffer( decl, numVertices, BufferUsage.StaticWriteOnly, false );

				// lock the vertex buffer
				IntPtr ipBuf = vertexBuffer.Lock( BufferLocking.Discard );

				unsafe
				{
					float* buffer = (float*)ipBuf.ToPointer();
					for ( int i = 0; i < numVertices * 3; i++ )
						buffer[ i ] = 0f;

					// Set each vertex
					foreach ( KeyValuePair<int, Vector3> pair in vertexOffsetMap )
					{
						int offset = 3 * pair.Key;
						Vector3 v = pair.Value;
						buffer[ offset++ ] = v.x;
						buffer[ offset++ ] = v.y;
						buffer[ offset ] = v.z;
					}
					vertexBuffer.Unlock();
				}
			}
			return vertexBuffer;
		}
        /// <summary>
        ///		Updates the face normals for this edge list based on (changed)
        ///		position information, useful for animated objects. 
        /// </summary>
        /// <param name="vertexSet">The vertex set we are updating.</param>
        /// <param name="positionBuffer">The updated position buffer, must contain ONLY xyz.</param>
        public void UpdateFaceNormals(int vertexSet, HardwareVertexBuffer positionBuffer)
        {
            unsafe {
                Debug.Assert(positionBuffer.VertexSize == sizeof(float) * 3, "Position buffer should contain only positions!");

                // Lock buffer for reading
                IntPtr posPtr = positionBuffer.Lock(BufferLocking.ReadOnly);
                float* pVert = (float*)posPtr.ToPointer();

                // Iterate over the triangles
                for (int i = 0; i < triangles.Count; i++) {
                    Triangle t = (Triangle)triangles[i];

                    // Only update tris which are using this vertex set
                    if (t.vertexSet == vertexSet) {
                        int offset = t.vertIndex[0] * 3;
                        Vector3 v1 = new Vector3(pVert[offset], pVert[offset + 1], pVert[offset + 2]);

                        offset = t.vertIndex[1] * 3;
                        Vector3 v2 = new Vector3(pVert[offset], pVert[offset + 1], pVert[offset + 2]);

                        offset = t.vertIndex[2] * 3;
                        Vector3 v3 = new Vector3(pVert[offset], pVert[offset + 1], pVert[offset + 2]);

                        t.normal = MathUtil.CalculateFaceNormal(v1, v2, v3);
                    }
                }
            }

            // unlock the buffer
            positionBuffer.Unlock();
        }
        private static void GenerateCurvedIllusionPlaneVertexData(HardwareVertexBuffer vertexBuffer, int ySegments, int xSegments, float xSpace, float halfWidth, float ySpace, float halfHeight, Matrix4 xform, bool firstTime, bool normals, Quaternion orientation, float cameraPosition, float sphereRadius, float uTiles, float vTiles, int numberOfTexCoordSets, ref Vector3 min, ref Vector3 max, ref float maxSquaredLength)
        {
            Vector3 vec;
            Vector3 norm;
            float sphereDistance;
            unsafe {
                // lock the vertex buffer
                IntPtr data = vertexBuffer.Lock(BufferLocking.Discard);

                float* pData = (float*)data.ToPointer();

                for (int y = 0; y < ySegments + 1; ++y) {
                    for (int x = 0; x < xSegments + 1; ++x) {
                        // centered on origin
                        vec.x = (x * xSpace) - halfWidth;
                        vec.y = (y * ySpace) - halfHeight;
                        vec.z = 0.0f;

                        // transform by orientation and distance
                        vec = xform * vec;

                        // assign to geometry
                        *pData++ = vec.x;
                        *pData++ = vec.y;
                        *pData++ = vec.z;

                        // build bounds as we go
                        if (firstTime) {
                            min = vec;
                            max = vec;
                            maxSquaredLength = vec.LengthSquared;
                            firstTime = false;
                        } else {
                            min.Floor(vec);
                            max.Ceil(vec);
                            maxSquaredLength = MathUtil.Max(maxSquaredLength, vec.LengthSquared);
                        }

                        if (normals) {
                            norm = Vector3.UnitZ;
                            norm = orientation * norm;

                            *pData++ = vec.x;
                            *pData++ = vec.y;
                            *pData++ = vec.z;
                        }

                        // generate texture coordinates, normalize position, modify by orientation to return +y up
                        vec = orientation.Inverse() * vec;
                        vec.Normalize();

                        // find distance to sphere
                        sphereDistance = MathUtil.Sqrt(cameraPosition * cameraPosition * (vec.y * vec.y - 1.0f) + sphereRadius * sphereRadius) - cameraPosition * vec.y;

                        vec.x *= sphereDistance;
                        vec.z *= sphereDistance;

                        // use x and y on sphere as texture coordinates, tiled
                        float s = vec.x * (0.01f * uTiles);
                        float t = vec.z * (0.01f * vTiles);
                        for (int i = 0; i < numberOfTexCoordSets; i++) {
                            *pData++ = s;
                            *pData++ = (1 - t);
                        }
                    } // x
                } // y

                // unlock the buffer
                vertexBuffer.Unlock();
            } // unsafe
        }
Exemple #22
0
		private void _generateCurvedIllusionPlaneVertexData( HardwareVertexBuffer vertexBuffer, int ySegments, int xSegments, float xSpace, float halfWidth, float ySpace, float halfHeight, Matrix4 xform, bool firstTime, bool normals, Quaternion orientation, float curvature, float uTiles, float vTiles, int numberOfTexCoordSets, ref Vector3 min, ref Vector3 max, ref float maxSquaredLength )
		{
			// Imagine a large sphere with the camera located near the top
			// The lower the curvature, the larger the sphere
			// Use the angle from viewer to the points on the plane
			// Credit to Aftershock for the general approach
			Real cameraPosition;      // Camera position relative to sphere center

			// Derive sphere radius
			//Vector3 vertPos;  // position relative to camera
			//Real sphDist;      // Distance from camera to sphere along box vertex vector
			// Vector3 camToSph; // camera position to sphere
			Real sphereRadius;// Sphere radius
			// Actual values irrelevant, it's the relation between sphere radius and camera position that's important
			Real sphRadius = 100.0f;
			Real camDistance = 5.0f;

			sphereRadius = sphRadius - curvature;
			cameraPosition = sphereRadius - camDistance;

			Vector3 vec;
			Vector3 norm;
			float sphereDistance;
			unsafe
			{
				// lock the vertex buffer
				IntPtr data = vertexBuffer.Lock( BufferLocking.Discard );

				float* pData = (float*)data.ToPointer();

				for ( int y = 0; y < ySegments + 1; ++y )
				{
					for ( int x = 0; x < xSegments + 1; ++x )
					{
						// centered on origin
						vec.x = ( x * xSpace ) - halfWidth;
						vec.y = ( y * ySpace ) - halfHeight;
						vec.z = 0.0f;

						// transform by orientation and distance
						vec = xform * vec;

						// assign to geometry
						*pData++ = vec.x;
						*pData++ = vec.y;
						*pData++ = vec.z;

						// build bounds as we go
						if ( firstTime )
						{
							min = vec;
							max = vec;
							maxSquaredLength = vec.LengthSquared;
							firstTime = false;
						}
						else
						{
							min.Floor( vec );
							max.Ceil( vec );
							maxSquaredLength = Utility.Max( maxSquaredLength, vec.LengthSquared );
						}

						if ( normals )
						{
							norm = Vector3.UnitZ;
							norm = orientation * norm;

							*pData++ = vec.x;
							*pData++ = vec.y;
							*pData++ = vec.z;
						}

						// generate texture coordinates, normalize position, modify by orientation to return +y up
						vec = orientation.Inverse() * vec;
						vec.Normalize();

						// find distance to sphere
						sphereDistance = Utility.Sqrt( cameraPosition * cameraPosition * ( vec.y * vec.y - 1.0f ) + sphereRadius * sphereRadius ) - cameraPosition * vec.y;

						vec.x *= sphereDistance;
						vec.z *= sphereDistance;

						// use x and y on sphere as texture coordinates, tiled
						float s = vec.x * ( 0.01f * uTiles );
						float t = vec.z * ( 0.01f * vTiles );
						for ( int i = 0; i < numberOfTexCoordSets; i++ )
						{
							*pData++ = s;
							*pData++ = ( 1 - t );
						}
					} // x
				} // y

				// unlock the buffer
				vertexBuffer.Unlock();
			} // unsafe
		}
Exemple #23
0
		/// <summary>
		///		Updates the face normals for this edge list based on (changed)
		///		position information, useful for animated objects. 
		/// </summary>
		/// <param name="vertexSet">The vertex set we are updating.</param>
		/// <param name="positionBuffer">The updated position buffer, must contain ONLY xyz.</param>
		public void UpdateFaceNormals( int vertexSet, HardwareVertexBuffer positionBuffer )
		{
#if !AXIOM_SAFE_ONLY
			unsafe
#endif
			{
				Debug.Assert( positionBuffer.VertexSize == sizeof ( float )*3, "Position buffer should contain only positions!" );

				// Lock buffer for reading
				var posPtr = positionBuffer.Lock( BufferLocking.ReadOnly );
				var pVert = posPtr.ToFloatPointer();

				// Iterate over the triangles
				for ( var i = 0; i < this.triangles.Count; i++ )
				{
					var t = (Triangle)this.triangles[ i ];

					// Only update tris which are using this vertex set
					if ( t.vertexSet == vertexSet )
					{
						var offset = t.vertIndex[ 0 ]*3;
						var v1 = new Vector3( pVert[ offset ], pVert[ offset + 1 ], pVert[ offset + 2 ] );

						offset = t.vertIndex[ 1 ]*3;
						var v2 = new Vector3( pVert[ offset ], pVert[ offset + 1 ], pVert[ offset + 2 ] );

						offset = t.vertIndex[ 2 ]*3;
						var v3 = new Vector3( pVert[ offset ], pVert[ offset + 1 ], pVert[ offset + 2 ] );

						t.normal = Utility.CalculateFaceNormal( v1, v2, v3 );
					}
				}
			}

			// unlock the buffer
			positionBuffer.Unlock();
		}
		protected void WriteGeometryVertexBuffer( BinaryWriter writer, short bindIndex, HardwareVertexBuffer vertexBuffer )
		{
			var start_offset = writer.Seek( 0, SeekOrigin.Current );
			WriteChunk( writer, MeshChunkID.GeometryVertexBuffer, 0 );

			WriteShort( writer, bindIndex );
			WriteShort( writer, (short)vertexBuffer.VertexSize );
			var buf = vertexBuffer.Lock( BufferLocking.Discard );
			try
			{
				WriteGeometryVertexBufferData( writer, vertexBuffer.Size, buf );
			}
			finally
			{
				vertexBuffer.Unlock();
			}

			var end_offset = writer.Seek( 0, SeekOrigin.Current );
			writer.Seek( (int)start_offset, SeekOrigin.Begin );
			WriteChunk( writer, MeshChunkID.GeometryVertexBuffer, (int)( end_offset - start_offset ) );
			writer.Seek( (int)end_offset, SeekOrigin.Begin );
		}
Exemple #25
0
		/// <summary>
		///     Performs a software vertex morph, of the kind used for
		///     morph animation although it can be used for other purposes.
		/// </summary>
		/// <remarks>
		///   	This function will linearly interpolate positions between two
		/// 	source buffers, into a third buffer.
		/// </remarks>
		/// <param name="t">Parametric distance between the start and end buffer positions</param>
		/// <param name="b1">Vertex buffer containing VertexElementType.Float3 entries for the start positions</param>
		/// <param name="b2">Vertex buffer containing VertexElementType.Float3 entries for the end positions</param>
		/// <param name="targetVertexData"> VertexData destination; assumed to have a separate position
		///	     buffer already bound, and the number of vertices must agree with the
		///   number in start and end
		/// </param>
		public static void SoftwareVertexMorph( float t, HardwareVertexBuffer b1, HardwareVertexBuffer b2,
		                                        VertexData targetVertexData )
		{
#if !AXIOM_SAFE_ONLY
			unsafe
#endif
			{
				var bpb1 = b1.Lock( BufferLocking.ReadOnly ).ToFloatPointer();
				var pb1 = 0;
				var bpb2 = b2.Lock( BufferLocking.ReadOnly ).ToFloatPointer();
				var pb2 = 0;
				var posElem = targetVertexData.vertexDeclaration.FindElementBySemantic( VertexElementSemantic.Position );
				Debug.Assert( posElem != null );
				var destBuf = targetVertexData.vertexBufferBinding.GetBuffer( posElem.Source );
				Debug.Assert( posElem.Size == destBuf.VertexSize, "Positions must be in a buffer on their own for morphing" );
				var bpdst = destBuf.Lock( BufferLocking.Discard ).ToFloatPointer();
				var pdst = 0;
				for ( var i = 0; i < targetVertexData.vertexCount; ++i )
				{
					// x
					bpdst[ pdst++ ] = bpb1[ pb1 ] + t*( bpb2[ pb2 ] - bpb1[ pb1 ] );
					++pb1;
					++pb2;
					// y
					bpdst[ pdst++ ] = bpb1[ pb1 ] + t*( bpb2[ pb2 ] - bpb1[ pb1 ] );
					++pb1;
					++pb2;
					// z
					bpdst[ pdst++ ] = bpb1[ pb1 ] + t*( bpb2[ pb2 ] - bpb1[ pb1 ] );
					++pb1;
					++pb2;
				}
				destBuf.Unlock();
				b1.Unlock();
				b2.Unlock();
			}
		}
        private void ReadBuffer(HardwareVertexBuffer vBuffer, int vertexOffset, int vertexStride, int vertexCount, int vertexSize, uint[] data)
        {
            IntPtr bufData = vBuffer.Lock(BufferLocking.ReadOnly);
            int intOffset = vertexOffset / sizeof(int);
            int intStride = vertexStride / sizeof(int);
            Debug.Assert(vertexOffset % sizeof(int) == 0);

            unsafe {
                uint* pInts = (uint*)bufData.ToPointer();
                for (int i = 0; i < vertexCount; ++i) {
                    Debug.Assert(sizeof(int) * i < vertexCount * vertexStride,
                        "Read off end of vertex buffer");
                    data[i] = pInts[i * intStride + intOffset];
                }
            }

            // unlock the buffer
            vBuffer.Unlock();
        }
Exemple #27
0
		private void _generateCurvedPlaneVertexData( HardwareVertexBuffer vbuf, int ySegments, int xSegments, float xSpace, float halfWidth, float ySpace, float halfHeight, Matrix4 transform, bool firstTime, bool normals, Matrix4 rotation, float curvature, int numTexCoordSets, float xTexCoord, float yTexCoord, SubMesh subMesh, ref Vector3 min, ref Vector3 max, ref float maxSquaredLength )
		{
			Vector3 vec;
			unsafe
			{
				// lock the vertex buffer
				IntPtr data = vbuf.Lock( BufferLocking.Discard );

				float* pData = (float*)data.ToPointer();

				for ( int y = 0; y <= ySegments; y++ )
				{
					for ( int x = 0; x <= xSegments; x++ )
					{
						// centered on origin
						vec.x = ( x * xSpace ) - halfWidth;
						vec.y = ( y * ySpace ) - halfHeight;

						// Here's where curved plane is different from standard plane.  Amazing, I know.
						Real diff_x = ( x - ( (Real)xSegments / 2 ) ) / (Real)xSegments;
						Real diff_y = ( y - ( (Real)ySegments / 2 ) ) / (Real)ySegments;
						Real dist = Utility.Sqrt( diff_x * diff_x + diff_y * diff_y );
						vec.z = ( -Utility.Sin( ( 1 - dist ) * ( Utility.PI / 2 ) ) * curvature ) + curvature;

						// Transform by orientation and distance
						Vector3 pos = transform.TransformAffine( vec );

						*pData++ = pos.x;
						*pData++ = pos.y;
						*pData++ = pos.z;

						// Build bounds as we go
						if ( firstTime )
						{
							min = vec;
							max = vec;
							maxSquaredLength = vec.LengthSquared;
							firstTime = false;
						}
						else
						{
							min.Floor( vec );
							max.Ceil( vec );
							maxSquaredLength = Utility.Max( maxSquaredLength, vec.LengthSquared );
						}

						if ( normals )
						{
							// This part is kinda 'wrong' for curved planes... but curved planes are
							//   very valuable outside sky planes, which don't typically need normals
							//   so I'm not going to mess with it for now.

							// Default normal is along unit Z
							//vec = Vector3::UNIT_Z;
							// Rotate
							vec = rotation.TransformAffine( vec );

							*pData++ = vec.x;
							*pData++ = vec.y;
							*pData++ = vec.z;
						}

						for ( int i = 0; i < numTexCoordSets; i++ )
						{
							*pData++ = x * xTexCoord;
							*pData++ = 1 - ( y * yTexCoord );
						} // for texCoords
					} // for x
				} // for y

				// unlock the buffer
				vbuf.Unlock();

				subMesh.useSharedVertices = true;

			} // unsafe
		}
        /// <summary>
        ///   Fill a vertex buffer with the contents of a two dimensional 
        ///   float array
        /// </summary>
        /// <param name="vBuffer">HardwareVertexBuffer to populate</param>
        /// <param name="vertexCount">the number of vertices</param>
        /// <param name="vertexSize">the size of each vertex</param>
        /// <param name="vertexOffset">the offset (in bytes) of this element in the vertex buffer</param>
        /// <param name="vertexStride">the stride (in bytes) between vertices</param>
        /// <param name="data">the array of data to put in the buffer</param>
        internal static void FillBuffer( HardwareVertexBuffer vBuffer, int vertexCount, int vertexSize,
                                       int vertexOffset, int vertexStride, uint[ , ] data )
        {
            int count = data.GetLength( 1 );
            IntPtr bufData = vBuffer.Lock( BufferLocking.Discard );

            int uintStride = vertexStride / sizeof( uint );
            int uintOffset = vertexOffset / sizeof( uint );
            unsafe
            {
                uint* pUints = (uint*) bufData.ToPointer();
                for( int i = 0; i < vertexCount; ++i )
                    for( int j = 0; j < count; ++j )
                    {
                        Debug.Assert( sizeof( uint ) * (i * uintStride + uintOffset + j) < vertexCount * vertexSize,
                            "Wrote off end of vertex buffer" );
                        pUints[ i * uintStride + uintOffset + j ] = data[ i, j ];
                    }
            }

            // unlock the buffer
            vBuffer.Unlock();
        }
Exemple #29
0
        public List <TriangleVertices> Build()
        {
            List <TriangleVertices> triangles = new  List <TriangleVertices>();

            try {
                for (int ind = 0, indexSet = 0; ind < indexDataList.Count; ind++, indexSet++)
                {
                    int vertexSet = (int)indexDataVertexDataSetList[ind];

                    IndexData     indexData = (IndexData)indexDataList[indexSet];
                    OperationType opType    = operationTypes[indexSet];

                    int iterations = 0;

                    switch (opType)
                    {
                    case OperationType.TriangleList:
                        iterations = indexData.indexCount / 3;
                        break;

                    case OperationType.TriangleFan:
                    case OperationType.TriangleStrip:
                        iterations = indexData.indexCount - 2;
                        break;
                    }

                    // locate position element & the buffer to go with it
                    VertexData    vertexData = (VertexData)vertexDataList[vertexSet];
                    VertexElement posElem    =
                        vertexData.vertexDeclaration.FindElementBySemantic(VertexElementSemantic.Position);

                    HardwareVertexBuffer posBuffer = vertexData.vertexBufferBinding.GetBuffer(posElem.Source);
                    try {
                        IntPtr posPtr = posBuffer.Lock(BufferLocking.ReadOnly);
                        IntPtr idxPtr = indexData.indexBuffer.Lock(BufferLocking.ReadOnly);

                        unsafe {
                            byte *pBaseVertex = (byte *)posPtr.ToPointer();

                            ushort *p16Idx = null;
                            uint *  p32Idx = null;

                            // counters used for pointer indexing
                            int count16 = 0;
                            int count32 = 0;

                            if (indexData.indexBuffer.Type == IndexType.Size16)
                            {
                                p16Idx = (ushort *)idxPtr.ToPointer();
                            }
                            else
                            {
                                p32Idx = (uint *)idxPtr.ToPointer();
                            }

                            float *pReal = null;

                            int triStart = triangles.Count;

                            // iterate over all the groups of 3 indices
                            triangles.Capacity = triStart + iterations;

                            uint[] index = new uint[3];

                            for (int t = 0; t < iterations; t++)
                            {
                                Vector3[]        v      = new Vector3[3];
                                TriangleVertices tri    = new TriangleVertices(v);
                                bool             broken = false;
                                for (int i = 0; i < 3; i++)
                                {
                                    // Standard 3-index read for tri list or first tri in strip / fan
                                    if (opType == OperationType.TriangleList || t == 0)
                                    {
                                        if (indexData.indexBuffer.Type == IndexType.Size32)
                                        {
                                            index[i] = p32Idx[count32++];
                                        }
                                        else
                                        {
                                            index[i] = p16Idx[count16++];
                                        }
                                    }
                                    else
                                    {
                                        // Strips and fans are formed from last 2 indexes plus the
                                        // current one for triangles after the first
                                        if (indexData.indexBuffer.Type == IndexType.Size32)
                                        {
                                            index[i] = p32Idx[i - 2];
                                        }
                                        else
                                        {
                                            index[i] = p16Idx[i - 2];
                                        }

                                        // Perform single-index increment at the last tri index
                                        if (i == 2)
                                        {
                                            if (indexData.indexBuffer.Type == IndexType.Size32)
                                            {
                                                count32++;
                                            }
                                            else
                                            {
                                                count16++;
                                            }
                                        }
                                    }

                                    // Retrieve the vertex position
                                    if (index[i] >= posBuffer.VertexCount)
                                    {
                                        log.InfoFormat("TriangleListBuilder.Build: Error: index[i] {0} is not less than posBuffer.VertexCount {1}, iteration t {2}",
                                                       index[i], posBuffer.VertexCount, t);
                                        broken = true;
                                        break;
                                    }
                                    Debug.Assert(index[i] < posBuffer.VertexCount);
                                    byte *pVertex = pBaseVertex + (index[i] * posBuffer.VertexSize);
                                    pReal  = (float *)(pVertex + posElem.Offset);
                                    v[i].x = *pReal++;
                                    v[i].y = *pReal++;
                                    v[i].z = *pReal++;
                                }
                                if (!broken)
                                {
                                    // Put the points in in counter-clockwise order
                                    if (((v[0].x - v[2].x) * (v[1].y - v[2].y) - (v[1].x - v[2].x) * (v[0].y - v[2].y)) < 0)
                                    {
                                        // Clockwise, so reverse points 1 and 2
                                        Vector3 tmp = v[1];
                                        v[1] = v[2];
                                        v[2] = tmp;
                                    }
                                    // Debug.Assert(((v[0].x - v[2].x) * (v[1].y - v[2].y) - (v[1].x - v[2].x) * (v[0].y - v[2].y)) >= 0);
                                    // Add to the list of triangles
                                    triangles.Add(new TriangleVertices(v));
                                }
                            } // for iterations
                        }     // unsafe
                    }
                    finally {
                        // unlock those buffers!
                        indexData.indexBuffer.Unlock();
                        posBuffer.Unlock();
                    }
                }
                return(triangles);
            }
            catch (Exception e) {
                log.ErrorFormat("TriangleListBuilder.Build: Exception raised during triangle building: {0}", e.Message);
                triangles.Clear();
                return(triangles);
            }
        }
        protected unsafe byte *CopyVertices(HardwareVertexBuffer srcBuf, byte *pDst, List<VertexElement> elems, QueuedGeometry geom, Vector3 regionCenter)
        {
            // lock source
            IntPtr src = srcBuf.Lock(BufferLocking.ReadOnly);
            int bufInc = srcBuf.VertexSize;

            byte * pSrc = (byte *)src.ToPointer();
            float * pSrcReal;
            float * pDstReal;
            Vector3 temp = Vector3.Zero;

            // Calculate elem sizes outside the loop
            int [] elemSizes = new int[elems.Count];
            for (int i=0; i<elems.Count; i++)
                elemSizes[i] = VertexElement.GetTypeSize(elems[i].Type);

            // Move the position offset calculation outside the loop
            Vector3 positionDelta = geom.position - regionCenter;

            for(int v = 0; v < geom.geometry.vertexData.vertexCount; ++v)
            {
                // iterate over vertex elements
                for (int i=0; i<elems.Count; i++) {
                    VertexElement elem = elems[i];
                    pSrcReal = (float *)(pSrc + elem.Offset);
                    pDstReal = (float *)(pDst + elem.Offset);

                    switch(elem.Semantic)
                    {
                        case VertexElementSemantic.Position:
                            temp.x = *pSrcReal++;
                            temp.y = *pSrcReal++;
                            temp.z = *pSrcReal++;
                            // transform
                            temp = (geom.orientation * (temp * geom.scale));
                            *pDstReal++ = temp.x + positionDelta.x;
                            *pDstReal++ = temp.y + positionDelta.y;
                            *pDstReal++ = temp.z + positionDelta.z;
                            break;
                        case VertexElementSemantic.Normal:
                        case VertexElementSemantic.Tangent:
                        case VertexElementSemantic.Binormal:
                            temp.x = *pSrcReal++;
                            temp.y = *pSrcReal++;
                            temp.z = *pSrcReal++;
                            // rotation only
                            temp = geom.orientation * temp;
                            *pDstReal++ = temp.x;
                            *pDstReal++ = temp.y;
                            *pDstReal++ = temp.z;
                            break;
                        default:
                            // just raw copy
                            int size = elemSizes[i];
                            // Optimize the loop for the case that
                            // these things are in units of 4
                            if ((size & 0x3) == 0x0) {
                                int cnt = size / 4;
                                while (cnt-- > 0)
                                    *pDstReal++ = *pSrcReal++;
                            }
                            else {
                                // Fall back to the byte-by-byte copy
                                byte * pbSrc = (byte*)pSrcReal;
                                byte * pbDst = (byte*)pDstReal;
                                while(size-- > 0)
                                    *pbDst++ = *pbSrc++;
                            }
                            break;
                    }
                }

                // Increment both pointers
                pDst += bufInc;
                pSrc += bufInc;
            }

            srcBuf.Unlock();
            return pDst;
        }
Exemple #31
0
		/// <summary>
		///		Modifies the vertex data to be suitable for use for rendering shadow geometry.
		/// </summary>
		/// <remarks>
		///		<para>
		///			Preparing vertex data to generate a shadow volume involves firstly ensuring that the
		///			vertex buffer containing the positions is a standalone vertex buffer,
		///			with no other components in it. This method will therefore break apart any existing
		///			vertex buffers if position is sharing a vertex buffer.
		///			Secondly, it will double the size of this vertex buffer so that there are 2 copies of
		///			the position data for the mesh. The first half is used for the original, and the second
		///			half is used for the 'extruded' version. The vertex count used to render will remain
		///			the same though, so as not to add any overhead to regular rendering of the object.
		///			Both copies of the position are required in one buffer because shadow volumes stretch
		///			from the original mesh to the extruded version.
		///		</para>
		///		<para>
		///			It's important to appreciate that this method can fundamentally change the structure of your
		///			vertex buffers, although in reality they will be new buffers. As it happens, if other
		///			objects are using the original buffers then they will be unaffected because the reference
		///			counting will keep them intact. However, if you have made any assumptions about the
		///			structure of the vertex data in the buffers of this object, you may have to rethink them.
		///		</para>
		/// </remarks>
		public void PrepareForShadowVolume()
		{
			/* NOTE
			Sinbad would dearly, dearly love to just use a 4D position buffer in order to
			store the extra 'w' value I need to differentiate between extruded and
			non-extruded sections of the buffer, so that vertex programs could use that.
			Hey, it works fine for GL. However, D3D9 in it's infinite stupidity, does not
			support 4d position vertices in the fixed-function pipeline. If you use them,
			you just see nothing. Since we can't know whether the application is going to use
			fixed function or vertex programs, we have to stick to 3d position vertices and
			store the 'w' in a separate 1D texture coordinate buffer, which is only used
			when rendering the shadow.
			*/

			// Upfront, lets check whether we have vertex program capability
			RenderSystem renderSystem = Root.Instance.RenderSystem;
			bool useVertexPrograms = false;

			if ( renderSystem != null && renderSystem.Capabilities.HasCapability( Capabilities.VertexPrograms ) )
			{
				useVertexPrograms = true;
			}

			// Look for a position element
			VertexElement posElem =	vertexDeclaration.FindElementBySemantic( VertexElementSemantic.Position );

			if ( posElem != null )
			{
				short posOldSource = posElem.Source;

				HardwareVertexBuffer vbuf = vertexBufferBinding.GetBuffer( posOldSource );

				bool wasSharedBuffer = false;

				// Are there other elements in the buffer except for the position?
				if ( vbuf.VertexSize > posElem.Size )
				{
					// We need to create another buffer to contain the remaining elements
					// Most drivers don't like gaps in the declaration, and in any case it's waste
					wasSharedBuffer = true;
				}

				HardwareVertexBuffer newPosBuffer = null, newRemainderBuffer = null;
                VertexDeclaration newRemainderDeclaration = (VertexDeclaration)vertexDeclaration.Clone();

				if ( wasSharedBuffer )
				{
                    bool found = false;
                    int index = 0;
                    do 
                    {
                        if (newRemainderDeclaration.GetElement(index).Semantic == VertexElementSemantic.Position)
                        {
                            newRemainderDeclaration.RemoveElement(index);
                            found = true;
                        }
                        index++;
                    } while ( !found );

					newRemainderBuffer = HardwareBufferManager.Instance.CreateVertexBuffer( newRemainderDeclaration, vbuf.VertexCount, vbuf.Usage, vbuf.HasShadowBuffer );
				}

				// Allocate new position buffer, will be FLOAT3 and 2x the size
				int oldVertexCount = vbuf.VertexCount;
				int newVertexCount = oldVertexCount * 2;

                VertexDeclaration newPosDecl = HardwareBufferManager.Instance.CreateVertexDeclaration();
                newPosDecl.AddElement( 0, 0, VertexElementType.Float3, VertexElementSemantic.Position );
                newPosBuffer = HardwareBufferManager.Instance.CreateVertexBuffer( newPosDecl, newVertexCount, vbuf.Usage, vbuf.HasShadowBuffer );

				// Iterate over the old buffer, copying the appropriate elements and initializing the rest
				IntPtr baseSrcPtr = vbuf.Lock( BufferLocking.ReadOnly );

				// Point first destination pointer at the start of the new position buffer,
				// the other one half way along
				IntPtr destPtr = newPosBuffer.Lock( BufferLocking.Discard );
				// oldVertexCount * 3 * 4, since we are dealing with byte offsets here
				IntPtr dest2Ptr = new IntPtr( destPtr.ToInt64() + ( oldVertexCount * 12 ) );

				int prePosVertexSize = 0;
				int postPosVertexSize = 0;
				int postPosVertexOffset = 0;

				if ( wasSharedBuffer )
				{
					// Precalculate any dimensions of vertex areas outside the position
					prePosVertexSize = posElem.Offset;
					postPosVertexOffset = prePosVertexSize + posElem.Size;
					postPosVertexSize = vbuf.VertexSize - postPosVertexOffset;

					// the 2 separate bits together should be the same size as the remainder buffer vertex
					Debug.Assert( newRemainderBuffer.VertexSize == ( prePosVertexSize + postPosVertexSize ) );

					IntPtr baseDestRemPtr = newRemainderBuffer.Lock( BufferLocking.Discard );

					int baseSrcOffset = 0;
					int baseDestRemOffset = 0;

					unsafe
					{
						float* pDest = (float*)destPtr.ToPointer();
						float* pDest2 = (float*)dest2Ptr.ToPointer();

						int destCount = 0, dest2Count = 0;

						// Iterate over the vertices
						for ( int v = 0; v < oldVertexCount; v++ )
						{
							float* pSrc = (float*)( (byte*)baseSrcPtr.ToPointer() + posElem.Offset + baseSrcOffset );

							// Copy position, into both buffers
							pDest[ destCount++ ] = pDest2[ dest2Count++ ] = pSrc[ 0 ];
							pDest[ destCount++ ] = pDest2[ dest2Count++ ] = pSrc[ 1 ];
							pDest[ destCount++ ] = pDest2[ dest2Count++ ] = pSrc[ 2 ];

							// now deal with any other elements
							// Basically we just memcpy the vertex excluding the position
							if ( prePosVertexSize > 0 )
							{
								Memory.Copy( baseSrcPtr, baseDestRemPtr, baseSrcOffset, baseDestRemOffset, prePosVertexSize );
							}

							if ( postPosVertexSize > 0 )
							{
								Memory.Copy( baseSrcPtr, baseDestRemPtr, baseSrcOffset + postPosVertexOffset, baseDestRemOffset + prePosVertexSize, postPosVertexSize );
							}

							// increment the pointer offsets
							baseDestRemOffset += newRemainderBuffer.VertexSize;
							baseSrcOffset += vbuf.VertexSize;
						} // next vertex
					} // unsafe
				}
				else
				{
					// copy the data directly
					Memory.Copy( baseSrcPtr, destPtr, vbuf.Size );
					Memory.Copy( baseSrcPtr, dest2Ptr, vbuf.Size );
				}

				vbuf.Unlock();
				newPosBuffer.Unlock();

				if ( wasSharedBuffer )
				{
					newRemainderBuffer.Unlock();
				}

				// At this stage, he original vertex buffer is going to be destroyed
				// So we should force the deallocation of any temporary copies
				HardwareBufferManager.Instance.ForceReleaseBufferCopies( vbuf );

				if ( useVertexPrograms )
				{
					unsafe
					{
                        VertexDeclaration decl = HardwareBufferManager.Instance.CreateVertexDeclaration();
                        decl.AddElement(0, 0, VertexElementType.Float1, VertexElementSemantic.Position);

						// Now it's time to set up the w buffer
						hardwareShadowVolWBuffer = HardwareBufferManager.Instance.CreateVertexBuffer( decl,	newVertexCount,	BufferUsage.StaticWriteOnly, false );

						// Fill the first half with 1.0, second half with 0.0
						IntPtr wPtr = hardwareShadowVolWBuffer.Lock( BufferLocking.Discard );
						float* pDest = (float*)wPtr.ToPointer();
						int destCount = 0;

						for ( int v = 0; v < oldVertexCount; v++ )
						{
							pDest[ destCount++ ] = 1.0f;
						}
						for ( int v = 0; v < oldVertexCount; v++ )
						{
							pDest[ destCount++ ] = 0.0f;
						}
					} // unsafe

					hardwareShadowVolWBuffer.Unlock();
				} // if vertexPrograms

				short newPosBufferSource = 0;

				if ( wasSharedBuffer )
				{
					// Get the a new buffer binding index
					newPosBufferSource = vertexBufferBinding.NextIndex;

					// Re-bind the old index to the remainder buffer
					vertexBufferBinding.SetBinding( posOldSource, newRemainderBuffer );
				}
				else
				{
					// We can just re-use the same source idex for the new position buffer
					newPosBufferSource = posOldSource;
				}

				// Bind the new position buffer
				vertexBufferBinding.SetBinding( newPosBufferSource, newPosBuffer );

				// Now, alter the vertex declaration to change the position source
				// and the offsets of elements using the same buffer
				for ( int i = 0; i < vertexDeclaration.ElementCount; i++ )
				{
					VertexElement element = vertexDeclaration.GetElement( i );

					if ( element.Semantic == VertexElementSemantic.Position )
					{
						// Modify position to point at new position buffer
						vertexDeclaration.ModifyElement( i, newPosBufferSource /* new source buffer */,  0 /* no offset now */, VertexElementType.Float3, VertexElementSemantic.Position );
					}
					else if ( wasSharedBuffer &&
						element.Source == posOldSource &&
						element.Offset > prePosVertexSize )
					{
						// This element came after position, remove the position's size
						vertexDeclaration.ModifyElement( i, posOldSource /* same old source */, 	element.Offset - posElem.Size /* less offset now */, element.Type, element.Semantic, element.Index );
					}
				}
			} // if posElem != null
		}
        protected void SetPointsImpl(List <Vector3> points, List <ColorEx> colors, List <List <VertexBoneAssignment> > boneAssignments)
        {
            if (colors != null && points.Count != colors.Count)
            {
                throw new Exception("Invalid parameters to SetPoints.  Point list length does not match colors list length");
            }
            Vector3 min = Vector3.Zero;
            Vector3 max = Vector3.Zero;

            // set up vertex data
            vertexData = new VertexData();

            // set up vertex declaration
            VertexDeclaration vertexDeclaration = vertexData.vertexDeclaration;
            int currentOffset = 0;

            // always need positions
            vertexDeclaration.AddElement(0, currentOffset, VertexElementType.Float3, VertexElementSemantic.Position);
            currentOffset += VertexElement.GetTypeSize(VertexElementType.Float3);
            int colorOffset = currentOffset / sizeof(float);

            if (colors != null)
            {
                vertexDeclaration.AddElement(0, currentOffset, VertexElementType.Color, VertexElementSemantic.Diffuse);
                currentOffset += VertexElement.GetTypeSize(VertexElementType.Color);
            }
            int boneIndexOffset = currentOffset / sizeof(float);

            if (boneAssignments != null)
            {
                vertexDeclaration.AddElement(0, currentOffset, VertexElementType.UByte4, VertexElementSemantic.BlendIndices);
                currentOffset += VertexElement.GetTypeSize(VertexElementType.UByte4);
            }
            int boneWeightOffset = currentOffset / sizeof(float);

            if (boneAssignments != null)
            {
                vertexDeclaration.AddElement(0, currentOffset, VertexElementType.Float4, VertexElementSemantic.BlendWeights);
                currentOffset += VertexElement.GetTypeSize(VertexElementType.Float4);
            }
            int stride = currentOffset / sizeof(float);

            vertexData.vertexCount = points.Count;

            // allocate vertex buffer
            HardwareVertexBuffer vertexBuffer = HardwareBufferManager.Instance.CreateVertexBuffer(vertexDeclaration.GetVertexSize(0), vertexData.vertexCount, BufferUsage.StaticWriteOnly);

            // set up the binding, one source only
            VertexBufferBinding binding = vertexData.vertexBufferBinding;

            binding.SetBinding(0, vertexBuffer);

            // Generate vertex data
            unsafe {
                // lock the vertex buffer
                IntPtr data = vertexBuffer.Lock(BufferLocking.Discard);

                byte * pData  = (byte *)data.ToPointer();
                float *pFloat = (float *)pData;
                uint * pInt   = (uint *)pData;
                for (int i = 0; i < points.Count; ++i)
                {
                    Vector3 vec = points[i];
                    // assign to geometry
                    pFloat[stride * i]     = vec.x;
                    pFloat[stride * i + 1] = vec.y;
                    pFloat[stride * i + 2] = vec.z;
                    if (colors != null)
                    {
                        // assign to diffuse
                        pInt[stride * i + colorOffset] = Root.Instance.RenderSystem.ConvertColor(colors[i]);
                    }
                    if (boneAssignments != null)
                    {
                        for (int j = 0; j < 4; ++j)
                        {
                            pData[4 * (stride * i + boneIndexOffset) + j] = (byte)(boneAssignments[i][j].boneIndex);
                            pFloat[stride * i + boneWeightOffset + j]     = boneAssignments[i][j].weight;
                        }
                    }
                }
                // unlock the buffer
                vertexBuffer.Unlock();
            } // unsafe

            for (int i = 0; i < points.Count; ++i)
            {
                Vector3 vec = points[i];
                // Also update the bounding sphere radius
                float len = vec.Length;
                if (len > boundingSphereRadius)
                {
                    boundingSphereRadius = len;
                }
                // Also update the bounding box
                if (vec.x < min.x)
                {
                    min.x = vec.x;
                }
                if (vec.y < min.y)
                {
                    min.y = vec.y;
                }
                if (vec.z < min.z)
                {
                    min.z = vec.z;
                }
                if (vec.x > max.x)
                {
                    max.x = vec.x;
                }
                if (vec.y > max.y)
                {
                    max.y = vec.y;
                }
                if (vec.z > max.z)
                {
                    max.z = vec.z;
                }
            }

            // Set the SimpleRenderable bounding box
            box = new AxisAlignedBox(min, max);
        }