/// <inheritdoc/>
 internal override void OnDraw(GraphicsDevice graphicsDevice, Rectangle rectangle, Vector2F topLeftPosition, Vector2F bottomRightPosition)
 {
     if (Submesh != null)
     {
         Submesh.Draw();
     }
 }
 /// <summary>
 /// Sets the road mesh and related properties.
 /// </summary>
 /// <param name="submesh">The submesh that represents the road.</param>
 /// <param name="aabb">The axis-aligned bounding box of the mesh.</param>
 /// <param name="roadLength">The length of the road in world space units.</param>
 /// <param name="disposeWithRoadLayer">
 /// <see langword="true" /> to automatically dispose of the mesh when the
 /// <see cref="TerrainRoadLayer"/> is disposed of; otherwise, <see langword="false"/>.
 /// </param>
 /// <remarks>
 /// <see cref="CreateMesh"/> can be used to create a suitable mesh.
 /// </remarks>
 public void SetMesh(Submesh submesh, Aabb aabb, float roadLength, bool disposeWithRoadLayer)
 {
     Submesh      = submesh;
     Aabb         = aabb;
     RoadLength   = roadLength;
     _disposeMesh = disposeWithRoadLayer;
 }
Exemple #3
0
    public void GetMesh(Shape shape, out Submesh submesh, out Matrix matrix)
    {
      ThrowIfDisposed();
      if (shape == null)
        throw new ArgumentNullException("shape");

      var index = GetCacheIndex(shape);
      if (index >= 0)
      {
        // Found cache entry!

        var entry = _cache[index];

        Debug.Assert(entry.ShapeWeak.Target == shape, "ShapeMeshCache.GetCacheIndex() returned wrong index.");

        // Get submesh from strong or weak reference.
        submesh = entry.Submesh ?? (Submesh)entry.SubmeshWeak.Target;
        matrix = entry.Matrix;

        if (submesh != null)
        {
          // Recreate submesh if number of triangles in TriangleMeshShape has changed.
          var triangleMeshShape = shape as TriangleMeshShape;
          if (triangleMeshShape != null && triangleMeshShape.Mesh.NumberOfTriangles != submesh.PrimitiveCount)
          {
            DisposeMesh(entry);
            submesh = null;
          }
        }

        // Recreate submesh if necessary.
        if (submesh == null)
          CreateMesh(shape, out submesh, out matrix);

        _cache[index].Submesh = submesh;
        _cache[index].Matrix = matrix;
        _cache[index].Age = 0;
      }
      else
      {
        // No cache entry found.

        // GetCacheIndex returns the bitwise complement of the next index.
        index = ~index;

        // No submesh in cache.
        CreateMesh(shape, out submesh, out matrix);
        var entry = new CacheEntry(shape)
        {
          HashCode = _tempEntry.HashCode,
          Age = 0,
          Submesh = submesh,
          Matrix = matrix,
        };
        _cache.Insert(index, entry);

        // If shape changes, we must invalidate the cache entry:
        shape.Changed += OnCachedShapeChanged;
      }
    }
        public static Submesh CreateCircleLines(GraphicsDevice graphicsDevice, int numberOfSegments)
        {
            if (graphicsDevice == null)
            {
                throw new ArgumentNullException("graphicsDevice");
            }
            if (numberOfSegments < 3)
            {
                throw new ArgumentOutOfRangeException("numberOfSegments", "numberOfSegments must be greater than 2");
            }

            var submesh = new Submesh
            {
                PrimitiveType = PrimitiveType.LineList,
            };

            // Create vertices for a circle on the floor.
            var vertices = new Vector3[numberOfSegments];

            for (int i = 0; i < numberOfSegments; i++)
            {
                float angle = i * ConstantsF.TwoPi / numberOfSegments;

                float x = (float)Math.Cos(angle);
                float y = (float)Math.Sin(angle);
                vertices[i] = new Vector3(x, y, 0);
            }

            submesh.VertexBuffer = new VertexBuffer(
                graphicsDevice,
                VertexPosition.VertexDeclaration,
                vertices.Length,
                BufferUsage.None);
            submesh.VertexBuffer.SetData(vertices);
            submesh.VertexCount = submesh.VertexBuffer.VertexCount;

            // Create indices for base circle.
            var indices = new ushort[2 * numberOfSegments];

            for (int i = 0; i < numberOfSegments; i++)
            {
                indices[2 * i]     = (ushort)i;
                indices[2 * i + 1] = (ushort)(i + 1);
            }

            // Correct last index to be 0 to close circle.
            indices[2 * numberOfSegments - 1] = 0;

            submesh.IndexBuffer = new IndexBuffer(
                graphicsDevice,
                IndexElementSize.SixteenBits,
                indices.Length,
                BufferUsage.None);
            submesh.IndexBuffer.SetData(indices);

            submesh.PrimitiveCount = indices.Length / 2;

            return(submesh);
        }
Exemple #5
0
        public static Submesh CreateIcosphere(GraphicsDevice graphicsDevice, int numberOfSubdivisions)
        {
            if (graphicsDevice == null)
            {
                throw new ArgumentNullException("graphicsDevice");
            }
            if (numberOfSubdivisions < 1)
            {
                throw new ArgumentOutOfRangeException("numberOfSubdivisions", "numberOfSegments must be greater than 0");
            }

            var submesh = new Submesh
            {
                PrimitiveType = PrimitiveType.TriangleList,
            };

            var mesh             = GeometryHelper.CreateIcosphere(numberOfSubdivisions, false);
            int numberOfVertices = mesh.Vertices.Count;
            var vertexData       = new VertexPositionNormal[numberOfVertices];

            for (int i = 0; i < numberOfVertices; i++)
            {
                Vector3 v = (Vector3)mesh.Vertices[i];
                vertexData[i] = new VertexPositionNormal(v, v);
            }

            submesh.VertexBuffer = new VertexBuffer(
                graphicsDevice,
                VertexPositionNormal.VertexDeclaration,
                vertexData.Length,
                BufferUsage.None);
            submesh.VertexBuffer.SetData(vertexData);

            submesh.VertexCount = submesh.VertexBuffer.VertexCount;

            int numberOfTriangles = mesh.NumberOfTriangles;
            int numberOfIndices   = mesh.Indices.Count;
            var indexData         = new ushort[numberOfIndices];

            for (int i = 0; i < numberOfTriangles; i++)
            {
                // Flip vertex order. (DigitalRune Geometry uses CCW, XNA uses CW.)
                indexData[3 * i + 0] = (ushort)mesh.Indices[3 * i + 0];
                indexData[3 * i + 2] = (ushort)mesh.Indices[3 * i + 1];
                indexData[3 * i + 1] = (ushort)mesh.Indices[3 * i + 2];
            }

            submesh.IndexBuffer = new IndexBuffer(
                graphicsDevice,
                IndexElementSize.SixteenBits,
                indexData.Length,
                BufferUsage.None);
            submesh.IndexBuffer.SetData(indexData);

            submesh.PrimitiveCount = indexData.Length / 3;

            return(submesh);
        }
Exemple #6
0
    public static void SetMaterial(this Submesh submesh, Material material)
    {
      if (submesh == null)
        throw new ArgumentNullException("submesh");

      var mesh = submesh.Mesh;
      if (mesh == null)
        throw new InvalidOperationException("Cannot add material to submesh. Submesh needs to be added to Mesh first.");
      if (material == null)
        throw new ArgumentNullException("material");

      var oldMaterial = GetMaterial(submesh);
      if (oldMaterial == material)
        return;

      // Find out if the old or new material is used by other submeshes which belong
      // to the same mesh.
      bool oldMaterialStillInUse = false;
      bool newMaterialAlreadyInUse = false;
      foreach (var otherSubmesh in mesh.Submeshes)
      {
        if (otherSubmesh != submesh)
        {
          Material otherMaterial = GetMaterial(otherSubmesh);
          if (otherMaterial == oldMaterial)
            oldMaterialStillInUse = true;
          else if (otherMaterial == material)
            newMaterialAlreadyInUse = true;
        }
      }

      // Remove old material from parent mesh material collection if it is not used by 
      // any submesh.
      int oldIndex = submesh.MaterialIndex;
      if (!oldMaterialStillInUse && oldMaterial != null)
      {
        mesh.Materials.RemoveAt(oldIndex);

        // One material was removed --> Update indices of meshes.
        foreach (var otherSubmesh in mesh.Submeshes)
          if (otherSubmesh.MaterialIndex > oldIndex)
            otherSubmesh.MaterialIndex--;
      }

      // Add new material to parent mesh material collection if this is the first submesh
      // that uses this material.
      if (newMaterialAlreadyInUse)
      {
        // Get index of the new material.
        submesh.MaterialIndex = mesh.Materials.IndexOf(material);
      }
      else
      {
        // Add new material to the mesh at the end of the material collection.
        mesh.Materials.Add(material);
        submesh.MaterialIndex = mesh.Materials.Count - 1;
      }
    }
