/// <summary>
        /// Combines an array of GeometryPrimitives into a single primitive.
        /// The order and all characteristics of the vertices are preserved.
        /// </summary>
        /// <param name="primitives"></param>
        /// <returns></returns>
        public static GeometryPrimitive Combine(GeometryPrimitive[] primitives)
        {
            int numVertices = 0;
            int numIndices = 0;

            for (int i = 0; i < primitives.Length; i++)
            {
                numVertices += primitives[i].Vertices.Length;
                numIndices += primitives[i].Indices.Length;
            }

            GeometryPrimitive output = new GeometryPrimitive();

            output.Vertices = new VertexPositionNormalTexture[numVertices];
            output.Indices = new int[numIndices];

            int vertIndex = 0;
            int indIndex = 0;

            for (int i = 0; i < primitives.Length; i++)
            {
                for (int j = 0; j < primitives[i].Vertices.Length; j++)
                    output.Vertices[j + vertIndex] = primitives[i].Vertices[j];

                for (int j = 0; j < primitives[i].Indices.Length; j++)
                    output.Indices[j + indIndex] = primitives[i].Indices[j] + vertIndex;

                vertIndex += primitives[i].Vertices.Length;
                indIndex += primitives[i].Indices.Length;
            }

            return output;
        }
Example #2
0
        public static void LoadContent(Game game)
        {
            entityPrimitive = GeometryPrimitive.Make3DRectangle(
                Vector3.One * buffer, Vector3.One * size,
                Vector2.Zero, new Vector2(1.0f, 1.0f),
                true, true, true, true, true, true);

            texture = game.Content.Load<Texture2D>("Textures/Cubes/Dirt");
        }
