private static int GetVoxelVertexExploredNeighbors(VoxelHandle V, Geo.TemplateFace Face, SliceCache Cache)
        {
            var exploredVerts = 0;

            if (V.IsExplored)
            {
                exploredVerts = 4;
            }
            else
            {
                for (int faceVertex = 0; faceVertex < Face.Mesh.VertexCount; ++faceVertex)
                {
                    var cacheKey            = SliceCache.GetCacheKey(V, Face.Mesh.Verticies[faceVertex].LogicalVertex);
                    var anyNeighborExplored = true;

                    if (!Cache.ExploredCache.TryGetValue(cacheKey, out anyNeighborExplored))
                    {
                        anyNeighborExplored = VoxelHelpers.EnumerateVertexNeighbors2D(V.Coordinate, Face.Mesh.Verticies[faceVertex].LogicalVertex)
                                              .Select(c => new VoxelHandle(V.Chunk.Manager, c))
                                              .Any(n => n.IsValid && n.IsExplored);
                        Cache.ExploredCache.Add(cacheKey, anyNeighborExplored);
                    }

                    if (anyNeighborExplored)
                    {
                        exploredVerts += 1;
                    }
                }
            }

            return(exploredVerts);
        }
예제 #2
0
        public static VertexColorInfo CalculateVertexLight(VoxelHandle Vox, VoxelVertex Vertex, ChunkManager Chunks, SliceCache Cache)
        {
            var r = new VertexColorInfo();

            var cacheKey = SliceCache.GetCacheKey(Vox, Vertex);

            if (!Cache.LightCache.TryGetValue(cacheKey, out r))
            {
                r = CalculateVertexLight(Vox, Vertex, Chunks);
                Cache.LightCache.Add(cacheKey, r);
            }

            return(r);
        }
예제 #3
0
 private static void GenerateSliceGeometry(
     RawPrimitive Into,
     VoxelChunk Chunk,
     int LocalY,
     TerrainTileSheet TileSheet,
     WorldManager World,
     SliceCache Cache)
 {
     for (var x = 0; x < VoxelConstants.ChunkSizeX; ++x)
     {
         for (var z = 0; z < VoxelConstants.ChunkSizeZ; ++z)
         {
             GenerateVoxelGeometry(Into, VoxelHandle.UnsafeCreateLocalHandle(Chunk, new LocalVoxelCoordinate(x, LocalY, z)), TileSheet, World, Cache);
         }
     }
 }
예제 #4
0
        private static void GenerateHangingCornerFringe(
            RawPrimitive Into,
            Geo.TemplateFace Face,
            TerrainTileSheet TileSheet,
            SliceCache Cache,
            GrassType decalType,
            Geo.TemplateCorner Corner,
            Vector3 Sag)
        {
            var vertex = Cache.FaceGeometry[Corner.Vertex];

            Cache.TempVerticies[0] = new ExtendedVertex(
                vertex.Position,
                vertex.Color, vertex.VertColor,
                TileSheet.MapTileUVs(new Vector2(0.0f, 0.0f), decalType.FringeTiles[2]), TileSheet.GetTileBounds(decalType.FringeTiles[2]));

            Cache.TempVerticies[1] = new ExtendedVertex(
                Cache.EdgeFringeTempVerticies[Corner.EdgeA].Set ? Cache.EdgeFringeTempVerticies[Corner.EdgeA].End :
                (vertex.Position
                 + OrientationHelper.GetFaceNeighborOffset(Face.Edges[Corner.EdgeA].Orientation).AsVector3() * 0.5f
                 + Sag),
                vertex.Color, vertex.VertColor,
                TileSheet.MapTileUVs(new Vector2(0.5f, 0.0f), decalType.FringeTiles[2]), TileSheet.GetTileBounds(decalType.FringeTiles[2]));

            Cache.TempVerticies[2] = new ExtendedVertex(
                vertex.Position
                + OrientationHelper.GetFaceNeighborOffset(Face.Edges[Corner.EdgeA].Orientation).AsVector3() * 0.5f
                + OrientationHelper.GetFaceNeighborOffset(Face.Edges[Corner.EdgeB].Orientation).AsVector3() * 0.5f
                + Sag,
                vertex.Color, vertex.VertColor,
                TileSheet.MapTileUVs(new Vector2(0.5f, 0.5f), decalType.FringeTiles[2]), TileSheet.GetTileBounds(decalType.FringeTiles[2]));

            Cache.TempVerticies[3] = new ExtendedVertex(
                Cache.EdgeFringeTempVerticies[Corner.EdgeB].Set ? Cache.EdgeFringeTempVerticies[Corner.EdgeB].Start :
                (vertex.Position
                 + OrientationHelper.GetFaceNeighborOffset(Face.Edges[Corner.EdgeB].Orientation).AsVector3() * 0.5f
                 + Sag),
                vertex.Color, vertex.VertColor,
                TileSheet.MapTileUVs(new Vector2(0.0f, 0.5f), decalType.FringeTiles[2]), TileSheet.GetTileBounds(decalType.FringeTiles[2]));

            AddQuad(Into, Cache.TempVerticies, QuadIndicies);
        }