Exemple #7
0
    public static Material GetMaterial(this Submesh submesh)
    {
      if (submesh == null)
        throw new ArgumentNullException("submesh");

      var mesh = submesh.Mesh;
      if (mesh == null)
        return null;

      var index = submesh.MaterialIndex;

      if (0 <= index && index < mesh.Materials.Count)
        return mesh.Materials[index];

      return null;
    }
Exemple #8
0
 public static void GetMesh(IGraphicsService graphicsService, Shape shape, out Submesh submesh, out Matrix matrix)
 {
   // Update submesh.
   var graphicsManager = graphicsService as GraphicsManager;
   if (graphicsManager != null)
   {
     graphicsManager.ShapeMeshCache.GetMesh(shape, out submesh, out matrix);
   }
   else
   {
     // This happens if the user has implemented his own graphics manager - 
     // which is very unlikely.
     submesh = MeshHelper.CreateSubmesh(graphicsService.GraphicsDevice, shape.GetMesh(0.05f, 4), MathHelper.ToRadians(70));
     matrix = Matrix.Identity;
   }
 }
Exemple #9
0
    public static void Draw(this Submesh submesh)
    {
      if (submesh == null)
        throw new ArgumentNullException("submesh");

      Debug.Assert(!submesh.HasMorphTargets, "Submesh without morph targets expected.");

      var vertexBuffer = submesh.VertexBuffer;
      if (vertexBuffer == null || submesh.VertexCount <= 0)
        return;

      // VertexBuffer.GraphicsDevice is set to null when VertexBuffer is disposed of.
      // Check VertexBuffer.IsDisposed to avoid NullReferenceException.
      if (vertexBuffer.IsDisposed)
          throw new ObjectDisposedException("VertexBuffer", "Cannot draw mesh. The vertex buffer has already been disposed of.");

      var graphicsDevice = vertexBuffer.GraphicsDevice;
      graphicsDevice.SetVertexBuffer(vertexBuffer);

      var indexBuffer = submesh.IndexBuffer;
      if (indexBuffer == null)
      {
        graphicsDevice.DrawPrimitives(
          submesh.PrimitiveType,
          submesh.StartVertex,
          submesh.PrimitiveCount);
      }
      else
      {
        graphicsDevice.Indices = indexBuffer;

        graphicsDevice.DrawIndexedPrimitives(
          submesh.PrimitiveType,
          submesh.StartVertex,
          submesh.StartIndex,
          submesh.PrimitiveCount);
#else
        graphicsDevice.DrawIndexedPrimitives(
          submesh.PrimitiveType,
          submesh.StartVertex,
          0,
          submesh.VertexCount,
          submesh.StartIndex,
          submesh.PrimitiveCount);

      }
    }
        /// <inheritdoc/>
        protected override void Dispose(bool disposing)
        {
            if (!IsDisposed)
            {
                if (disposing)
                {
                    // Dispose managed resources.
                    if (_disposeMesh)
                    {
                        Submesh.SafeDispose();
                    }
                }

                // Release unmanaged resources.
            }

            base.Dispose(disposing);
        }
        public static Submesh CreateTeapot(GraphicsDevice graphicsDevice, float size, int tessellation)
        {
            if (graphicsDevice == null)
            {
                throw new ArgumentNullException("graphicsDevice");
            }
            if (tessellation < 1)
            {
                throw new ArgumentOutOfRangeException("tessellation");
            }

            var submesh = new Submesh
            {
                PrimitiveType = PrimitiveType.TriangleList,
            };

            var teapot = new Teapot(size, tessellation);

            submesh.VertexBuffer = new VertexBuffer(
                graphicsDevice,
                VertexPositionNormal.VertexDeclaration,
                teapot.Vertices.Length,
                BufferUsage.None);
            submesh.VertexBuffer.SetData(teapot.Vertices);

            submesh.VertexCount = submesh.VertexBuffer.VertexCount;

            submesh.IndexBuffer = new IndexBuffer(
                graphicsDevice,
                IndexElementSize.SixteenBits,
                teapot.Indices.Length,
                BufferUsage.None);
            submesh.IndexBuffer.SetData(teapot.Indices);

            submesh.PrimitiveCount = teapot.Indices.Length / 3;

            return(submesh);
        }
Exemple #12
0
    private void CreateMesh(Shape shape, out Submesh submesh, out Matrix matrix)
    {
      // Use a special shared submesh for box shapes.
      var boxShape = shape as BoxShape;
      if (boxShape != null)
      {
        if (_boxSubmesh == null)
          _boxSubmesh = MeshHelper.GetBox(_graphicsService);

        submesh = _boxSubmesh;
        matrix = Matrix.CreateScale(boxShape.Extent);
        return;
      }

      var transformedShape = shape as TransformedShape;
      boxShape = (transformedShape != null) ? transformedShape.Child.Shape as BoxShape : null;
      if (boxShape != null)
      {
        if (_boxSubmesh == null)
          _boxSubmesh = MeshHelper.GetBox(_graphicsService);

        submesh = _boxSubmesh;
        matrix = transformedShape.Child.Pose
                 * Matrix.CreateScale(transformedShape.Child.Scale * boxShape.Extent);
        return;
      }

      // Create the submesh. Return EmptySubmesh if the MeshHelper returns null.
      var newSubmesh = MeshHelper.CreateSubmesh(
        _graphicsService.GraphicsDevice,
        shape.GetMesh(MeshRelativeError, MeshIterationLimit),
        NormalAngleLimit);

      submesh = newSubmesh ?? EmptySubmesh;
      matrix = Matrix.Identity;
    }
Exemple #13
0
        public static Submesh CreateCone(GraphicsDevice graphicsDevice, int numberOfSegments)
        {
            if (graphicsDevice == null)
            {
                throw new ArgumentNullException("graphicsDevice");
            }
            if (numberOfSegments < 3)
            {
                throw new ArgumentOutOfRangeException("numberOfSegments", "numberOfSegments must be greater than 2");
            }

            var submesh = new Submesh
            {
                PrimitiveType = PrimitiveType.TriangleList,
            };

            var vertices = new List <VertexPositionNormal>();

            // Base
            Vector3 normal = -Vector3.UnitY;

            vertices.Add(new VertexPositionNormal(new Vector3(0, 0, 0), normal));
            for (int i = 0; i < numberOfSegments; i++)
            {
                float angle = i * ConstantsF.TwoPi / numberOfSegments;
                float x     = (float)Math.Cos(angle);
                float z     = -(float)Math.Sin(angle);
                vertices.Add(new VertexPositionNormal(new Vector3(x, 0, z), normal));
            }

            // Side
            vertices.Add(new VertexPositionNormal(new Vector3(0, 1, 0), new Vector3(0, 1, 0)));
            for (int i = 0; i < numberOfSegments; i++)
            {
                float       angle = i * ConstantsF.TwoPi / numberOfSegments;
                const float cos45 = 0.707106781f; // cos(45°)
                float       x     = (float)Math.Cos(angle);
                float       z     = -(float)Math.Sin(angle);
                vertices.Add(new VertexPositionNormal(new Vector3(x, 0, z), new Vector3(x * cos45, cos45, z * cos45)));
            }

            submesh.VertexBuffer = new VertexBuffer(
                graphicsDevice,
                VertexPositionNormal.VertexDeclaration,
                vertices.Count,
                BufferUsage.None);
            submesh.VertexBuffer.SetData(vertices.ToArray());

            submesh.VertexCount = submesh.VertexBuffer.VertexCount;

            var indices = new List <ushort>();

            // Base
            for (int i = 0; i < numberOfSegments - 1; i++)
            {
                indices.Add(0);
                indices.Add((ushort)(i + 1));
                indices.Add((ushort)(i + 2));
            }

            // Last base triangle.
            indices.Add(0);
            indices.Add((ushort)numberOfSegments);
            indices.Add(1);

            // Side triangle.
            for (int i = 0; i < numberOfSegments - 1; i++)
            {
                indices.Add((ushort)(numberOfSegments + 1));
                indices.Add((ushort)(numberOfSegments + i + 3));
                indices.Add((ushort)(numberOfSegments + i + 2));
            }

            // Last side triangle.
            indices.Add((ushort)(numberOfSegments + 1));
            indices.Add((ushort)(numberOfSegments + 2));
            indices.Add((ushort)(numberOfSegments + numberOfSegments + 1));

            submesh.IndexBuffer = new IndexBuffer(
                graphicsDevice,
                IndexElementSize.SixteenBits,
                indices.Count,
                BufferUsage.None);
            submesh.IndexBuffer.SetData(indices.ToArray());

            submesh.PrimitiveCount = indices.Count / 3;

            return(submesh);
        }