Example #3
0
        /// <summary>
        /// Recalculates the Visual geometry for the Chunk.  The supplied chunks can be null;
        /// if not, will be used for visual occlusion (if null, will be assumed see-through).
        /// </summary>
        public void RecalculateVisualGeometry()
        {
            Chunk leftChunk, rightChunk, forwardChunk, backwardChunk;
            LoadNeighborChunks(out leftChunk, out rightChunk, out forwardChunk, out backwardChunk);

            GeometryPrimitive[] newCombinedPrimitives = new GeometryPrimitive[BlockHandler.TotalNumberOfTextures];
            int[] newCombinedVerticesCount = new int[BlockHandler.TotalNumberOfTextures];
            int[] newCombinedTrianglesCount = new int[BlockHandler.TotalNumberOfTextures];
            bool[] newUsesTextureIndex = new bool[BlockHandler.TotalNumberOfTextures];

            float visualXMin = GameConstants.CHUNK_X_WIDTH;
            float visualXMax = 0;

            float visualYMin = GameConstants.CHUNK_Y_HEIGHT;
            float visualYMax = 0;

            float visualZMin = GameConstants.CHUNK_Z_LENGTH;
            float visualZMax = 0;

            for (int textureIndex = 0; textureIndex < BlockHandler.TotalNumberOfTextures; textureIndex++)
            {
                List<GeometryPrimitive> buildingBlocks = new List<GeometryPrimitive>();

                for (int x = 0; x < GameConstants.CHUNK_X_WIDTH; x++)
                {
                    for (int y = 0; y < GameConstants.CHUNK_Y_HEIGHT; y++)
                    {
                        for (int z = 0; z < GameConstants.CHUNK_Z_LENGTH; z++)
                        {
                            Block relevantBlock = this[x, y, z];

                            if (!BlockHandler.IsVisible(relevantBlock) || BlockHandler.TextureIndex(relevantBlock) != textureIndex)
                                continue;

                            bool includeFrontFace, includeBackFace;
                            bool includeTopFace, includeBottomFace;
                            bool includeLeftFace, includeRightFace;

                            MakeOcclusionTags(x, y, z,
                                out includeFrontFace, out includeBackFace,
                                out includeTopFace, out includeBottomFace,
                                out includeLeftFace, out includeRightFace,
                                leftChunk, rightChunk,
                                forwardChunk, backwardChunk);

                            bool hasVisibleFace = (includeTopFace || includeBottomFace || includeBackFace || includeFrontFace || includeRightFace || includeLeftFace);

                            if (!hasVisibleFace)
                                continue;

                            visualXMin = MathHelper.Min(visualXMin, x);
                            visualXMax = MathHelper.Max(visualXMax, x + 1);

                            visualYMin = MathHelper.Min(visualYMin, y);
                            visualYMax = MathHelper.Max(visualYMax, y + 1);

                            visualZMin = MathHelper.Min(visualZMin, z);
                            visualZMax = MathHelper.Max(visualZMax, z + 1);

                            GeometryPrimitive drawingPrimitive = BlockHandler.DrawingPrimitive(relevantBlock,
                                includeFrontFace, includeBackFace, includeTopFace, includeBottomFace,
                                includeLeftFace, includeRightFace);

                            if (drawingPrimitive.Vertices.Length > 0)
                                buildingBlocks.Add(drawingPrimitive.Translate(new Vector3(x, y, z)));
                        }
                    }
                }

                GeometryPrimitive[] primitivesArray = new GeometryPrimitive[buildingBlocks.Count];
                buildingBlocks.CopyTo(primitivesArray);

                newUsesTextureIndex[textureIndex] = (primitivesArray.Length > 0);

                if (newUsesTextureIndex[textureIndex])
                {
                    newCombinedPrimitives[textureIndex] = GeometryPrimitive.Combine(primitivesArray);
                }
            }

            lock (this)
            {
                combinedPrimitives = newCombinedPrimitives;
                usesTextureIndex = newUsesTextureIndex;

                visualBoundingBox = new BoundingBox(
                    new Vector3(visualXMin, visualYMin, visualZMin),
                    new Vector3(visualXMax, visualYMax, visualZMax));
            }
        }
        /// <summary>
        /// This constructs a 3D rectangle (interval in 3-space if you prefer) with the 
        /// specified "minimal corner" and size vector.  Minimal corner means the point where
        /// x, y, and z are all lowest, and size should be a strictly positive vector in all
        /// components.
        /// 
        /// There are a big pile of optional bools, indicating which (if any) faces to include.
        /// </summary>
        /// <param name="minimalCorner">Corner where x, y, and z are minimal.</param>
        /// <param name="size">Positive vector expressing the x, y, and z size.</param>
        /// <param name="textureMinimalCorner">Where the relevant part of the texture starts, in UV coordinates.</param>
        /// <param name="textureSize">How big the relevant part of the texture is, in UV coordinates.</param>
        /// <returns></returns>
        public static GeometryPrimitive Make3DRectangle(Vector3 minimalCorner, Vector3 size,
            Vector2 textureMinimalCorner, Vector2 textureSize,
            bool includeFrontFace, bool includeBackFace,
            bool includeTopFace, bool includeBottomFace,
            bool includeLeftFace, bool includeRightFace)
        {
            int faceCount = 0;

            if (includeFrontFace) faceCount++;
            if (includeBackFace) faceCount++;
            if (includeTopFace) faceCount++;
            if (includeBottomFace) faceCount++;
            if (includeLeftFace) faceCount++;
            if (includeRightFace) faceCount++;

            //physical dimensions
            float xmin = minimalCorner.X;
            float xmid = minimalCorner.X + (size.X / 2.0f);
            float xmax = minimalCorner.X + size.X;

            float xSize = size.X;

            float ymin = minimalCorner.Y;
            float ymid = minimalCorner.Y + (size.Y / 2.0f);
            float ymax = minimalCorner.Y + size.Y;

            float ySize = size.Y;

            float zmin = minimalCorner.Z;
            float zmid = minimalCorner.Z + (size.Z / 2.0f);
            float zmax = minimalCorner.Z + size.Z;

            float zSize = size.Z;

            //texture dimensions
            float texIncX = textureSize.X * 0.25f; //texture increment x
            float texIncY = textureSize.Y * 0.25f;  //texture increment y

            Vector2 faceTextureSize = new Vector2(texIncX, texIncY);

            //and now for the geometry!
            GeometryPrimitive[] faces = new GeometryPrimitive[faceCount];

            int faceIndex = 0;

            //Front face
            if (includeFrontFace)
            {
                faces[faceIndex++] = GeometryPrimitive.MakeRectangle(
                    new Vector3(xmid, ymid, zmin),
                    Vector3.Forward, Vector3.Up,
                    new Vector2(texIncX, 2.0f * texIncY) + textureMinimalCorner,
                    faceTextureSize,
                    xSize, ySize);
            }

            //Back face
            if (includeBackFace)
            {
                faces[faceIndex++] = GeometryPrimitive.MakeRectangle(
                    new Vector3(xmid, ymid, zmax),
                    Vector3.Backward, Vector3.Down,
                    new Vector2(texIncX, 0) + textureMinimalCorner,
                    faceTextureSize,
                    xSize, ySize);
            }

            //top face
            if (includeTopFace)
            {
                faces[faceIndex++] = GeometryPrimitive.MakeRectangle(
                    new Vector3(xmid, ymax, zmid),
                    Vector3.Up, Vector3.Forward,
                    new Vector2(texIncX, texIncY) + textureMinimalCorner,
                    faceTextureSize,
                    xSize, zSize);
            }

            //bottom face
            if (includeBottomFace)
            {
                faces[faceIndex++] = GeometryPrimitive.MakeRectangle(
                    new Vector3(xmid, ymin, zmid),
                    Vector3.Down, Vector3.Forward,
                    new Vector2(texIncX, 3.0f * texIncY) + textureMinimalCorner,
                    faceTextureSize,
                    xSize, zSize);
            }

            //left face
            if (includeLeftFace)
            {
                faces[faceIndex++] = GeometryPrimitive.MakeRectangle(
                    new Vector3(xmin, ymid, zmid),
                    Vector3.Left, Vector3.Forward,
                    new Vector2(0, texIncY) + textureMinimalCorner,
                    faceTextureSize,
                    ySize, zSize);
            }

            //right face
            if (includeRightFace)
            {
                faces[faceIndex++] = GeometryPrimitive.MakeRectangle(
                    new Vector3(xmax, ymid, zmid),
                    Vector3.Right, Vector3.Forward,
                    new Vector2(2.0f * texIncX, texIncY) + textureMinimalCorner,
                    faceTextureSize,
                    ySize, zSize);
            }

            return GeometryPrimitive.Combine(faces);
        }
        /// <summary>
        /// Translates the given GeometryPrimitive by the specified vector.
        /// </summary>
        /// <param name="original"></param>
        /// <param name="translation"></param>
        /// <returns></returns>
        public GeometryPrimitive Translate(Vector3 translation)
        {
            GeometryPrimitive output = new GeometryPrimitive();

            output.Indices = new int[Indices.Length];
            output.Vertices = new VertexPositionNormalTexture[Vertices.Length];

            for (int i = 0; i < Indices.Length; i++)
                output.Indices[i] = Indices[i];

            for (int i = 0; i < Vertices.Length; i++)
            {
                output.Vertices[i] = Vertices[i];
                output.Vertices[i].Position += translation;
            }

            return output;
        }
        /// <summary>
        /// Constructs a new GeometryPrimitive from this original and a scaling factor.
        /// </summary>
        /// <param name="scalingFactor"></param>
        /// <returns></returns>
        public GeometryPrimitive Scale(float scalingFactor)
        {
            GeometryPrimitive output = new GeometryPrimitive();

            output.Indices = new int[Indices.Length];
            output.Vertices = new VertexPositionNormalTexture[Vertices.Length];

            for (int i = 0; i < Indices.Length; i++)
                output.Indices[i] = Indices[i];

            for (int i = 0; i < Vertices.Length; i++)
            {
                output.Vertices[i] = Vertices[i];
                output.Vertices[i].Position *= scalingFactor;
            }

            return output;
        }
        /// <summary>
        /// This is exactly like the Make3DRectangle method, including texture usage,
        /// except that all the faces are looking IN (as would be expected).  So you
        /// can hang this around the camera and that'll look fine.
        /// </summary>
        /// <param name="minimalCorner"></param>
        /// <param name="size"></param>
        /// <param name="textureMinimalCorner"></param>
        /// <param name="textureSize"></param>
        /// <returns></returns>
        public static GeometryPrimitive MakeSkybox(Vector3 minimalCorner, Vector3 size,
            Vector2 textureMinimalCorner, Vector2 textureSize)
        {
            //physical dimensions
            float xmin = minimalCorner.X;
            float xmid = minimalCorner.X + (size.X / 2.0f);
            float xmax = minimalCorner.X + size.X;

            float xSize = size.X;

            float ymin = minimalCorner.Y;
            float ymid = minimalCorner.Y + (size.Y / 2.0f);
            float ymax = minimalCorner.Y + size.Y;

            float ySize = size.Y;

            float zmin = minimalCorner.Z;
            float zmid = minimalCorner.Z + (size.Z / 2.0f);
            float zmax = minimalCorner.Z + size.Z;

            float zSize = size.Z;

            //texture dimensions
            float texIncX = textureSize.X * 0.25f; //texture increment x
            float texIncY = textureSize.Y * 0.25f;  //texture increment y

            Vector2 faceTextureSize = new Vector2(texIncX, texIncY);

            //and now for the geometry!
            GeometryPrimitive[] faces = new GeometryPrimitive[6];

            //Front face
            faces[0] = GeometryPrimitive.MakeRectangle(
                new Vector3(xmid, ymid, zmin),
                Vector3.Backward, Vector3.Up,
                new Vector2(texIncX, 2.0f * texIncY) + textureMinimalCorner,
                faceTextureSize,
                xSize, ySize);

            //Back face
            faces[1] = GeometryPrimitive.MakeRectangle(
                new Vector3(xmid, ymid, zmax),
                Vector3.Forward, Vector3.Down,
                new Vector2(texIncX, 0) + textureMinimalCorner,
                faceTextureSize,
                xSize, ySize);

            //top face
            faces[2] = GeometryPrimitive.MakeRectangle(
                new Vector3(xmid, ymax, zmid),
                Vector3.Down, Vector3.Backward,
                new Vector2(texIncX, texIncY) + textureMinimalCorner,
                faceTextureSize,
                xSize, zSize);

            //bottom face
            faces[3] = GeometryPrimitive.MakeRectangle(
                new Vector3(xmid, ymin, zmid),
                Vector3.Up, Vector3.Forward,
                new Vector2(texIncX, 3.0f * texIncY) + textureMinimalCorner,
                faceTextureSize,
                xSize, zSize);

            //left face
            faces[4] = GeometryPrimitive.MakeRectangle(
                new Vector3(xmin, ymid, zmid),
                Vector3.Right, Vector3.Backward,
                new Vector2(0, texIncY) + textureMinimalCorner,
                faceTextureSize,
                zSize, ySize);

            //right face
            faces[5] = GeometryPrimitive.MakeRectangle(
                new Vector3(xmax, ymid, zmid),
                Vector3.Left, Vector3.Backward,
                new Vector2(2.0f * texIncX, texIncY) + textureMinimalCorner,
                faceTextureSize,
                zSize, ySize);

            return GeometryPrimitive.Combine(faces);
        }
        /// <summary>
        /// Construct a rectangle at the specified location, which displays a
        /// portion of a texture.
        /// </summary>
        /// <param name="center">The center of the rectangle.</param>
        /// <param name="normal">UNIT VECTOR facing directly out of the rectangle.
        /// If you're facing the rectangle (and you want it to be visible)
        /// then this should be pointing at you.</param>
        /// <param name="up">UNIT VECTOR pointing in the direction that should be
        /// "up" on the texture.  Messing this up may flip the texture.</param>
        /// <param name="textureCornerUL">The "upper left corner" of the relevant
        /// part of the texture in UV coordinates.</param>
        /// <param name="textureSize">The "size" of the relevant part of the
        /// texture in UV coordinates.  For clarity, note that the lower left
        /// corner should be textureCornerUL + size.</param>
        /// <param name="width">The width of the rectangle.</param>
        /// <param name="height">The height of the rectangle.</param>
        /// <returns></returns>
        public static GeometryPrimitive MakeRectangle(
            Vector3 center, Vector3 normal, Vector3 up,
            Vector2 textureCornerUL, Vector2 textureSize,
            float width, float height)
        {
            GeometryPrimitive quad = new GeometryPrimitive();

            Vector3 left = Vector3.Cross(normal, up);
            Vector3 upperCenter = center + up * (height / 2.0f);

            Vector3 upperLeft = upperCenter + left * (width / 2.0f);
            Vector3 upperRight = upperCenter - left * (width / 2.0f);

            Vector3 lowerLeft = upperLeft - up * height;
            Vector3 lowerRight = upperRight - up * height;

            Vector2 textureUL = new Vector2(textureCornerUL.X, textureCornerUL.Y);
            Vector2 textureUR = new Vector2(textureCornerUL.X + textureSize.X, textureCornerUL.Y);
            Vector2 textureDL = new Vector2(textureCornerUL.X, textureCornerUL.Y + textureSize.Y);
            Vector2 textureDR = new Vector2(textureCornerUL.X + textureSize.X, textureCornerUL.Y + textureSize.Y);

            //with all those preliminaries set up, just define the corners!
            quad.Vertices = new VertexPositionNormalTexture[4];

            quad.Vertices[0] = new VertexPositionNormalTexture(lowerLeft, normal, textureDL);
            quad.Vertices[1] = new VertexPositionNormalTexture(upperLeft, normal, textureUL);
            quad.Vertices[2] = new VertexPositionNormalTexture(lowerRight, normal, textureDR);
            quad.Vertices[3] = new VertexPositionNormalTexture(upperRight, normal, textureUR);

            quad.Indices = new int[] { 0, 1, 2, 2, 1, 3 };

            return quad;
        }