Пример #1
0
        public override float GenerateLayer(Chunk chunk, int layerIndex, int x, int z, float heightSoFar, float strength)
        {
            LocalPools pools = Globals.WorkPool.GetPool(chunk.ThreadID);
            NoiseItem  ni    = pools.noiseItems[layerIndex];

            // Calculate height to add and sum it with the min height (because the height of this
            // layer should fluctuate between minHeight and minHeight+the max noise) and multiply
            // it by strength so that a fraction of the result that gets used can be decided
            float heightToAdd = ni.noiseGen.Interpolate(x, z, ni.lookupTable);

            heightToAdd += MinHeight;
            heightToAdd *= strength;

            // Absolute layers add from the minY and up but if the layer height is lower than
            // the existing terrain there's nothing to add so just return the initial value
            if (heightToAdd > heightSoFar)
            {
                SetBlocks(chunk, x, z, (int)heightSoFar, (int)heightToAdd, blockToPlace);

                //Return the height of this layer from minY as this is the new height of the column
                return(heightToAdd);
            }

            return(heightSoFar);
        }
Пример #2
0
    public override void BuildFace(Chunk chunk, Vector3[] vertices, Color32[] palette, ref BlockFace face, bool rotated)
    {
        bool backFace = DirectionUtils.IsBackface(face.side);

        LocalPools pools = chunk.pools;
        var        verts = pools.Vector3ArrayPool.PopExact(4);
        var        cols  = pools.Color32ArrayPool.PopExact(4);

        {
            verts[0] = vertices[0];
            verts[1] = vertices[1];
            verts[2] = vertices[2];
            verts[3] = vertices[3];

            cols[0] = palette[face.block.Type];
            cols[1] = palette[face.block.Type];
            cols[2] = palette[face.block.Type];
            cols[3] = palette[face.block.Type];

            BlockUtils.AdjustColors(chunk, cols, face.light);
            magicMeshConfig.AddFace(verts, cols, backFace);
        }

        pools.Color32ArrayPool.Push(cols);
        pools.Vector3ArrayPool.Push(verts);
    }
Пример #3
0
        public override void PostProcess(Chunk chunk, int layerIndex)
        {
            LocalPools pools = Globals.WorkPool.GetPool(chunk.ThreadID);
            NoiseItem  ni    = pools.noiseItems[layerIndex];

            pools.floatArrayPool.Push(ni.lookupTable);
        }
Пример #4
0
 public virtual void BuildMesh(
     Map map, RenderGeometryBatcher batcher, int offsetX, int offsetY, int offsetZ,
     int minX, int maxX, int minY, int maxY, int minZ, int maxZ, int lod,
     LocalPools pools
     )
 {
     throw new NotImplementedException();
 }
Пример #5
0
        public TaskPool()
        {
            Pools = new LocalPools();

            m_items  = new List <TaskPoolItem>();
            m_event  = new AutoResetEvent(false);
            m_thread = new Thread(ThreadFunc)
            {
                IsBackground = true
            };
        }
Пример #6
0
        public Chunk() :
            base(6)
        {
            Blocks = new BlockStorage();

            m_threadID = Globals.WorkPool.GetThreadIDFromIndex(s_id++);
            Pools      = Globals.WorkPool.GetPool(m_threadID);

            m_drawCallBatcher       = new DrawCallBatcher(Globals.CubeMeshBuilder, this);
            BBoxVertices            = new List <Vector3>();
            BBoxVerticesTransformed = new List <Vector3>();

            Reset();
        }
Пример #7
0
        /// <summary>
        ///     Finalize the draw calls
        /// </summary>
        public void Commit()
        {
            ReleaseOldData();

            // No data means there's no mesh to build
            if (m_renderBuffers[0].IsEmpty())
            {
                return;
            }

            for (int i = 0; i < m_renderBuffers.Count; i++)
            {
                var go = GameObjectProvider.PopObject(GOPChunk);
                Assert.IsTrue(go != null);
                if (go != null)
                {
                    Mesh mesh = Globals.Pools.MeshPool.Pop();
                    Assert.IsTrue(mesh.vertices.Length <= 0);
                    m_meshBuilder.BuildMesh(mesh, m_renderBuffers[i]);

                    MeshFilter filter = go.GetComponent <MeshFilter>();
                    filter.sharedMesh         = null;
                    filter.sharedMesh         = mesh;
                    filter.transform.position = Vector3.zero;

                    m_drawCalls.Add(go);
                    m_drawCallRenderers.Add(go.GetComponent <Renderer>());
                }
            }

            // Make vertex data available again. We need to make this a task because our pooling system works on a per-thread
            // basis. Therefore, all Push()-es need to be called on the same thread as their respective Pop()-s.
            m_chunk.EnqueueGenericTask(
                () =>
            {
                LocalPools pools = m_chunk.Pools;

                for (int i = 0; i < m_renderBuffers.Count; i++)
                {
                    RenderBuffer buffer = m_renderBuffers[i];
                    for (int v = 0; v < buffer.Vertices.Count; v++)
                    {
                        pools.PushVertexData(buffer.Vertices[v]);
                    }

                    buffer.Clear();
                }
            });
        }
Пример #8
0
        public Chunk()
        {
            Blocks = new BlockStorage();

            // Associate Chunk with a certain thread and make use of its memory pool
            // This is necessary in order to have lock-free caches
            ThreadID = Globals.WorkPool.GetThreadIDFromIndex(s_id++);
            Pools    = Globals.WorkPool.GetPool(ThreadID);

            RenderGeometryBatcher   = new RenderGeometryBatcher(Globals.CubeMeshGeometryBuilder, this);
            BBoxVertices            = new List <Vector3>();
            BBoxVerticesTransformed = new List <Vector3>();

            StateManager = new ChunkStateManagerClient(this);
        }