예제 #5
0
        public static void GenerateFaceGeometry(
            RawPrimitive Into,
            VoxelHandle Voxel,
            Geo.TemplateFace Face,
            TerrainTileSheet TileSheet,
            WorldManager World,
            SliceCache Cache)
        {
            if (Face.CullType == Geo.FaceCullType.Cull && !IsFaceVisible(Voxel, Face, World.ChunkManager, out var neighbor))
            {
                return;
            }

            if (Face.Orientation == FaceOrientation.Top)
            {
                if (Voxel.GrassType != 0)
                {
                    var decalType = Library.GetGrassType(Voxel.GrassType);
                    PrepVerticies(World, Voxel, Face, Cache, GetVoxelVertexExploredNeighbors(Voxel, Face, Cache), TileSheet, decalType.Tile, true, 0.0f);

                    GenerateGrassFringe(Into, Voxel, Face, TileSheet, Cache, decalType);
                }
                else
                {
                    PrepVerticies(World, Voxel, Face, Cache, GetVoxelVertexExploredNeighbors(Voxel, Face, Cache), TileSheet, SelectTile(Voxel.Type, Face.Orientation), true, 0.0f);
                }

                AddQuad(Into, Cache.FaceGeometry, QuadIndicies);

                if (Voxel.DecalType != 0)
                {
                    var decalType = Library.GetDecalType(Voxel.DecalType);
                    PrepVerticies(World, Voxel, Face, Cache, GetVoxelVertexExploredNeighbors(Voxel, Face, Cache), TileSheet, decalType.Tile, true, 0.02f);
                    AddQuad(Into, Cache.FaceGeometry, QuadIndicies);
                }
            }
            else
            {
                PrepVerticies(World, Voxel, Face, Cache, GetVoxelVertexExploredNeighbors(Voxel, Face, Cache), TileSheet, SelectTile(Voxel.Type, Face.Orientation), true, 0.0f);
                AddQuad(Into, Cache.FaceGeometry, QuadIndicies);
            }
        }
예제 #6
0
        public static void GenerateVoxelGeometry(
            RawPrimitive Into,
            VoxelHandle Voxel,
            TerrainTileSheet TileSheet,
            WorldManager World,
            SliceCache Cache)
        {
            BuildDesignationGeometry(Into, Voxel, Cache, TileSheet, World);
            if (Voxel.IsEmpty && Voxel.IsExplored)
            {
                return;
            }

            var templateSolid = TemplateSolidLibrary.GetTemplateSolid(Voxel.Type.TemplateSolid);

            foreach (var face in templateSolid.Faces)
            {
                GenerateFaceGeometry(Into, Voxel, face, TileSheet, World, Cache);
            }
        }
