MOGRE GeneratingAMesh        

If you look at the original code snippet for generating a Mesh, you will see that some pointers arithmetic is needed. That could be fine with C++, but by default C# does not support pointer arithmetic. However, by using the unsafe keyword, it is possible to define an unsafe context in which pointers can be used. In order to hide the complexity of unsafe code we use the following class:

using System;
using Mogre;

namespace Mogre.Helpers
{
    /// <summary>
    /// A helper class for manual mesh
    //  This class hide unsafe code
    /// This code is based on MeshBuilderHelper.h
    /// originally developed by rastaman 11/16/2005
    /// </summary>
    public class MeshBuilderHelper
    {
        public MeshBuilderHelper(String name, String resourcegroup,
            bool usesharedvertices, uint vertexstart, uint vertexcount)
        {
            mName = name;
            mResourceGroup = resourcegroup;
            mVertextStart = vertexstart;
            mVertexCount = vertexcount;

            // Return now if already exists
            if (MeshManager.Singleton.ResourceExists(name))
                return;

            mMeshPtr = MeshManager.Singleton.CreateManual(mName, mResourceGroup);
            mSubMesh = mMeshPtr.CreateSubMesh();
            mSubMesh.useSharedVertices = usesharedvertices;
            mSubMesh.vertexData = new VertexData();
            mSubMesh.vertexData.vertexStart = mVertextStart;
            mSubMesh.vertexData.vertexCount = mVertexCount;
            offset = 0;
            mIndexType = HardwareIndexBuffer.IndexType.IT_16BIT;
        }

        public virtual VertexElement AddElement(VertexElementType theType, 
                                                VertexElementSemantic semantic)
        {
            VertexElement ve = mSubMesh.vertexData.vertexDeclaration.AddElement(0, offset, 
                                                                         theType, semantic);
            offset += VertexElement.GetTypeSize(theType);
            return ve;
        }

        public virtual void CreateVertexBuffer(uint numVerts, HardwareBuffer.Usage usage)
        {
            CreateVertexBuffer(numVerts, usage, false);
        }

        public virtual void CreateVertexBuffer(uint numVerts, 
                                               HardwareBuffer.Usage usage, 
                                               bool useShadowBuffer)
        {
            mVertexSize = offset;
            mNumVerts = numVerts;
            mvbuf = HardwareBufferManager.Singleton.CreateVertexBuffer(
                    mVertexSize, mNumVerts, usage, useShadowBuffer);
            unsafe
            {
                pVBuffStart = mvbuf.Lock(HardwareBuffer.LockOptions.HBL_DISCARD);
            }
        }

        public virtual void SetVertFloat(uint vertexindex, uint byteoffset, float val1)
        {
            if (vertexindex >= mNumVerts)
                throw new IndexOutOfRangeException(
                             "'vertexIndex' cannot be greater than the number of vertices.");
            unsafe
            {
                byte* pp = (byte*)pVBuffStart;
                pp += (mVertexSize * vertexindex) + byteoffset;
                float* p = (float*)pp;
                *p = val1;
            }
        }

        public virtual void SetVertFloat(uint vertexindex,
                                         uint byteoffset,
                                         float val1,
                                         float val2)
        {
            if (vertexindex >= mNumVerts)
                throw new IndexOutOfRangeException(
                                "'vertexIndex' cannot be greater than the number of vertices.");
            unsafe
            {
                byte* pp = (byte*)pVBuffStart;
                pp += (mVertexSize * vertexindex) + byteoffset;
                float* p = (float*)pp;
                *p++ = val1;
                *p = val2;
            }
        }

        public virtual void SetVertFloat(uint vertexindex, 
                                         uint byteoffset,
                                         float val1,
                                         float val2, 
                                         float val3)
        {
            if (vertexindex >= mNumVerts)
                throw new IndexOutOfRangeException(
                                "'vertexIndex' cannot be greater than the number of vertices.");
            unsafe
            {
                byte* pp = (byte*)pVBuffStart;
                pp += (mVertexSize * vertexindex) + byteoffset;
                float* p = (float*)pp;
                *p++ = val1;
                *p++ = val2;
                *p = val3;
            }
        }