Пример #9
0
        public override float GetHeight(Chunk chunk, int layerIndex, int x, int z, float heightSoFar, float strength)
        {
            LocalPools pools = Globals.WorkPool.GetPool(chunk.ThreadID);
            NoiseItem  ni    = pools.noiseItems[layerIndex];

            // Calculate height to add and sum it with the min height (because the height of this
            // layer should fluctuate between minHeight and minHeight+the max noise) and multiply
            // it by strength so that a fraction of the result that gets used can be decided
            float heightToAdd = ni.noiseGen.Interpolate(x, z, ni.lookupTable);

            heightToAdd += MinHeight;
            heightToAdd *= strength;

            return(heightSoFar + heightToAdd);
        }
Пример #10
0
        public override void PreProcess(Chunk chunk, int layerIndex)
        {
            LocalPools pools = Globals.WorkPool.GetPool(chunk.ThreadID);
            NoiseItem  ni    = pools.noiseItems[layerIndex];

            ni.noiseGen.SetInterpBitStep(Env.CHUNK_SIZE_WITH_PADDING, 2);
            ni.lookupTable = pools.floatArrayPool.Pop((ni.noiseGen.Size + 1) * (ni.noiseGen.Size + 1));

#if (UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN) && ENABLE_FASTSIMD
            float[] noiseSet = pools.floatArrayPool.Pop(ni.noiseGen.Size * ni.noiseGen.Size * ni.noiseGen.Size);

            // Generate SIMD noise
            int   offsetShift   = Env.CHUNK_POW - ni.noiseGen.Step;
            int   xStart        = (chunk.Pos.x * Env.CHUNK_SIZE) << offsetShift;
            int   yStart        = (chunk.Pos.y * Env.CHUNK_SIZE) << offsetShift;
            int   zStart        = (chunk.Pos.z * Env.CHUNK_SIZE) << offsetShift;
            float scaleModifier = 1 << ni.noiseGen.Step;
            noiseSIMD.Noise.FillNoiseSet(noiseSet, xStart, yStart, zStart, ni.noiseGen.Size, ni.noiseGen.Size, ni.noiseGen.Size, scaleModifier);

            // Generate a lookup table
            int i = 0;
            for (int z = 0; z < ni.noiseGen.Size; z++)
            {
                for (int x = 0; x < ni.noiseGen.Size; x++)
                {
                    ni.lookupTable[i++] = NoiseUtilsSIMD.GetNoise(noiseSet, ni.noiseGen.Size, x, 0, z, amplitude, noise.Gain);
                }
            }

            pools.floatArrayPool.Push(noiseSet);
#else
            int xOffset = chunk.Pos.x;
            int zOffset = chunk.Pos.z;

            // Generate a lookup table
            int i = 0;
            for (int z = 0; z < ni.noiseGen.Size; z++)
            {
                float zf = (z << ni.noiseGen.Step) + zOffset;

                for (int x = 0; x < ni.noiseGen.Size; x++)
                {
                    float xf = (x << ni.noiseGen.Step) + xOffset;
                    ni.lookupTable[i++] = NoiseUtils.GetNoise(noise.Noise, xf, 0, zf, 1f, amplitude, noise.Gain);
                }
            }
#endif
        }
Пример #11
0
    public override void BuildFace(Chunk chunk, Vector3[] vertices, Color32[] palette, ref BlockFace face, bool rotated)
    {
        bool backFace = DirectionUtils.IsBackface(face.side);
        int  d        = DirectionUtils.Get(face.side);

        LocalPools pools = chunk.pools;
        var        verts = pools.Vector3ArrayPool.PopExact(4);
        var        cols  = pools.Color32ArrayPool.PopExact(4);

        {
            if (vertices == null)
            {
                Vector3 pos = face.pos;

                verts[0] = pos + BlockUtils.PaddingOffsets[d][0];
                verts[1] = pos + BlockUtils.PaddingOffsets[d][1];
                verts[2] = pos + BlockUtils.PaddingOffsets[d][2];
                verts[3] = pos + BlockUtils.PaddingOffsets[d][3];

                cols[0] = colors[d];
                cols[1] = colors[d];
                cols[2] = colors[d];
                cols[3] = colors[d];
            }
            else
            {
                verts[0] = vertices[0];
                verts[1] = vertices[1];
                verts[2] = vertices[2];
                verts[3] = vertices[3];

                cols[0] = colors[d];
                cols[1] = colors[d];
                cols[2] = colors[d];
                cols[3] = colors[d];
            }

            BlockUtils.AdjustColors(chunk, cols, face.light);

            RenderGeometryBatcher batcher = chunk.GeometryHandler.Batcher;
            batcher.AddFace(face.materialID, verts, cols, backFace);
        }

        pools.Color32ArrayPool.Push(cols);
        pools.Vector3ArrayPool.Push(verts);
    }