Exemple #14
0
    public static void ToTriangleMesh(this Submesh submesh, TriangleMesh triangleMesh)
    {
      // This method is similar to TriangleMesh.FromModel().

      if (submesh == null)
        throw new ArgumentNullException("submesh");
      if (triangleMesh == null)
        throw new ArgumentNullException("triangleMesh");

      if (submesh.PrimitiveType != PrimitiveType.TriangleList)
        throw new NotSupportedException("All submeshes must be triangle lists. ToTriangleMesh() does not support other primitive types.");

      if (submesh.VertexBuffer == null)
        return;
      if (triangleMesh.Vertices == null)
        triangleMesh.Vertices = new List<Vector3>(submesh.VertexCount);
      if (triangleMesh.Indices == null)
        triangleMesh.Indices = new List<int>(submesh.PrimitiveCount * 3);

      // Get vertex element info.
      var vertexDeclaration = submesh.VertexBuffer.VertexDeclaration;
      var vertexElements = vertexDeclaration.GetVertexElements();

      // Get the vertex positions.
      var positionElement = vertexElements.First(e => e.VertexElementUsage == VertexElementUsage.Position);
      if (positionElement.VertexElementFormat != VertexElementFormat.Vector3)
        throw new NotSupportedException("For vertex positions only VertexElementFormat.Vector3 is supported.");

      Vector3[] positions = new Vector3[submesh.VertexCount];
      submesh.VertexBuffer.GetData(
        submesh.StartVertex * vertexDeclaration.VertexStride + positionElement.Offset,
        positions,
        0,
        submesh.VertexCount,
        vertexDeclaration.VertexStride);

      if (submesh.IndexBuffer != null)
      {
        // Remember the number of vertices already in the mesh.
        int vertexCount = triangleMesh.Vertices.Count;

        // Add the vertices of the current modelMeshPart.
        foreach (Vector3 p in positions)
          triangleMesh.Vertices.Add((Vector3)p);

        // Get indices.
        int indexElementSize = (submesh.IndexBuffer.IndexElementSize == IndexElementSize.SixteenBits) ? 2 : 4;
        if (indexElementSize == 2)
        {
          ushort[] indices = new ushort[submesh.PrimitiveCount * 3];
          submesh.IndexBuffer.GetData(
            submesh.StartIndex * 2,
            indices,
            0,
            submesh.PrimitiveCount * 3);

          // Add indices to triangle mesh.
          for (int i = 0; i < submesh.PrimitiveCount; i++)
          {
            // The three indices of the next triangle.
            // We add 'vertexCount' because the triangleMesh already contains other mesh parts.
            int i0 = indices[i * 3 + 0] + vertexCount;
            int i1 = indices[i * 3 + 1] + vertexCount;
            int i2 = indices[i * 3 + 2] + vertexCount;

            triangleMesh.Indices.Add(i0);
            triangleMesh.Indices.Add(i2);     // DigitalRune Geometry uses other winding order!
            triangleMesh.Indices.Add(i1);
          }
        }
        else
        {
          Debug.Assert(indexElementSize == 4);
          int[] indices = new int[submesh.PrimitiveCount * 3];
          submesh.IndexBuffer.GetData(
            submesh.StartIndex * 4,
            indices,
            0,
            submesh.PrimitiveCount * 3);

          // Add indices to triangle mesh.
          for (int i = 0; i < submesh.PrimitiveCount; i++)
          {
            // The three indices of the next triangle.
            // We add 'vertexCount' because the triangleMesh already contains other mesh parts.
            int i0 = indices[i * 3 + 0] + vertexCount;
            int i1 = indices[i * 3 + 1] + vertexCount;
            int i2 = indices[i * 3 + 2] + vertexCount;

            triangleMesh.Indices.Add(i0);
            triangleMesh.Indices.Add(i2);     // DigitalRune Geometry uses other winding order!
            triangleMesh.Indices.Add(i1);
          }
        }
      }
      else
      {
        // No index buffer:
        int vertexCount = triangleMesh.Vertices.Count;
        for (int i = 0; i < submesh.VertexCount; i += 3)
        {
          triangleMesh.Vertices.Add((Vector3)positions[i]);
          triangleMesh.Vertices.Add((Vector3)positions[i + 1]);
          triangleMesh.Vertices.Add((Vector3)positions[i + 2]);

          triangleMesh.Indices.Add(i + vertexCount);
          triangleMesh.Indices.Add(i + 2 + vertexCount);     // DigitalRune Geometry uses other winding order!
          triangleMesh.Indices.Add(i + 1 + vertexCount);
        }
      }
    }
Exemple #15
0
 public static TriangleMesh ToTriangleMesh(this Submesh submesh)
 {
   var triangleMesh = new TriangleMesh();
   ToTriangleMesh(submesh, triangleMesh);
   return triangleMesh;
 }