예제 #7
0
        private static void GenerateEdgeFringe(
            RawPrimitive Into,
            Geo.TemplateFace Face,
            int EdgeIndex,
            TerrainTileSheet TileSheet,
            SliceCache Cache,
            GrassType decalType,
            Vector3 Sag,
            float Scale)
        {
            var start = Cache.FaceGeometry[Face.Edges[EdgeIndex].Start];
            var end   = Cache.FaceGeometry[Face.Edges[EdgeIndex].End];

            Cache.EdgeFringeTempVerticies[EdgeIndex].Set = true;

            Cache.TempVerticies[0] = new ExtendedVertex(
                start.Position,
                start.Color, start.VertColor,
                TileSheet.MapTileUVs(new Vector2(0.0f, 0.0f), decalType.FringeTiles[0]), TileSheet.GetTileBounds(decalType.FringeTiles[0]));

            Cache.TempVerticies[1] = new ExtendedVertex(
                end.Position,
                end.Color, end.VertColor,
                TileSheet.MapTileUVs(new Vector2(1.0f, 0.0f), decalType.FringeTiles[0]), TileSheet.GetTileBounds(decalType.FringeTiles[0]));

            Cache.EdgeFringeTempVerticies[EdgeIndex].End = end.Position + OrientationHelper.GetFaceNeighborOffset(Face.Edges[EdgeIndex].Orientation).AsVector3() * Scale + Sag;
            Cache.TempVerticies[2] = new ExtendedVertex(
                Cache.EdgeFringeTempVerticies[EdgeIndex].End,
                end.Color, end.VertColor,
                TileSheet.MapTileUVs(new Vector2(1.0f, 0.5f), decalType.FringeTiles[0]), TileSheet.GetTileBounds(decalType.FringeTiles[0]));

            Cache.EdgeFringeTempVerticies[EdgeIndex].Start = start.Position + OrientationHelper.GetFaceNeighborOffset(Face.Edges[EdgeIndex].Orientation).AsVector3() * Scale + Sag;
            Cache.TempVerticies[3] = new ExtendedVertex(
                Cache.EdgeFringeTempVerticies[EdgeIndex].Start,
                start.Color, start.VertColor,
                TileSheet.MapTileUVs(new Vector2(0.0f, 0.5f), decalType.FringeTiles[0]), TileSheet.GetTileBounds(decalType.FringeTiles[0]));

            AddQuad(Into, Cache.TempVerticies, QuadIndicies);
        }