Пример #12
0
        public static void Build(List <Vector3> targetBuffer, ref Bounds bounds, LocalPools pools)
        {
            Vector3[] vertices = pools.PopVector3Array(24);

            // Vertices as they are seen in faces
            //Front
            vertices[0] = new Vector3(bounds.max.x, bounds.min.y, bounds.min.z);
            vertices[1] = new Vector3(bounds.max.x, bounds.max.y, bounds.min.z);
            vertices[2] = new Vector3(bounds.min.x, bounds.max.y, bounds.min.z);
            vertices[3] = new Vector3(bounds.min.x, bounds.min.y, bounds.min.z);
            //Back
            vertices[4] = new Vector3(bounds.min.x, bounds.min.y, bounds.max.z);
            vertices[5] = new Vector3(bounds.min.x, bounds.max.y, bounds.max.z);
            vertices[6] = new Vector3(bounds.max.x, bounds.max.y, bounds.max.z);
            vertices[7] = new Vector3(bounds.max.x, bounds.min.y, bounds.max.z);
            //Right
            vertices[8]  = new Vector3(bounds.max.x, bounds.min.y, bounds.max.z);
            vertices[9]  = new Vector3(bounds.max.x, bounds.max.y, bounds.max.z);
            vertices[10] = new Vector3(bounds.max.x, bounds.max.y, bounds.min.z);
            vertices[11] = new Vector3(bounds.max.x, bounds.min.y, bounds.min.z);
            //Left
            vertices[12] = new Vector3(bounds.min.x, bounds.min.y, bounds.min.z);
            vertices[13] = new Vector3(bounds.min.x, bounds.max.y, bounds.min.z);
            vertices[14] = new Vector3(bounds.min.x, bounds.max.y, bounds.max.z);
            vertices[15] = new Vector3(bounds.min.x, bounds.min.y, bounds.max.z);
            //Top
            vertices[16] = new Vector3(bounds.max.x, bounds.max.y, bounds.min.z);
            vertices[17] = new Vector3(bounds.max.x, bounds.max.y, bounds.max.z);
            vertices[18] = new Vector3(bounds.min.x, bounds.max.y, bounds.max.z);
            vertices[19] = new Vector3(bounds.min.x, bounds.max.y, bounds.min.z);
            //Bottom
            vertices[20] = new Vector3(bounds.min.x, bounds.min.y, bounds.min.z);
            vertices[21] = new Vector3(bounds.min.x, bounds.min.y, bounds.max.z);
            vertices[22] = new Vector3(bounds.max.x, bounds.min.y, bounds.max.z);
            vertices[23] = new Vector3(bounds.max.x, bounds.min.y, bounds.min.z);

            // Add vertices to buffer
            for (int i = 0; i < 24; i++)
            {
                targetBuffer.Add(vertices[i]);
            }

            pools.PushVector3Array(vertices);
        }
Пример #13
0
        public TaskPool()
        {
            Pools = new LocalPools();

            m_items  = new List <ITaskPoolItem>();
            m_itemsP = new List <ITaskPoolItem>();

            m_itemsTmp  = new List <ITaskPoolItem>();
            m_itemsTmpP = new List <ITaskPoolItem>();

            m_event  = new AutoResetEvent(false);
            m_thread = new Thread(ThreadFunc)
            {
                IsBackground = true
            };

            m_stop             = false;
            m_hasPriorityItems = false;

            m_curr = m_max = m_currP = m_maxP = 0;
        }
Пример #14
0
    public override void BuildBlock(Chunk chunk, ref Vector3Int localPos, int materialID)
    {
        LocalPools            pools   = chunk.pools;
        RenderGeometryBatcher batcher = chunk.GeometryHandler.Batcher;

        // Using the block positions hash is much better for random numbers than saving the offset and height in the block data
        int hash = localPos.GetHashCode();

        float blockHeight = (hash & 63) * coef * Env.BlockSize;

        hash *= 39;
        float offsetX = (hash & 63) * coef * Env.BlockSizeHalf - Env.BlockSizeHalf * 0.5f;

        hash *= 39;
        float offsetZ = (hash & 63) * coef * Env.BlockSizeHalf - Env.BlockSizeHalf * 0.5f;

        // Converting the position to a vector adjusts it based on block size and gives us real world coordinates for x, y and z
        Vector3 vPos = localPos;

        vPos += new Vector3(offsetX, 0, offsetZ);

        float x1 = vPos.x - BlockUtils.blockPadding;
        float x2 = vPos.x + BlockUtils.blockPadding + Env.BlockSize;
        float y1 = vPos.y - BlockUtils.blockPadding;
        float y2 = vPos.y + BlockUtils.blockPadding + blockHeight;
        float z1 = vPos.z - BlockUtils.blockPadding;
        float z2 = vPos.z + BlockUtils.blockPadding + Env.BlockSize;

        var verts  = pools.Vector3ArrayPool.PopExact(4);
        var uvs    = pools.Vector2ArrayPool.PopExact(4);
        var colors = pools.Color32ArrayPool.PopExact(4);

        BlockUtils.PrepareTexture(chunk, ref localPos, uvs, Direction.north, texture, false);

        // TODO: How do I make sure that if I supply no color value, white is used?
        // TODO: These colors could be removed and memory would be saved
        {
            colors[0] = new Color32(255, 255, 255, 255);
            colors[1] = new Color32(255, 255, 255, 255);
            colors[2] = new Color32(255, 255, 255, 255);
            colors[3] = new Color32(255, 255, 255, 255);
        }

        {
            verts[0] = new Vector3(x1, y1, z2);
            verts[1] = new Vector3(x1, y2, z2);
            verts[2] = new Vector3(x2, y2, z1);
            verts[3] = new Vector3(x2, y1, z1);
            batcher.AddFace(materialID, verts, colors, uvs, false);
        }
        {
            verts[0] = new Vector3(x2, y1, z1);
            verts[1] = new Vector3(x2, y2, z1);
            verts[2] = new Vector3(x1, y2, z2);
            verts[3] = new Vector3(x1, y1, z2);
            batcher.AddFace(materialID, verts, colors, uvs, false);
        }
        {
            verts[0] = new Vector3(x2, y1, z2);
            verts[1] = new Vector3(x2, y2, z2);
            verts[2] = new Vector3(x1, y2, z1);
            verts[3] = new Vector3(x1, y1, z1);
            batcher.AddFace(materialID, verts, colors, uvs, false);
        }
        {
            verts[0] = new Vector3(x1, y1, z1);
            verts[1] = new Vector3(x1, y2, z1);
            verts[2] = new Vector3(x2, y2, z2);
            verts[3] = new Vector3(x2, y1, z2);
            batcher.AddFace(materialID, verts, colors, uvs, false);
        }

        pools.Color32ArrayPool.Push(colors);
        pools.Vector2ArrayPool.Push(uvs);
        pools.Vector3ArrayPool.Push(verts);
    }