Exemple #16
0
    private static void MergeSubmeshes(List<MergeJob> mergeJobs, Mesh mergedMesh,
                                       List<VertexDeclaration> vertexDeclarations,
                                       List<int> totalVertexCounts, int totalIndexCount)
    {
      var graphicsDevice = mergeJobs[0].Submesh.VertexBuffer.GraphicsDevice;

      VertexBuffer vertexBuffer = null;
      IndexBuffer indexBuffer = null;
      if (totalIndexCount > ushort.MaxValue)
        indexBuffer = new IndexBuffer(graphicsDevice, IndexElementSize.ThirtyTwoBits, totalIndexCount, BufferUsage.None);
      else if (totalIndexCount > 0)
        indexBuffer = new IndexBuffer(graphicsDevice, IndexElementSize.SixteenBits, totalIndexCount, BufferUsage.None);

      Submesh submesh = null;
      int vertexDeclarationIndex = -1;
      int vertexCount = 0;
      int indexCount = 0;
      uint sortKey = 0;
      for (int jobIndex = 0; jobIndex < mergeJobs.Count; jobIndex++)
      {
        var job = mergeJobs[jobIndex];

        // As long as the sort key is equal we can merge into the current submesh.
        if (submesh != null && job.SortKey != sortKey)
          submesh = null;

        // We have to begin a new vertex buffer if the vertex declaration has changed.
        if (job.VertexDeclarationIndex != vertexDeclarationIndex)
          vertexBuffer = null;

        if (vertexBuffer == null)
        {
          vertexDeclarationIndex = job.VertexDeclarationIndex;
          vertexCount = 0;
          vertexBuffer = new VertexBuffer(
            graphicsDevice,
            vertexDeclarations[vertexDeclarationIndex],
            totalVertexCounts[vertexDeclarationIndex],
            BufferUsage.None);
        }

        if (submesh == null)
        {
          sortKey = job.SortKey;
          submesh = new Submesh
          {
            VertexBuffer = vertexBuffer,
            StartVertex = vertexCount,
            StartIndex = indexCount,
            PrimitiveType = job.Submesh.PrimitiveType,
            MaterialIndex = job.MergedMaterialIndex,
            IndexBuffer = (job.Submesh.IndexBuffer != null) ? indexBuffer : null,
          };
          mergedMesh.Submeshes.Add(submesh);
        }

        // ----- Merge indices
        if (job.Submesh.IndexBuffer != null)
        {
          Debug.Assert(indexBuffer != null);
          int submeshIndexCount = GetNumberOfIndices(job.Submesh.PrimitiveType, job.Submesh.PrimitiveCount);
          if (job.Submesh.IndexBuffer.IndexElementSize == IndexElementSize.SixteenBits)
          {
            ushort[] indices16 = new ushort[submeshIndexCount];
            job.Submesh.IndexBuffer.GetData(job.Submesh.StartIndex * 2, indices16, 0, submeshIndexCount);

            if (indexBuffer.IndexElementSize == IndexElementSize.SixteenBits)
            {
              for (int i = 0; i < indices16.Length; i++)
                indices16[i] = (ushort)(indices16[i] + submesh.VertexCount);

              indexBuffer.SetData(indexCount * 2, indices16, 0, indices16.Length);
            }
            else
            {
              uint[] indices32 = new uint[submeshIndexCount];
              for (int i = 0; i < indices16.Length; i++)
                indices32[i] = (uint)(indices16[i] + submesh.VertexCount);

              indexBuffer.SetData(indexCount * 4, indices32, 0, indices32.Length);
            }
          }
          else
          {
            uint[] indices32 = new uint[submeshIndexCount];
            job.Submesh.IndexBuffer.GetData(job.Submesh.StartIndex * 4, indices32, 0, submeshIndexCount);

            if (indexBuffer.IndexElementSize == IndexElementSize.SixteenBits)
            {
              ushort[] indices16 = new ushort[submeshIndexCount];
              for (int i = 0; i < indices32.Length; i++)
                indices16[i] = (ushort)(indices32[i] + submesh.VertexCount);

              indexBuffer.SetData(indexCount * 2, indices16, 0, indices16.Length);
            }
            else
            {
              for (int i = 0; i < indices32.Length; i++)
                indices32[i] = (uint)(indices32[i] + submesh.VertexCount);

              indexBuffer.SetData(indexCount * 4, indices32, 0, indices32.Length);
            }
          }

          indexCount += submeshIndexCount;
        }

        // ----- Merge vertices
        var vertexDeclaration = vertexBuffer.VertexDeclaration;
        int vertexStride = vertexDeclaration.VertexStride;

        // Get the whole vertex buffer as byte array.
        byte[] buffer = new byte[job.Submesh.VertexBuffer.VertexCount * vertexStride];
        job.Submesh.VertexBuffer.GetData(buffer);

        // Transform position and normals.
        TransformVertices(buffer, job.Submesh.StartVertex, job.Submesh.VertexCount, vertexDeclaration, job.Scale, job.Pose);

        vertexBuffer.SetData(
          vertexCount * vertexStride,
          buffer,
          job.Submesh.StartVertex * vertexStride,
          job.Submesh.VertexCount * vertexStride,
          1);

        submesh.VertexCount += job.Submesh.VertexCount;
        vertexCount += job.Submesh.VertexCount;
        submesh.PrimitiveCount += job.Submesh.PrimitiveCount;
      }
    }
Exemple #17
0
        public static Submesh CreateTorus(GraphicsDevice graphicsDevice, float radius, float thickness, int numberOfSegments)
        {
            if (graphicsDevice == null)
            {
                throw new ArgumentNullException("graphicsDevice");
            }
            if (numberOfSegments < 3)
            {
                throw new ArgumentOutOfRangeException("numberOfSegments", "numberOfSegments must be greater than 2");
            }

            var submesh = new Submesh
            {
                PrimitiveType = PrimitiveType.TriangleList,
            };

            var vertices = new List <VertexPositionNormal>();
            var indices  = new List <ushort>();

            for (int i = 0; i < numberOfSegments; i++)
            {
                float outerAngle = i * MathHelper.TwoPi / numberOfSegments;

                // Create a transformation that will align geometry to slice perpendicularly
                // though the current ring position.
                Matrix transform = Matrix.CreateTranslation(radius, 0, 0) * Matrix.CreateRotationY(outerAngle);

                // Now loop along the other axis, around the side of the tube.
                for (int j = 0; j < numberOfSegments; j++)
                {
                    float innerAngle = j * MathHelper.TwoPi / numberOfSegments;

                    float dx = (float)Math.Cos(innerAngle);
                    float dy = (float)Math.Sin(innerAngle);

                    // Create a vertex.
                    Vector3 normal   = new Vector3(dx, dy, 0);
                    Vector3 position = normal * thickness / 2.0f;

                    position = Vector3.Transform(position, transform);
                    normal   = Vector3.TransformNormal(normal, transform);

                    vertices.Add(new VertexPositionNormal(position, normal));

                    // And create indices for two triangles.
                    int nextI = (i + 1) % numberOfSegments;
                    int nextJ = (j + 1) % numberOfSegments;

                    indices.Add((ushort)(i * numberOfSegments + j));
                    indices.Add((ushort)(i * numberOfSegments + nextJ));
                    indices.Add((ushort)(nextI * numberOfSegments + j));

                    indices.Add((ushort)(i * numberOfSegments + nextJ));
                    indices.Add((ushort)(nextI * numberOfSegments + nextJ));
                    indices.Add((ushort)(nextI * numberOfSegments + j));
                }
            }

            submesh.VertexBuffer = new VertexBuffer(
                graphicsDevice,
                VertexPositionNormal.VertexDeclaration,
                vertices.Count,
                BufferUsage.None);
            submesh.VertexBuffer.SetData(vertices.ToArray());

            submesh.VertexCount = submesh.VertexBuffer.VertexCount;

            submesh.IndexBuffer = new IndexBuffer(
                graphicsDevice,
                IndexElementSize.SixteenBits,
                indices.Count,
                BufferUsage.None);
            submesh.IndexBuffer.SetData(indices.ToArray());

            submesh.PrimitiveCount = indices.Count / 3;

            return(submesh);
        }
