public override MeshDraw CreateDebugPrimitive(GraphicsDevice device)
        {
            if (cachedDebugPrimitive != null) return cachedDebugPrimitive;

            var verts = new VertexPositionNormalTexture[pointsList.Count];
            for (var i = 0; i < pointsList.Count; i++)
            {
                verts[i].Position = pointsList[i];
                verts[i].TextureCoordinate = Vector2.Zero;
                verts[i].Normal = Vector3.Zero;
            }

            var intIndices = indicesList.Select(x => (int)x).ToArray();

            ////calculate basic normals
            ////todo verify, winding order might be wrong?
            for (var i = 0; i < indicesList.Count; i += 3)
            {
                var i1 = intIndices[i];
                var i2 = intIndices[i + 1];
                var i3 = intIndices[i + 2];
                var a = verts[i1];
                var b = verts[i2];
                var c = verts[i3];
                var n = Vector3.Cross((b.Position - a.Position), (c.Position - a.Position));
                n.Normalize();
                verts[i1].Normal = verts[i2].Normal = verts[i3].Normal = n;
            }

            var meshData = new GeometricMeshData<VertexPositionNormalTexture>(verts, intIndices, false);

            cachedDebugPrimitive = new GeometricPrimitive(device, meshData).ToMeshDraw();

            return cachedDebugPrimitive;
        }
Exemple #2
0
 /// <summary>
 /// Initializes a new instance of the <see cref="Mesh" /> class.
 /// </summary>
 /// <param name="meshDraw">The mesh draw.</param>
 /// <param name="parameters">The parameters.</param>
 /// <exception cref="System.ArgumentNullException">parameters</exception>
 public Mesh(MeshDraw meshDraw, ParameterCollection parameters)
 {
     if (meshDraw == null) throw new ArgumentNullException("meshDraw");
     if (parameters == null) throw new ArgumentNullException("parameters");
     Draw = meshDraw;
     Parameters = parameters;
 }
Exemple #3
0
 /// <summary>
 /// Initializes a new instance of the <see cref="Mesh" /> class.
 /// </summary>
 /// <param name="meshDraw">The mesh draw.</param>
 /// <param name="parameters">The parameters.</param>
 /// <exception cref="System.ArgumentNullException">parameters</exception>
 public Mesh(MeshDraw meshDraw, ParameterCollection parameters)
 {
     if (meshDraw == null)
     {
         throw new ArgumentNullException("meshDraw");
     }
     if (parameters == null)
     {
         throw new ArgumentNullException("parameters");
     }
     Draw       = meshDraw;
     Parameters = parameters;
 }
        protected override async Task LoadContent()
        {
            await base.LoadContent();

            var vertices = new Vertex[4];
            vertices[0] = new Vertex { Position = new Vector3(-1, -1, 0.5f), TexCoords = new Vector2(0, 0) };
            vertices[1] = new Vertex { Position = new Vector3(-1, 1, 0.5f), TexCoords = new Vector2(3, 0) };
            vertices[2] = new Vertex { Position = new Vector3(1, 1, 0.5f), TexCoords = new Vector2(3, 3) };
            vertices[3] = new Vertex { Position = new Vector3(1, -1, 0.5f), TexCoords = new Vector2(0, 3) };

            var indices = new short[] { 0, 1, 2, 0, 2, 3 };

            var vertexBuffer = Buffer.Vertex.New(GraphicsDevice, vertices, GraphicsResourceUsage.Default);
            var indexBuffer = Buffer.Index.New(GraphicsDevice, indices, GraphicsResourceUsage.Default);
            var meshDraw = new MeshDraw
            {
                DrawCount = 4,
                PrimitiveType = PrimitiveType.TriangleList,
                VertexBuffers = new[]
                {
                    new VertexBufferBinding(vertexBuffer,
                        new VertexDeclaration(VertexElement.Position<Vector3>(),
                            VertexElement.TextureCoordinate<Vector2>()),
                        4)
                },
                IndexBuffer = new IndexBufferBinding(indexBuffer, false, indices.Length),
            };

            var mesh = new Mesh
            {
                Draw = meshDraw,
            };

            simpleEffect = new Effect(GraphicsDevice, SpriteEffect.Bytecode);
            parameterCollection = new ParameterCollection();
            parameterCollectionGroup = new EffectParameterCollectionGroup(GraphicsDevice, simpleEffect, new[] { parameterCollection });
            parameterCollection.Set(TexturingKeys.Texture0, UVTexture);

            vao = VertexArrayObject.New(GraphicsDevice, mesh.Draw.IndexBuffer, mesh.Draw.VertexBuffers);

            myDraws = new DrawOptions[3];
            myDraws[0] = new DrawOptions { Sampler = GraphicsDevice.SamplerStates.LinearClamp, Transform = Matrix.Multiply(Matrix.Scaling(0.4f), Matrix.Translation(-0.5f, 0.5f, 0f)) };
            myDraws[1] = new DrawOptions { Sampler = GraphicsDevice.SamplerStates.LinearWrap, Transform = Matrix.Multiply(Matrix.Scaling(0.4f), Matrix.Translation(0.5f, 0.5f, 0f)) };
            myDraws[2] = new DrawOptions { Sampler = SamplerState.New(GraphicsDevice, new SamplerStateDescription(TextureFilter.Linear, TextureAddressMode.Mirror)), Transform = Matrix.Multiply(Matrix.Scaling(0.4f), Matrix.Translation(0.5f, -0.5f, 0f)) };
            //var borderDescription = new SamplerStateDescription(TextureFilter.Linear, TextureAddressMode.Border) { BorderColor = Color.Purple };
            //var border = SamplerState.New(GraphicsDevice, borderDescription);
            //myDraws[3] = new DrawOptions { Sampler = border, Transform = Matrix.Multiply(Matrix.Scale(0.3f), Matrix.Translation(-0.5f, -0.5f, 0f)) };
        }