예제 #8
0
        private static void GenerateGrassFringe(RawPrimitive Into, VoxelHandle Voxel, Geo.TemplateFace Face, TerrainTileSheet TileSheet, SliceCache Cache, GrassType decalType)
        {
            for (var i = 0; i < 4; ++i)
            {
                Cache.EdgeFringeTempVerticies[i].Set = false;
            }

            if (Face.Edges != null)
            {
                for (var e = 0; e < Face.Edges.Length; ++e)
                {
                    var fringeNeighbor = VoxelHelpers.GetNeighbor(Voxel, OrientationHelper.GetFaceNeighborOffset(Face.Edges[e].Orientation));
                    if (fringeNeighbor.IsValid)
                    {
                        if (fringeNeighbor.IsEmpty)
                        {
                            GenerateEdgeFringe(Into, Face, e, TileSheet, Cache, decalType, new Vector3(0.0f, -0.5f, 0.0f), 0.5f);
                        }
                        else
                        {
                            var above = VoxelHelpers.GetVoxelAbove(fringeNeighbor);
                            if (above.IsValid && !above.IsEmpty)
                            {
                                GenerateEdgeFringe(Into, Face, e, TileSheet, Cache, decalType, new Vector3(0.0f, 0.5f, 0.0f), -0.1f);
                            }
                            else if (fringeNeighbor.GrassType == 0 || (fringeNeighbor.GrassType != Voxel.GrassType && Library.GetGrassType(fringeNeighbor.GrassType).FringePrecedence < decalType.FringePrecedence))
                            {
                                GenerateEdgeFringe(Into, Face, e, TileSheet, Cache, decalType, new Vector3(0.0f, 0.2f, 0.0f), 0.5f);
                            }
                        }
                    }
                }
            }

            if (Face.Corners != null)
            {
                for (var c = 0; c < Face.Corners.Length; ++c)
                {
                    var cornerNeighbor = VoxelHelpers.GetNeighbor(Voxel, OrientationHelper.GetFaceNeighborOffset(Face.Edges[Face.Corners[c].EdgeA].Orientation) + OrientationHelper.GetFaceNeighborOffset(Face.Edges[Face.Corners[c].EdgeB].Orientation));

                    var manhattanA = VoxelHelpers.GetNeighbor(Voxel, OrientationHelper.GetFaceNeighborOffset(Face.Edges[Face.Corners[c].EdgeA].Orientation));
                    var manhattanB = VoxelHelpers.GetNeighbor(Voxel, OrientationHelper.GetFaceNeighborOffset(Face.Edges[Face.Corners[c].EdgeB].Orientation));

                    if (manhattanA.IsValid && !manhattanA.IsEmpty && manhattanA.GrassType == Voxel.GrassType)
                    {
                        continue;
                    }

                    if (manhattanB.IsValid && !manhattanB.IsEmpty && manhattanB.GrassType == Voxel.GrassType)
                    {
                        continue;
                    }


                    if (cornerNeighbor.IsValid)
                    {
                        if (cornerNeighbor.IsEmpty) // Todo: Do not generate fringe if horizontal neighbors are occupied.
                        // Todo: Also - needs to use corners set by edge fringe when they are at different heights. Maybe specify which edges the corner is in between?
                        {
                            GenerateHangingCornerFringe(Into, Face, TileSheet, Cache, decalType, Face.Corners[c], new Vector3(0.0f, -0.5f, 0.0f));
                        }
                        else
                        {
                            var above = VoxelHelpers.GetVoxelAbove(cornerNeighbor);
                            if (above.IsValid && !above.IsEmpty)
                            {
                            }
                            else if (cornerNeighbor.GrassType == 0 || (cornerNeighbor.GrassType != Voxel.GrassType && Library.GetGrassType(cornerNeighbor.GrassType).FringePrecedence < decalType.FringePrecedence))
                            {
                                GenerateHangingCornerFringe(Into, Face, TileSheet, Cache, decalType, Face.Corners[c], new Vector3(0.0f, 0.1f, 0.0f));
                            }
                        }
                    }
                }
            }
        }