Exemple #18
0
        public static Submesh CreateHemisphere(GraphicsDevice graphicsDevice, int numberOfSegments)
        {
            if (graphicsDevice == null)
            {
                throw new ArgumentNullException("graphicsDevice");
            }
            if (numberOfSegments < 3)
            {
                throw new ArgumentOutOfRangeException("numberOfSegments", "numberOfSegments must be greater than 2");
            }

            var submesh = new Submesh
            {
                PrimitiveType = PrimitiveType.TriangleList,
            };

            // The number of rings.
            int numberOfRings = numberOfSegments / 4;

            int numberOfVertices = numberOfSegments * numberOfRings + 1;
            var vertices         = new VertexPositionNormal[numberOfVertices];

            // Create rings.
            float angle = ConstantsF.TwoPi / numberOfSegments;

            // Next free index in vertices.
            int i = 0;

            // Top vertex.
            vertices[i++] = new VertexPositionNormal(new Vector3(0, 1, 0), new Vector3(0, 1, 0));

            // Compute vertices for rings from pole to equator and from the x-axis in
            // counterclockwise direction (when viewed from top).
            for (int ring = 0; ring < numberOfRings; ring++)
            {
                float upAngle    = angle * (ring + 1);
                float y          = (float)Math.Cos(upAngle);
                float ringRadius = (float)Math.Sin(upAngle);

                for (int segment = 0; segment < numberOfSegments; segment++)
                {
                    float x = ringRadius * (float)Math.Cos(angle * segment);
                    float z = ringRadius * (float)Math.Sin(angle * segment);
                    vertices[i++] = new VertexPositionNormal(new Vector3(x, y, z), new Vector3(x, y, z));
                }
            }

            Debug.Assert(i == numberOfVertices);

            submesh.VertexBuffer = new VertexBuffer(
                graphicsDevice,
                VertexPositionNormal.VertexDeclaration,
                vertices.Length,
                BufferUsage.None);
            submesh.VertexBuffer.SetData(vertices);

            submesh.VertexCount = submesh.VertexBuffer.VertexCount;

            // Build array of indices.
            int numberOfTriangles = numberOfSegments // Triangles in top cap.
                                    + numberOfSegments * 2 * (numberOfRings - 1);
            int numberOfIndices = 3 * numberOfTriangles;

            var indices = new ushort[numberOfIndices];

            i = 0;

            // Indices for top cap.
            for (int segment = 0; segment < numberOfSegments; segment++)
            {
                indices[i++] = 0;
                indices[i++] = (ushort)(segment + 1);
                if (segment + 1 < numberOfSegments)
                {
                    indices[i++] = (ushort)(segment + 2);
                }
                else
                {
                    indices[i++] = 1; // Wrap around to first vertex of the first ring.
                }
            }

            // Indices for rings between the caps.
            for (int ring = 1; ring < numberOfRings; ring++)
            {
                for (int segment = 0; segment < numberOfSegments; segment++)
                {
                    // Each segment has 2 triangles.
                    if (segment + 1 < numberOfSegments)
                    {
                        indices[i++] = (ushort)(1 + (ring - 1) * numberOfSegments + segment);
                        indices[i++] = (ushort)(1 + ring * numberOfSegments + segment);
                        indices[i++] = (ushort)(1 + ring * numberOfSegments + segment + 1);

                        indices[i++] = (ushort)(1 + ring * numberOfSegments + segment + 1);
                        indices[i++] = (ushort)(1 + (ring - 1) * numberOfSegments + segment + 1);
                        indices[i++] = (ushort)(1 + (ring - 1) * numberOfSegments + segment);
                    }
                    else
                    {
                        // Handle wrap around.
                        indices[i++] = (ushort)(1 + (ring - 1) * numberOfSegments + segment);
                        indices[i++] = (ushort)(1 + ring * numberOfSegments + segment);
                        indices[i++] = (ushort)(1 + ring * numberOfSegments);

                        indices[i++] = (ushort)(1 + ring * numberOfSegments);
                        indices[i++] = (ushort)(1 + (ring - 1) * numberOfSegments);
                        indices[i++] = (ushort)(1 + (ring - 1) * numberOfSegments + segment);
                    }
                }
            }

            Debug.Assert(i == numberOfIndices);

            submesh.IndexBuffer = new IndexBuffer(
                graphicsDevice,
                IndexElementSize.SixteenBits,
                indices.Length,
                BufferUsage.None);
            submesh.IndexBuffer.SetData(indices);

            submesh.PrimitiveCount = indices.Length / 3;

            return(submesh);
        }
        public static Submesh CreateBox(GraphicsDevice graphicsDevice)
        {
            if (graphicsDevice == null)
            {
                throw new ArgumentNullException("graphicsDevice");
            }

            var submesh = new Submesh
            {
                PrimitiveType = PrimitiveType.TriangleList,
            };

            var vertices = new List <VertexPositionNormal>();
            var indices  = new List <ushort>();

            var p0 = new Vector3(-0.5f, -0.5f, -0.5f);
            var p1 = new Vector3(-0.5f, -0.5f, +0.5f);
            var p2 = new Vector3(-0.5f, +0.5f, -0.5f);
            var p3 = new Vector3(-0.5f, +0.5f, +0.5f);
            var p4 = new Vector3(+0.5f, -0.5f, -0.5f);
            var p5 = new Vector3(+0.5f, -0.5f, +0.5f);
            var p6 = new Vector3(+0.5f, +0.5f, -0.5f);
            var p7 = new Vector3(+0.5f, +0.5f, +0.5f);

            var normal = Vector3.UnitX;

            vertices.Add(new VertexPositionNormal(p4, normal));
            vertices.Add(new VertexPositionNormal(p5, normal));
            vertices.Add(new VertexPositionNormal(p6, normal));
            vertices.Add(new VertexPositionNormal(p7, normal));

            indices.Add(0);
            indices.Add(1);
            indices.Add(2);

            indices.Add(1);
            indices.Add(3);
            indices.Add(2);

            normal = Vector3.UnitY;
            vertices.Add(new VertexPositionNormal(p6, normal));
            vertices.Add(new VertexPositionNormal(p7, normal));
            vertices.Add(new VertexPositionNormal(p2, normal));
            vertices.Add(new VertexPositionNormal(p3, normal));

            indices.Add(4);
            indices.Add(5);
            indices.Add(6);

            indices.Add(5);
            indices.Add(7);
            indices.Add(6);

            normal = Vector3.UnitZ;
            vertices.Add(new VertexPositionNormal(p5, normal));
            vertices.Add(new VertexPositionNormal(p1, normal));
            vertices.Add(new VertexPositionNormal(p7, normal));
            vertices.Add(new VertexPositionNormal(p3, normal));

            indices.Add(8);
            indices.Add(9);
            indices.Add(10);

            indices.Add(9);
            indices.Add(11);
            indices.Add(10);

            normal = -Vector3.UnitX;
            vertices.Add(new VertexPositionNormal(p1, normal));
            vertices.Add(new VertexPositionNormal(p0, normal));
            vertices.Add(new VertexPositionNormal(p3, normal));
            vertices.Add(new VertexPositionNormal(p2, normal));

            indices.Add(12);
            indices.Add(13);
            indices.Add(14);

            indices.Add(13);
            indices.Add(15);
            indices.Add(14);

            normal = -Vector3.UnitY;
            vertices.Add(new VertexPositionNormal(p4, normal));
            vertices.Add(new VertexPositionNormal(p0, normal));
            vertices.Add(new VertexPositionNormal(p5, normal));
            vertices.Add(new VertexPositionNormal(p1, normal));

            indices.Add(16);
            indices.Add(17);
            indices.Add(18);

            indices.Add(17);
            indices.Add(19);
            indices.Add(18);

            normal = -Vector3.UnitZ;
            vertices.Add(new VertexPositionNormal(p0, normal));
            vertices.Add(new VertexPositionNormal(p4, normal));
            vertices.Add(new VertexPositionNormal(p2, normal));
            vertices.Add(new VertexPositionNormal(p6, normal));

            indices.Add(20);
            indices.Add(21);
            indices.Add(22);

            indices.Add(21);
            indices.Add(23);
            indices.Add(22);

            submesh.VertexBuffer = new VertexBuffer(
                graphicsDevice,
                VertexPositionNormal.VertexDeclaration,
                vertices.Count,
                BufferUsage.None);
            submesh.VertexBuffer.SetData(vertices.ToArray());

            submesh.VertexCount = submesh.VertexBuffer.VertexCount;

            submesh.IndexBuffer = new IndexBuffer(
                graphicsDevice,
                IndexElementSize.SixteenBits,
                indices.Count,
                BufferUsage.None);
            submesh.IndexBuffer.SetData(indices.ToArray());

            submesh.PrimitiveCount = indices.Count / 3;

            return(submesh);
        }
        public static Submesh CreateCylinderLines(GraphicsDevice graphicsDevice, int numberOfSegments)
        {
            if (graphicsDevice == null)
            {
                throw new ArgumentNullException("graphicsDevice");
            }
            if (numberOfSegments < 3)
            {
                throw new ArgumentOutOfRangeException("numberOfSegments", "numberOfSegments must be greater than 2");
            }

            var submesh = new Submesh
            {
                PrimitiveType = PrimitiveType.LineList,
            };

            var vertices = new List <Vector3>();

            // Top circle.
            for (int i = 0; i < numberOfSegments; i++)
            {
                float angle = i * ConstantsF.TwoPi / numberOfSegments;
                vertices.Add(new Vector3((float)Math.Cos(angle), 1, -(float)Math.Sin(angle)));
            }

            // Bottom circle.
            for (int i = 0; i < numberOfSegments; i++)
            {
                Vector3 p = vertices[i];
                vertices.Add(new Vector3(p.X, -1, p.Z));
            }

            submesh.VertexBuffer = new VertexBuffer(
                graphicsDevice,
                VertexPosition.VertexDeclaration,
                vertices.Count,
                BufferUsage.None);
            submesh.VertexBuffer.SetData(vertices.ToArray());
            submesh.VertexCount = submesh.VertexBuffer.VertexCount;

            var indices = new List <ushort>();

            // Top circle.
            for (int i = 0; i < numberOfSegments - 1; i++)
            {
                indices.Add((ushort)i);       // Line start (= same as previous line end)
                indices.Add((ushort)(i + 1)); // Line end
            }

            // Last line of top circle.
            indices.Add((ushort)(numberOfSegments - 1));
            indices.Add(0);

            // Bottom circle.
            for (int i = 0; i < numberOfSegments - 1; i++)
            {
                indices.Add((ushort)(numberOfSegments + i));     // Line start (= same as previous line end)
                indices.Add((ushort)(numberOfSegments + i + 1)); // Line end
            }

            // Last line of bottom circle.
            indices.Add((ushort)(numberOfSegments + numberOfSegments - 1));
            indices.Add((ushort)(numberOfSegments));

            // Side (represented by 4 lines).
            for (int i = 0; i < 4; i++)
            {
                indices.Add((ushort)(i * numberOfSegments / 4));
                indices.Add((ushort)(numberOfSegments + i * numberOfSegments / 4));
            }

            submesh.IndexBuffer = new IndexBuffer(
                graphicsDevice,
                IndexElementSize.SixteenBits,
                indices.Count,
                BufferUsage.None);
            submesh.IndexBuffer.SetData(indices.ToArray());

            submesh.PrimitiveCount = indices.Count / 2;

            return(submesh);
        }
