Пример #1
0
        private static bool AddCaches(List <LiquidPrimitive> primitivesToInit, ref LiquidPrimitive[] lps)
        {
            // We are going to first set up the internal array.
            foreach (LiquidPrimitive lp in primitivesToInit)
            {
                if (lp != null)
                {
                    lps[(int)lp.LiqType] = lp;
                }
            }

            // We are going to lock around the IsBuilding check/set to avoid the situation where two threads could both pass through
            // if they both checked IsBuilding at the same time before either of them set IsBuilding.
            lock (caches)
            {
                // We check all parts of the array before setting any to avoid somehow setting a few then leaving before we can unset them.
                for (int i = 0; i < lps.Length; i++)
                {
                    if (lps[i] != null && lps[i].IsBuilding)
                    {
                        return(false);
                    }
                }

                // Now we know we are safe so we can set IsBuilding.
                for (int i = 0; i < lps.Length; i++)
                {
                    if (lps[i] != null)
                    {
                        lps[i].IsBuilding = true;
                    }
                }

                // Now we have to get a valid cache object.
                bool cacheSet = false;
                for (int i = 0; i < caches.Count; i++)
                {
                    if (!caches[i].inUse)
                    {
                        cache       = caches[i];
                        cache.inUse = true;
                        cacheSet    = true;
                    }
                }
                if (!cacheSet)
                {
                    cache       = new LiquidRebuildCache();
                    cache.inUse = true;
                    caches.Add(cache);
                }
            }

            return(true);
        }