Exemple #5
0
 public override MeshDraw CreateDebugPrimitive(GraphicsDevice device)
 {
     return cachedDebugPrimitive ?? (cachedDebugPrimitive = GeometricPrimitive.Cube.New(device).ToMeshDraw());
 }
        /// <summary>
        /// Transform a vertex buffer positions, normals, tangents and bitangents using the given matrix.
        /// </summary>
        /// <param name="meshDrawDatas">The mesh draw datas.</param>
        /// <param name="can32BitIndex">A flag stating if 32 bit index buffers.</param>
        public unsafe static MeshDraw MergeDrawData(IList<MeshDraw> meshDrawDatas, bool can32BitIndex)
        {
            if (meshDrawDatas.Count == 0)
                throw new ArgumentException("Need at least 1 MeshDrawData.", "meshDrawDatas");

            if (meshDrawDatas.Count == 1)
                return meshDrawDatas[0];

            // Check that vertex buffer declarations are matching
            var firstMeshDrawData = meshDrawDatas[0];
            if (!firstMeshDrawData.IsSimple())
                throw new InvalidOperationException("Can only merge simple MeshDrawData.");

            var firstVertexBuffer = firstMeshDrawData.VertexBuffers[0];
            var hasIndexBuffer = IsIndexed(meshDrawDatas);
            int totalVertexCount = 0;
            int totalIndexCount = 0;

            //TODO: extend to non-simple vertex declarations, fill with default values it missing declarations etc. ?

            for (int i = 0; i < meshDrawDatas.Count; i++)
            {
                var meshDrawData = meshDrawDatas[i];

                // This should not happen anymore
                if (i != 0)
                {
                    if (!meshDrawData.IsSimple())
                        throw new InvalidOperationException("Can only merge simple MeshDrawData.");

                    if (meshDrawData.VertexBuffers.Length != firstMeshDrawData.VertexBuffers.Length)
                        throw new InvalidOperationException("Non-matching vertex buffer declarations.");

                    if (!meshDrawData.VertexBuffers[0].Declaration.Equals(firstMeshDrawData.VertexBuffers[0].Declaration))
                        throw new InvalidOperationException("Non-matching vertex buffer declarations.");
                }

                if (meshDrawData.PrimitiveType != PrimitiveType.TriangleList)
                    throw new InvalidOperationException("Can only merge TriangleList.");

                // Update vertex/index counts
                totalVertexCount += meshDrawData.VertexBuffers[0].Count;
                if (hasIndexBuffer)
                {
                    if (meshDrawData.IndexBuffer != null)
                        totalIndexCount += meshDrawData.IndexBuffer.Count;
                    else
                        totalIndexCount += meshDrawData.VertexBuffers[0].Count;
                }
            }

            // Allocate vertex buffer
            var result = new MeshDraw { PrimitiveType = PrimitiveType.TriangleList };
            var destBufferData = new byte[firstVertexBuffer.Declaration.VertexStride * totalVertexCount];
            result.VertexBuffers = new VertexBufferBinding[] {
                new VertexBufferBinding(
                    new BufferData(BufferFlags.VertexBuffer, destBufferData).ToSerializableVersion(),
                    firstVertexBuffer.Declaration,
                    totalVertexCount,
                    firstVertexBuffer.Stride)};

            // Copy vertex buffers
            fixed (byte* destBufferDataStart = &destBufferData[0])
            {
                var destBufferDataCurrent = destBufferDataStart;
                foreach (var meshDrawData in meshDrawDatas)
                {
                    var sourceBuffer = meshDrawData.VertexBuffers[0].Buffer.GetSerializationData();
                    fixed (byte* sourceBufferDataStart = &sourceBuffer.Content[0])
                    {
                        Utilities.CopyMemory((IntPtr)destBufferDataCurrent, (IntPtr)sourceBufferDataStart, sourceBuffer.Content.Length);
                        destBufferDataCurrent += sourceBuffer.Content.Length;
                    }
                }
            }

            if (hasIndexBuffer)
            {
                var use32BitIndex = can32BitIndex && totalVertexCount > ushort.MaxValue; // 65535 = 0xFFFF is kept for primitive restart in strip

                // Allocate index buffer
                destBufferData = new byte[(use32BitIndex ? sizeof(uint) : sizeof(ushort)) * totalIndexCount];
                result.IndexBuffer = new IndexBufferBinding(
                    new BufferData(BufferFlags.IndexBuffer, destBufferData).ToSerializableVersion(),
                    use32BitIndex,
                    totalIndexCount);

                // Copy index buffers
                fixed (byte* destBufferDataStart = &destBufferData[0])
                {
                    var destBufferDataCurrent = destBufferDataStart;
                    var offset = 0;
                    foreach (var meshDrawData in meshDrawDatas)
                    {
                        var indexBuffer = meshDrawData.IndexBuffer;
                        byte[] sourceBufferContent = null;
                        var is32Bit = false;

                        if (indexBuffer != null)
                        {
                            sourceBufferContent = indexBuffer.Buffer.GetSerializationData().Content;
                            is32Bit = indexBuffer.Is32Bit;
                        }

                        if (offset != 0 || (use32BitIndex != meshDrawData.IndexBuffer.Is32Bit))
                        {
                            if (use32BitIndex)
                                sourceBufferContent = CreateIntIndexBuffer(offset, meshDrawData.IndexBuffer.Count, sourceBufferContent, is32Bit);
                            else
                                sourceBufferContent = CreateShortIndexBuffer(offset, meshDrawData.IndexBuffer.Count, sourceBufferContent, is32Bit);
                        }
                        
                        fixed (byte* sourceBufferDataStart = &sourceBufferContent[0])
                        {
                            Utilities.CopyMemory((IntPtr)destBufferDataCurrent, (IntPtr)sourceBufferDataStart,
                                sourceBufferContent.Length);
                            destBufferDataCurrent += sourceBufferContent.Length;
                        }

                        offset += meshDrawData.VertexBuffers[0].Count;
                    }
                }

                result.DrawCount = totalIndexCount;
            }
            else
            {
                result.DrawCount = totalVertexCount;
            }

            return result;
        }
        public void Generate(IServiceRegistry services, Model model)
        {
            if (services == null) throw new ArgumentNullException("services");
            if (model == null) throw new ArgumentNullException("model");

            var graphicsDevice = services.GetSafeServiceAs<IGraphicsDeviceService>().GraphicsDevice;

            var data = this.CreatePrimitiveMeshData();

            if (data.Vertices.Length == 0)
            {
                throw new InvalidOperationException("Invalid GeometricPrimitive [{0}]. Expecting non-zero Vertices array");
            }

            var boundingBox = BoundingBox.Empty;
            for (int i = 0; i < data.Vertices.Length; i++)
                BoundingBox.Merge(ref boundingBox, ref data.Vertices[i].Position, out boundingBox);

            BoundingSphere boundingSphere;
            unsafe
            {
                fixed (void* verticesPtr = data.Vertices)
                    BoundingSphere.FromPoints((IntPtr)verticesPtr, 0, data.Vertices.Length, VertexPositionNormalTexture.Size, out boundingSphere);
            }

            var originalLayout = data.Vertices[0].GetLayout();

            // Generate Tangent/BiNormal vectors
            var resultWithTangentBiNormal = VertexHelper.GenerateTangentBinormal(originalLayout, data.Vertices, data.Indices);

            // Generate Multitexcoords
            var result = VertexHelper.GenerateMultiTextureCoordinates(resultWithTangentBiNormal);

            var meshDraw = new MeshDraw();

            var layout = result.Layout;
            var vertexBuffer = result.VertexBuffer;
            var indices = data.Indices;

            if (indices.Length < 0xFFFF)
            {
                var indicesShort = new ushort[indices.Length];
                for (int i = 0; i < indicesShort.Length; i++)
                {
                    indicesShort[i] = (ushort)indices[i];
                }
                meshDraw.IndexBuffer = new IndexBufferBinding(Buffer.Index.New(graphicsDevice, indicesShort).RecreateWith(indicesShort), false, indices.Length);
            }
            else
            {
                if (graphicsDevice.Features.Profile <= GraphicsProfile.Level_9_3)
                {
                    throw new InvalidOperationException("Cannot generate more than 65535 indices on feature level HW <= 9.3");
                }

                meshDraw.IndexBuffer = new IndexBufferBinding(Buffer.Index.New(graphicsDevice, indices).RecreateWith(indices), true, indices.Length);
            }

            meshDraw.VertexBuffers = new[] { new VertexBufferBinding(Buffer.New(graphicsDevice, vertexBuffer, BufferFlags.VertexBuffer).RecreateWith(vertexBuffer), layout, data.Vertices.Length) };

            meshDraw.DrawCount = indices.Length;
            meshDraw.PrimitiveType = PrimitiveType.TriangleList;

            var mesh = new Mesh { Draw = meshDraw, BoundingBox = boundingBox, BoundingSphere = boundingSphere };

            model.BoundingBox = boundingBox;
            model.BoundingSphere = boundingSphere;
            model.Add(mesh);

            if (MaterialInstance != null && MaterialInstance.Material != null)
            {
                model.Materials.Add(MaterialInstance);
            }
        }
        /// <summary>
        /// Split the mesh if it has strictly more than 65535 vertices (max index = 65534) on a plaftorm that does not support 32 bits indices.
        /// </summary>
        /// <param name="meshDrawData">The mesh to analyze.</param>
        /// <param name="can32bitIndex">A flag stating if 32 bit indices are allowed.</param>
        /// <returns>A list of meshes.</returns>
        public unsafe static List<MeshDraw> SplitMesh(MeshDraw meshDrawData, bool can32bitIndex)
        {
            if (meshDrawData.IndexBuffer == null)
                return new List<MeshDraw> { meshDrawData };

            if (!meshDrawData.IndexBuffer.Is32Bit) // already 16 bits buffer
                return new List<MeshDraw> { meshDrawData };

            var verticesCount = meshDrawData.VertexBuffers[0].Count;
            if (verticesCount <= ushort.MaxValue) // can be put in a 16 bits buffer - 65535 = 0xFFFF is kept for primitive restart in strip
            {
                meshDrawData.CompactIndexBuffer();
                return new List<MeshDraw> { meshDrawData };
            }

            // now, we only have a 32 bits buffer that is justified because of a large vertex buffer

            if (can32bitIndex) // do nothing
                return new List<MeshDraw> { meshDrawData };

            // TODO: handle primitives other than triangle list
            if (meshDrawData.PrimitiveType != PrimitiveType.TriangleList)
                return new List<MeshDraw> { meshDrawData };

            // Split the mesh
            var finalList = new List<MeshDraw>();
            fixed (byte* indicesByte = &meshDrawData.IndexBuffer.Buffer.GetSerializationData().Content[0])
            {
                var indicesUint = (uint*)indicesByte;

                var splitInfos = new List<SplitInformation>();
                var currentSplit = new SplitInformation();
                currentSplit.StartTriangleIndex = 0;
                var currentIndexUintPtr = indicesUint;
                for (int triangleIndex = 0; triangleIndex < meshDrawData.IndexBuffer.Count / 3; ++triangleIndex)
                {
                    var verticesToAdd = 0;
                    var index0 = *currentIndexUintPtr++;
                    var index1 = *currentIndexUintPtr++;
                    var index2 = *currentIndexUintPtr++;
                    if (!currentSplit.UsedIndices.Contains(index0)) ++verticesToAdd;
                    if (!currentSplit.UsedIndices.Contains(index1)) ++verticesToAdd;
                    if (!currentSplit.UsedIndices.Contains(index2)) ++verticesToAdd;

                    if (currentSplit.UsedIndices.Count + verticesToAdd > 65535) // append in the same group
                    {
                        splitInfos.Add(currentSplit);
                        currentSplit = new SplitInformation();
                        currentSplit.StartTriangleIndex = triangleIndex;
                    }
                    AddTriangle(currentSplit, index0, index1, index2, triangleIndex);
                }

                if (currentSplit.UsedIndices.Count > 0)
                    splitInfos.Add(currentSplit);

                foreach (var splitInfo in splitInfos)
                {
                    var triangleCount = splitInfo.LastTriangleIndex - splitInfo.StartTriangleIndex + 1;
                    var newMeshDrawData = new MeshDraw
                    {
                        PrimitiveType = PrimitiveType.TriangleList,
                        DrawCount = 3 * triangleCount,
                        VertexBuffers = new VertexBufferBinding[meshDrawData.VertexBuffers.Length]
                    };

                    // vertex buffers
                    for (int vbIndex = 0; vbIndex < meshDrawData.VertexBuffers.Length; ++ vbIndex)
                    {
                        var stride = meshDrawData.VertexBuffers[vbIndex].Stride;
                        if (stride == 0)
                            stride = meshDrawData.VertexBuffers[vbIndex].Declaration.VertexStride;
                        var newVertexBuffer = new byte[splitInfo.UsedIndices.Count * stride];

                        fixed (byte* vertexBufferPtr = &meshDrawData.VertexBuffers[vbIndex].Buffer.GetSerializationData().Content[0])
                        fixed (byte* newVertexBufferPtr = &newVertexBuffer[vbIndex])
                        {
                            //copy vertex buffer
                            foreach (var index in splitInfo.UsedIndices)
                                Utilities.CopyMemory((IntPtr)(newVertexBufferPtr + stride * splitInfo.IndexRemapping[index]), (IntPtr)(vertexBufferPtr + stride * index), stride);
                        }

                        newMeshDrawData.VertexBuffers[vbIndex] = new VertexBufferBinding(
                            new BufferData(BufferFlags.VertexBuffer, newVertexBuffer).ToSerializableVersion(),
                            meshDrawData.VertexBuffers[vbIndex].Declaration,
                            splitInfo.UsedIndices.Count);
                    }

                    // index buffer
                    var newIndexBuffer = new byte[sizeof(ushort) * 3 * triangleCount];
                    fixed (byte* newIndexBufferPtr = &newIndexBuffer[0])
                    {
                        var newIndexBufferUshortPtr = (ushort*)newIndexBufferPtr;
                        var currentIndexPtr = &indicesUint[3 * splitInfo.StartTriangleIndex];
                        for (int triangleIndex = 0; triangleIndex < triangleCount; ++triangleIndex)
                        {
                            var index0 = *currentIndexPtr++;
                            var index1 = *currentIndexPtr++;
                            var index2 = *currentIndexPtr++;

                            var newIndex0 = splitInfo.IndexRemapping[index0];
                            var newIndex1 = splitInfo.IndexRemapping[index1];
                            var newIndex2 = splitInfo.IndexRemapping[index2];

                            *newIndexBufferUshortPtr++ = newIndex0;
                            *newIndexBufferUshortPtr++ = newIndex1;
                            *newIndexBufferUshortPtr++ = newIndex2;
                        }
                    }

                    newMeshDrawData.IndexBuffer = new IndexBufferBinding(
                        new BufferData(BufferFlags.IndexBuffer, newIndexBuffer).ToSerializableVersion(),
                        false,
                        triangleCount*3);

                    finalList.Add(newMeshDrawData);
                }
            }
            return finalList;
        }