        public virtual void SetVertFloat(uint vertexindex, 
                                         uint byteoffset,
                                         float val1, float val2, float val3, float val4)
        {
            if (vertexindex >= mNumVerts)
                throw new IndexOutOfRangeException(
                             "'vertexIndex' cannot be greater than the number of vertices.");
            unsafe
            {
                byte* pp = (byte*)pVBuffStart;
                pp += (mVertexSize * vertexindex) + byteoffset;
                float* p = (float*)pp;
                *p++ = val1;
                *p++ = val2;
                *p++ = val3;
                *p = val4;
            }
        }

        public virtual void CreateIndexBuffer(uint triaglecount,
                                                HardwareIndexBuffer.IndexType itype,
                                                HardwareBuffer.Usage usage)
        {
            CreateIndexBuffer(triaglecount, itype, usage, false);
        }

        public virtual void CreateIndexBuffer(uint triaglecount,
                                               HardwareIndexBuffer.IndexType itype,
                                                HardwareBuffer.Usage usage,
                                                bool useShadowBuffer)
        {
            mvbuf.Unlock();
            mTriagleCount = triaglecount;
            mIndexType = itype;
            mSubMesh.vertexData.vertexBufferBinding.SetBinding(0, mvbuf);
            mSubMesh.indexData.indexCount = mTriagleCount * 3;
            HardwareIndexBufferSharedPtr ibuf = HardwareBufferManager.Singleton
                .CreateIndexBuffer(mIndexType, mTriagleCount * 3, usage, useShadowBuffer);
            mSubMesh.indexData.indexBuffer = ibuf;
            unsafe
            {
                pIBuffStart = ibuf.Lock(HardwareBuffer.LockOptions.HBL_DISCARD);
            }
        }

        public virtual void SetIndex16bit(uint triagleIdx, 
                                          ushort vidx1, ushort vidx2, ushort vidx3)
        {
            if (triagleIdx >= mTriagleCount)
                throw new IndexOutOfRangeException(
                              "'triagleIdx' cannot be greater than the number of triangles.");
            if (mIndexType != HardwareIndexBuffer.IndexType.IT_16BIT)
                throw new NotSupportedException(
                              "HardwareIndexBuffer.IndexType other than 'IT_16BIT' is not supported.");
            unsafe
            {
                ushort* p = (ushort*)pIBuffStart;
                p += (triagleIdx * 3);
                *p++ = vidx1;
                *p++ = vidx2;
                *p = vidx3;
            }
        }

        public virtual void SetIndex32bit(uint triagleIdx, 
                                          uint vidx1, uint vidx2, uint vidx3)
        {
            if (triagleIdx >= mTriagleCount)
                throw new IndexOutOfRangeException(
                            "'triagleIdx' cannot be greater than the number of triangles.");
            if (mIndexType != HardwareIndexBuffer.IndexType.IT_16BIT)
                throw new NotSupportedException(
                            "HardwareIndexBuffer.IndexType other than 'IT_16BIT' is not supported.");
            unsafe
            {

                uint* p = (uint*)pIBuffStart;
                p += (triagleIdx * 3);
                *p++ = vidx1;
                *p++ = vidx2;
                *p = vidx3;
            }
        }
        public virtual MeshPtr Load(String materialname)
        {
            mSubMesh.indexData.indexBuffer.Unlock();
            mSubMesh.MaterialName = materialname;
            mMeshPtr.Load();
            return mMeshPtr;
        }

        #region Protected and Private fields
        protected MeshPtr mMeshPtr;
        protected SubMesh mSubMesh;
        protected String mName, mResourceGroup;
        protected uint mVertextStart, mVertexCount;
        protected HardwareVertexBufferSharedPtr mvbuf;
        protected uint offset;
        protected uint mVertexSize;
        protected uint mNumVerts;
        protected unsafe void* pVBuffStart = (void*)0;
        protected uint mTriagleCount;
        protected HardwareIndexBuffer.IndexType mIndexType;
        protected unsafe void* pIBuffStart = (void*)0;