Пример #15
0
        public void Build(RenderGeometryBatcher batcher, ref BlockData block, BlockFace face, bool backFace, ref Vector3[] vecs, LocalPools pools)
        {
            int iface = (int)face;

            // Randomize the color a bit
            Color32 color = BlockDatabase.GetBlockInfo(block.BlockType).Color;

            if (block.BlockType != BlockType.None)
            {
                float value = m_noise.GetValue(vecs[0] + vecs[1] + vecs[2] + vecs[3]); // -1.0f..1.0f
                float noise = (255.0f * value) * 0.02f;                                // Deviation of 0.02f points from the original
                int   n     = (int)noise;
                byte  r     = (byte)Math.Max(0, Math.Min(color.r + n, 255));
                byte  g     = (byte)Math.Max(0, Math.Min(color.g + n, 255));
                byte  b     = (byte)Math.Max(0, Math.Min(color.b + n, 255));
                color = new Color32(r, g, b, color.a);
            }

            VertexData[]      vertexData      = pools.PopVertexDataArray(4);
            VertexDataFixed[] vertexDataFixed = pools.PopVertexDataFixedArray(4);
            {
                for (int i = 0; i < 4; i++)
                {
                    vertexData[i] = pools.PopVertexData();
                }

                for (int i = 0; i < 4; i++)
                {
                    vertexData[i].Vertex = vecs[i];
                    vertexData[i].Color  = color;
                    vertexData[i].UV     = AddFaceUV(i, GetTexture(iface), backFace);
                    vertexData[i].Normal = SNormals[iface][i];
                }

                for (int i = 0; i < 4; i++)
                {
                    vertexDataFixed[i] = VertexDataUtils.ClassToStruct(vertexData[i]);
                }
                batcher.AddFace(vertexDataFixed, backFace);

                for (int i = 0; i < 4; i++)
                {
                    pools.PushVertexData(vertexData[i]);
                }
            }
            pools.PushVertexDataFixedArray(vertexDataFixed);
            pools.PushVertexDataArray(vertexData);
        }
Пример #16
0
        public bool DoDecompression()
        {
            LocalPools pools    = Chunk.pools;
            var        provider = Chunk.world.blockProvider;

            if (IsDifferential)
            {
                if (m_positionsBytes != null && m_blocksBytes != null)
                {
                    int blockPosSize  = StructSerialization.TSSize <BlockPos> .ValueSize;
                    int blockDataSize = StructSerialization.TSSize <BlockData> .ValueSize;

                    m_positionsModified = new BlockPos[m_positionsBytes.Length / blockPosSize];
                    m_blocksModified    = new BlockData[m_blocksBytes.Length / blockDataSize];

                    int i, j;
                    unsafe
                    {
                        // Extract positions
                        fixed(byte *pSrc = m_positionsBytes)
                        {
                            for (i = 0, j = 0; j < m_positionsModified.Length; i += blockPosSize, j++)
                            {
                                m_positionsModified[j] = *(BlockPos *)&pSrc[i];
                            }
                        }

                        // Extract block data
                        fixed(byte *pSrc = m_blocksBytes)
                        {
                            for (i = 0, j = 0; j < m_blocksModified.Length; i += blockDataSize, j++)
                            {
                                BlockData *bd = (BlockData *)&pSrc[i];
                                // Convert global block types into internal optimized version
                                ushort type = provider.GetTypeFromTypeInConfig(bd->Type);

                                m_blocksModified[j] = new BlockData(type, bd->Solid);
                            }
                        }
                    }
                }
            }
            else
            {
                m_positionsBytes = null;
                if (m_blocksBytes != null)
                {
                    int blockDataSize     = StructSerialization.TSSize <BlockData> .ValueSize;
                    int requestedByteSize = Env.ChunkSizePow3 * blockDataSize;

                    // Pop a large enough buffers from the pool
                    var bytes = pools.ByteArrayPool.Pop(requestedByteSize);
                    {
                        // Decompress data
                        int decompressedLength = CLZF2.lzf_decompress(m_blocksBytes, m_blocksBytes.Length, ref bytes);
                        if (decompressedLength != Env.ChunkSizePow3 * blockDataSize)
                        {
                            m_blocksBytes = null;
                            return(false);
                        }

                        // Fill chunk with decompressed data
                        ChunkBlocks blocks = Chunk.blocks;
                        int         i      = 0;
                        unsafe
                        {
                            fixed(byte *pSrc = bytes)
                            {
                                int index   = Helpers.ZeroChunkIndex;
                                int yOffset = Env.ChunkSizeWithPaddingPow2 - Env.ChunkSize * Env.ChunkSizeWithPadding;
                                int zOffset = Env.ChunkSizeWithPadding - Env.ChunkSize;

                                for (int y = 0; y < Env.ChunkSize; ++y, index += yOffset)
                                {
                                    for (int z = 0; z < Env.ChunkSize; ++z, index += zOffset)
                                    {
                                        for (int x = 0; x < Env.ChunkSize; ++x, i += blockDataSize, ++index)
                                        {
                                            BlockData *bd = (BlockData *)&pSrc[i];

                                            // Convert global block type into internal optimized version
                                            ushort type = provider.GetTypeFromTypeInConfig(bd->Type);

                                            blocks.SetRaw(index + x, new BlockData(type, bd->Solid));
                                        }
                                    }
                                }
                            }
                        }
                    }
                    // Return our temporary buffer back to the pool
                    pools.ByteArrayPool.Push(bytes);
                }
            }

            // We no longer need the temporary buffers
            m_positionsBytes = null;
            m_blocksBytes    = null;

            return(true);
        }