Exemple #21
0
        public static Submesh CreateUncappedCylinder(GraphicsDevice graphicsDevice, int numberOfSegments)
        {
            if (graphicsDevice == null)
            {
                throw new ArgumentNullException("graphicsDevice");
            }
            if (numberOfSegments < 3)
            {
                throw new ArgumentOutOfRangeException("numberOfSegments", "numberOfSegments must be greater than 2");
            }

            var submesh = new Submesh
            {
                PrimitiveType = PrimitiveType.TriangleList,
            };

            // ----- Vertices
            var vertices = new List <VertexPositionNormal>();

            for (int i = 0; i < numberOfSegments; i++)
            {
                float angle = i * ConstantsF.TwoPi / numberOfSegments;
                float x     = (float)Math.Cos(angle);
                float z     = -(float)Math.Sin(angle);
                vertices.Add(new VertexPositionNormal(new Vector3(x, 1, z), new Vector3(x, 0, z)));
                vertices.Add(new VertexPositionNormal(new Vector3(x, -1, z), new Vector3(x, 0, z)));
            }

            submesh.VertexBuffer = new VertexBuffer(
                graphicsDevice,
                VertexPositionNormal.VertexDeclaration,
                vertices.Count,
                BufferUsage.None);
            submesh.VertexBuffer.SetData(vertices.ToArray());

            submesh.VertexCount = submesh.VertexBuffer.VertexCount;

            // ----- Indices
            var indices = new List <ushort>();

            for (int i = 0; i < numberOfSegments - 1; i++)
            {
                indices.Add((ushort)(2 * i));
                indices.Add((ushort)(2 * i + 2));
                indices.Add((ushort)(2 * i + 1));

                indices.Add((ushort)(2 * i + 2));
                indices.Add((ushort)(2 * i + 3));
                indices.Add((ushort)(2 * i + 1));
            }

            // Indices of last 2 triangle.
            indices.Add((ushort)(numberOfSegments + numberOfSegments - 2));
            indices.Add(0);
            indices.Add((ushort)(numberOfSegments + numberOfSegments - 1));

            indices.Add(0);
            indices.Add(1);
            indices.Add((ushort)(numberOfSegments + numberOfSegments - 1));

            submesh.IndexBuffer = new IndexBuffer(
                graphicsDevice,
                IndexElementSize.SixteenBits,
                indices.Count,
                BufferUsage.None);
            submesh.IndexBuffer.SetData(indices.ToArray());

            submesh.PrimitiveCount = indices.Count / 3;

            return(submesh);
        }
        internal static Submesh CreateGrid(GraphicsDevice graphicsDevice, float widthX, float widthY, int numberOfCellsX, int numberOfCellsY)
        {
            if (graphicsDevice == null)
            {
                throw new ArgumentNullException("graphicsDevice");
            }
            if (widthX <= 0)
            {
                throw new ArgumentOutOfRangeException("widthX", "The number of cells must be greater than 0.");
            }
            if (widthY <= 0)
            {
                throw new ArgumentOutOfRangeException("widthY", "The number of cells must be greater than 0.");
            }
            if (numberOfCellsX < 1)
            {
                throw new ArgumentOutOfRangeException("numberOfCellsX", "The number of cells must be greater than 0.");
            }
            if (numberOfCellsY < 1)
            {
                throw new ArgumentOutOfRangeException("numberOfCellsY", "The number of cells must be greater than 0.");
            }

            var submesh = new Submesh
            {
                PrimitiveType = PrimitiveType.TriangleList,
            };

            int numberOfVertices = (numberOfCellsX + 1) * (numberOfCellsY + 1);
            var vertices         = new VertexPositionNormalTexture[numberOfVertices];

            int index = 0;

            for (int y = 0; y <= numberOfCellsY; y++)
            {
                for (int x = 0; x <= numberOfCellsX; x++)
                {
                    vertices[index++] = new VertexPositionNormalTexture(
                        new Vector3(x * widthX / numberOfCellsX, y * widthY / numberOfCellsY, 0),
                        new Vector3(0, 0, 1),
                        new Vector2(x / (float)numberOfCellsX, y / (float)numberOfCellsY));
                }
            }

            submesh.VertexBuffer = new VertexBuffer(
                graphicsDevice,
                VertexPositionNormalTexture.VertexDeclaration,
                vertices.Length,
                BufferUsage.None);
            submesh.VertexBuffer.SetData(vertices);
            submesh.VertexCount = submesh.VertexBuffer.VertexCount;

            // Build array of indices.
            int numberOfTriangles = numberOfCellsX * numberOfCellsY * 2;
            int numberOfIndices   = 3 * numberOfTriangles;

            if (numberOfIndices < ushort.MaxValue)
            {
                var indices = new ushort[numberOfIndices];

                index = 0;
                for (int y = 0; y < numberOfCellsY; y++)
                {
                    for (int x = 0; x < numberOfCellsX; x++)
                    {
                        int baseIndex = y * (numberOfCellsX + 1) + x;

                        indices[index++] = (ushort)baseIndex;
                        indices[index++] = (ushort)(baseIndex + numberOfCellsX + 1);
                        indices[index++] = (ushort)(baseIndex + 1);

                        indices[index++] = (ushort)(baseIndex + 1);
                        indices[index++] = (ushort)(baseIndex + numberOfCellsX + 1);
                        indices[index++] = (ushort)(baseIndex + numberOfCellsX + 2);
                    }
                }

                submesh.IndexBuffer = new IndexBuffer(
                    graphicsDevice,
                    IndexElementSize.SixteenBits,
                    indices.Length,
                    BufferUsage.None);
                submesh.IndexBuffer.SetData(indices);
                submesh.PrimitiveCount = indices.Length / 3;
            }
            else
            {
                var indices = new int[numberOfIndices];

                index = 0;
                for (int y = 0; y < numberOfCellsY; y++)
                {
                    for (int x = 0; x < numberOfCellsX; x++)
                    {
                        int baseIndex = y * (numberOfCellsX + 1) + x;

                        indices[index++] = baseIndex;
                        indices[index++] = (baseIndex + numberOfCellsX + 1);
                        indices[index++] = (baseIndex + 1);

                        indices[index++] = (baseIndex + 1);
                        indices[index++] = (baseIndex + numberOfCellsX + 1);
                        indices[index++] = (baseIndex + numberOfCellsX + 2);
                    }
                }

                submesh.IndexBuffer = new IndexBuffer(
                    graphicsDevice,
                    IndexElementSize.ThirtyTwoBits,
                    indices.Length,
                    BufferUsage.None);
                submesh.IndexBuffer.SetData(indices);
                submesh.PrimitiveCount = indices.Length / 3;
            }

            return(submesh);
        }
        public static Submesh CreateHemisphereLines(GraphicsDevice graphicsDevice, int numberOfSegments)
        {
            if (graphicsDevice == null)
            {
                throw new ArgumentNullException("graphicsDevice");
            }
            if (numberOfSegments < 3)
            {
                throw new ArgumentOutOfRangeException("numberOfSegments", "numberOfSegments must be greater than 2");
            }

            var submesh = new Submesh
            {
                PrimitiveType = PrimitiveType.LineList,
            };

            // Create vertices for a circle on the floor.
            var vertices = new List <Vector3>();

            for (int i = 0; i < numberOfSegments; i++)
            {
                float angle = i * ConstantsF.TwoPi / numberOfSegments;
                vertices.Add(new Vector3((float)Math.Cos(angle), 0, -(float)Math.Sin(angle)));
            }

            // Top vertex of the sphere.
            var topVertexIndex = vertices.Count;

            vertices.Add(new Vector3(0, 1, 0));

            // 4 quarter arcs. Each arc starts at the base circle and ends at the top vertex. We already
            // have the first and last vertex.
            // Arc from +x to top.
            int firstArcIndex = vertices.Count;

            for (int i = 0; i < numberOfSegments / 4 - 1; i++)
            {
                float angle = (i + 1) * ConstantsF.TwoPi / numberOfSegments;
                vertices.Add(new Vector3((float)Math.Cos(angle), (float)Math.Sin(angle), 0));
            }

            // Arc from -z to top. (Copy from first arc.)
            int secondArcIndex = vertices.Count;

            for (int i = 0; i < numberOfSegments / 4 - 1; i++)
            {
                Vector3 p = vertices[firstArcIndex + i];
                vertices.Add(new Vector3(0, p.Y, -p.X));
            }

            // Arc from -x to top. (Copy from first arc.)
            int thirdArcIndex = vertices.Count;

            for (int i = 0; i < numberOfSegments / 4 - 1; i++)
            {
                Vector3 p = vertices[firstArcIndex + i];
                vertices.Add(new Vector3(-p.X, p.Y, 0));
            }

            // Arc from +z to top. (Copy from first arc.)
            int fourthArcIndex = vertices.Count;

            for (int i = 0; i < numberOfSegments / 4 - 1; i++)
            {
                Vector3 p = vertices[firstArcIndex + i];
                vertices.Add(new Vector3(0, p.Y, p.X));
            }

            submesh.VertexBuffer = new VertexBuffer(
                graphicsDevice,
                VertexPosition.VertexDeclaration,
                vertices.Count,
                BufferUsage.None);
            submesh.VertexBuffer.SetData(vertices.ToArray());

            submesh.VertexCount = submesh.VertexBuffer.VertexCount;

            var indices = new List <ushort>();

            // Create indices for base circle.
            for (int i = 0; i < numberOfSegments; i++)
            {
                indices.Add((ushort)i);       // Line start (= same as previous line end)
                indices.Add((ushort)(i + 1)); // Line end
            }

            // Correct last index to be 0 to close circle.
            indices[(ushort)(2 * numberOfSegments - 1)] = 0;

            // Indices for first arc.
            indices.Add(0);                       // Line start
            for (int i = 0; i < numberOfSegments / 4 - 1; i++)
            {
                indices.Add((ushort)(firstArcIndex + i)); // Line end
                indices.Add((ushort)(firstArcIndex + i)); // Line start (= same as previous line end)
            }
            indices.Add((ushort)topVertexIndex);          // Line end

            // Next arcs
            indices.Add((ushort)(numberOfSegments / 4));
            for (int i = 0; i < numberOfSegments / 4 - 1; i++)
            {
                indices.Add((ushort)(secondArcIndex + i));
                indices.Add((ushort)(secondArcIndex + i));
            }
            indices.Add((ushort)topVertexIndex);

            indices.Add((ushort)(2 * numberOfSegments / 4));
            for (int i = 0; i < numberOfSegments / 4 - 1; i++)
            {
                indices.Add((ushort)(thirdArcIndex + i));
                indices.Add((ushort)(thirdArcIndex + i));
            }
            indices.Add((ushort)topVertexIndex);

            indices.Add((ushort)(3 * numberOfSegments / 4));
            for (int i = 0; i < numberOfSegments / 4 - 1; i++)
            {
                indices.Add((ushort)(fourthArcIndex + i));
                indices.Add((ushort)(fourthArcIndex + i));
            }
            indices.Add((ushort)topVertexIndex);

            submesh.IndexBuffer = new IndexBuffer(
                graphicsDevice,
                IndexElementSize.SixteenBits,
                indices.Count,
                BufferUsage.None);
            submesh.IndexBuffer.SetData(indices.ToArray());

            submesh.PrimitiveCount = indices.Count / 2;

            return(submesh);
        }