        #endregion

    }
}

Remember that you must compile your MeshBuilderHelper class with the unsafe option. Now, you can create your own mesh. In our example, we create a classical triangle with the following code.

void CreateTriangle(string name)
        {
            MeshBuilderHelper mbh = new MeshBuilderHelper(name, "General", false, 0, 3);

            UInt32 offPos = mbh.AddElement(VertexElementType.VET_FLOAT3,
                                           VertexElementSemantic.VES_POSITION).Offset;
            UInt32 offDiff = mbh.AddElement(VertexElementType.VET_FLOAT3,
                                            VertexElementSemantic.VES_DIFFUSE).Offset;

            mbh.CreateVertexBuffer(3, HardwareBuffer.Usage.HBU_STATIC_WRITE_ONLY);

            mbh.SetVertFloat(0, offPos, 0, 0, 0);      //position
            mbh.SetVertFloat(0, offDiff, 1, 0, 0);      //color

            mbh.SetVertFloat(1, offPos, 0, 10, 0);      //position
            mbh.SetVertFloat(1, offDiff, 0, 0, 1);      //color

            mbh.SetVertFloat(2, offPos, 10, 0, 0);      //position
            mbh.SetVertFloat(2, offDiff, 0, 1, 0);      //color

            mbh.CreateIndexBuffer(1, HardwareIndexBuffer.IndexType.IT_16BIT,
                                  HardwareBuffer.Usage.HBU_STATIC_WRITE_ONLY);

            mbh.SetIndex16bit(0, (UInt16)0, (UInt16)2, (UInt16)1);

            // we create a material for our triangle. This could/must be defined outside
            MaterialPtr material = MaterialManager.Singleton.Create("Test/ColourTest",
                                         ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME);
            material.GetTechnique(0).GetPass(0).VertexColourTracking = 
                           (int)TrackVertexColourEnum.TVC_AMBIENT;

            
            MeshPtr m = mbh.Load("Test/ColourTest");
            m._setBounds(new AxisAlignedBox(0.0f, 0.0f, 0.0f, 10.0f, 10.0f, 10.0f), false);
            m._setBoundingSphereRadius((float)System.Math.Sqrt(10.0f * 10.0f + 10.0f * 10.0f));
        }


To display this triangle within your Mogre application, you'll need to set up a material definition that looks like:

material Test/ColourTest
{
    technique
    {
        pass
        {
            ambient vertexcolour
        }
    }
}


Alternatively, the material can be created directly in C#:

MaterialPtr material = MaterialManager.Singleton.Create("Test/ColourTest",
                                             ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME);
material.GetTechnique(0).GetPass(0).VertexColourTracking = 
                                                  (int)TrackVertexColourEnum.TVC_AMBIENT;

In our example we have defined the material inside our CreateTriangle function, but you are free to define it before calling CreateTriangle.

Now, if I want to insert the mesh into a scene:

public override void CreateScene()
   {
      CreateTriangle("myTriangle");
      Entity ent1 = base.sceneMgr.CreateEntity("Triangle1", "myTriangle");
      SceneNode node1 = base.sceneMgr.RootSceneNode.CreateChildSceneNode("TriangleNode");
      node1.AttachObject(ent1);
   }


A final note. If you are using the sample Application, our camera is too far from our triangle. I recomend to use this code in your main program:

public override void CreateCamera()
{
   // Create the camera
   camera = sceneMgr.CreateCamera("PlayerCam");

   // Position it at 30 in Z direction
   camera.Position = new Vector3(0, 0, 30);
   // Look at our triangle
   camera.LookAt(new Vector3(5, 5, 5));
   camera.NearClipDistance = 1;
}


Finally, if everything is OK, you will see:
TriangleScreenshotWithMogre.jpg