예제 #9
0
        private static void PrepVerticies(
            WorldManager World,
            VoxelHandle Voxel,
            Geo.TemplateFace Face,
            SliceCache Cache,
            int ExploredVertexCount,
            TerrainTileSheet TileSheet,
            Point Tile,
            bool ApplyLighting,
            float explodeOffset)
        {
            for (var vertex = 0; vertex < Face.Mesh.VertexCount; ++vertex) // Blows up if face has more than 4 verticies.
            {
                var lighting = new VertexLighting.VertexColorInfo {
                    AmbientColor = 255, DynamicColor = 255, SunColor = 255
                };

                if (ApplyLighting)
                {
                    lighting = VertexLighting.CalculateVertexLight(Voxel, Face.Mesh.Verticies[vertex].LogicalVertex, World.ChunkManager, Cache);
                }

                var slopeOffset = Vector3.Zero;
                if (Face.Mesh.Verticies[vertex].ApplySlope && ShouldSlope(Face.Mesh.Verticies[vertex].LogicalVertex, Voxel))
                {
                    slopeOffset = new Vector3(0.0f, -0.5f, 0.0f);
                }

                var voxelPosition = Face.Mesh.Verticies[vertex].Position + slopeOffset + Voxel.WorldPosition;
                voxelPosition += VertexNoise.GetNoiseVectorFromRepeatingTexture(voxelPosition);
                voxelPosition += explodeOffset * OrientationHelper.GetFaceNeighborOffset(Face.Orientation).AsVector3();

                if (ExploredVertexCount == 0)
                {
                    Cache.FaceGeometry[vertex] = new ExtendedVertex
                    {
                        Position          = voxelPosition,
                        TextureCoordinate = TileSheet.MapTileUVs(Face.Mesh.Verticies[vertex].TextureCoordinate, BlackTile),
                        TextureBounds     = TileSheet.GetTileBounds(BlackTile),
                        VertColor         = new Color(0.0f, 0.0f, 0.0f, 1.0f),
                        Color             = new Color(0.0f, 0.0f, 0.0f, 1.0f)
                    };
                }
                else
                {
                    var anyNeighborExplored = true;
                    if (!Cache.ExploredCache.TryGetValue(SliceCache.GetCacheKey(Voxel, Face.Mesh.Verticies[vertex].LogicalVertex), out anyNeighborExplored))
                    {
                        anyNeighborExplored = true;
                    }

                    Cache.FaceGeometry[vertex] = new ExtendedVertex
                    {
                        Position          = voxelPosition,
                        TextureCoordinate = TileSheet.MapTileUVs(Face.Mesh.Verticies[vertex].TextureCoordinate, Tile),
                        TextureBounds     = TileSheet.GetTileBounds(Tile),
                        VertColor         = anyNeighborExplored ? new Color(1.0f, 1.0f, 1.0f, 1.0f) : new Color(0.0f, 0.0f, 0.0f, 1.0f),
                        Color             = lighting.AsColor()
                    };
                }
            }
        }
예제 #10
0
        public static GeometricPrimitive CreateFromChunk(VoxelChunk Chunk, WorldManager World)
        {
            DebugHelper.AssertNotNull(Chunk);
            DebugHelper.AssertNotNull(World);

            var sliceStack = new List <RawPrimitive>();
            var sliceCache = new SliceCache();

            int maxViewingLevel  = World.Renderer.PersistentSettings.MaxViewingLevel;
            var terrainTileSheet = new TerrainTileSheet(512, 512, 32, 32);

            for (var localY = 0; localY < maxViewingLevel - Chunk.Origin.Y && localY < VoxelConstants.ChunkSizeY; ++localY)
            {
                RawPrimitive sliceGeometry = null;
                sliceCache.ClearSliceCache();

                lock (Chunk.Data.SliceCache)
                {
                    var cachedSlice = Chunk.Data.SliceCache[localY];

                    if (cachedSlice != null)
                    {
                        sliceStack.Add(cachedSlice); // Todo: Get rid of the raw primitive / geometric primitive bullshit entirely

                        if (GameSettings.Current.GrassMotes)
                        {
                            Chunk.RebuildMoteLayerIfNull(localY);
                        }

                        continue;
                    }

                    sliceGeometry = new RawPrimitive();

                    Chunk.Data.SliceCache[localY] = sliceGeometry;
                }

                if (GameSettings.Current.CalculateRamps)
                {
                    PrecomputeVoxelSlopesSlice(World.ChunkManager, Chunk, localY);
                }

                if (GameSettings.Current.GrassMotes)
                {
                    Chunk.RebuildMoteLayer(localY);
                }

                DebugHelper.AssertNotNull(sliceGeometry);
                GenerateSliceGeometry(sliceGeometry, Chunk, localY, terrainTileSheet, World, sliceCache);

                sliceStack.Add(sliceGeometry);
            }

            var chunkGeo = RawPrimitive.Concat(sliceStack);

            var r = new GeometricPrimitive();

            r.Vertices    = chunkGeo.Vertices;
            r.VertexCount = chunkGeo.VertexCount;
            r.Indexes     = chunkGeo.Indexes.Select(c => (ushort)c).ToArray();
            r.IndexCount  = chunkGeo.IndexCount;

            return(r);
        }