Exemple #24
0
        public static Submesh CreateBoxLines(GraphicsDevice graphicsDevice)
        {
            if (graphicsDevice == null)
            {
                throw new ArgumentNullException("graphicsDevice");
            }

            var submesh = new Submesh
            {
                PrimitiveType = PrimitiveType.LineList,
            };

            var vertices = new[]
            {
                new Vector3(-0.5f, -0.5f, +0.5f),
                new Vector3(+0.5f, -0.5f, +0.5f),
                new Vector3(+0.5f, +0.5f, +0.5f),
                new Vector3(-0.5f, +0.5f, +0.5f),
                new Vector3(-0.5f, -0.5f, -0.5f),
                new Vector3(+0.5f, -0.5f, -0.5f),
                new Vector3(+0.5f, +0.5f, -0.5f),
                new Vector3(-0.5f, +0.5f, -0.5f)
            };

            submesh.VertexBuffer = new VertexBuffer(
                graphicsDevice,
                VertexPosition.VertexDeclaration,
                vertices.Length,
                BufferUsage.None);
            submesh.VertexBuffer.SetData(vertices);
            submesh.VertexCount = submesh.VertexBuffer.VertexCount;

            var indices = new ushort[]
            {
                0, 1,
                1, 2,
                2, 3,
                3, 0,

                4, 5,
                5, 6,
                6, 7,
                7, 4,

                0, 4,
                1, 5,
                2, 6,
                3, 7
            };

            submesh.IndexBuffer = new IndexBuffer(
                graphicsDevice,
                IndexElementSize.SixteenBits,
                indices.Length,
                BufferUsage.None);
            submesh.IndexBuffer.SetData(indices);

            submesh.PrimitiveCount = indices.Length / 2;

            return(submesh);
        }
        public static void CreateMesh(GraphicsDevice graphicsDevice, Path3F path, float defaultWidth,
                                      int maxNumberOfIterations, float tolerance,
                                      out Submesh submesh, out Aabb aabb, out float roadLength)
        {
            if (graphicsDevice == null)
            {
                throw new ArgumentNullException("graphicsDevice");
            }
            if (path == null)
            {
                throw new ArgumentNullException("path");
            }

            // Compute list of line segments. (2 points per line segment!)
            var flattenedPoints = new List <Vector3>();

            path.Flatten(flattenedPoints, maxNumberOfIterations, tolerance);

            // Abort if path is empty.
            int numberOfLineSegments = flattenedPoints.Count / 2;

            if (numberOfLineSegments <= 0)
            {
                submesh    = null;
                aabb       = new Aabb();
                roadLength = 0;
                return;
            }

            // Compute accumulated lengths. (One entry for each entry in flattenedPoints.)
            float[] accumulatedLengths = new float[flattenedPoints.Count];
            accumulatedLengths[0] = 0;
            for (int i = 1; i < flattenedPoints.Count; i += 2)
            {
                Vector3 previous = flattenedPoints[i - 1];
                Vector3 current  = flattenedPoints[i];
                float   length   = (current - previous).Length;

                accumulatedLengths[i] = accumulatedLengths[i - 1] + length;
                if (i + 1 < flattenedPoints.Count)
                {
                    accumulatedLengths[i + 1] = accumulatedLengths[i];
                }
            }

            // Total road length.
            roadLength = accumulatedLengths[accumulatedLengths.Length - 1];

            // Create a mapping between accumulatedLength and the path key widths.
            // (accumulatedLength --> TerrainRoadPathKey.Width)
            var widthKeys = new List <Pair <float, float> >();
            {
                int index = 0;
                foreach (var key in path)
                {
                    Vector3 position = key.Point;
                    var     roadKey  = key as TerrainRoadPathKey;
                    float   width    = (roadKey != null) ? roadKey.Width : defaultWidth;

                    for (; index < flattenedPoints.Count; index++)
                    {
                        if (Vector3.AreNumericallyEqual(position, flattenedPoints[index]))
                        {
                            widthKeys.Add(new Pair <float, float>(accumulatedLengths[index], width));
                            break;
                        }

                        bool isLastLineSegment = (index + 2 == flattenedPoints.Count);
                        if (!isLastLineSegment)
                        {
                            index++;
                        }
                    }

                    index++;
                }
            }

            // Create a list of interpolated road widths. (One entry for each entry in flattenedPoints.)
            var widths           = new float[flattenedPoints.Count];
            int previousKeyIndex = 0;
            var previousKey      = widthKeys[0];
            var nextKey          = widthKeys[1];

            widths[0] = widthKeys[0].Second;
            for (int i = 1; i < flattenedPoints.Count; i += 2)
            {
                if (accumulatedLengths[i] > nextKey.First)
                {
                    previousKey = nextKey;
                    previousKeyIndex++;
                    nextKey = widthKeys[previousKeyIndex + 1];
                }

                float p = (accumulatedLengths[i] - previousKey.First) / (nextKey.First - previousKey.First);
                widths[i] = InterpolationHelper.Lerp(previousKey.Second, nextKey.Second, p);

                if (i + 1 < flattenedPoints.Count)
                {
                    widths[i + 1] = widths[i];
                }
            }

            // Compute vertices and indices.
            var     vertices        = new List <TerrainLayerVertex>(numberOfLineSegments * 2 + 2);
            var     indices         = new List <int>(numberOfLineSegments * 6); // Two triangles per line segment.
            Vector3 lastOrthonormal = Vector3.UnitX;

            aabb = new Aabb(flattenedPoints[0], flattenedPoints[0]);
            bool isClosed = Vector3.AreNumericallyEqual(flattenedPoints[0], flattenedPoints[flattenedPoints.Count - 1]);

            for (int i = 0; i < flattenedPoints.Count; i++)
            {
                Vector3 start = flattenedPoints[i];

                Vector3 previous;
                bool    isFirstPoint = (i == 0);
                if (!isFirstPoint)
                {
                    previous = flattenedPoints[i - 1];
                }
                else if (isClosed && path.SmoothEnds)
                {
                    previous = flattenedPoints[flattenedPoints.Count - 2];
                }
                else
                {
                    previous = start;
                }

                Vector3 next;
                bool    isLastPoint = (i + 1 == flattenedPoints.Count);
                if (!isLastPoint)
                {
                    next = flattenedPoints[i + 1];
                }
                else if (isClosed && path.SmoothEnds)
                {
                    next = flattenedPoints[1];
                }
                else
                {
                    next = start;
                }

                Vector3 tangent = next - previous;

                Vector3 orthonormal = new Vector3(tangent.Z, 0, -tangent.X);
                if (!orthonormal.TryNormalize())
                {
                    orthonormal = lastOrthonormal;
                }

                // Add indices to add two triangles between the current and the next vertices.
                if (!isLastPoint)
                {
                    int baseIndex = vertices.Count;

                    //  2      3
                    //   x----x
                    //   |\   |   ^
                    //   | \  |   | road
                    //   |  \ |   | direction
                    //   |   \|   |
                    //   x----x
                    //  0      1

                    indices.Add(baseIndex);
                    indices.Add(baseIndex + 1);
                    indices.Add(baseIndex + 2);

                    indices.Add(baseIndex + 1);
                    indices.Add(baseIndex + 3);
                    indices.Add(baseIndex + 2);
                }

                // Add two vertices.
                Vector3 leftVertex  = start - orthonormal * (widths[i] / 2);
                Vector3 rightVertex = start + orthonormal * (widths[i] / 2);
                vertices.Add(new TerrainLayerVertex(new Vector2(leftVertex.X, leftVertex.Z), new Vector2(0, accumulatedLengths[i])));
                vertices.Add(new TerrainLayerVertex(new Vector2(rightVertex.X, rightVertex.Z), new Vector2(1, accumulatedLengths[i])));

                // Grow AABB
                aabb.Grow(leftVertex);
                aabb.Grow(rightVertex);

                lastOrthonormal = orthonormal;

                // The flattened points list contains 2 points per line segment, which means that there
                // are duplicate intermediate points, which we skip.
                bool isLastLineSegment = (i + 2 == flattenedPoints.Count);
                if (!isLastLineSegment)
                {
                    i++;
                }
            }

            Debug.Assert(vertices.Count == (numberOfLineSegments * 2 + 2));
            Debug.Assert(indices.Count == (numberOfLineSegments * 6));

            // The road is projected onto the terrain, therefore the computed y limits are not correct.
            // (unless the terrain was clamped to the road).
            aabb.Minimum.Y = 0;
            aabb.Maximum.Y = 0;

            // Convert to submesh.
            submesh = new Submesh
            {
                PrimitiveCount = indices.Count / 3,
                PrimitiveType  = PrimitiveType.TriangleList,
                VertexCount    = vertices.Count,
                VertexBuffer   = new VertexBuffer(graphicsDevice, TerrainLayerVertex.VertexDeclaration, vertices.Count, BufferUsage.WriteOnly),
                IndexBuffer    = new IndexBuffer(graphicsDevice, IndexElementSize.ThirtyTwoBits, indices.Count, BufferUsage.WriteOnly)
            };
            submesh.VertexBuffer.SetData(vertices.ToArray());
            submesh.IndexBuffer.SetData(indices.ToArray());
        }
        internal static Submesh CreateSpherePatch(
            GraphicsDevice graphicsDevice,
            float originRadius, float sphereRadius,
            int numberOfDivisions)
        {
            if (graphicsDevice == null)
            {
                throw new ArgumentNullException("graphicsDevice");
            }
            if (numberOfDivisions < 1 || numberOfDivisions > 255)
            {
                throw new ArgumentOutOfRangeException("numberOfDivisions", "numberOfDivisions must be in the range [0, 255].");
            }

            var submesh = new Submesh
            {
                PrimitiveType = PrimitiveType.TriangleList,
            };

            int numberOfVertices = (numberOfDivisions + 1) * (numberOfDivisions + 1);
            var vertices         = new VertexPositionNormalTexture[numberOfVertices];

            float groundPlaneSize = 2 * (float)Math.Sqrt(sphereRadius * sphereRadius - originRadius * originRadius);
            int   index           = 0;

            for (int i = 0; i <= numberOfDivisions; i++)
            {
                for (int j = 0; j <= numberOfDivisions; j++)
                {
                    float x = -groundPlaneSize / 2 + groundPlaneSize / numberOfDivisions * j;
                    float z = -groundPlaneSize / 2 + groundPlaneSize / numberOfDivisions * i;

                    //float groundDist2 = x * x + z * z;

                    var direction = new Vector3(x, originRadius, z);
                    direction.Normalize();

                    var p = direction * sphereRadius - new Vector3(0, originRadius, 0);

                    var t = new Vector2(
                        j / (float)numberOfDivisions,
                        i / (float)numberOfDivisions);

                    vertices[index++] = new VertexPositionNormalTexture(p, new Vector3(0, -1, 0), t);
                }
            }

            submesh.VertexBuffer = new VertexBuffer(
                graphicsDevice,
                VertexPositionNormalTexture.VertexDeclaration,
                vertices.Length,
                BufferUsage.None);
            submesh.VertexBuffer.SetData(vertices);
            submesh.VertexCount = submesh.VertexBuffer.VertexCount;

            // Build array of indices.
            int numberOfTriangles = numberOfDivisions * numberOfDivisions * 2;
            int numberOfIndices   = 3 * numberOfTriangles;

            var indices = new ushort[numberOfIndices];

            index = 0;
            for (int i = 0; i < numberOfDivisions; i++)
            {
                for (int j = 0; j < numberOfDivisions; j++)
                {
                    int baseIndex = i * (numberOfDivisions + 1) + j;

                    indices[index++] = (ushort)baseIndex;
                    indices[index++] = (ushort)(baseIndex + numberOfDivisions + 1);
                    indices[index++] = (ushort)(baseIndex + 1);

                    indices[index++] = (ushort)(baseIndex + 1);
                    indices[index++] = (ushort)(baseIndex + numberOfDivisions + 1);
                    indices[index++] = (ushort)(baseIndex + numberOfDivisions + 2);
                }
            }

            submesh.IndexBuffer = new IndexBuffer(
                graphicsDevice,
                IndexElementSize.SixteenBits,
                indices.Length,
                BufferUsage.None);
            submesh.IndexBuffer.SetData(indices);

            submesh.PrimitiveCount = indices.Length / 3;

            return(submesh);
        }