Пример #17
0
        public override void BuildMesh(
            Map map, DrawCallBatcher batcher, int offsetX, int offsetY, int offsetZ,
            int minX, int maxX, int minY, int maxY, int minZ, int maxZ, int lod,
            LocalPools pools
            )
        {
            BlockFace face = 0;

            int stepSize = 1 << lod;

            Assert.IsTrue(lod <= EngineSettings.ChunkConfig.LogSize); // LOD can't be bigger than chunk size
            int width = EngineSettings.ChunkConfig.Size >> lod;

            int[] mins  = { minX >> lod, minY >> lod, minZ >> lod };
            int[] maxes = { maxX >> lod, maxY >> lod, maxZ >> lod };

            int[] x  = { 0, 0, 0 };                                                    // Relative position of a block
            int[] xx = { 0, 0, 0 };                                                    // Relative position of a block after applying lod
            int[] q  = { 0, 0, 0 };                                                    // Direction in which we compare neighbors when building mask (q[d] is our current direction)
            int[] du = { 0, 0, 0 };                                                    // Width in a given dimension (du[u] is our current dimension)
            int[] dv = { 0, 0, 0 };                                                    // Height in a given dimension (dv[v] is our current dimension)
            int[] s  = { map.VoxelLogScaleX, map.VoxelLogScaleY, map.VoxelLogScaleZ }; // Scale in each dimension

            BlockData[] mask = pools.PopBlockDataArray(width * width);
            Vector3[]   vecs = pools.PopVector3Array(4);

            // Iterate over 3 dimensions. Once for front faces, once for back faces
            for (int dd = 0; dd < 2 * 3; dd++)
            {
                int d = dd % 3;
                int u = (d + 1) % 3;
                int v = (d + 2) % 3;

                x[0] = 0;
                x[1] = 0;
                x[2] = 0;

                q[0] = 0;
                q[1] = 0;
                q[2] = 0;
                q[d] = stepSize << s[d];

                // Determine which side we're meshing
                bool backFace = dd < 3;
                switch (dd)
                {
                case 0: face = BlockFace.Left; break;

                case 3: face = BlockFace.Right; break;

                case 1: face = BlockFace.Bottom; break;

                case 4: face = BlockFace.Top; break;

                case 2: face = BlockFace.Back; break;

                case 5: face = BlockFace.Front; break;
                }

                // Move through the dimension from front to back
                for (x[d] = mins[d] - 1; x[d] <= maxes[d];)
                {
                    // Compute the mask
                    int n = 0;

                    for (x[v] = 0; x[v] < mins[v]; x[v]++)
                    {
                        for (x[u] = 0; x[u] < width; x[u]++)
                        {
                            mask[n++] = BlockData.Air;
                        }
                    }

                    for (x[v] = mins[v]; x[v] <= maxes[v]; x[v]++)
                    {
                        for (x[u] = 0; x[u] < mins[u]; x[u]++)
                        {
                            mask[n++] = BlockData.Air;
                        }

                        for (x[u] = mins[u]; x[u] <= maxes[u]; x[u]++)
                        {
                            int realX = (x[0] << lod << s[0]) + offsetX;
                            int realY = (x[1] << lod << s[1]) + offsetY;
                            int realZ = (x[2] << lod << s[2]) + offsetZ;

                            BlockData voxelFace0 = map.GetBlock(realX, realY, realZ);
                            BlockData voxelFace1 = map.GetBlock(realX + q[0], realY + q[1], realZ + q[2]);

                            mask[n++] = (voxelFace0.IsSolid() && voxelFace1.IsSolid())
                                            ? BlockData.Air
                                            : (backFace ? voxelFace1 : voxelFace0);
                        }

                        for (x[u] = maxes[u] + 1; x[u] < width; x[u]++)
                        {
                            mask[n++] = BlockData.Air;
                        }
                    }

                    for (x[v] = maxes[v] + 1; x[v] < width; x[v]++)
                    {
                        for (x[u] = 0; x[u] < width; x[u]++)
                        {
                            mask[n++] = BlockData.Air;
                        }
                    }

                    x[d]++;
                    n = 0;

                    // Build faces from the mask if it's possible
                    int j;
                    for (j = 0; j < width; j++)
                    {
                        int i;
                        for (i = 0; i < width;)
                        {
                            if (mask[n].IsEmpty())
                            {
                                i++;
                                n++;
                                continue;
                            }

                            BlockType type = mask[n].BlockType;

                            // Compute width
                            int w;
                            for (w = 1; i + w < width && mask[n + w].BlockType == type; w++)
                            {
                            }

                            // Compute height
                            bool done = false;
                            int  k;
                            int  h;
                            for (h = 1; j + h < width; h++)
                            {
                                for (k = 0; k < w; k++)
                                {
                                    if (
                                        mask[n + k + h * width].IsEmpty() ||
                                        mask[n + k + h * width].BlockType != type
                                        )
                                    {
                                        done = true;
                                        break;
                                    }
                                }

                                if (done)
                                {
                                    break;
                                }
                            }

                            // Determine whether we really want to build this face
                            // TODO: Skip bottom faces at the bottom of the world
                            bool buildFace = true;
                            if (buildFace)
                            {
                                // Prepare face coordinates and dimensions
                                x[u] = i;
                                x[v] = j;

                                xx[0] = ((x[0] << lod) << s[0]) + offsetX;
                                xx[1] = ((x[1] << lod) << s[1]) + offsetY;
                                xx[2] = ((x[2] << lod) << s[2]) + offsetZ;

                                du[0] = du[1] = du[2] = 0;
                                dv[0] = dv[1] = dv[2] = 0;
                                du[u] = (w << lod) << s[u];
                                dv[v] = (h << lod) << s[v];

                                // Face vertices
                                Vector3Int v1 = new Vector3Int(
                                    xx[0], xx[1], xx[2]
                                    );
                                Vector3Int v2 = new Vector3Int(
                                    xx[0] + du[0], xx[1] + du[1], xx[2] + du[2]
                                    );
                                Vector3Int v3 = new Vector3Int(
                                    xx[0] + du[0] + dv[0], xx[1] + du[1] + dv[1], xx[2] + du[2] + dv[2]
                                    );
                                Vector3Int v4 = new Vector3Int(
                                    xx[0] + dv[0], xx[1] + dv[1], xx[2] + dv[2]
                                    );

                                // Face vertices transformed to world coordinates
                                // 0--1
                                // |  |
                                // |  |
                                // 3--2
                                vecs[0] = new Vector3(v4.X, v4.Y, v4.Z);
                                vecs[1] = new Vector3(v3.X, v3.Y, v3.Z);
                                vecs[2] = new Vector3(v2.X, v2.Y, v2.Z);
                                vecs[3] = new Vector3(v1.X, v1.Y, v1.Z);

                                // Build the face
                                IFaceBuilder builder = BlockDatabase.GetFaceBuilder(type);
                                builder.Build(batcher, ref mask[n], face, backFace, ref vecs, pools);
                            }

                            // Zero out the mask
                            int l;
                            for (l = 0; l < h; ++l)
                            {
                                for (k = 0; k < w; ++k)
                                {
                                    mask[n + k + l * width] = BlockData.Air;
                                }
                            }

                            i += w;
                            n += w;
                        }
                    }
                }
            }

            pools.PushBlockDataArray(mask);
            pools.PushVector3Array(vecs);
        }
