private void _setupGeometry() { var vertexCount = this._caption.Length * 6; if (renderOperation.vertexData != null) { renderOperation.vertexData = null; this._updateColor = true; } if (renderOperation.vertexData == null) { renderOperation.vertexData = new VertexData(); } renderOperation.indexData = null; renderOperation.vertexData.vertexStart = 0; renderOperation.vertexData.vertexCount = vertexCount; renderOperation.operationType = OperationType.TriangleList; renderOperation.useIndices = false; var decl = renderOperation.vertexData.vertexDeclaration; var bind = renderOperation.vertexData.vertexBufferBinding; var offset = 0; // create/bind positions/tex.ccord. buffer if (decl.FindElementBySemantic(VertexElementSemantic.Position) == null) { decl.AddElement(POS_TEX_BINDING, offset, VertexElementType.Float3, VertexElementSemantic.Position); } offset += VertexElement.GetTypeSize(VertexElementType.Float3); if (decl.FindElementBySemantic(VertexElementSemantic.TexCoords) == null) { decl.AddElement(POS_TEX_BINDING, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 0); } var vbuf = HardwareBufferManager.Instance.CreateVertexBuffer(decl.Clone(POS_TEX_BINDING), renderOperation.vertexData.vertexCount, BufferUsage.DynamicWriteOnly); bind.SetBinding(POS_TEX_BINDING, vbuf); // Colors - store these in a separate buffer because they change less often if (decl.FindElementBySemantic(VertexElementSemantic.Diffuse) == null) { decl.AddElement(COLOR_BINDING, 0, VertexElementType.Color, VertexElementSemantic.Diffuse); } var cbuf = HardwareBufferManager.Instance.CreateVertexBuffer(decl.Clone(COLOR_BINDING), renderOperation.vertexData.vertexCount, BufferUsage.DynamicWriteOnly); bind.SetBinding(COLOR_BINDING, cbuf); var charlen = this._caption.Length; var largestWidth = 0.0f; var left = 0f * 2.0f - 1.0f; var top = -((0f * 2.0f) - 1.0f); // Derive space with from a capital A if (this._spaceWidth == 0) { this._spaceWidth = (int)(this._font.GetGlyphAspectRatio('A') * this._characterHeight * 2.0f); } // for calculation of AABB Vector3 min, max, currPos; var maxSquaredRadius = 0.0f; var first = true; min = max = currPos = Vector3.NegativeUnitY; // Use iterator var newLine = true; var len = 0.0f; if (this._verticalAlignment == VerticalAlignment.Above) { // Raise the first line of the caption top += this._characterHeight; for (var i = 0; i != charlen; i++) { if (this._caption[i] == '\n') { top += this._characterHeight * 2.0f; } } } //Real *pPCBuff = static_cast<Real*>(ptbuf.lock(HardwareBuffer::HBL_DISCARD)); var ipPos = vbuf.Lock(BufferLocking.Discard); var cntPos = 0; #if !AXIOM_SAFE_ONLY unsafe #endif { var pPCBuff = ipPos.ToFloatPointer(); for (var i = 0; i != charlen; i++) { if (newLine) { len = 0.0f; for (var j = i; j != charlen && this._caption[j] != '\n'; j++) { if (this._caption[j] == ' ') { len += this._spaceWidth; } else { len += this._font.GetGlyphAspectRatio(this._caption[j]) * this._characterHeight * 2.0f; } } newLine = false; } if (this._caption[i] == '\n') { left = 0f * 2.0f - 1.0f; top -= this._characterHeight * 2.0f; newLine = true; continue; } if (this._caption[i] == ' ') { // Just leave a gap, no tris left += this._spaceWidth; // Also reduce tri count renderOperation.vertexData.vertexCount -= 6; continue; } var horiz_height = this._font.GetGlyphAspectRatio(this._caption[i]); Real u1, u2, v1, v2; this._font.GetGlyphTexCoords(this._caption[i], out u1, out v1, out u2, out v2); // each vert is (x, y, z, u, v) //------------------------------------------------------------------------------------- // First tri // // Upper left if (this._horizontalAlignment == HorizontalAlignment.Left) { pPCBuff[cntPos++] = left; } else { pPCBuff[cntPos++] = left - (len / 2.0f); } pPCBuff[cntPos++] = top; pPCBuff[cntPos++] = -1.0f; pPCBuff[cntPos++] = u1; pPCBuff[cntPos++] = v1; // Deal with bounds if (this._horizontalAlignment == HorizontalAlignment.Left) { currPos = new Vector3(left, top, -1.0f); } else { currPos = new Vector3(left - (len / 2.0f), top, -1.0f); } if (first) { min = max = currPos; maxSquaredRadius = currPos.LengthSquared; first = false; } else { min.Floor(currPos); max.Ceil(currPos); maxSquaredRadius = Max(maxSquaredRadius, currPos.LengthSquared); } top -= this._characterHeight * 2.0f; // Bottom left if (this._horizontalAlignment == HorizontalAlignment.Left) { pPCBuff[cntPos++] = left; } else { pPCBuff[cntPos++] = left - (len / 2.0f); } pPCBuff[cntPos++] = top; pPCBuff[cntPos++] = -1.0f; pPCBuff[cntPos++] = u1; pPCBuff[cntPos++] = v2; // Deal with bounds if (this._horizontalAlignment == HorizontalAlignment.Left) { currPos = new Vector3(left, top, -1.0f); } else { currPos = new Vector3(left - (len / 2.0f), top, -1.0f); } min.Floor(currPos); max.Ceil(currPos); maxSquaredRadius = Max(maxSquaredRadius, currPos.LengthSquared); top += this._characterHeight * 2.0f; left += horiz_height * this._characterHeight * 2.0f; // Top right if (this._horizontalAlignment == HorizontalAlignment.Left) { pPCBuff[cntPos++] = left; } else { pPCBuff[cntPos++] = left - (len / 2.0f); } pPCBuff[cntPos++] = top; pPCBuff[cntPos++] = -1.0f; pPCBuff[cntPos++] = u2; pPCBuff[cntPos++] = v1; //------------------------------------------------------------------------------------- // Deal with bounds if (this._horizontalAlignment == HorizontalAlignment.Left) { currPos = new Vector3(left, top, -1.0f); } else { currPos = new Vector3(left - (len / 2.0f), top, -1.0f); } min.Floor(currPos); max.Ceil(currPos); maxSquaredRadius = Max(maxSquaredRadius, currPos.LengthSquared); //------------------------------------------------------------------------------------- // Second tri // // Top right (again) if (this._horizontalAlignment == HorizontalAlignment.Left) { pPCBuff[cntPos++] = left; } else { pPCBuff[cntPos++] = left - (len / 2.0f); } pPCBuff[cntPos++] = top; pPCBuff[cntPos++] = -1.0f; pPCBuff[cntPos++] = u2; pPCBuff[cntPos++] = v1; currPos = new Vector3(left, top, -1.0f); min.Floor(currPos); max.Ceil(currPos); maxSquaredRadius = Max(maxSquaredRadius, currPos.LengthSquared); top -= this._characterHeight * 2.0f; left -= horiz_height * this._characterHeight * 2.0f; // Bottom left (again) if (this._horizontalAlignment == HorizontalAlignment.Left) { pPCBuff[cntPos++] = left; } else { pPCBuff[cntPos++] = left - (len / 2.0f); } pPCBuff[cntPos++] = top; pPCBuff[cntPos++] = -1.0f; pPCBuff[cntPos++] = u1; pPCBuff[cntPos++] = v2; currPos = new Vector3(left, top, -1.0f); min.Floor(currPos); max.Ceil(currPos); maxSquaredRadius = Max(maxSquaredRadius, currPos.LengthSquared); left += horiz_height * this._characterHeight * 2.0f; // Bottom right if (this._horizontalAlignment == HorizontalAlignment.Left) { pPCBuff[cntPos++] = left; } else { pPCBuff[cntPos++] = left - (len / 2.0f); } pPCBuff[cntPos++] = top; pPCBuff[cntPos++] = -1.0f; pPCBuff[cntPos++] = u2; pPCBuff[cntPos++] = v2; //------------------------------------------------------------------------------------- currPos = new Vector3(left, top, -1.0f); min.Floor(currPos); max.Ceil(currPos); maxSquaredRadius = Max(maxSquaredRadius, currPos.LengthSquared); // Go back up with top top += this._characterHeight * 2.0f; var currentWidth = (left + 1.0f) / 2.0f - 0.0f; if (currentWidth > largestWidth) { largestWidth = currentWidth; } } } // Unlock vertex buffer vbuf.Unlock(); // update AABB/Sphere radius box = new AxisAlignedBox(min, max); this._radius = Sqrt(maxSquaredRadius); if (this._updateColor) { _updateColors(); } this._needUpdate = false; }
private static void _createCube(Mesh mesh) { var sub = mesh.CreateSubMesh(); const int NUM_VERTICES = 4 * 6; // 4 vertices per side * 6 sides const int NUM_ENTRIES_PER_VERTEX = 8; const int NUM_VERTEX_ENTRIES = NUM_VERTICES * NUM_ENTRIES_PER_VERTEX; const int NUM_INDICES = 3 * 2 * 6; // 3 indices per face * 2 faces per side * 6 sides const float CUBE_SIZE = 100.0f; const float CUBE_HALF_SIZE = CUBE_SIZE / 2.0f; // Create 4 vertices per side instead of 6 that are shared for the whole cube. // The reason for this is with only 6 vertices the normals will look bad // since each vertex can "point" in a different direction depending on the face it is included in. var vertices = new float[NUM_VERTEX_ENTRIES] { // front side -CUBE_HALF_SIZE, -CUBE_HALF_SIZE, CUBE_HALF_SIZE, // pos 0, 0, 1, // normal 0, 1, // texcoord CUBE_HALF_SIZE, -CUBE_HALF_SIZE, CUBE_HALF_SIZE, 0, 0, 1, 1, 1, CUBE_HALF_SIZE, CUBE_HALF_SIZE, CUBE_HALF_SIZE, 0, 0, 1, 1, 0, -CUBE_HALF_SIZE, CUBE_HALF_SIZE, CUBE_HALF_SIZE, 0, 0, 1, 0, 0, // back side CUBE_HALF_SIZE, -CUBE_HALF_SIZE, -CUBE_HALF_SIZE, 0, 0, -1, 0, 1, -CUBE_HALF_SIZE, -CUBE_HALF_SIZE, -CUBE_HALF_SIZE, 0, 0, -1, 1, 1, -CUBE_HALF_SIZE, CUBE_HALF_SIZE, -CUBE_HALF_SIZE, 0, 0, -1, 1, 0, CUBE_HALF_SIZE, CUBE_HALF_SIZE, -CUBE_HALF_SIZE, 0, 0, -1, 0, 0, // left side -CUBE_HALF_SIZE, -CUBE_HALF_SIZE, -CUBE_HALF_SIZE, -1, 0, 0, 0, 1, -CUBE_HALF_SIZE, -CUBE_HALF_SIZE, CUBE_HALF_SIZE, -1, 0, 0, 1, 1, -CUBE_HALF_SIZE, CUBE_HALF_SIZE, CUBE_HALF_SIZE, -1, 0, 0, 1, 0, -CUBE_HALF_SIZE, CUBE_HALF_SIZE, -CUBE_HALF_SIZE, -1, 0, 0, 0, 0, // right side CUBE_HALF_SIZE, -CUBE_HALF_SIZE, CUBE_HALF_SIZE, 1, 0, 0, 0, 1, CUBE_HALF_SIZE, -CUBE_HALF_SIZE, -CUBE_HALF_SIZE, 1, 0, 0, 1, 1, CUBE_HALF_SIZE, CUBE_HALF_SIZE, -CUBE_HALF_SIZE, 1, 0, 0, 1, 0, CUBE_HALF_SIZE, CUBE_HALF_SIZE, CUBE_HALF_SIZE, 1, 0, 0, 0, 0, // up side -CUBE_HALF_SIZE, CUBE_HALF_SIZE, CUBE_HALF_SIZE, 0, 1, 0, 0, 1, CUBE_HALF_SIZE, CUBE_HALF_SIZE, CUBE_HALF_SIZE, 0, 1, 0, 1, 1, CUBE_HALF_SIZE, CUBE_HALF_SIZE, -CUBE_HALF_SIZE, 0, 1, 0, 1, 0, -CUBE_HALF_SIZE, CUBE_HALF_SIZE, -CUBE_HALF_SIZE, 0, 1, 0, 0, 0, // down side -CUBE_HALF_SIZE, -CUBE_HALF_SIZE, -CUBE_HALF_SIZE, 0, -1, 0, 0, 1, CUBE_HALF_SIZE, -CUBE_HALF_SIZE, -CUBE_HALF_SIZE, 0, -1, 0, 1, 1, CUBE_HALF_SIZE, -CUBE_HALF_SIZE, CUBE_HALF_SIZE, 0, -1, 0, 1, 0, -CUBE_HALF_SIZE, -CUBE_HALF_SIZE, CUBE_HALF_SIZE, 0, -1, 0, 0, 0 }; mesh.SharedVertexData = new VertexData(); mesh.SharedVertexData.vertexCount = NUM_VERTICES; var decl = mesh.SharedVertexData.vertexDeclaration; var bind = mesh.SharedVertexData.vertexBufferBinding; var offset = 0; decl.AddElement(0, offset, VertexElementType.Float3, VertexElementSemantic.Position); offset += VertexElement.GetTypeSize(VertexElementType.Float3); decl.AddElement(0, offset, VertexElementType.Float3, VertexElementSemantic.Normal); offset += VertexElement.GetTypeSize(VertexElementType.Float3); decl.AddElement(0, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 0); offset += VertexElement.GetTypeSize(VertexElementType.Float2); var vbuf = HardwareBufferManager.Instance.CreateVertexBuffer(decl, NUM_VERTICES, BufferUsage.StaticWriteOnly); bind.SetBinding(0, vbuf); vbuf.WriteData(0, vbuf.Size, vertices, true); sub.useSharedVertices = true; var ibuf = HardwareBufferManager.Instance.CreateIndexBuffer(IndexType.Size16, NUM_INDICES, BufferUsage.StaticWriteOnly); var faces = new short[NUM_INDICES] { // front 0, 1, 2, 0, 2, 3, // back 4, 5, 6, 4, 6, 7, // left 8, 9, 10, 8, 10, 11, // right 12, 13, 14, 12, 14, 15, // up 16, 17, 18, 16, 18, 19, // down 20, 21, 22, 20, 22, 23 }; sub.IndexData.indexBuffer = ibuf; sub.IndexData.indexCount = NUM_INDICES; sub.IndexData.indexStart = 0; ibuf.WriteData(0, ibuf.Size, faces, true); mesh.BoundingBox = new AxisAlignedBox(new Vector3(-CUBE_HALF_SIZE, -CUBE_HALF_SIZE, -CUBE_HALF_SIZE), new Vector3(CUBE_HALF_SIZE, CUBE_HALF_SIZE, CUBE_HALF_SIZE)); mesh.BoundingSphereRadius = CUBE_HALF_SIZE; }
public void Init(TerrainOptions options) { this.options = options; this.numMipMaps = options.maxMipmap; this.size = options.size; this.terrain = new VertexData(); this.terrain.vertexStart = 0; this.terrain.vertexCount = options.size * options.size; VertexDeclaration decl = this.terrain.vertexDeclaration; VertexBufferBinding binding = this.terrain.vertexBufferBinding; int offset = 0; // Position/Normal decl.AddElement(POSITION, 0, VertexElementType.Float3, VertexElementSemantic.Position); decl.AddElement(NORMAL, 0, VertexElementType.Float3, VertexElementSemantic.Normal); // TexCoords decl.AddElement(TEXCOORD, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 0); offset += VertexElement.GetTypeSize(VertexElementType.Float2); decl.AddElement(TEXCOORD, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 1); offset += VertexElement.GetTypeSize(VertexElementType.Float2); // TODO: Color HardwareVertexBuffer buffer = HardwareBufferManager.Instance.CreateVertexBuffer(decl.Clone(POSITION), this.terrain.vertexCount, BufferUsage.StaticWriteOnly, true); binding.SetBinding(POSITION, buffer); buffer = HardwareBufferManager.Instance.CreateVertexBuffer(decl.Clone(NORMAL), this.terrain.vertexCount, BufferUsage.StaticWriteOnly, true); binding.SetBinding(NORMAL, buffer); buffer = HardwareBufferManager.Instance.CreateVertexBuffer(decl.Clone(TEXCOORD), this.terrain.vertexCount, BufferUsage.StaticWriteOnly, true); binding.SetBinding(TEXCOORD, buffer); this.minLevelDistSqr = new float[this.numMipMaps]; int endx = options.startx + options.size; int endz = options.startz + options.size; // TODO: name buffers different so we can unlock HardwareVertexBuffer posBuffer = binding.GetBuffer(POSITION); var pos = posBuffer.Lock(BufferLocking.Discard); HardwareVertexBuffer texBuffer = binding.GetBuffer(TEXCOORD); var tex = texBuffer.Lock(BufferLocking.Discard); float min = 99999999, max = 0; #if !AXIOM_SAFE_ONLY unsafe #endif { var posPtr = pos.ToFloatPointer(); var texPtr = tex.ToFloatPointer(); int posCount = 0; int texCount = 0; for (int j = options.startz; j < endz; j++) { for (int i = options.startx; i < endx; i++) { float height = options.GetWorldHeight(i, j) * options.scaley; posPtr[posCount++] = i * options.scalex; posPtr[posCount++] = height; posPtr[posCount++] = j * options.scalez; texPtr[texCount++] = (float)i / options.worldSize; texPtr[texCount++] = (float)j / options.worldSize; texPtr[texCount++] = ((float)i / options.size) * options.detailTile; texPtr[texCount++] = ((float)j / options.size) * options.detailTile; if (height < min) { min = height; } if (height > max) { max = height; } } // for i } // for j } // unsafe // unlock the buffers posBuffer.Unlock(); texBuffer.Unlock(); this.box.SetExtents(new Vector3(options.startx * options.scalex, min, options.startz * options.scalez), new Vector3((endx - 1) * options.scalex, max, (endz - 1) * options.scalez)); this.center = new Vector3((options.startx * options.scalex + endx - 1) / 2, (min + max) / 2, (options.startz * options.scalez + endz - 1) / 2); float C = CalculateCFactor(); CalculateMinLevelDist2(C); }
public GeometryBucket(MaterialBucket parent, String formatString, VertexData vData, IndexData iData) : base() { mParent = parent; mFormatString = formatString; mVertexData = null; mIndexData = null; mBatch = mParent.Parent.Parent.Parent; if (mBatch.BaseSkeleton != null) { SetCustomParameter(0, new Vector4(mBatch.BaseSkeleton.BoneCount, 0, 0, 0)); } mVertexData = vData.Clone(false); renderOperation.useIndices = true; renderOperation.indexData = new IndexData(); renderOperation.indexData.indexCount = 0; renderOperation.indexData.indexStart = 0; renderOperation.vertexData = new VertexData(); renderOperation.vertexData.vertexCount = 0; renderOperation.vertexData.vertexDeclaration = (VertexDeclaration)vData.vertexDeclaration.Clone(); mIndexType = iData.indexBuffer.Type; // Derive the max vertices if (mIndexType == IndexType.Size32) { mMaxVertexIndex = 0xFFFFFFFF; } else { mMaxVertexIndex = 0xFFFF; } int offset = 0, tcOffset = 0; short texCoordOffset = 0; short texCoordSource = 0; for (int i = 0; i < renderOperation.vertexData.vertexDeclaration.ElementCount; i++) { if (renderOperation.vertexData.vertexDeclaration.GetElement(i).Semantic == VertexElementSemantic.TexCoords) { texCoordOffset++; texCoordSource = renderOperation.vertexData.vertexDeclaration.GetElement(i).Source; tcOffset = renderOperation.vertexData.vertexDeclaration.GetElement(i).Offset + VertexElement.GetTypeSize( renderOperation.vertexData.vertexDeclaration.GetElement(i).Type); } offset += VertexElement.GetTypeSize(renderOperation.vertexData.vertexDeclaration.GetElement(i).Type); } renderOperation.vertexData.vertexDeclaration.AddElement(texCoordSource, tcOffset, VertexElementType.Float1, VertexElementSemantic.TexCoords, texCoordOffset); mTexCoordIndex = texCoordOffset; }
/// <summary> /// /// </summary> public void Build() { if (mRenderMethod == BillboardMethod.Accelerated) { Clear(); //If there are no billboards to create, exit if (mBillboardBuffer.Count == 0) { return; } //Create manual mesh to store billboard quads mMesh = MeshManager.Instance.CreateManual(GetUniqueID("SBSMesh"), ResourceGroupManager.DefaultResourceGroupName, null); mSubMesh = mMesh.CreateSubMesh(); mSubMesh.useSharedVertices = false; //Setup vertex format information mSubMesh.vertexData = new VertexData(); mSubMesh.vertexData.vertexStart = 0; mSubMesh.vertexData.vertexCount = 4 * mBillboardBuffer.Count; VertexDeclaration dcl = mSubMesh.vertexData.vertexDeclaration; int offset = 0; dcl.AddElement(0, offset, VertexElementType.Float3, VertexElementSemantic.Position); offset += VertexElement.GetTypeSize(VertexElementType.Float3); dcl.AddElement(0, offset, VertexElementType.Float3, VertexElementSemantic.Normal); offset += VertexElement.GetTypeSize(VertexElementType.Float3); dcl.AddElement(0, offset, VertexElementType.Float3, VertexElementSemantic.Diffuse); offset += VertexElement.GetTypeSize(VertexElementType.Color); dcl.AddElement(0, offset, VertexElementType.Float3, VertexElementSemantic.TexCoords); offset += VertexElement.GetTypeSize(VertexElementType.Float2); //Populate a new vertex buffer HardwareVertexBuffer vbuf = HardwareBufferManager.Instance.CreateVertexBuffer( /*offset*/ dcl, mSubMesh.vertexData.vertexCount, BufferUsage.StaticWriteOnly, false); unsafe { float *pReal = (float *)vbuf.Lock(BufferLocking.Discard); float minX = float.PositiveInfinity; float maxX = float.NegativeInfinity; float minY = float.PositiveInfinity; float maxY = float.NegativeInfinity; float minZ = float.PositiveInfinity; float maxZ = float.NegativeInfinity; foreach (StaticBillboard it in mBillboardBuffer) { StaticBillboard bb = it; float halfXScale = bb.XScale * 0.5f; float halfYScale = bb.YScale * 0.5f; // position *pReal++ = bb.Position.x; *pReal++ = bb.Position.y; *pReal++ = bb.Position.z; // normals (actually used as scale / translate info for vertex shader) *pReal++ = halfXScale; *pReal++ = halfYScale; *pReal++ = 0.0f; // color *((uint *)pReal++) = bb.Color; // uv *pReal++ = (float)(bb.TextCoordIndexU * mUFactor); *pReal++ = (float)(bb.TextCoordIndexV * mVFactor); // position *pReal++ = bb.Position.x; *pReal++ = bb.Position.y; *pReal++ = bb.Position.z; // normals (actually used as scale / translate info for vertex shader) *pReal++ = halfXScale; *pReal++ = halfYScale; *pReal++ = 1.0f; // color *((uint *)pReal++) = bb.Color; // uv *pReal++ = (float)((bb.TextCoordIndexU + 1) * mUFactor); *pReal++ = (float)(bb.TextCoordIndexV * mVFactor); // position *pReal++ = bb.Position.x; *pReal++ = bb.Position.y; *pReal++ = bb.Position.z; // normals (actually used as scale / translate info for vertex shader) *pReal++ = halfXScale; *pReal++ = halfYScale; *pReal++ = 2.0f; // color *((uint *)pReal++) = bb.Color; // uv *pReal++ = (float)(bb.TextCoordIndexU * mUFactor); *pReal++ = (float)((bb.TextCoordIndexV + 1) * mVFactor); // position *pReal++ = bb.Position.x; *pReal++ = bb.Position.y; *pReal++ = bb.Position.z; // normals (actually used as scale / translate info for vertex shader) *pReal++ = halfXScale; *pReal++ = halfYScale; *pReal++ = 3.0f; // color *((uint *)pReal++) = bb.Color; // uv *pReal++ = (float)((bb.TextCoordIndexU + 1) * mUFactor); *pReal++ = (float)((bb.TextCoordIndexV + 1) * mVFactor); //Update bounding box if (bb.Position.x - halfXScale < minX) { minX = bb.Position.x - halfXScale; } if (bb.Position.x + halfXScale > maxX) { maxX = bb.Position.x + halfXScale; } if (bb.Position.y - halfYScale < minY) { minY = bb.Position.y - halfYScale; } if (bb.Position.y + halfYScale > maxY) { maxY = bb.Position.y + halfYScale; } if (bb.Position.z - halfXScale < minZ) { minZ = bb.Position.z - halfXScale; } if (bb.Position.z + halfXScale > maxZ) { maxZ = bb.Position.z + halfXScale; } } AxisAlignedBox bounds = new AxisAlignedBox( new Vector3(minX, minY, minZ), new Vector3(maxX, maxY, maxZ)); vbuf.Unlock(); mSubMesh.vertexData.vertexBufferBinding.SetBinding(0, vbuf); //Populate index buffer mSubMesh.indexData.indexStart = 0; mSubMesh.indexData.indexCount = 6 * mBillboardBuffer.Count; mSubMesh.indexData.indexBuffer = HardwareBufferManager.Instance.CreateIndexBuffer( IndexType.Size16, mSubMesh.indexData.indexCount, BufferUsage.StaticWriteOnly); ushort *pI = (ushort *)mSubMesh.indexData.indexBuffer.Lock(BufferLocking.Discard); for (ushort i = 0; i < mBillboardBuffer.Count; i++) { ushort ofset = (ushort)(i * 4); *pI++ = (ushort)(0 + ofset); *pI++ = (ushort)(2 + ofset); *pI++ = (ushort)(1 + ofset); *pI++ = (ushort)(1 + ofset); *pI++ = (ushort)(2 + ofset); *pI++ = (ushort)(3 + ofset); } mSubMesh.indexData.indexBuffer.Unlock(); //Finish up mesh mMesh.BoundingBox = bounds; Vector3 tmp = bounds.Maximum - bounds.Minimum; mMesh.BoundingSphereRadius = tmp.Length * 0.5f; LoggingLevel lvl = LogManager.Instance.LogDetail; LogManager.Instance.LogDetail = LoggingLevel.Low; mMesh.Load(); LogManager.Instance.LogDetail = lvl; //Empty the billboardBuffer now, because all billboards have been built mBillboardBuffer.Clear(); //Create an entity for the mesh mEntity = mSceneMgr.CreateEntity(mEntityName, mMesh.Name); mEntity.CastShadows = false; //Apply texture if (mFadeEnabled) { Debug.Assert(mFadeMaterial != null); mEntity.MaterialName = mFadeMaterial.Name; } else { Debug.Assert(mMaterial != null); mEntity.MaterialName = mMaterial.Name; } //Add to scene mNode.AttachObject(mEntity); mEntity.IsVisible = mVisible; } } }
private XmlVertexData GetXmlVertexData(VertexData vertexData) { XmlVertexData xmlVertexData = new XmlVertexData(vertexData.vertexCount); xmlVertexData.positionData = null; xmlVertexData.normalData = null; xmlVertexData.diffuseData = null; xmlVertexData.specularData = null; // Normals are transformed by the transpose of the inverse of the spatial transform. // Exclude the scale though, since I don't want to mess that up. float scale = GetScale(exportTransform); Matrix4 tmpTransform = ScaleMatrix(exportTransform, 1 / scale); Matrix4 invTrans = tmpTransform.Inverse().Transpose(); // I'm going to write all the texture buffers to one vertex // buffer, so I can leave textureOffset at zero. int textureOffset = 0; for (short bindIdx = 0; bindIdx < vertexData.vertexDeclaration.ElementCount; ++bindIdx) { VertexElement element = vertexData.vertexDeclaration.GetElement(bindIdx); HardwareVertexBuffer vBuffer = vertexData.vertexBufferBinding.GetBuffer(element.Source); int vertexOffset = element.Offset; int vertexStride = vBuffer.VertexSize; switch (element.Semantic) { case VertexElementSemantic.Position: xmlVertexData.positionData = new float[xmlVertexData.vertexCount, 3]; ReadBuffer(vBuffer, vertexOffset, vertexStride, xmlVertexData.vertexCount, element.Size, xmlVertexData.positionData, exportTransform); break; case VertexElementSemantic.Normal: xmlVertexData.normalData = new float[xmlVertexData.vertexCount, 3]; ReadBuffer(vBuffer, vertexOffset, vertexStride, xmlVertexData.vertexCount, element.Size, xmlVertexData.normalData, invTrans); break; case VertexElementSemantic.Diffuse: xmlVertexData.diffuseData = new uint[xmlVertexData.vertexCount]; ReadBuffer(vBuffer, vertexOffset, vertexStride, xmlVertexData.vertexCount, element.Size, xmlVertexData.diffuseData); break; case VertexElementSemantic.Specular: xmlVertexData.specularData = new uint[xmlVertexData.vertexCount]; ReadBuffer(vBuffer, vertexOffset, vertexStride, xmlVertexData.vertexCount, element.Size, xmlVertexData.specularData); break; case VertexElementSemantic.TexCoords: { int dim = VertexElement.GetTypeSize(element.Type) / VertexElement.GetTypeSize(VertexElementType.Float1); float[,] data = new float[xmlVertexData.vertexCount, dim]; ReadBuffer(vBuffer, vertexOffset, vertexStride, xmlVertexData.vertexCount, element.Size, data); // pad out the list while (textureOffset + element.Index >= xmlVertexData.multiTexData.Count) { xmlVertexData.multiTexData.Add(null); } // set this element xmlVertexData.multiTexData[textureOffset + element.Index] = data; textureOffset++; } break; case VertexElementSemantic.Tangent: case VertexElementSemantic.Binormal: { int dim = VertexElement.GetTypeSize(element.Type) / VertexElement.GetTypeSize(VertexElementType.Float1); float[,] data = new float[xmlVertexData.vertexCount, dim]; ReadBuffer(vBuffer, vertexOffset, vertexStride, xmlVertexData.vertexCount, element.Size, data); // pad out the list while (textureOffset + element.Index >= xmlVertexData.multiTexData.Count) { xmlVertexData.multiTexData.Add(null); } // set this element xmlVertexData.multiTexData[textureOffset + element.Index] = data; textureOffset++; } break; default: log.WarnFormat("Unknown vertex buffer semantic: {0}", element.Semantic); break; } } return(xmlVertexData); }
/// <summary> /// /// </summary> /// <param name="name"></param> /// <param name="plane"></param> /// <param name="width"></param> /// <param name="height"></param> /// <param name="curvature"></param> /// <param name="xSegments"></param> /// <param name="ySegments"></param> /// <param name="normals"></param> /// <param name="numberOfTexCoordSets"></param> /// <param name="uTiles"></param> /// <param name="vTiles"></param> /// <param name="upVector"></param> /// <param name="orientation"></param> /// <param name="vertexBufferUsage"></param> /// <param name="indexBufferUsage"></param> /// <param name="vertexShadowBuffer"></param> /// <param name="indexShadowBuffer"></param> /// <returns></returns> public Mesh CreateCurvedIllusionPlane(string name, Plane plane, float width, float height, float curvature, int xSegments, int ySegments, bool normals, int numberOfTexCoordSets, float uTiles, float vTiles, Vector3 upVector, Quaternion orientation, BufferUsage vertexBufferUsage, BufferUsage indexBufferUsage, bool vertexShadowBuffer, bool indexShadowBuffer) { Mesh mesh = CreateManual(name); SubMesh subMesh = mesh.CreateSubMesh(name + "SubMesh"); // set up vertex data, use a single shared buffer mesh.SharedVertexData = new VertexData(); VertexData vertexData = mesh.SharedVertexData; // 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); // optional normals if (normals) { vertexDeclaration.AddElement(0, currentOffset, VertexElementType.Float3, VertexElementSemantic.Normal); currentOffset += VertexElement.GetTypeSize(VertexElementType.Float3); } for (ushort i = 0; i < numberOfTexCoordSets; i++) { // assumes 2d texture coordinates vertexDeclaration.AddElement(0, currentOffset, VertexElementType.Float2, VertexElementSemantic.TexCoords, i); currentOffset += VertexElement.GetTypeSize(VertexElementType.Float2); } vertexData.vertexCount = (xSegments + 1) * (ySegments + 1); // allocate vertex buffer HardwareVertexBuffer vertexBuffer = HardwareBufferManager.Instance.CreateVertexBuffer(vertexDeclaration.GetVertexSize(0), vertexData.vertexCount, vertexBufferUsage, vertexShadowBuffer); // set up the binding, one source only VertexBufferBinding binding = vertexData.vertexBufferBinding; binding.SetBinding(0, vertexBuffer); // work out the transform required, default orientation of plane is normal along +z, distance 0 Matrix4 xlate, xform, rot; Matrix3 rot3 = Matrix3.Identity; xlate = rot = Matrix4.Identity; // determine axes Vector3 zAxis, yAxis, xAxis; zAxis = plane.Normal; zAxis.Normalize(); yAxis = upVector; yAxis.Normalize(); xAxis = yAxis.Cross(zAxis); if (xAxis.Length == 0) { throw new AxiomException("The up vector for a plane cannot be parallel to the planes normal."); } rot3.FromAxes(xAxis, yAxis, zAxis); rot = rot3; // set up standard xform from origin xlate.Translation = plane.Normal * -plane.D; // concatenate xform = xlate * rot; // generate vertex data, imagine a large sphere with the camera located near the top, // the lower the curvature, the larger the sphere. use the angle from the viewer to the // points on the plane float cameraPosition; // camera position relative to the sphere center // derive sphere radius (unused) //float sphereDistance; // distance from the camera to the sphere along box vertex vector float sphereRadius; // actual values irrelevant, it's the relation between the sphere's radius and the camera's position which is important float SPHERE_RADIUS = 100; float CAMERA_DISTANCE = 5; sphereRadius = SPHERE_RADIUS - curvature; cameraPosition = sphereRadius - CAMERA_DISTANCE; // lock the whole buffer float xSpace = width / xSegments; float ySpace = height / ySegments; float halfWidth = width / 2; float halfHeight = height / 2; Vector3 vec = Vector3.Zero; Vector3 norm = Vector3.Zero; Vector3 min = Vector3.Zero; Vector3 max = Vector3.Zero; float maxSquaredLength = 0; bool firstTime = true; // generate vertex data GenerateCurvedIllusionPlaneVertexData(vertexBuffer, ySegments, xSegments, xSpace, halfWidth, ySpace, halfHeight, xform, firstTime, normals, orientation, cameraPosition, sphereRadius, uTiles, vTiles, numberOfTexCoordSets, ref min, ref max, ref maxSquaredLength); // generate face list subMesh.useSharedVertices = true; Tesselate2DMesh(subMesh, xSegments + 1, ySegments + 1, false, indexBufferUsage, indexShadowBuffer); // generate bounds for the mesh mesh.BoundingBox = new AxisAlignedBox(min, max); mesh.BoundingSphereRadius = MathUtil.Sqrt(maxSquaredLength); mesh.Load(); mesh.Touch(); return(mesh); }
/// <summary> /// /// </summary> private unsafe void CreateGeometry() { // Vertex buffers _subMesh.vertexData = new VertexData(); _subMesh.vertexData.vertexStart = 0; _subMesh.vertexData.vertexCount = (uint)_vertexCount; VertexDeclaration vdecl = _subMesh.vertexData.vertexDeclaration; VertexBufferBinding vbind = _subMesh.vertexData.vertexBufferBinding; uint offset = 0; // Position vdecl.AddElement(0, offset, VertexElementType.VET_FLOAT3, VertexElementSemantic.VES_POSITION); offset += VertexElement.GetTypeSize(VertexElementType.VET_FLOAT3); // 3D coords vdecl.AddElement(0, offset, VertexElementType.VET_FLOAT3, VertexElementSemantic.VES_TEXTURE_COORDINATES, 0); offset += VertexElement.GetTypeSize(VertexElementType.VET_FLOAT3); // Noise coords vdecl.AddElement(0, offset, VertexElementType.VET_FLOAT2, VertexElementSemantic.VES_TEXTURE_COORDINATES, 1); offset += VertexElement.GetTypeSize(VertexElementType.VET_FLOAT2); // Opacity vdecl.AddElement(0, offset, VertexElementType.VET_FLOAT1, VertexElementSemantic.VES_TEXTURE_COORDINATES, 2); offset += VertexElement.GetTypeSize(VertexElementType.VET_FLOAT1); _vertexBuffer = HardwareBufferManager.Singleton.CreateVertexBuffer( offset, (uint)_vertexCount, HardwareBuffer.Usage.HBU_DYNAMIC_WRITE_ONLY); vbind.SetBinding(0, _vertexBuffer); int[] indexbuffer = new int[_numberOfTriangles * 3]; int IndexOffset = 0; int VertexOffset = 0; // C for (int k = 0; k < _nc; k++) { // First triangle indexbuffer[IndexOffset] = VertexOffset; indexbuffer[IndexOffset + 1] = VertexOffset + 1; indexbuffer[IndexOffset + 2] = VertexOffset + 3; // Second triangle indexbuffer[IndexOffset + 3] = VertexOffset; indexbuffer[IndexOffset + 4] = VertexOffset + 3; indexbuffer[IndexOffset + 5] = VertexOffset + 2; IndexOffset += 6; VertexOffset += 4; } // B for (int k = 0; k < _nb; k++) { // First triangle indexbuffer[IndexOffset] = VertexOffset; indexbuffer[IndexOffset + 1] = VertexOffset + 1; indexbuffer[IndexOffset + 2] = VertexOffset + 3; // Second triangle indexbuffer[IndexOffset + 3] = VertexOffset; indexbuffer[IndexOffset + 4] = VertexOffset + 3; indexbuffer[IndexOffset + 5] = VertexOffset + 2; // Third triangle indexbuffer[IndexOffset + 6] = VertexOffset + 2; indexbuffer[IndexOffset + 7] = VertexOffset + 3; indexbuffer[IndexOffset + 8] = VertexOffset + 5; // Fourth triangle indexbuffer[IndexOffset + 9] = VertexOffset + 2; indexbuffer[IndexOffset + 10] = VertexOffset + 5; indexbuffer[IndexOffset + 11] = VertexOffset + 4; IndexOffset += 12; VertexOffset += 6; } // A for (int k = 0; k < _na; k++) { // First triangle indexbuffer[IndexOffset] = VertexOffset; indexbuffer[IndexOffset + 1] = VertexOffset + 1; indexbuffer[IndexOffset + 2] = VertexOffset + 3; // Second triangle indexbuffer[IndexOffset + 3] = VertexOffset; indexbuffer[IndexOffset + 4] = VertexOffset + 3; indexbuffer[IndexOffset + 5] = VertexOffset + 2; // Third triangle indexbuffer[IndexOffset + 6] = VertexOffset + 2; indexbuffer[IndexOffset + 7] = VertexOffset + 3; indexbuffer[IndexOffset + 8] = VertexOffset + 5; // Fourth triangle indexbuffer[IndexOffset + 9] = VertexOffset + 2; indexbuffer[IndexOffset + 10] = VertexOffset + 5; indexbuffer[IndexOffset + 11] = VertexOffset + 4; // Fifth triangle indexbuffer[IndexOffset + 12] = VertexOffset + 4; indexbuffer[IndexOffset + 13] = VertexOffset + 5; indexbuffer[IndexOffset + 14] = VertexOffset + 6; IndexOffset += 15; VertexOffset += 7; } // Prepare buffer for indices _indexBuffer = HardwareBufferManager.Singleton.CreateIndexBuffer(Mogre.HardwareIndexBuffer.IndexType.IT_32BIT, (uint)_numberOfTriangles * 3, HardwareBuffer.Usage.HBU_STATIC, true); fixed(int *addr = &indexbuffer[0]) { _indexBuffer.WriteData( 0, _indexBuffer.SizeInBytes, addr, true); } //indexbufferArr = null; // Set index buffer for this submesh _subMesh.indexData.indexBuffer = _indexBuffer; _subMesh.indexData.indexStart = 0; _subMesh.indexData.indexCount = (uint)_numberOfTriangles * 3; // Create our internal buffer for manipulations _vertices = new Vertex[_vertexCount]; // Update geometry UpdateGeometry(); }
/// <summary> /// /// </summary> /// <param name="name">Name of the plane mesh.</param> /// <param name="plane">Plane to use for distance and orientation of the mesh.</param> /// <param name="width">Width in world coordinates.</param> /// <param name="height">Height in world coordinates.</param> /// <param name="xSegments">Number of x segments for tesselation.</param> /// <param name="ySegments">Number of y segments for tesselation.</param> /// <param name="normals">If true, plane normals are created.</param> /// <param name="numTexCoordSets">Number of 2d texture coord sets to use.</param> /// <param name="uTile">Number of times the texture should be repeated in the u direction.</param> /// <param name="vTile">Number of times the texture should be repeated in the v direction.</param> /// <param name="upVec">The up direction of the plane.</param> /// <returns></returns> public Mesh CreatePlane(string name, Plane plane, float width, float height, int xSegments, int ySegments, bool normals, int numTexCoordSets, float uTile, float vTile, Vector3 upVec, BufferUsage vertexBufferUsage, BufferUsage indexBufferUsage, bool vertexShadowBuffer, bool indexShadowBuffer) { Mesh mesh = CreateManual(name); SubMesh subMesh = mesh.CreateSubMesh(name + "SubMesh"); mesh.SharedVertexData = new VertexData(); VertexData vertexData = mesh.SharedVertexData; VertexDeclaration decl = vertexData.vertexDeclaration; int currOffset = 0; // add position data decl.AddElement(0, currOffset, VertexElementType.Float3, VertexElementSemantic.Position); currOffset += VertexElement.GetTypeSize(VertexElementType.Float3); // normals are optional if (normals) { decl.AddElement(0, currOffset, VertexElementType.Float3, VertexElementSemantic.Normal); currOffset += VertexElement.GetTypeSize(VertexElementType.Float3); } // add texture coords for (ushort i = 0; i < numTexCoordSets; i++) { decl.AddElement(0, currOffset, VertexElementType.Float2, VertexElementSemantic.TexCoords, i); currOffset += VertexElement.GetTypeSize(VertexElementType.Float2); } vertexData.vertexCount = (xSegments + 1) * (ySegments + 1); // create a new vertex buffer (based on current API) HardwareVertexBuffer vbuf = HardwareBufferManager.Instance.CreateVertexBuffer(decl.GetVertexSize(0), vertexData.vertexCount, vertexBufferUsage, vertexShadowBuffer); // get a reference to the vertex buffer binding VertexBufferBinding binding = vertexData.vertexBufferBinding; // bind the first vertex buffer binding.SetBinding(0, vbuf); // transform the plane based on its plane def Matrix4 translate = Matrix4.Identity; Matrix4 transform = Matrix4.Zero; Matrix4 rotation = Matrix4.Identity; Matrix3 rot3x3 = Matrix3.Zero; Vector3 xAxis, yAxis, zAxis; zAxis = plane.Normal; zAxis.Normalize(); yAxis = upVec; yAxis.Normalize(); xAxis = yAxis.Cross(zAxis); if (xAxis.Length == 0) { throw new AxiomException("The up vector for a plane cannot be parallel to the planes normal."); } rot3x3.FromAxes(xAxis, yAxis, zAxis); rotation = rot3x3; // set up transform from origin translate.Translation = plane.Normal * -plane.D; transform = translate * rotation; float xSpace = width / xSegments; float ySpace = height / ySegments; float halfWidth = width / 2; float halfHeight = height / 2; float xTexCoord = (1.0f * uTile) / xSegments; float yTexCoord = (1.0f * vTile) / ySegments; Vector3 vec = Vector3.Zero; Vector3 min = Vector3.Zero; Vector3 max = Vector3.Zero; float maxSquaredLength = 0; bool firstTime = true; // generate vertex data GeneratePlaneVertexData(vbuf, ySegments, xSegments, xSpace, halfWidth, ySpace, halfHeight, transform, firstTime, normals, rotation, numTexCoordSets, xTexCoord, yTexCoord, subMesh, ref min, ref max, ref maxSquaredLength); // generate face list Tesselate2DMesh(subMesh, xSegments + 1, ySegments + 1, false, indexBufferUsage, indexShadowBuffer); // generate bounds for the mesh mesh.BoundingBox = new AxisAlignedBox(min, max); mesh.BoundingSphereRadius = MathUtil.Sqrt(maxSquaredLength); mesh.Load(); mesh.Touch(); return(mesh); }
public Mesh CreateBoneMesh(string name) { Mesh mesh = CreateManual(name); mesh.SkeletonName = name + ".skeleton"; SubMesh subMesh = mesh.CreateSubMesh("BoneSubMesh"); subMesh.useSharedVertices = true; subMesh.MaterialName = "BaseWhite"; // short[] faces = { 0, 2, 3, 0, 3, 4, 0, 4, 5, 0, 5, 2, 1, 2, 5, 1, 5, 4, 1, 4, 3, 1, 3, 2 }; // short[] faces = { 0, 3, 2, 0, 4, 3, 0, 5, 4, 0, 2, 5, 1, 5, 2, 1, 4, 5, 1, 3, 4, 1, 2, 3 }; short[] faces = { 0, 2, 3, 0, 3, 4, 0, 4, 5, 0, 5, 2, 1, 2, 5, 1, 5, 4, 1, 4, 3, 1, 3, 2, 0, 3, 2, 0, 4, 3, 0, 5, 4, 0, 2, 5, 1, 5, 2, 1, 4, 5, 1, 3, 4, 1, 2, 3 }; int faceCount = faces.Length / 3; // faces per bone int vertexCount = 6; // vertices per bone // set up vertex data, use a single shared buffer mesh.SharedVertexData = new VertexData(); VertexData vertexData = mesh.SharedVertexData; // 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); vertexDeclaration.AddElement(0, currentOffset, VertexElementType.Float3, VertexElementSemantic.Normal); currentOffset += VertexElement.GetTypeSize(VertexElementType.Float3); int boneCount = mesh.Skeleton.BoneCount; // I want 6 vertices per bone - exclude the root bone vertexData.vertexCount = boneCount * vertexCount; // 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); Vector3[] vertices = new Vector3[vertexData.vertexCount]; GetVertices(ref vertices, mesh.Skeleton.RootBone); // Generate vertex data unsafe { // lock the vertex buffer IntPtr data = vertexBuffer.Lock(BufferLocking.Discard); float *pData = (float *)data.ToPointer(); foreach (Vector3 vec in vertices) { // assign to geometry *pData++ = vec.x; *pData++ = vec.y; *pData++ = vec.z; // fake normals *pData++ = 0; *pData++ = 1; *pData++ = 0; } // unlock the buffer vertexBuffer.Unlock(); } // unsafe // Generate index data HardwareIndexBuffer indexBuffer = HardwareBufferManager.Instance.CreateIndexBuffer(IndexType.Size16, faces.Length * boneCount, BufferUsage.StaticWriteOnly); subMesh.indexData.indexBuffer = indexBuffer; subMesh.indexData.indexCount = faces.Length * boneCount; subMesh.indexData.indexStart = 0; for (ushort boneIndex = 0; boneIndex < mesh.Skeleton.BoneCount; ++boneIndex) { Axiom.Animating.Bone bone = mesh.Skeleton.GetBone(boneIndex); short[] tmpFaces = new short[faces.Length]; for (int tmp = 0; tmp < faces.Length; ++tmp) { tmpFaces[tmp] = (short)(faces[tmp] + vertexCount * bone.Handle); } indexBuffer.WriteData(faces.Length * bone.Handle * sizeof(short), tmpFaces.Length * sizeof(short), tmpFaces, true); } for (ushort boneIndex = 0; boneIndex < mesh.Skeleton.BoneCount; ++boneIndex) { Axiom.Animating.Bone bone = mesh.Skeleton.GetBone(boneIndex); Axiom.Animating.Bone parentBone = bone; if (bone.Parent != null) { parentBone = (Axiom.Animating.Bone)bone.Parent; } for (int vertexIndex = 0; vertexIndex < vertexCount; ++vertexIndex) { Axiom.Animating.VertexBoneAssignment vba = new Axiom.Animating.VertexBoneAssignment(); // associate the base of the joint display with the bone's parent, // and the rest of the points with the bone. vba.boneIndex = parentBone.Handle; vba.weight = 1.0f; vba.vertexIndex = vertexCount * bone.Handle + vertexIndex; mesh.AddBoneAssignment(vba); } } mesh.Load(); mesh.Touch(); return(mesh); }
private void CreateGrassMesh() { // Each grass section is 3 planes at 60 degrees to each other // Normals point straight up to simulate correct lighting Mesh msh = MeshManager.Singleton.CreateManual(GRASS_MESH_NAME, ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME, null); SubMesh sm = msh.CreateSubMesh(); sm.useSharedVertices = false; sm.vertexData = new VertexData(); sm.vertexData.vertexStart = 0; sm.vertexData.vertexCount = 12; VertexDeclaration dcl = sm.vertexData.vertexDeclaration; uint offset = 0; dcl.AddElement(0, offset, VertexElementType.VET_FLOAT3, VertexElementSemantic.VES_POSITION); offset += VertexElement.GetTypeSize(VertexElementType.VET_FLOAT3); dcl.AddElement(0, offset, VertexElementType.VET_FLOAT3, VertexElementSemantic.VES_NORMAL); offset += VertexElement.GetTypeSize(VertexElementType.VET_FLOAT3); dcl.AddElement(0, offset, VertexElementType.VET_FLOAT2, VertexElementSemantic.VES_TEXTURE_COORDINATES); offset += VertexElement.GetTypeSize(VertexElementType.VET_FLOAT2); HardwareVertexBufferSharedPtr vbuf = HardwareBufferManager.Singleton.CreateVertexBuffer(offset, 12, HardwareBuffer.Usage.HBU_STATIC_WRITE_ONLY); int i; unsafe { float *pData = (float *)(vbuf.Lock(HardwareBuffer.LockOptions.HBL_DISCARD)); Vector3 baseVec = new Vector3(GRASS_WIDTH / 2, 0, 0); Vector3 vec = baseVec; Quaternion rot = new Quaternion(); rot.FromAngleAxis(Math.DegreesToRadians(60), Vector3.UNIT_Y); for (i = 0; i < 3; ++i) { //position *pData++ = -vec.x; *pData++ = GRASS_HEIGHT; *pData++ = -vec.z; // normal *pData++ = 0; *pData++ = 1; *pData++ = 0; // uv *pData++ = 0; *pData++ = 0; // position *pData++ = vec.x; *pData++ = GRASS_HEIGHT; *pData++ = vec.z; // normal *pData++ = 0; *pData++ = 1; *pData++ = 0; // uv *pData++ = 1; *pData++ = 0; // position *pData++ = -vec.x; *pData++ = 0; *pData++ = -vec.z; // normal *pData++ = 0; *pData++ = 1; *pData++ = 0; // uv *pData++ = 0; *pData++ = 1; // position *pData++ = vec.x; *pData++ = 0; *pData++ = vec.z; // normal *pData++ = 0; *pData++ = 1; *pData++ = 0; // uv *pData++ = 1; *pData++ = 1; vec = rot * vec; } //for } //unsafe vbuf.Unlock(); sm.vertexData.vertexBufferBinding.SetBinding(0, vbuf); sm.indexData.indexCount = 6 * 3; sm.indexData.indexBuffer = HardwareBufferManager.Singleton.CreateIndexBuffer(HardwareIndexBuffer.IndexType.IT_16BIT, 6 * 3, HardwareBuffer.Usage.HBU_STATIC_WRITE_ONLY); unsafe { ushort *pI = (ushort *)(sm.indexData.indexBuffer.Lock(HardwareBuffer.LockOptions.HBL_DISCARD)); for (i = 0; i < 3; ++i) { int off = i * 4; * pI++ = (ushort)(off); * pI++ = (ushort)(off + 3); * pI++ = (ushort)(off + 1); *pI++ = (ushort)(off + 0); *pI++ = (ushort)(off + 2); *pI++ = (ushort)(off + 3); } } sm.indexData.indexBuffer.Unlock(); sm.SetMaterialName(GRASS_MATERIAL); msh.Load(); }
public void Stitch(HeightField south1, HeightField south2, HeightField east1, HeightField east2, HeightField southEast, bool stitchMiddleSouth, bool stitchMiddleEast) { Debug.Assert((south2 == null || south2.metersPerSample == south1.metersPerSample), "south neighbors have different LOD"); Debug.Assert((east2 == null || east2.metersPerSample == east1.metersPerSample), "east neighbors have different LOD"); // // Determine the stitch types for south and east direction // StitchType southStitchType; StitchType eastStitchType; int southMetersPerSample = 0; if (south1 == null) { southStitchType = StitchType.None; } else { southMetersPerSample = south1.metersPerSample; if (south1.metersPerSample == metersPerSample) { southStitchType = StitchType.ToSame; } else if (south1.metersPerSample > metersPerSample) { Debug.Assert(south1.metersPerSample == (2 * metersPerSample), "stitching:south LOD not half"); southStitchType = StitchType.ToLower; } else { Debug.Assert((south1.metersPerSample * 2) == metersPerSample, "stitching: south LOD not double"); southStitchType = StitchType.ToHigher; } } int eastMetersPerSample = 0; if (east1 == null) { eastStitchType = StitchType.None; } else { eastMetersPerSample = east1.metersPerSample; if (east1.metersPerSample == metersPerSample) { eastStitchType = StitchType.ToSame; } else if (east1.metersPerSample > metersPerSample) { Debug.Assert(east1.metersPerSample == (2 * metersPerSample), "stitching:east LOD not half"); eastStitchType = StitchType.ToLower; } else { Debug.Assert((east1.metersPerSample * 2) == metersPerSample, "stitching:east LOD not double"); eastStitchType = StitchType.ToHigher; } } if (stitchRenderable != null) { if (stitchRenderable.IsValid(numSamples, southMetersPerSample, eastMetersPerSample)) { // existing stitchRenderable is still ok, so just use it return; } else { stitchRenderable.Dispose(); stitchRenderable = null; } } // // The following combinations are acceptable: // 1) both same // 2) one same and one lower // 3) one same and one higher // 4) both lower // Debug.Assert(((southStitchType == StitchType.ToSame) || (eastStitchType == StitchType.ToSame)) || ((southStitchType == StitchType.ToLower) && (eastStitchType == StitchType.ToLower)) || ((southStitchType == StitchType.None) && (eastStitchType == StitchType.None)), "stitching:invalid stitchType combination"); bool bothSame = false; bool bothLower = false; int vertexCount; if (southStitchType == eastStitchType) { if (southStitchType == StitchType.ToSame) { bothSame = true; vertexCount = numSamples * 4; } else if (southStitchType == StitchType.ToLower) { bothLower = true; vertexCount = numSamples * 3; } else { // both are StitchType.None, which means we are at the NE corner, so we dont need stitching return; } } else { if ((southStitchType == StitchType.ToLower) || (eastStitchType == StitchType.ToLower)) { // one same and one lower vertexCount = numSamples * 3 + (numSamples / 2); } else if ((southStitchType == StitchType.ToHigher) || (eastStitchType == StitchType.ToHigher)) { // one same and one higher vertexCount = numSamples * 5; } else { // one same and one none vertexCount = numSamples * 2; } } VertexData vertexData = new VertexData(); vertexData.vertexCount = vertexCount; vertexData.vertexStart = 0; // set up the vertex declaration int vDecOffset = 0; vertexData.vertexDeclaration.AddElement(0, vDecOffset, VertexElementType.Float3, VertexElementSemantic.Position); vDecOffset += VertexElement.GetTypeSize(VertexElementType.Float3); vertexData.vertexDeclaration.AddElement(0, vDecOffset, VertexElementType.Float3, VertexElementSemantic.Normal); vDecOffset += VertexElement.GetTypeSize(VertexElementType.Float3); vertexData.vertexDeclaration.AddElement(0, vDecOffset, VertexElementType.Float2, VertexElementSemantic.TexCoords); vDecOffset += VertexElement.GetTypeSize(VertexElementType.Float2); // create the hardware vertex buffer and set up the buffer binding HardwareVertexBuffer hvBuffer = HardwareBufferManager.Instance.CreateVertexBuffer( vertexData.vertexDeclaration.GetVertexSize(0), vertexData.vertexCount, BufferUsage.StaticWriteOnly, false); vertexData.vertexBufferBinding.SetBinding(0, hvBuffer); // lock the vertex buffer IntPtr ipBuf = hvBuffer.Lock(BufferLocking.Discard); int bufferOff = 0; int southSamples = 0; int eastSamples = 0; int vertOff = 0; unsafe { float *buffer = (float *)ipBuf.ToPointer(); if (southStitchType != StitchType.None) { // // First the south edge of this tile // fillVerts(this, buffer, vertOff, numSamples, 0, numSamples - 1, 1, 0, 0, 0, tile.Page.Location); vertOff += numSamples; } if (eastStitchType != StitchType.None) { int adjust = 0; if (southStitchType == StitchType.None) { // include the inner corner because it wasnt done with the south edge adjust = 1; } // // Now the east edge of the tile // fillVerts(this, buffer, vertOff, numSamples - 1 + adjust, numSamples - 1, numSamples - 2 + adjust, 0, -1, 0, 0, tile.Page.Location); vertOff += (numSamples - 1 + adjust); } if (southStitchType != StitchType.None) { // // fill the verts from the south neighbor // southSamples = neighborSamples(southStitchType); if (south2 == null) { // only one southern neighbor int xStart = 0; int xSampOff = 0; if (stitchMiddleSouth) { // go from bottom to middle of east tile, rather than middle to top xStart = southSamples; xSampOff = -tile.Size; } fillVerts(south1, buffer, vertOff, southSamples, xStart, 0, 1, 0, xSampOff, tile.Size, tile.Page.Location); vertOff += southSamples; } else { // two southern neighbors int halfSamples = southSamples / 2; fillVerts(south1, buffer, vertOff, halfSamples, 0, 0, 1, 0, 0, tile.Size, tile.Page.Location); vertOff += halfSamples; fillVerts(south2, buffer, vertOff, halfSamples, 0, 0, 1, 0, south1.tile.Size, tile.Size, tile.Page.Location); vertOff += halfSamples; } } if ((southStitchType != StitchType.None) && (eastStitchType != StitchType.None)) { // // fill the single sample from the SE neighbor // if (southEast == east1) { fillVerts(southEast, buffer, vertOff, 1, 0, neighborSamples(eastStitchType), 0, 0, tile.Size, 0, tile.Page.Location); } else if (southEast == south1) { fillVerts(southEast, buffer, vertOff, 1, neighborSamples(southStitchType), 0, 0, 0, 0, tile.Size, tile.Page.Location); } else { fillVerts(southEast, buffer, vertOff, 1, 0, 0, 0, 0, tile.Size, tile.Size, tile.Page.Location); } vertOff++; } if (eastStitchType != StitchType.None) { // // fill the verts from the east neighbor // eastSamples = neighborSamples(eastStitchType); if (east2 == null) { // only one eastern neighbor int zStart = eastSamples - 1; int zSampOff = 0; if (stitchMiddleEast) { // go from bottom to middle of east tile, rather than middle to top zStart = (eastSamples * 2) - 1; zSampOff = -tile.Size; } fillVerts(east1, buffer, vertOff, eastSamples, 0, zStart, 0, -1, tile.Size, zSampOff, tile.Page.Location); vertOff += eastSamples; } else { // two eastern neighbors int halfSamples = eastSamples / 2; fillVerts(east2, buffer, vertOff, halfSamples, 0, halfSamples - 1, 0, -1, tile.Size, east1.tile.Size, tile.Page.Location); vertOff += halfSamples; fillVerts(east1, buffer, vertOff, halfSamples, 0, halfSamples - 1, 0, -1, tile.Size, 0, tile.Page.Location); vertOff += halfSamples; } } Debug.Assert(vertexCount == vertOff, "stitching: generated incorrect number of vertices"); } hvBuffer.Unlock(); IndexData indexData = IndexBufferManager.Instance.GetStitchIndexBuffer(numSamples, southSamples, eastSamples); stitchRenderable = new StitchRenderable(this, vertexData, indexData, numSamples, southMetersPerSample, eastMetersPerSample); }
private VertexData buildVertexData() { VertexData vertexData = new VertexData(); vertexData.vertexCount = numSamples * numSamples; vertexData.vertexStart = 0; // set up the vertex declaration int vDecOffset = 0; vertexData.vertexDeclaration.AddElement(0, vDecOffset, VertexElementType.Float3, VertexElementSemantic.Position); vDecOffset += VertexElement.GetTypeSize(VertexElementType.Float3); vertexData.vertexDeclaration.AddElement(0, vDecOffset, VertexElementType.Float3, VertexElementSemantic.Normal); vDecOffset += VertexElement.GetTypeSize(VertexElementType.Float3); vertexData.vertexDeclaration.AddElement(0, vDecOffset, VertexElementType.Float2, VertexElementSemantic.TexCoords); vDecOffset += VertexElement.GetTypeSize(VertexElementType.Float2); // create the hardware vertex buffer and set up the buffer binding HardwareVertexBuffer hvBuffer = HardwareBufferManager.Instance.CreateVertexBuffer( vertexData.vertexDeclaration.GetVertexSize(0), vertexData.vertexCount, BufferUsage.StaticWriteOnly, false); vertexData.vertexBufferBinding.SetBinding(0, hvBuffer); // lock the vertex buffer IntPtr ipBuf = hvBuffer.Lock(BufferLocking.Discard); int bufferOff = 0; unsafe { float *buffer = (float *)ipBuf.ToPointer(); int heightMapOffset = 0; for (int zIndex = 0; zIndex < numSamples; zIndex++) { float z = (zIndex * metersPerSample * WorldManager.oneMeter); for (int xIndex = 0; xIndex < numSamples; xIndex++) { float height = heightMap[heightMapOffset++]; // Position float x = (xIndex * metersPerSample * WorldManager.oneMeter); buffer[bufferOff++] = x; buffer[bufferOff++] = height; buffer[bufferOff++] = z; // normals // XXX - this can be optimized quite a bit Vector3 norm = tile.GetNormalAt(new Vector3(x + tile.Location.x, height, z + tile.Location.z)); buffer[bufferOff++] = norm.x; buffer[bufferOff++] = norm.y; buffer[bufferOff++] = norm.z; // Texture // XXX - assumes one unit of texture space is one page. // how does the vertex shader deal with texture coords? buffer[bufferOff++] = (x + location.x - tile.Page.Location.x) / (WorldManager.Instance.PageSize * WorldManager.oneMeter); buffer[bufferOff++] = (z + location.z - tile.Page.Location.z) / (WorldManager.Instance.PageSize * WorldManager.oneMeter); } } } hvBuffer.Unlock(); return(vertexData); }
private static void _createSphere(Mesh mesh) { // sphere creation code taken from the DeferredShading sample, originally from the [Ogre] wiki var pSphereVertex = mesh.CreateSubMesh(); const int NUM_SEGMENTS = 16; const int NUM_RINGS = 16; const float SPHERE_RADIUS = 50.0f; mesh.SharedVertexData = new VertexData(); var vertexData = mesh.SharedVertexData; // define the vertex format var vertexDecl = vertexData.vertexDeclaration; var offset = 0; // positions vertexDecl.AddElement(0, offset, VertexElementType.Float3, VertexElementSemantic.Position); offset += VertexElement.GetTypeSize(VertexElementType.Float3); // normals vertexDecl.AddElement(0, offset, VertexElementType.Float3, VertexElementSemantic.Normal); offset += VertexElement.GetTypeSize(VertexElementType.Float3); // two dimensional texture coordinates vertexDecl.AddElement(0, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 0); offset += VertexElement.GetTypeSize(VertexElementType.Float2); // allocate the vertex buffer vertexData.vertexCount = (NUM_RINGS + 1) * (NUM_SEGMENTS + 1); var vBuf = HardwareBufferManager.Instance.CreateVertexBuffer(vertexDecl.Clone(0), vertexData.vertexCount, BufferUsage.StaticWriteOnly, false); var binding = vertexData.vertexBufferBinding; binding.SetBinding(0, vBuf); // allocate index buffer pSphereVertex.IndexData.indexCount = 6 * NUM_RINGS * (NUM_SEGMENTS + 1); pSphereVertex.IndexData.indexBuffer = HardwareBufferManager.Instance.CreateIndexBuffer(IndexType.Size16, pSphereVertex.IndexData. indexCount, BufferUsage.StaticWriteOnly, false); var iBuf = pSphereVertex.IndexData.indexBuffer; #if !AXIOM_SAFE_ONLY unsafe #endif { var iVertex = 0; var pVertex = vBuf.Lock(BufferLocking.Discard).ToFloatPointer(); var iIndices = 0; var pIndices = iBuf.Lock(BufferLocking.Discard).ToUShortPointer(); float fDeltaRingAngle = (Utility.PI / NUM_RINGS); float fDeltaSegAngle = (2 * Utility.PI / NUM_SEGMENTS); ushort wVerticeIndex = 0; // Generate the group of rings for the sphere for (var ring = 0; ring <= NUM_RINGS; ring++) { float r0 = SPHERE_RADIUS * Utility.Sin(ring * fDeltaRingAngle); float y0 = SPHERE_RADIUS * Utility.Cos(ring * fDeltaRingAngle); // Generate the group of segments for the current ring for (var seg = 0; seg <= NUM_SEGMENTS; seg++) { float x0 = r0 * Utility.Sin(seg * fDeltaSegAngle); float z0 = r0 * Utility.Cos(seg * fDeltaSegAngle); // Add one vertex to the strip which makes up the sphere pVertex[iVertex++] = x0; pVertex[iVertex++] = y0; pVertex[iVertex++] = z0; var vNormal = new Vector3(x0, y0, z0).ToNormalized(); pVertex[iVertex++] = vNormal.x; pVertex[iVertex++] = vNormal.y; pVertex[iVertex++] = vNormal.z; pVertex[iVertex++] = (float)seg / (float)NUM_SEGMENTS; pVertex[iVertex++] = (float)ring / (float)NUM_RINGS; if (ring != NUM_RINGS) { // each vertex (except the last) has six indicies pointing to it pIndices[iIndices++] = (ushort)(wVerticeIndex + NUM_SEGMENTS + 1); pIndices[iIndices++] = (ushort)(wVerticeIndex); pIndices[iIndices++] = (ushort)(wVerticeIndex + NUM_SEGMENTS); pIndices[iIndices++] = (ushort)(wVerticeIndex + NUM_SEGMENTS + 1); pIndices[iIndices++] = (ushort)(wVerticeIndex + 1); pIndices[iIndices++] = (ushort)(wVerticeIndex); wVerticeIndex++; } } ; // end for seg } // end for ring } // Unlock vBuf.Unlock(); iBuf.Unlock(); // Generate face list pSphereVertex.useSharedVertices = true; // the original code was missing this line: mesh.BoundingBox = new AxisAlignedBox(new Vector3(-SPHERE_RADIUS, -SPHERE_RADIUS, -SPHERE_RADIUS), new Vector3(SPHERE_RADIUS, SPHERE_RADIUS, SPHERE_RADIUS)); mesh.BoundingSphereRadius = SPHERE_RADIUS; }
/** Initializes the LandScapeRenderable with the given options and the starting coordinates of this block. */ public Renderable() : base() { info = null; materialLODIndex = 0; neighbors = new Renderable[4]; for (long i = 0; i < 4; i++) { neighbors[i] = null; } inUse = false; isLoaded = false; // Setup render op renderOp = new RenderOperation(); renderOp.vertexData = new VertexData(); renderOp.vertexData.vertexStart = 0; long tileSize = Options.Instance.TileSize; renderOp.vertexData.vertexCount = (int)((tileSize + 1) * (tileSize + 1)); box = new AxisAlignedBox(); // Vertex declaration VertexDeclaration decl = renderOp.vertexData.vertexDeclaration; VertexBufferBinding bind = renderOp.vertexData.vertexBufferBinding; HardwareVertexBuffer vbuf; // Vertex buffer #1, position // positions int offset = 0; decl.AddElement(POSITION, offset, VertexElementType.Float3, VertexElementSemantic.Position); offset += VertexElement.GetTypeSize(VertexElementType.Float3); if (Options.Instance.Lit) { decl.AddElement(POSITION, offset, VertexElementType.Float3, VertexElementSemantic.Normal); offset += VertexElement.GetTypeSize(VertexElementType.Float3); } decl.AddElement(POSITION, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 0); offset += VertexElement.GetTypeSize(VertexElementType.Float2); vbuf = HardwareBufferManager.Instance.CreateVertexBuffer( decl.GetVertexSize(POSITION), renderOp.vertexData.vertexCount, BufferUsage.StaticWriteOnly, false); bind.SetBinding(POSITION, vbuf); // if (Options.Instance.Lit) // { // offset = 0; // decl.AddElement(NORMAL, offset, VertexElementType.Float3, VertexElementSemantic.Normal); // offset += VertexElement.GetTypeSize(VertexElementType.Float3); // vbuf = HardwareBufferManager.Instance.CreateVertexBuffer( // decl.GetVertexSize(NORMAL), // renderOp.vertexData.vertexCount, // BufferUsage.StaticWriteOnly); // // bind.SetBinding(NORMAL, vbuf); // } // // offset = 0; // decl.AddElement(TEXCOORD, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 0); // offset += VertexElement.GetTypeSize(VertexElementType.Float2); // vbuf = HardwareBufferManager.Instance.CreateVertexBuffer( // decl.GetVertexSize(TEXCOORD), // renderOp.vertexData.vertexCount, // BufferUsage.StaticWriteOnly); // // bind.SetBinding(TEXCOORD, vbuf); // // // if (Options.Instance.Colored || // Options.Instance.Coverage_Vertex_Color || // Options.Instance.Base_Vertex_Color) // { // offset = 0; // decl.AddElement(COLORS, offset, VertexElementType.Float3, VertexElementSemantic.Diffuse); // offset += VertexElement.GetTypeSize(VertexElementType.Color); // vbuf = HardwareBufferManager.Instance.CreateVertexBuffer( // decl.GetVertexSize(COLORS), // renderOp.vertexData.vertexCount, // BufferUsage.StaticWriteOnly); // // bind.SetBinding(COLORS, vbuf); // } //No need to set the indexData since it is shared from IndexBuffer class renderOp.operationType = OperationType.TriangleList; renderOp.useIndices = true; renderOp.indexData = null; RenderLevel = Options.Instance.MaxRenderLevel / 2; }
private unsafe void createCube(string name, Mogre.Vector3 gpose, double d) { MeshPtr msh = MeshManager.Singleton.CreateManual(name, "General"); SubMesh sub1 = msh.CreateSubMesh("1"); const float sqrt13 = 0.577350269f; /* sqrt(1/3) */ const int nVertices = 8; const int vbufCount = 3 * 2 * nVertices; float[] vertices = new float[vbufCount] { (float)(gpose.x - d / 2), (float)(gpose.y + d / 2), (float)(gpose.z - d / 2), //0 position -sqrt13, sqrt13, -sqrt13, //0 normal A (float)(gpose.x + d / 2), (float)(gpose.y + d / 2), (float)(gpose.z - d / 2), //1 position sqrt13, sqrt13, -sqrt13, //1 normal B (float)(gpose.x + d / 2), (float)(gpose.y - d / 2), (float)(gpose.z - d / 2), //2 position sqrt13, -sqrt13, -sqrt13, //2 normal F (float)(gpose.x - d / 2), (float)(gpose.y - d / 2), (float)(gpose.z - d / 2), //3 position -sqrt13, -sqrt13, -sqrt13, //3 normal H (float)(gpose.x - d / 2), (float)(gpose.y + d / 2), (float)(gpose.z + d / 2), -sqrt13, sqrt13, sqrt13, //4 normal C (float)(gpose.x + d / 2), (float)(gpose.y + d / 2), (float)(gpose.z + d / 2), sqrt13, sqrt13, sqrt13, //5 normal D (float)(gpose.x + d / 2), (float)(gpose.y - d / 2), (float)(gpose.z + d / 2), sqrt13, -sqrt13, sqrt13, //6 normal E (float)(gpose.x - d / 2), (float)(gpose.y - d / 2), (float)(gpose.z + d / 2), -sqrt13, -sqrt13, sqrt13, //7 normal G }; const int ibufCount = 36; ushort[] faces = new ushort[ibufCount] { //back 0, 2, 3, 0, 1, 2, //right 1, 6, 2, 1, 5, 6, //front 4, 6, 5, 4, 7, 6, //left 0, 7, 4, 0, 3, 7, //top 0, 5, 1, 0, 4, 5, //bottom 2, 7, 3, 2, 6, 7 }; sub1.vertexData = new VertexData(); sub1.vertexData.vertexCount = nVertices; VertexDeclaration decl = sub1.vertexData.vertexDeclaration; uint offset = 0; //position decl.AddElement(0, offset, VertexElementType.VET_FLOAT3, VertexElementSemantic.VES_POSITION); offset += VertexElement.GetTypeSize(VertexElementType.VET_FLOAT3); //normal decl.AddElement(0, offset, VertexElementType.VET_FLOAT3, VertexElementSemantic.VES_NORMAL); offset += VertexElement.GetTypeSize(VertexElementType.VET_FLOAT3); HardwareVertexBufferSharedPtr vbuf = HardwareBufferManager.Singleton.CreateVertexBuffer(offset, sub1.vertexData.vertexCount, HardwareBuffer.Usage.HBU_STATIC_WRITE_ONLY); VertexBufferBinding bind = sub1.vertexData.vertexBufferBinding; void *pVertices; fixed(float *pFVertice = vertices) { pVertices = (void *)pFVertice; } vbuf.WriteData(0, vbuf.SizeInBytes, pVertices, true); bind.SetBinding(0, vbuf); void *pFaces; fixed(ushort *pUFaces = faces) { pFaces = (void *)pUFaces; } HardwareIndexBufferSharedPtr ibuf = HardwareBufferManager.Singleton.CreateIndexBuffer(HardwareIndexBuffer.IndexType.IT_16BIT, ibufCount, HardwareBuffer.Usage.HBU_STATIC_WRITE_ONLY); ibuf.WriteData(0, ibuf.SizeInBytes, pFaces, true); sub1.useSharedVertices = false; sub1.indexData.indexBuffer = ibuf; sub1.indexData.indexCount = ibufCount; sub1.indexData.indexStart = 0; sub1.SetMaterialName("Examples/10PointBlock"); msh._setBounds(new AxisAlignedBox(-100, -100, -100, 100, 100, 100)); msh._setBoundingSphereRadius(Mogre.Math.Sqrt(3 * 100 * 100)); msh.Load(); }
/// <summary> /// /// </summary> /// <param name="page"></param> /// <param name="layer"></param> /// <param name="grassPostions"></param> /// <param name="grassCount"></param> /// <returns></returns> private Mesh GenerateGrassCrossQuads(PageInfo page, GrassLayer layer, IntPtr grassPostions, int grassCount) { //Calculate the number of quads to be added int quadCount = grassCount * 2; //Create manual mesh to store grass quads Mesh mesh = (Mesh)MeshManager.Instance.CreateManual(GetUniqueID(), ResourceGroupManager.DefaultResourceGroupName, null); SubMesh subMesh = mesh.CreateSubMesh(); subMesh.useSharedVertices = false; //Setup vertex format information subMesh.vertexData = new VertexData(); subMesh.vertexData.vertexStart = 0; subMesh.vertexData.vertexCount = 4 * quadCount; VertexDeclaration dcl = subMesh.vertexData.vertexDeclaration; int offset = 0; dcl.AddElement(0, offset, VertexElementType.Float3, VertexElementSemantic.Position); offset += VertexElement.GetTypeSize(VertexElementType.Float3); dcl.AddElement(0, offset, VertexElementType.Color, VertexElementSemantic.Diffuse); offset += VertexElement.GetTypeSize(VertexElementType.Color); dcl.AddElement(0, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords); offset += VertexElement.GetTypeSize(VertexElementType.Float2); //Populate a new vertex buffer with grass HardwareVertexBuffer vbuf = HardwareBufferManager.Instance.CreateVertexBuffer( /*offset*/ dcl, subMesh.vertexData.vertexCount, BufferUsage.DynamicWriteOnly, false); unsafe { float *pReal = (float *)vbuf.Lock(BufferLocking.Discard); //Calculate size variance float rndWidth = layer.mMaxWidth - layer.mMinWidth; float rndHeight = layer.mMaxHeight - layer.mMinHeight; float minY = float.PositiveInfinity, maxY = float.NegativeInfinity; float *posPtr = (float *)grassPostions; //Position array "iterator" for (int i = 0; i < grassCount; i++) { //Get the x and z positions from the position array float x = *posPtr++; float z = *posPtr++; //Get the color at the grass position uint color = 0; if (layer.ColorMap != null) { color = layer.ColorMap.GetColorAt(x, z); } else { color = 0xFFFFFFFF; } //Calculate size float rnd = MogreLibMath.Utility.UnitRandom();//The same rnd value is used for width and height to maintain aspect ratio float halfXScale = (layer.mMinWidth + rndWidth * rnd) * 0.5f; float scaleY = (layer.mMinWidth + rndHeight * rnd); //Calculate rotation float angle = MogreLibMath.Utility.RangeRandom(0, MogreLibMath.Utility.TWO_PI); float xTrans = MogreLibMath.Utility.Cos(angle) * halfXScale; float zTrans = MogreLibMath.Utility.Sin(angle) * halfXScale; //Calculate heights and edge positions float x1 = x - xTrans, z1 = z - zTrans; float x2 = x + xTrans, z2 = z + zTrans; float y1, y2; if (mHeightFunction != null) { y1 = mHeightFunction.GetHeightAt(x1, z1, mHeightFunctionUserData); y2 = mHeightFunction.GetHeightAt(x2, z2, mHeightFunctionUserData); } else { y1 = 0; y2 = 0; } //Add vertices *pReal++ = (x1 - page.CenterPoint.x); *pReal++ = (y1 + scaleY); *pReal++ = (z1 - page.CenterPoint.z); //pos *((uint *)pReal++) = color; //color *pReal++ = 0; *pReal++ = 0; //uv *pReal++ = (x2 - page.CenterPoint.x); *pReal++ = (y2 + scaleY); *pReal++ = (z2 - page.CenterPoint.z); //pos *((uint *)pReal++) = color; //color *pReal++ = 1; *pReal++ = 0; //uv *pReal++ = (x1 - page.CenterPoint.x); *pReal++ = (y1); *pReal++ = (z1 - page.CenterPoint.z); //pos *((uint *)pReal++) = color; //color *pReal++ = 0; *pReal++ = 1; //uv *pReal++ = (x2 - page.CenterPoint.x); *pReal++ = (y2); *pReal++ = (z2 - page.CenterPoint.z); //pos *((uint *)pReal++) = color; //color *pReal++ = 1; *pReal++ = 1; //uv //Update bounds if (y1 < minY) { minY = y1; } if (y2 < minY) { minY = y2; } if (y1 + scaleY > maxY) { maxY = y1 + scaleY; } if (y2 + scaleY > maxY) { maxY = y2 + scaleY; } //Calculate heights and edge positions float x3 = x + zTrans, z3 = z - xTrans; float x4 = x - zTrans, z4 = z + xTrans; float y3, y4; if (mHeightFunction != null) { y3 = mHeightFunction.GetHeightAt(x3, z3, mHeightFunctionUserData); y4 = mHeightFunction.GetHeightAt(x4, z4, mHeightFunctionUserData); } else { y3 = 0; y4 = 0; } //Add vertices *pReal++ = (x3 - page.CenterPoint.x); *pReal++ = (y3 + scaleY); *pReal++ = (z3 - page.CenterPoint.z); //pos *((uint *)pReal++) = color; //color *pReal++ = 0; *pReal++ = 0; //uv *pReal++ = (x4 - page.CenterPoint.x); *pReal++ = (y4 + scaleY); *pReal++ = (z4 - page.CenterPoint.z); //pos *((uint *)pReal++) = color; //color *pReal++ = 1; *pReal++ = 0; //uv *pReal++ = (x3 - page.CenterPoint.x); *pReal++ = (y3); *pReal++ = (z3 - page.CenterPoint.z); //pos *((uint *)pReal++) = color; //color *pReal++ = 0; *pReal++ = 1; //uv *pReal++ = (x4 - page.CenterPoint.x); *pReal++ = (y4); *pReal++ = (z4 - page.CenterPoint.z); //pos *((uint *)pReal++) = color; //color *pReal++ = 1; *pReal++ = 1; //uv //Update bounds if (y3 < minY) { minY = y1; } if (y4 < minY) { minY = y2; } if (y3 + scaleY > maxY) { maxY = y3 + scaleY; } if (y4 + scaleY > maxY) { maxY = y4 + scaleY; } } vbuf.Unlock(); subMesh.vertexData.vertexBufferBinding.SetBinding(0, vbuf); //Populate index buffer subMesh.indexData.indexStart = 0; subMesh.indexData.indexCount = 6 * quadCount; subMesh.indexData.indexBuffer = HardwareBufferManager.Instance.CreateIndexBuffer( IndexType.Size16, subMesh.indexData.indexCount, BufferUsage.DynamicWriteOnly); ushort *pI = (ushort *)subMesh.indexData.indexBuffer.Lock(BufferLocking.Discard); for (ushort i = 0; i < quadCount; i++) { ushort ofset = (ushort)(i * 4); * pI++ = (ushort)(0 + ofset); * pI++ = (ushort)(2 + ofset); * pI++ = (ushort)(1 + ofset); *pI++ = (ushort)(1 + ofset); *pI++ = (ushort)(2 + ofset); *pI++ = (ushort)(3 + ofset); } subMesh.indexData.indexBuffer.Unlock(); //Finish up mesh AxisAlignedBox bounds = new AxisAlignedBox( new Vector3(page.Bounds.Left - page.CenterPoint.x, minY, page.Bounds.Top - page.CenterPoint.z), new Vector3(page.Bounds.Right - page.CenterPoint.x, maxY, page.Bounds.Bottom - page.CenterPoint.z)); mesh.BoundingBox = bounds; Vector3 tmp = bounds.Maximum - bounds.Minimum; mesh.BoundingSphereRadius = tmp.Length * 0.5f; mesh.Load(); //Apply grass material to mesh subMesh.MaterialName = layer.Material.Name; //Return the mesh return(mesh); } }
private void LoadLevelVertices(Quake3Level q3lvl) { //----------------------------------------------------------------------- // Vertices //----------------------------------------------------------------------- // Allocate memory for vertices & copy vertexData = new VertexData(); // Create vertex declaration VertexDeclaration decl = vertexData.vertexDeclaration; int offset = 0; int lightTexOffset = 0; decl.AddElement(0, offset, VertexElementType.Float3, VertexElementSemantic.Position); offset += VertexElement.GetTypeSize(VertexElementType.Float3); decl.AddElement(0, offset, VertexElementType.Float3, VertexElementSemantic.Normal); offset += VertexElement.GetTypeSize(VertexElementType.Float3); decl.AddElement(0, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 0); offset += VertexElement.GetTypeSize(VertexElementType.Float2); decl.AddElement(0, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 1); // Build initial patches - we need to know how big the vertex buffer needs to be // to accommodate the subdivision // we don't want to include the elements for texture lighting, so we clone it InitQuake3Patches(q3lvl, (VertexDeclaration)decl.Clone()); // this is for texture lighting color and alpha decl.AddElement(1, lightTexOffset, VertexElementType.Color, VertexElementSemantic.Diffuse); lightTexOffset += VertexElement.GetTypeSize(VertexElementType.Color); // this is for texture lighting coords decl.AddElement(1, lightTexOffset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 2); // Create the vertex buffer, allow space for patches HardwareVertexBuffer vbuf = HardwareBufferManager.Instance.CreateVertexBuffer( Marshal.SizeOf(typeof(BspVertex)), q3lvl.NumVertices + patchVertexCount, BufferUsage.StaticWriteOnly, // the vertices will be read often for texture lighting, use shadow buffer true ); // Create the vertex buffer for texture lighting, allow space for patches HardwareVertexBuffer texLightBuf = HardwareBufferManager.Instance.CreateVertexBuffer( Marshal.SizeOf(typeof(TextureLightMap)), q3lvl.NumVertices + patchVertexCount, BufferUsage.DynamicWriteOnly, false ); // COPY static vertex data - Note that we can't just block-copy the vertex data because we have to reorder // our vertex elements; this is to ensure compatibility with older cards when using // hardware vertex buffers - Direct3D requires that the buffer format maps onto a // FVF in those older drivers. // Lock just the non-patch area for now. unsafe { BspVertex vert = new BspVertex(); TextureLightMap texLightMap = new TextureLightMap(); // Keep another base pointer for use later in patch building for (int v = 0; v < q3lvl.NumVertices; v++) { QuakeVertexToBspVertex(q3lvl.Vertices[v], out vert, out texLightMap); BspVertex * bvptr = | TextureLightMap *tlptr = &texLightMap; vbuf.WriteData( v * sizeof(BspVertex), sizeof(BspVertex), (IntPtr)bvptr ); texLightBuf.WriteData( v * sizeof(TextureLightMap), sizeof(TextureLightMap), (IntPtr)tlptr ); } } // Setup binding vertexData.vertexBufferBinding.SetBinding(0, vbuf); // Setup texture lighting binding vertexData.vertexBufferBinding.SetBinding(1, texLightBuf); // Set other data vertexData.vertexStart = 0; vertexData.vertexCount = q3lvl.NumVertices + patchVertexCount; }
/// <summary> /// /// </summary> /// <param name="page"></param> /// <param name="layer"></param> /// <param name="grassPostions"></param> /// <param name="grassCount"></param> /// <returns></returns> private Mesh GenerateGrassSprite(PageInfo page, GrassLayer layer, IntPtr grassPostions, int grassCount) { //Calculate the number of quads to be added int quadCount = grassCount; //Create manual mesh to store grass quads Mesh mesh = (Mesh)MeshManager.Instance.CreateManual(GetUniqueID(), ResourceGroupManager.DefaultResourceGroupName, null); SubMesh subMesh = mesh.CreateSubMesh(); subMesh.useSharedVertices = false; //Setup vertex format information subMesh.vertexData = new VertexData(); subMesh.vertexData.vertexStart = 0; subMesh.vertexData.vertexCount = 4 * quadCount; VertexDeclaration dcl = subMesh.vertexData.vertexDeclaration; int offset = 0; dcl.AddElement(0, offset, VertexElementType.Float3, VertexElementSemantic.Position); offset += VertexElement.GetTypeSize(VertexElementType.Float3); dcl.AddElement(0, offset, VertexElementType.Float4, VertexElementSemantic.Normal); offset += VertexElement.GetTypeSize(VertexElementType.Float4); dcl.AddElement(0, offset, VertexElementType.Color, VertexElementSemantic.Diffuse); offset += VertexElement.GetTypeSize(VertexElementType.Color); dcl.AddElement(0, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords); offset += VertexElement.GetTypeSize(VertexElementType.Float2); //Populate a new vertex buffer with grass HardwareVertexBuffer vbuf = HardwareBufferManager.Instance.CreateVertexBuffer( /*offset*/ dcl, subMesh.vertexData.vertexCount, BufferUsage.DynamicWriteOnly, false); unsafe { float *pReal = (float *)vbuf.Lock(BufferLocking.Discard); //Calculate size variance float rndWidth = layer.mMaxWidth - layer.mMinWidth; float rndHeight = layer.mMaxHeight - layer.mMinHeight; float minY = float.PositiveInfinity, maxY = float.NegativeInfinity; float *posPtr = (float *)grassPostions; //Position array "iterator" for (int i = 0; i < grassCount; i++) { //Get the x and z positions from the position array float x = *posPtr++; float z = *posPtr++; //Calculate height float y = 0; if (mHeightFunction != null) { y = mHeightFunction.GetHeightAt(x, z, mHeightFunctionUserData); } else { y = 0; } float x1 = (x - page.CenterPoint.x); float z1 = (z - page.CenterPoint.z); //Get the color at the grass position uint color = 0; if (layer.ColorMap != null) { color = layer.ColorMap.GetColorAt(x, z); } else { color = 0xFFFFFFFF; } //Calculate size float rnd = MogreLibMath.Utility.UnitRandom();//The same rnd value is used for width and height to maintain aspect ratio float halfXScale = (layer.mMinWidth + rndWidth * rnd) * 0.5f; float scaleY = (layer.mMinWidth + rndHeight * rnd); //Randomly mirror grass textures float uvLeft, uvRight; if (MogreLibMath.Utility.UnitRandom() > 0.5f) { uvLeft = 0; uvRight = 1; } else { uvLeft = 1; uvRight = 0; } //Add vertices *pReal++ = x1; *pReal++ = y; *pReal++ = z1; //center position *pReal++ = -halfXScale; *pReal++ = scaleY; *pReal++ = 0; *pReal++ = 0; //normal (used to store relative corner positions) *((uint *)pReal++) = color; //color *pReal++ = uvLeft; *pReal++ = 0; //uv *pReal++ = x1; *pReal++ = y; *pReal++ = z1; //center position *pReal++ = +halfXScale; *pReal++ = scaleY; *pReal++ = 0; *pReal++ = 0; //normal (used to store relative corner positions) *((uint *)pReal++) = color; //color *pReal++ = uvRight; *pReal++ = 0; //uv *pReal++ = x1; *pReal++ = y; *pReal++ = z1; //center position *pReal++ = -halfXScale; *pReal++ = 0.0f; *pReal++ = 0; *pReal++ = 0; //normal (used to store relative corner positions) *((uint *)pReal++) = color; //color *pReal++ = uvLeft; *pReal++ = 1; //uv *pReal++ = x1; *pReal++ = y; *pReal++ = z1; //center position *pReal++ = +halfXScale; *pReal++ = 0.0f; *pReal++ = 0; *pReal++ = 0; //normal (used to store relative corner positions) *((uint *)pReal++) = color; //color *pReal++ = uvRight; *pReal++ = 1; //uv //Update bounds if (y < minY) { minY = y; } if (y + scaleY > maxY) { maxY = y + scaleY; } } vbuf.Unlock(); subMesh.vertexData.vertexBufferBinding.SetBinding(0, vbuf); //Populate index buffer subMesh.indexData.indexStart = 0; subMesh.indexData.indexCount = 6 * quadCount; subMesh.indexData.indexBuffer = HardwareBufferManager.Instance.CreateIndexBuffer( IndexType.Size16, subMesh.indexData.indexCount, BufferUsage.DynamicWriteOnly); ushort *pI = (ushort *)subMesh.indexData.indexBuffer.Lock(BufferLocking.Discard); for (ushort i = 0; i < quadCount; i++) { ushort ofset = (ushort)(i * 4); * pI++ = (ushort)(0 + ofset); * pI++ = (ushort)(2 + ofset); * pI++ = (ushort)(1 + ofset); *pI++ = (ushort)(1 + ofset); *pI++ = (ushort)(2 + ofset); *pI++ = (ushort)(3 + ofset); } subMesh.indexData.indexBuffer.Unlock(); //Finish up mesh AxisAlignedBox bounds = new AxisAlignedBox( new Vector3(page.Bounds.Left - page.CenterPoint.x, minY, page.Bounds.Top - page.CenterPoint.z), new Vector3(page.Bounds.Right - page.CenterPoint.x, maxY, page.Bounds.Bottom - page.CenterPoint.z)); mesh.BoundingBox = bounds; Vector3 tmp = bounds.Maximum - bounds.Minimum; mesh.BoundingSphereRadius = tmp.Length * 0.5f; mesh.Load(); //Apply grass material to mesh subMesh.MaterialName = layer.Material.Name; //Return the mesh return(mesh); } }
public unsafe void createMesh() { /// Create the mesh via the MeshManager MeshPtr msh = MeshManager.Singleton.CreateManual("ColourCube", "General"); /// Create one submesh SubMesh sub = msh.CreateSubMesh(); /// Define the vertices (8 vertices, each consisting of 2 groups of 3 floats //const int nVertices = 8; //int row = recordno; // int col = demcol; int row = recordno; int col = 1100; int step = 10; int vbufCount; uint nVertices = (uint)(col * row); float[] vertices = CreateVertices(row, col, step, out vbufCount); /// Define 12 triangles (two triangles per cube face) /// The values in this table refer to vertices in the above table uint ibufCount; ushort[] faces = CreateFaces(row, col, out ibufCount); /// Create vertex data structure for 8 vertices shared between submeshes msh.sharedVertexData = new VertexData(); msh.sharedVertexData.vertexCount = nVertices; /// Create declaration (memory format) of vertex data VertexDeclaration decl = msh.sharedVertexData.vertexDeclaration; uint offset = 0; // 1st buffer decl.AddElement(0, offset, VertexElementType.VET_FLOAT3, VertexElementSemantic.VES_POSITION); offset += VertexElement.GetTypeSize(VertexElementType.VET_FLOAT3); decl.AddElement(0, offset, VertexElementType.VET_FLOAT2, VertexElementSemantic.VES_TEXTURE_COORDINATES); offset += VertexElement.GetTypeSize(VertexElementType.VET_FLOAT2); /// Allocate vertex buffer of the requested number of vertices (vertexCount) /// and bytes per vertex (offset) HardwareVertexBufferSharedPtr vbuf = HardwareBufferManager.Singleton.CreateVertexBuffer(offset, msh.sharedVertexData.vertexCount, HardwareBuffer.Usage.HBU_STATIC_WRITE_ONLY); /// Upload the vertex data to the card fixed(void *p = vertices) { vbuf.WriteData(0, vbuf.SizeInBytes, p, true);// writeData(0, vbuf->getSizeInBytes(), vertices, true); } /// Set vertex buffer binding so buffer 0 is bound to our vertex buffer VertexBufferBinding bind = msh.sharedVertexData.vertexBufferBinding;// msh->sharedVertexData->vertexBufferBinding; bind.SetBinding(0, vbuf); /// Allocate index buffer of the requested number of vertices (ibufCount) HardwareIndexBufferSharedPtr ibuf = HardwareBufferManager.Singleton.CreateIndexBuffer(HardwareIndexBuffer.IndexType.IT_16BIT, ibufCount, HardwareBuffer.Usage.HBU_STATIC_WRITE_ONLY); /// Upload the index data to the card fixed(void *p = faces) { ibuf.WriteData(0, ibuf.SizeInBytes, p, true); } /// Set parameters of the submesh sub.useSharedVertices = true; sub.indexData.indexBuffer = ibuf; sub.indexData.indexCount = ibufCount; sub.indexData.indexStart = 0; /// Set bounding information (for culling) msh._setBounds(new AxisAlignedBox(min, max)); // msh._setBoundingSphereRadius(Mogre.Math.Sqrt(3 * 100 * 100)); /// Notify Mesh object that it has been loaded msh.Load(); }
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); } }