예제 #11
0
        private static void BuildDesignationGeometry(
            RawPrimitive Into,
            VoxelHandle Voxel,
            SliceCache Cache,
            TerrainTileSheet TileSheet,
            WorldManager World)
        {
            // Todo: Store designations per chunk.
            foreach (var designation in World.PersistentData.Designations.EnumerateDesignations(Voxel).ToList())
            {
                if ((designation.Type & World.Renderer.PersistentSettings.VisibleTypes) != designation.Type) // If hidden by player, do not draw.
                {
                    return;
                }

                var designationProperties = Library.GetDesignationTypeProperties(designation.Type).Value;
                var designationVisible    = false;

                if (designationProperties.DrawType == DesignationDrawType.PreviewVoxel)
                {
                    designationVisible = Voxel.Coordinate.Y < World.Renderer.PersistentSettings.MaxViewingLevel;
                }
                else
                {
                    designationVisible = VoxelHelpers.DoesVoxelHaveVisibleSurface(World, Voxel);
                }

                if (designationVisible &&
                    Library.GetVoxelPrimitive(Library.DesignationVoxelType).HasValue(out BoxPrimitive designationPrimitive))
                {
                    switch (designationProperties.DrawType)
                    {
                    case DesignationDrawType.FullBox:
                    {
                        var solid = TemplateSolidLibrary.GetTemplateSolid(Voxel.Type.TemplateSolid);
                        for (var f = 0; f < solid.Faces.Count; ++f)
                        {
                            var face = solid.Faces[f];
                            if (face.CullType == Geo.FaceCullType.Cull && !IsFaceVisible(Voxel, face, World.ChunkManager, out var neighbor))
                            {
                                continue;
                            }

                            PrepVerticies(World, Voxel, face, Cache, GetVoxelVertexExploredNeighbors(Voxel, face, Cache), TileSheet, new Point(0, 0), false, 0.02f);
                            SetVertexTint(Cache.FaceGeometry, designationProperties.Color);
                            AddQuad(Into, Cache.FaceGeometry, QuadIndicies);
                        }
                    }
                    break;

                    case DesignationDrawType.TopBox:
                    {
                        var solid = TemplateSolidLibrary.GetTemplateSolid(Voxel.Type.TemplateSolid);
                        for (var f = 0; f < solid.Faces.Count; ++f)
                        {
                            var face = solid.Faces[f];
                            if (face.Orientation != FaceOrientation.Top)
                            {
                                continue;
                            }
                            if (face.CullType == Geo.FaceCullType.Cull && !IsFaceVisible(Voxel, face, World.ChunkManager, out var neighbor))
                            {
                                continue;
                            }

                            PrepVerticies(World, Voxel, face, Cache, GetVoxelVertexExploredNeighbors(Voxel, face, Cache), TileSheet, new Point(0, 0), false, 0.02f);
                            SetVertexTint(Cache.FaceGeometry, designationProperties.Color);
                            AddQuad(Into, Cache.FaceGeometry, QuadIndicies);
                        }
                    }
                    break;

                    case DesignationDrawType.PreviewVoxel:
                    {
                        if (Library.GetVoxelType(designation.Tag.ToString()).HasValue(out VoxelType voxelType))
                        {
                            var solid = TemplateSolidLibrary.GetTemplateSolid(voxelType.TemplateSolid);
                            for (var f = 0; f < solid.Faces.Count; ++f)
                            {
                                var face = solid.Faces[f];
                                if (face.CullType == Geo.FaceCullType.Cull && !IsFaceVisible(Voxel, face, World.ChunkManager, out var neighbor))
                                {
                                    continue;
                                }

                                PrepVerticies(World, Voxel, face, Cache, GetVoxelVertexExploredNeighbors(Voxel, face, Cache), TileSheet, SelectTile(voxelType, face.Orientation), false, 0.0f);
                                SetVertexTint(Cache.FaceGeometry, designationProperties.Color);
                                AddQuad(Into, Cache.FaceGeometry, QuadIndicies);
                            }
                        }
                    }
                    break;
                    }
                }
            }
        }