Пример #18
0
        public void Build(Chunk chunk, int minX, int maxX, int minY, int maxY, int minZ, int maxZ)
        {
            WorldBlocks blocks = chunk.world.blocks;

            const int stepSize = 1;
            const int width    = Env.ChunkSize;

            int[] mins  = { minX, minY, minZ };
            int[] maxes = { maxX, maxY, maxZ };

            int[] x = { 0, 0, 0 }; // Relative position of a block
            int[] q = { 0, 0, 0 };
            // Direction in which we compare neighbors when building mask (q[d] is our current direction)
            int[] du = { 0, 0, 0 }; // Width in a given dimension (du[u] is our current dimension)
            int[] dv = { 0, 0, 0 }; // Height in a given dimension (dv[v] is our current dimension)

            bool[]    mask = chunk.pools.PopBoolArray(width * width);
            Vector3[] vecs = chunk.pools.PopVector3Array(4);

            // Iterate over 3 dimensions. Once for front faces, once for back faces
            for (int dd = 0; dd < 2 * 3; dd++)
            {
                int d = dd % 3;
                int u = (d + 1) % 3;
                int v = (d + 2) % 3;

                x[0] = 0;
                x[1] = 0;
                x[2] = 0;

                q[0] = 0;
                q[1] = 0;
                q[2] = 0;
                q[d] = stepSize;

                // Determine which side we're meshing
                Direction dir = Direction.west;
                switch (dd)
                {
                // Back faces
                //case 0: dir = Direction.west; break;
                case 1: dir = Direction.down; break;

                case 2: dir = Direction.south; break;

                // Front faces
                case 3: dir = Direction.east; break;

                case 4: dir = Direction.up; break;

                case 5: dir = Direction.north; break;
                }
                bool backFace = DirectionUtils.Backface(dir);

                // Move through the dimension from front to back
                for (x[d] = mins[d] - 1; x[d] <= maxes[d];)
                {
                    // Compute the mask
                    int n = 0;

                    for (x[v] = 0; x[v] < mins[v]; x[v]++)
                    {
                        for (x[u] = 0; x[u] < width; x[u]++)
                        {
                            mask[n++] = false;
                        }
                    }

                    for (x[v] = mins[v]; x[v] <= maxes[v]; x[v]++)
                    {
                        for (x[u] = 0; x[u] < mins[u]; x[u]++)
                        {
                            mask[n++] = false;
                        }

                        for (x[u] = mins[u]; x[u] <= maxes[u]; x[u]++)
                        {
                            int realX = chunk.pos.x + x[0];
                            int realY = chunk.pos.y + x[1];
                            int realZ = chunk.pos.z + x[2];

                            bool voxelFace0 = blocks.GetBlock(new Vector3Int(realX, realY, realZ)).canBeWalkedOn;
                            bool voxelFace1 = blocks.GetBlock(new Vector3Int(realX + q[0], realY + q[1], realZ + q[2])).canBeWalkedOn;

                            mask[n++] = (!voxelFace0 || !voxelFace1) && (backFace ? voxelFace1 : voxelFace0);
                        }

                        for (x[u] = maxes[u] + 1; x[u] < width; x[u]++)
                        {
                            mask[n++] = false;
                        }
                    }

                    for (x[v] = maxes[v] + 1; x[v] < width; x[v]++)
                    {
                        for (x[u] = 0; x[u] < width; x[u]++)
                        {
                            mask[n++] = false;
                        }
                    }

                    x[d]++;
                    n = 0;

                    // Build faces from the mask if it's possible
                    int j;
                    for (j = 0; j < width; j++)
                    {
                        int i;
                        for (i = 0; i < width;)
                        {
                            if (mask[n] == false)
                            {
                                i++;
                                n++;
                                continue;
                            }

                            bool type = mask[n];

                            // Compute width
                            int w;
                            for (w = 1; i + w < width && mask[n + w] == type; w++)
                            {
                            }

                            // Compute height
                            bool done = false;
                            int  k;
                            int  h;
                            for (h = 1; j + h < width; h++)
                            {
                                for (k = 0; k < w; k++)
                                {
                                    if (mask[n + k + h * width] == false ||
                                        mask[n + k + h * width] != type)
                                    {
                                        done = true;
                                        break;
                                    }
                                }

                                if (done)
                                {
                                    break;
                                }
                            }

                            // Determine whether we really want to build this face
                            // TODO: Skip bottom faces at the bottom of the world
                            const bool buildFace = true;
                            if (buildFace)
                            {
                                // Prepare face coordinates and dimensions
                                x[u] = i;
                                x[v] = j;

                                du[0] = du[1] = du[2] = 0;
                                dv[0] = dv[1] = dv[2] = 0;
                                du[u] = w;
                                dv[v] = h;

                                // Face vertices transformed to world coordinates
                                // 0--1
                                // |  |
                                // |  |
                                // 3--2
                                vecs[0] = new Vector3(x[0], x[1], x[2]) - BlockUtils.HalfBlockVector;
                                vecs[1] = new Vector3(x[0] + du[0], x[1] + du[1], x[2] + du[2]) - BlockUtils.HalfBlockVector;
                                vecs[2] = new Vector3(x[0] + du[0] + dv[0], x[1] + du[1] + dv[1], x[2] + du[2] + dv[2]) - BlockUtils.HalfBlockVector;
                                vecs[3] = new Vector3(x[0] + dv[0], x[1] + dv[1], x[2] + dv[2]) - BlockUtils.HalfBlockVector;

                                {
                                    LocalPools        pool            = chunk.pools;
                                    VertexData[]      vertexData      = pool.PopVertexDataArray(4);
                                    VertexDataFixed[] vertexDataFixed = pool.PopVertexDataFixedArray(4);
                                    {
                                        for (int ii = 0; ii < 4; ii++)
                                        {
                                            vertexData[ii]        = pool.PopVertexData();
                                            vertexData[ii].Vertex = vecs[ii];
                                            vertexDataFixed[ii]   = VertexDataUtils.ClassToStruct(vertexData[ii]);
                                        }

                                        chunk.ChunkColliderGeometryHandler.Batcher.AddFace(vertexDataFixed, backFace);

                                        for (int ii = 0; ii < 4; ii++)
                                        {
                                            pool.PushVertexData(vertexData[ii]);
                                        }
                                    }
                                    pool.PushVertexDataFixedArray(vertexDataFixed);
                                    pool.PushVertexDataArray(vertexData);
                                }
                            }

                            // Zero out the mask
                            int l;
                            for (l = 0; l < h; ++l)
                            {
                                for (k = 0; k < w; ++k)
                                {
                                    mask[n + k + l * width] = false;
                                }
                            }

                            i += w;
                            n += w;
                        }
                    }
                }
            }

            chunk.pools.PushBoolArray(mask);
            chunk.pools.PushVector3Array(vecs);
        }