Пример #2
0
        // This will loop through the whole world and draw out all liquid primatives that are handed to the function.
        public static void InitializePrimativesFromChunk(VoxelChunk chunk, List <LiquidPrimitive> primitivesToInit)
        {
            LiquidPrimitive[] lps = new LiquidPrimitive[(int)LiquidType.Count];

            if (!AddCaches(primitivesToInit, ref lps))
            {
                return;
            }

            LiquidType      curLiqType   = LiquidType.None;
            LiquidPrimitive curPrimitive = null;

            ExtendedVertex[] curVertices = null;
            ushort[]         curIndexes  = null;
            int[]            maxVertices = new int[lps.Length];
            int[]            maxIndexes  = new int[lps.Length];

            int  maxVertex  = 0;
            int  maxIndex   = 0;
            int  totalFaces = 6;
            bool fogOfWar   = GameSettings.Current.FogofWar;

            for (int globalY = chunk.Origin.Y; globalY < Math.Min(chunk.Manager.World.Renderer.PersistentSettings.MaxViewingLevel + 1, chunk.Origin.Y + VoxelConstants.ChunkSizeY); globalY++)
            {
                var y = globalY - chunk.Origin.Y;
                if (chunk.Data.LiquidPresent[y] == 0)
                {
                    continue;
                }

                for (int x = 0; x < VoxelConstants.ChunkSizeX; x++)
                {
                    for (int z = 0; z < VoxelConstants.ChunkSizeZ; z++)
                    {
                        var voxel = VoxelHandle.UnsafeCreateLocalHandle(chunk, new LocalVoxelCoordinate(x, y, z));
                        if (fogOfWar && !voxel.IsExplored)
                        {
                            continue;
                        }

                        if (voxel.LiquidLevel > 0)
                        {
                            var liqType = voxel.LiquidType;

                            // We need to see if we changed types and should change the data we are writing to.
                            if (liqType != curLiqType)
                            {
                                LiquidPrimitive newPrimitive = lps[(int)liqType];
                                // We weren't passed a LiquidPrimitive object to work with for this type so we'll skip it.
                                if (newPrimitive == null)
                                {
                                    continue;
                                }

                                maxVertices[(int)curLiqType] = maxVertex;
                                maxIndexes[(int)curLiqType]  = maxIndex;

                                curVertices = newPrimitive.Vertices;
                                curIndexes  = newPrimitive.Indexes;

                                curLiqType   = liqType;
                                curPrimitive = newPrimitive;
                                maxVertex    = maxVertices[(int)liqType];
                                maxIndex     = maxIndexes[(int)liqType];
                            }

                            int facesToDraw = 0;
                            for (int i = 0; i < totalFaces; i++)
                            {
                                BoxFace face = (BoxFace)i;
                                // We won't draw the bottom face.  This might be needed down the line if we add transparent tiles like glass.
                                if (face == BoxFace.Bottom)
                                {
                                    continue;
                                }

                                var delta = faceDeltas[(int)face];

                                // Pull the current neighbor DestinationVoxel based on the face it would be touching.

                                var vox = VoxelHelpers.GetNeighbor(voxel, delta);

                                if (vox.IsValid)
                                {
                                    if (face == BoxFace.Top)
                                    {
                                        if (!(vox.LiquidLevel == 0 || y == (int)chunk.Manager.World.Renderer.PersistentSettings.MaxViewingLevel))
                                        {
                                            cache.drawFace[(int)face] = false;
                                            continue;
                                        }
                                    }
                                    else
                                    {
                                        if (vox.LiquidLevel != 0 || !vox.IsEmpty)
                                        {
                                            cache.drawFace[(int)face] = false;
                                            continue;
                                        }
                                    }
                                }
                                else
                                {
                                    cache.drawFace[(int)face] = false;
                                    continue;
                                }

                                cache.drawFace[(int)face] = true;
                                facesToDraw++;
                            }

                            // There's no faces to draw on this voxel.  Let's go to the next one.
                            if (facesToDraw == 0)
                            {
                                continue;
                            }

                            // Now we check to see if we need to resize the current Vertex array.
                            int vertexSizeIncrease = facesToDraw * 4;
                            int indexSizeIncrease  = facesToDraw * 6;

                            lock (curPrimitive.VertexLock)
                            {
                                // Check vertex array size
                                if (curVertices == null)
                                {
                                    curVertices           = new ExtendedVertex[256];
                                    curPrimitive.Vertices = curVertices;
                                }
                                else if (curVertices.Length <= maxVertex + vertexSizeIncrease)
                                {
                                    ExtendedVertex[] newVerts = new ExtendedVertex[MathFunctions.NearestPowerOf2(maxVertex + vertexSizeIncrease)];

                                    curVertices.CopyTo(newVerts, 0);
                                    curVertices           = newVerts;
                                    curPrimitive.Vertices = curVertices;
                                }

                                // Check index array size
                                if (curIndexes == null)
                                {
                                    curIndexes           = new ushort[256];
                                    curPrimitive.Indexes = curIndexes;
                                }
                                else if (curIndexes.Length <= maxIndex + indexSizeIncrease)
                                {
                                    ushort[] newIdxs = new ushort[MathFunctions.NearestPowerOf2(maxIndex + indexSizeIncrease)];

                                    curIndexes.CopyTo(newIdxs, 0);
                                    curIndexes           = newIdxs;
                                    curPrimitive.Indexes = curIndexes;
                                }
                            }

                            // Now we have a list of all the faces that will need to be drawn.  Let's draw  them.
                            CreateWaterFaces(voxel, chunk, x, y, z, curVertices, curIndexes, maxVertex, maxIndex);

                            // Finally increase the size so we can move on.
                            maxVertex += vertexSizeIncrease;
                            maxIndex  += indexSizeIncrease;
                        }
                    }
                }
            }

            // The last thing we need to do is make sure we set the current primative's maxVertices to the right value.
            maxVertices[(int)curLiqType] = maxVertex;
            maxIndexes[(int)curLiqType]  = maxIndex;

            // Now actually force the VertexBuffer to be recreated in each primative we worked with.
            for (int i = 0; i < lps.Length; i++)
            {
                LiquidPrimitive updatedPrimative = lps[i];
                if (updatedPrimative == null)
                {
                    continue;
                }

                maxVertex = maxVertices[i];
                maxIndex  = maxIndexes[i];

                if (maxVertex > 0)
                {
                    try
                    {
                        lock (updatedPrimative.VertexLock)
                        {
                            updatedPrimative.VertexCount  = maxVertex;
                            updatedPrimative.IndexCount   = maxIndex;
                            updatedPrimative.VertexBuffer = null;
                            updatedPrimative.IndexBuffer  = null;
                        }
                    }
                    catch (global::System.Threading.AbandonedMutexException e)
                    {
                        Console.Error.WriteLine(e.Message);
                    }
                }
                else
                {
                    try
                    {
                        lock (updatedPrimative.VertexLock)
                        {
                            updatedPrimative.VertexBuffer = null;
                            updatedPrimative.Vertices     = null;
                            updatedPrimative.IndexBuffer  = null;
                            updatedPrimative.Indexes      = null;
                            updatedPrimative.VertexCount  = 0;
                            updatedPrimative.IndexCount   = 0;
                        }
                    }
                    catch (global::System.Threading.AbandonedMutexException e)
                    {
                        Console.Error.WriteLine(e.Message);
                    }
                }
                updatedPrimative.IsBuilding = false;
            }

            cache.inUse = false;
            cache       = null;
        }