Пример #19
0
        public static void GenerateTangents(this RenderBuffer buffer, LocalPools pools)
        {
            var vertices  = buffer.Vertices;
            var triangles = buffer.Triangles;

            var tan1 = pools.PopVector3Array(vertices.Count);
            var tan2 = pools.PopVector3Array(vertices.Count);

            for (int t = 0; t < triangles.Count; t += 3)
            {
                int i1 = triangles[t + 0];
                int i2 = triangles[t + 1];
                int i3 = triangles[t + 2];

                VertexData vd1 = vertices[i1];
                VertexData vd2 = vertices[i2];
                VertexData vd3 = vertices[i3];

                Vector3 v1 = vd1.Vertex;
                Vector3 v2 = vd2.Vertex;
                Vector3 v3 = vd3.Vertex;

                Vector2 w1 = vd1.UV;
                Vector2 w2 = vd2.UV;
                Vector2 w3 = vd3.UV;

                float x1 = v2.x - v1.x;
                float y1 = v2.y - v1.y;
                float z1 = v2.z - v1.z;

                float x2 = v3.x - v1.x;
                float y2 = v3.y - v1.y;
                float z2 = v3.z - v1.z;

                float s1 = w2.x - w1.x;
                float s2 = w3.x - w1.x;

                float t1 = w2.y - w1.y;
                float t2 = w3.y - w1.y;

                // Avoid division by zero
                float div = s1 * t2 - s2 * t1;
                float r   = (Mathf.Abs(div) > Mathf.Epsilon) ? (1f / div) : 0f;

                Vector3 sdir = new Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r);
                Vector3 tdir = new Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r);

                tan1[i1] += sdir;
                tan1[i2] += sdir;
                tan1[i3] += sdir;

                tan2[i1] += tdir;
                tan2[i2] += tdir;
                tan2[i3] += tdir;
            }

            for (int v = 0; v < vertices.Count; ++v)
            {
                VertexData vd = vertices[v];

                Vector3 n = vd.Normal;
                Vector3 t = tan1[v];

                //Vector3 tmp = (t - n*Vector3.Dot(n, t)).normalized;
                //tangents[v] = new Vector4(tmp.x, tmp.y, tmp.z);
                Vector3.OrthoNormalize(ref n, ref t);

                vd.Tangent = new Vector4(
                    t.x, t.y, t.z,
                    (Vector3.Dot(Vector3.Cross(n, t), tan2[v]) < 0.0f) ? -1.0f : 1.0f
                    );

                tan1[v] = Vector3.zero;
                tan2[v] = Vector3.zero;
            }

            pools.PushVector3Array(tan1);
            pools.PushVector3Array(tan2);
        }
Пример #20
0
        public bool DoCompression()
        {
            if (Features.UseDifferentialSerialization)
            {
                if (m_blocksModified != null)
                {
                    var provider      = Chunk.world.blockProvider;
                    int blockPosSize  = StructSerialization.TSSize <BlockPos> .ValueSize;
                    int blockDataSize = StructSerialization.TSSize <BlockData> .ValueSize;

                    int posLenBytes = m_blocksModified.Length * blockPosSize;
                    int blkLenBytes = m_blocksModified.Length * blockDataSize;
                    m_positionsBytes = new byte[posLenBytes];
                    m_blocksBytes    = new byte[blkLenBytes];

                    unsafe
                    {
                        // Pack positions to a byte array
                        fixed(byte *pDst = m_positionsBytes)
                        {
                            for (int i = 0, j = 0; i < m_blocksModified.Length; i++, j += blockPosSize)
                            {
                                *(BlockPos *)&pDst[j] = m_positionsModified[i];
                            }
                        }

                        // Pack block data to a byte array
                        fixed(BlockData *pBD = m_blocksModified)
                        fixed(byte *pDst = m_blocksBytes)
                        {
                            for (int i = 0, j = 0; i < m_blocksModified.Length; i++, j += blockDataSize)
                            {
                                BlockData *bd = &pBD[i];
                                // Convert block types from internal optimized version into global types
                                ushort typeInConfig = provider.GetConfig(bd->Type).typeInConfig;

                                *(BlockData *)&pDst[j] = new BlockData(typeInConfig, bd->Solid);
                            }
                        }
                    }
                }
                else
                {
                    m_positionsBytes = null;
                    m_blocksBytes    = null;
                }
            }
            else
            {
                LocalPools pools    = Chunk.pools;
                var        provider = Chunk.world.blockProvider;

                int blockDataSize     = StructSerialization.TSSize <BlockData> .ValueSize;
                int requestedByteSize = Env.ChunkSizePow3 * blockDataSize;

                // Pop large enough buffers from the pool
                byte[] tmp             = pools.ByteArrayPool.Pop(requestedByteSize);
                byte[] bytesCompressed = pools.ByteArrayPool.Pop(requestedByteSize);
                {
                    ChunkBlocks blocks = Chunk.blocks;
                    int         i      = 0;

                    int index   = Helpers.ZeroChunkIndex;
                    int yOffset = Env.ChunkSizeWithPaddingPow2 - Env.ChunkSize * Env.ChunkSizeWithPadding;
                    int zOffset = Env.ChunkSizeWithPadding - Env.ChunkSize;

                    for (int y = 0; y < Env.ChunkSize; ++y, index += yOffset)
                    {
                        for (int z = 0; z < Env.ChunkSize; ++z, index += zOffset)
                        {
                            for (int x = 0; x < Env.ChunkSize; ++x, i += blockDataSize, ++index)
                            {
                                // Convert block types from internal optimized version into global types
                                BlockData bd           = blocks.Get(index + x);
                                ushort    typeInConfig = provider.GetConfig(bd.Type).typeInConfig;

                                // Write updated block data to destination buffer
                                unsafe
                                {
                                    fixed(byte *pDst = tmp)
                                    {
                                        *(BlockData *)&pDst[i] = new BlockData(typeInConfig, bd.Solid);
                                    }
                                }
                            }
                        }
                    }

                    // Compress bytes
                    int blkLenBytes = CLZF2.lzf_compress(tmp, requestedByteSize, ref bytesCompressed);
                    m_blocksBytes = new byte[blkLenBytes];

                    // Copy data from a temporary buffer to block buffer
                    Array.Copy(bytesCompressed, 0, m_blocksBytes, 0, blkLenBytes);
                }
                // Return our temporary buffer back to the pool
                pools.ByteArrayPool.Push(bytesCompressed);
                pools.ByteArrayPool.Push(tmp);
            }

            return(true);
        }