Пример #3
0
        // This will loop through the whole world and draw out all liquid primatives that are handed to the function.
        public static void InitializePrimativesFromChunk(VoxelChunk chunk, List <LiquidPrimitive> primitivesToInit)
        {
            LiquidPrimitive[] lps = new LiquidPrimitive[(int)LiquidType.Count];

            // We are going to first set up the internal array.
            foreach (LiquidPrimitive lp in primitivesToInit)
            {
                if (lp != null)
                {
                    lps[(int)lp.LiqType] = lp;
                }
            }

            // We are going to lock around the IsBuilding check/set to avoid the situation where two threads could both pass through
            // if they both checked IsBuilding at the same time before either of them set IsBuilding.
            lock (caches)
            {
                // We check all parts of the array before setting any to avoid somehow setting a few then leaving before we can unset them.
                for (int i = 0; i < lps.Length; i++)
                {
                    if (lps[i] != null && lps[i].IsBuilding)
                    {
                        return;
                    }
                }

                // Now we know we are safe so we can set IsBuilding.
                for (int i = 0; i < lps.Length; i++)
                {
                    if (lps[i] != null)
                    {
                        lps[i].IsBuilding = true;
                    }
                }

                // Now we have to get a valid cache object.
                bool cacheSet = false;
                for (int i = 0; i < caches.Count; i++)
                {
                    if (!caches[i].inUse)
                    {
                        cache       = caches[i];
                        cache.inUse = true;
                        cacheSet    = true;
                    }
                }
                if (!cacheSet)
                {
                    cache       = new LiquidRebuildCache();
                    cache.inUse = true;
                    caches.Add(cache);
                }
            }

            LiquidType      curLiqType   = LiquidType.None;
            LiquidPrimitive curPrimative = null;

            ExtendedVertex[] curVertices = null;
            int[]            maxVertices = new int[lps.Length];
            int maxY = (int)Math.Min(chunk.Manager.ChunkData.MaxViewingLevel + 1, chunk.SizeY);

            Voxel myVoxel   = chunk.MakeVoxel(0, 0, 0);
            Voxel vox       = chunk.MakeVoxel(0, 0, 0);
            int   maxVertex = 0;
            bool  fogOfWar  = GameSettings.Default.FogofWar;

            for (int x = 0; x < chunk.SizeX; x++)
            {
                for (int y = 0; y < maxY; y++)
                {
                    for (int z = 0; z < chunk.SizeZ; z++)
                    {
                        int index = chunk.Data.IndexAt(x, y, z);
                        if (fogOfWar && !chunk.Data.IsExplored[index])
                        {
                            continue;
                        }

                        if (chunk.Data.Water[index].WaterLevel > 0)
                        {
                            LiquidType liqType = chunk.Data.Water[index].Type;

                            // We need to see if we changed types and should change the data we are writing to.
                            if (liqType != curLiqType)
                            {
                                LiquidPrimitive newPrimitive = lps[(int)liqType];
                                // We weren't passed a LiquidPrimitive object to work with for this type so we'll skip it.
                                if (newPrimitive == null)
                                {
                                    continue;
                                }

                                maxVertices[(int)curLiqType] = maxVertex;

                                curVertices  = newPrimitive.Vertices;
                                curLiqType   = liqType;
                                curPrimative = newPrimitive;
                                maxVertex    = maxVertices[(int)liqType];
                            }

                            myVoxel.GridPosition = new Vector3(x, y, z);

                            int facesToDraw = 0;
                            for (int i = 0; i < 6; i++)
                            {
                                BoxFace face = (BoxFace)i;
                                // We won't draw the bottom face.  This might be needed down the line if we add transparent tiles like glass.
                                if (face == BoxFace.Bottom)
                                {
                                    continue;
                                }

                                Vector3 delta = faceDeltas[(int)face];

                                // Pull the current neighbor Voxel based on the face it would be touching.
                                bool success = myVoxel.GetNeighborBySuccessor(delta, ref vox, false);

                                if (success)
                                {
                                    if (face == BoxFace.Top)
                                    {
                                        if (!(vox.WaterLevel == 0 || y == (int)chunk.Manager.ChunkData.MaxViewingLevel))
                                        {
                                            cache.drawFace[(int)face] = false;
                                            continue;
                                        }
                                    }
                                    else
                                    {
                                        if (vox.WaterLevel != 0 || !vox.IsEmpty)
                                        {
                                            cache.drawFace[(int)face] = false;
                                            continue;
                                        }
                                    }
                                }

                                cache.drawFace[(int)face] = true;
                                facesToDraw++;
                            }

                            // There's no faces to draw on this voxel.  Let's go to the next one.
                            if (facesToDraw == 0)
                            {
                                continue;
                            }

                            // Now we check to see if we need to resize the current Vertex array.
                            int vertexSizeIncrease = facesToDraw * 6;
                            if (curVertices == null)
                            {
                                curVertices           = new ExtendedVertex[256];
                                curPrimative.Vertices = curVertices;
                            }
                            else if (curVertices.Length <= maxVertex + vertexSizeIncrease)
                            {
                                ExtendedVertex[] newVerts = new ExtendedVertex[curVertices.Length * 2];
                                curVertices.CopyTo(newVerts, 0);
                                curVertices           = newVerts;
                                curPrimative.Vertices = curVertices;
                            }

                            // Now we have a list of all the faces that will need to be drawn.  Let's draw them.
                            CreateWaterFaces(myVoxel, chunk, x, y, z, curVertices, maxVertex);

                            // Finally increase the size so we can move on.
                            maxVertex += vertexSizeIncrease;
                        }
                    }
                }
            }

            // The last thing we need to do is make sure we set the current primative's maxVertices to the right value.
            maxVertices[(int)curLiqType] = maxVertex;

            // Now actually force the VertexBuffer to be recreated in each primative we worked with.
            for (int i = 0; i < lps.Length; i++)
            {
                LiquidPrimitive updatedPrimative = lps[i];
                if (updatedPrimative == null)
                {
                    continue;
                }

                maxVertex = maxVertices[i];
                if (maxVertex > 0)
                {
                    try
                    {
                        lock (updatedPrimative.VertexLock)
                        {
                            updatedPrimative.MaxVertex    = maxVertex;
                            updatedPrimative.VertexBuffer = null;
                        }
                    }
                    catch (System.Threading.AbandonedMutexException e)
                    {
                        Console.Error.WriteLine(e.Message);
                    }
                }
                else
                {
                    try
                    {
                        lock (updatedPrimative.VertexLock)
                        {
                            updatedPrimative.VertexBuffer = null;
                            updatedPrimative.Vertices     = null;
                            updatedPrimative.Indexes      = null;
                            updatedPrimative.MaxVertex    = 0;
                            updatedPrimative.MaxIndex     = 0;
                        }
                    }
                    catch (System.Threading.AbandonedMutexException e)
                    {
                        Console.Error.WriteLine(e.Message);
                    }
                }
                updatedPrimative.IsBuilding = false;
            }

            cache.inUse = false;
            cache       = null;
        }