Exemple #1
0
        /// <summary>
        /// Decompresses chunk's memory.
        /// </summary>
        public void Decompress()
        {
            int sizeWithPadding     = sideSize + Env.CHUNK_PADDING_2;
            int sizeWithPaddingPow2 = sizeWithPadding * sizeWithPadding;

            for (int i = 0; i < blockCompressed.Count; i++)
            {
                BlockDataAABB box  = blockCompressed[i];
                int           x1   = box.MinX;
                int           y1   = box.MinY;
                int           z1   = box.MinZ;
                int           x2   = box.MaxX;
                int           y2   = box.MaxY;
                int           z2   = box.MaxZ;
                ushort        data = box.Data;

                int index   = Helpers.GetChunkIndex1DFrom3D(x1, y1, z1, pow);
                int yOffset = sizeWithPaddingPow2 - (z2 - z1) * sizeWithPadding;
                int zOffset = sizeWithPadding - (x2 - x1);
                for (int y = y1; y < y2; ++y, index += yOffset)
                {
                    for (int z = z1; z < z2; ++z, index += zOffset)
                    {
                        for (int x = x1; x < x2; ++x, ++index)
                        {
                            this[index] = new BlockData(data);
                        }
                    }
                }
            }
        }
Exemple #2
0
        private bool ExpandX(ref bool[] mask, ushort type, int y1, int z1, ref int x2, int y2, int z2)
        {
            int sizeWithPadding     = sideSize + Env.CHUNK_PADDING_2;
            int sizeWithPaddingPow2 = sizeWithPadding * sizeWithPadding;

            int yOffset = sizeWithPaddingPow2 - (z2 - z1) * sizeWithPadding;
            int index0  = Helpers.GetChunkIndex1DFrom3D(x2, y1, z1, pow);

            // Check the quad formed by YZ axes and try to expand the X asix
            int index = index0;

            for (int y = y1; y < y2; ++y, index += yOffset)
            {
                for (int z = z1; z < z2; ++z, index += sizeWithPadding)
                {
                    if (mask[index] || this[index].Type != type)
                    {
                        return(false);
                    }
                }
            }

            // If the box can expand, mark the position as tested and expand the X axis
            index = index0;
            for (int y = y1; y < y2; ++y, index += yOffset)
            {
                for (int z = z1; z < z2; ++z, index += sizeWithPadding)
                {
                    mask[index] = true;
                }
            }

            ++x2;
            return(true);
        }
        private bool ExpandZ(ChunkBlocks blocks, ref bool[] mask, Block block, int x1, int y1, int x2, int y2, ref int z2)
        {
            int sizeWithPadding     = sideSize + Env.CHUNK_PADDING_2;
            int sizeWithPaddingPow2 = sizeWithPadding * sizeWithPadding;

            int yOffset = sizeWithPaddingPow2 - x2 + x1;
            int index0  = Helpers.GetChunkIndex1DFrom3D(x1, y1, z2, pow);

            // Check the quad formed by XY axes and try to expand the Z axis
            int index = index0;

            for (int y = y1; y < y2; ++y, index += yOffset)
            {
                for (int x = x1; x < x2; ++x, ++index)
                {
                    if (mask[index] || !CanCreateBox(block, blocks.GetBlock(index)))
                    {
                        return(false);
                    }
                }
            }

            // If the box can expand, mark the position as tested and expand the X axis
            index = index0;
            for (int y = y1; y < y2; ++y, index += yOffset)
            {
                for (int x = x1; x < x2; ++x, ++index)
                {
                    mask[index] = true;
                }
            }

            ++z2;
            return(true);
        }
Exemple #4
0
        private bool ExpandY(ref bool[] mask, ushort type, int x1, int z1, int x2, ref int y2, int z2)
        {
            int sizeWithPadding = sideSize + Env.CHUNK_PADDING_2;

            int zOffset = sizeWithPadding - x2 + x1;
            int index0  = Helpers.GetChunkIndex1DFrom3D(x1, y2, z1, pow);

            // Check the quad formed by XZ axes and try to expand the Y axis
            int index = index0;

            for (int z = z1; z < z2; ++z, index += zOffset)
            {
                for (int x = x1; x < x2; ++x, ++index)
                {
                    if (mask[index] || this[index].Type != type)
                    {
                        return(false);
                    }
                }
            }

            // If the box can expand, mark the position as tested and expand the X axis
            index = index0;
            for (int z = z1; z < z2; ++z, index += zOffset)
            {
                for (int x = x1; x < x2; ++x, ++index)
                {
                    mask[index] = true;
                }
            }

            ++y2;
            return(true);
        }
Exemple #5
0
        /// <summary>
        /// Queues a modification of blocks in a given range
        /// </summary>
        /// <param name="posFrom">Starting positon in local chunk coordinates</param>
        /// <param name="posTo">Ending position in local chunk coordinates</param>
        /// <param name="blockData">BlockData to place at the given location</param>
        /// <param name="setBlockModified">Set to true to mark chunk data as modified</param>
        /// <param name="onModified">Action to perform once the operation finished</param>
        public void ModifyBlockDataRanged(ref Vector3Int posFrom, ref Vector3Int posTo, BlockData blockData, bool setBlockModified,
                                          Action <ModifyBlockContext> onModified = null)
        {
            // Make sure the values are okay.
            FixValues(ref posFrom.x, ref posTo.x);
            FixValues(ref posFrom.y, ref posTo.y);
            FixValues(ref posFrom.z, ref posTo.z);

            Vector3Int chunkPosFrom = Helpers.ContainingChunkPos(ref posFrom);
            Vector3Int chunkPosTo   = Helpers.ContainingChunkPos(ref posTo);

            ModifyBlockContext context = null;

            if (onModified != null)
            {
                context = new ModifyBlockContext(onModified, this,
                                                 Helpers.GetChunkIndex1DFrom3D(posFrom.x, posFrom.y, posFrom.z),
                                                 Helpers.GetChunkIndex1DFrom3D(posTo.x, posTo.y, posTo.z),
                                                 blockData, setBlockModified);
            }

            // Update all chunks in range
            int minY = Helpers.Mod(posFrom.y, Env.CHUNK_SIZE);

            for (int cy = chunkPosFrom.y; cy <= chunkPosTo.y; cy += Env.CHUNK_SIZE, minY = 0)
            {
                int maxY = Math.Min(posTo.y - cy, Env.CHUNK_SIZE_1);
                int minZ = Helpers.Mod(posFrom.z, Env.CHUNK_SIZE);

                for (int cz = chunkPosFrom.z; cz <= chunkPosTo.z; cz += Env.CHUNK_SIZE, minZ = 0)
                {
                    int maxZ = Math.Min(posTo.z - cz, Env.CHUNK_SIZE_1);
                    int minX = Helpers.Mod(posFrom.x, Env.CHUNK_SIZE);

                    for (int cx = chunkPosFrom.x; cx <= chunkPosTo.x; cx += Env.CHUNK_SIZE, minX = 0)
                    {
                        Vector3Int chunkPos = new Vector3Int(cx, cy, cz);
                        Chunk      chunk    = GetChunk(ref chunkPos);
                        if (chunk == null)
                        {
                            continue;
                        }

                        int maxX = Math.Min(posTo.x - cx, Env.CHUNK_SIZE_1);

                        chunk.Modify(
                            new ModifyOpCuboid(
                                blockData,
                                new Vector3Int(minX, minY, minZ),
                                new Vector3Int(maxX, maxY, maxZ),
                                setBlockModified,
                                context)
                            );
                    }
                }
            }
        }
Exemple #6
0
        public bool ConsumeChanges()
        {
            ChunkBlocks blocks = Chunk.Blocks;

            if (!Features.useDifferentialSerialization)
            {
                return(true);
            }

            if (Features.useDifferentialSerialization_ForceSaveHeaders)
            {
                if (blocks.modifiedBlocks.Count <= 0)
                {
                    return(true);
                }
            }
            else
            {
                if (blocks.modifiedBlocks.Count <= 0)
                {
                    return(false);
                }
            }

            Dictionary <BlockPos, BlockData> blocksDictionary = new Dictionary <BlockPos, BlockData>();

            // Create a map of modified blocks and their positions
            // TODO: Depending on the amount of changes this could become a performance bottleneck
            for (int i = 0; i < blocks.modifiedBlocks.Count; i++)
            {
                BlockPos pos = blocks.modifiedBlocks[i];
                // Remove any existing blocks in the dictionary. They come from the existing save and are overwritten
                blocksDictionary.Remove(pos);
                blocksDictionary.Add(pos, blocks.Get(Helpers.GetChunkIndex1DFrom3D(pos.x, pos.y, pos.z)));
            }

            int cnt = blocksDictionary.Keys.Count;

            if (cnt > 0)
            {
                blocksModified    = new BlockData[cnt];
                positionsModified = new BlockPos[cnt];

                int index = 0;
                foreach (KeyValuePair <BlockPos, BlockData> pair in blocksDictionary)
                {
                    blocksModified[index]    = pair.Value;
                    positionsModified[index] = pair.Key;
                    ++index;
                }
            }

            return(true);
        }
Exemple #7
0
        /// <summary>
        /// Fills chunk with layer data starting at startPlaceHeight and ending at endPlaceHeight
        /// </summary>
        /// <param name="chunk">Chunk filled with data</param>
        /// <param name="x">Position on x axis in local coordinates</param>
        /// <param name="z">Position on z axis in local coordinates</param>
        /// <param name="startPlaceHeight">Starting position on y axis in world coordinates</param>
        /// <param name="endPlaceHeight">Ending position on y axis in world coordinates</param>
        /// <param name="blockData">Block data to set</param>
        protected static void SetBlocks(Chunk chunk, int x, int z, int startPlaceHeight, int endPlaceHeight, BlockData blockData)
        {
            int chunkY    = chunk.Pos.y;
            int chunkYMax = chunkY + Env.CHUNK_SIZE;

            int y    = startPlaceHeight > chunkY ? startPlaceHeight : chunkY;
            int yMax = endPlaceHeight < chunkYMax ? endPlaceHeight : chunkYMax;

            ChunkBlocks blocks = chunk.Blocks;
            int         index  = Helpers.GetChunkIndex1DFrom3D(x, y - chunkY, z);

            while (y++ < yMax)
            {
                blocks.SetRaw(index, blockData);
                index += Env.CHUNK_SIZE_WITH_PADDING_POW_2;
            }
        }
Exemple #8
0
        /// <summary>
        /// Sets the block data at given world coordinates
        /// </summary>
        /// <param name="pos">Global position of the block</param>
        /// <param name="blockData">A block to be placed on a given position</param>
        public void SetBlockData(ref Vector3Int pos, BlockData blockData)
        {
            // Transform the position into chunk coordinates
            Vector3Int chunkPos = Helpers.ContainingChunkPos(ref pos);

            Chunk chunk = GetChunk(ref chunkPos);

            if (chunk == null)
            {
                return;
            }

            int xx = Helpers.Mod(pos.x, Env.CHUNK_SIZE);
            int yy = Helpers.Mod(pos.y, Env.CHUNK_SIZE);
            int zz = Helpers.Mod(pos.z, Env.CHUNK_SIZE);

            chunk.Blocks.SetInner(Helpers.GetChunkIndex1DFrom3D(xx, yy, zz), blockData);
        }
Exemple #9
0
        public BlockData GetBlockData(Vector3Int pos)
        {
            // Transform the position into chunk coordinates
            Vector3Int chunkPos = Helpers.ContainingChunkPos(ref pos);

            Chunk chunk = GetChunk(ref chunkPos);

            if (chunk == null)
            {
                // Return air if the chunk that do not exist
                return(BlockProvider.airBlock);
            }

            int xx = Helpers.Mod(pos.x, Env.CHUNK_SIZE);
            int yy = Helpers.Mod(pos.y, Env.CHUNK_SIZE);
            int zz = Helpers.Mod(pos.z, Env.CHUNK_SIZE);

            return(chunk.Blocks.Get(Helpers.GetChunkIndex1DFrom3D(xx, yy, zz)));
        }
Exemple #10
0
        public void CommitChanges()
        {
            if (!IsDifferential)
            {
                return;
            }

            // Rewrite generated blocks with differential positions
            if (blocksModified != null)
            {
                for (int i = 0; i < blocksModified.Length; i++)
                {
                    BlockPos pos = positionsModified[i];
                    Chunk.Blocks.SetRaw(Helpers.GetChunkIndex1DFrom3D(pos.x, pos.y, pos.z), blocksModified[i]);
                }
            }

            MarkAsProcessed();
        }
Exemple #11
0
        /// <summary>
        /// Sets blocks to a given value in a given range. It does not perform any logic. It simply sets the blocks.
        /// Use this function only when generating the terrain and structures.
        /// </summary>
        /// <param name="posFrom">Starting position in local chunk coordinates</param>
        /// <param name="posTo">Ending position in local chunk coordinates</param>
        /// <param name="blockData">A block to be placed on a given position</param>
        public void SetRangeRaw(ref Vector3Int posFrom, ref Vector3Int posTo, BlockData blockData)
        {
            int sizeWithPadding     = sideSize + Env.CHUNK_PADDING_2;
            int sizeWithPaddingPow2 = sizeWithPadding * sizeWithPadding;

            int index   = Helpers.GetChunkIndex1DFrom3D(posFrom.x, posFrom.y, posFrom.z, pow);
            int yOffset = sizeWithPaddingPow2 - (posTo.z - posFrom.z + 1) * sizeWithPadding;
            int zOffset = sizeWithPadding - (posTo.x - posFrom.x + 1);

            for (int y = posFrom.y; y <= posTo.y; ++y, index += yOffset)
            {
                for (int z = posFrom.z; z <= posTo.z; ++z, index += zOffset)
                {
                    for (int x = posFrom.x; x <= posTo.x; ++x, ++index)
                    {
                        SetRaw(index, blockData);
                    }
                }
            }
        }
Exemple #12
0
        /// <summary>
        /// Sets the block data at given world coordinates, updates the chunk and its
        /// neighbors if the Update chunk flag is true or not set.
        /// </summary>
        /// <param name="pos">Global position of the block</param>
        /// <param name="blockData">The block be placed</param>
        /// <param name="setBlockModified">Set to true to mark chunk data as modified</param>
        /// <param name="onModified">Action to perform once the operation finished</param>
        public void ModifyBlockData(ref Vector3Int pos, BlockData blockData, bool setBlockModified,
                                    Action <ModifyBlockContext> onModified = null)
        {
            // Transform the position into chunk coordinates
            Vector3Int chunkPos = Helpers.ContainingChunkPos(ref pos);

            Chunk chunk = GetChunk(ref chunkPos);

            if (chunk == null)
            {
                return;
            }

            int index = Helpers.GetChunkIndex1DFrom3D(
                Helpers.Mod(pos.x, Env.CHUNK_SIZE),
                Helpers.Mod(pos.y, Env.CHUNK_SIZE),
                Helpers.Mod(pos.z, Env.CHUNK_SIZE)
                );

            // Nothing for us to do if the block did not change
            BlockData oldBlockData = chunk.Blocks.Get(index);

            if (oldBlockData.Type == blockData.Type)
            {
                return;
            }

            ModifyBlockContext context = null;

            if (onModified != null)
            {
                context = new ModifyBlockContext(onModified, this, index, index, blockData, setBlockModified);
            }

            chunk.Modify(new ModifyOpBlock(blockData, index, setBlockModified, context));
        }
Exemple #13
0
        public Rect GetTexture(Chunk chunk, ref Vector3Int localPos, Direction direction)
        {
            if (uvs.Count == 1)
            {
                return(uvs[0]);
            }

            if (textureType == TextureConfigType.Connected)
            {
                ChunkBlocks blocks        = chunk.Blocks;
                int         localPosIndex = Helpers.GetChunkIndex1DFrom3D(localPos.x, localPos.y, localPos.z);
                ushort      blockType     = blocks.Get(localPosIndex).Type;

                // Side blocks
                bool n_, _e, s_, _w;
                // Corner blocks
                bool nw, ne, se, sw;

                int index1, index2, index3;
                int sizeWithPadding     = chunk.SideSize + Env.CHUNK_PADDING_2;
                int sizeWithPaddingPow2 = sizeWithPadding * sizeWithPadding;

                switch (direction)
                {
                case Direction.up:
                    index1 = localPosIndex + sizeWithPaddingPow2;       // + (0,1,0)
                    index2 = index1 - sizeWithPadding;                  // - (0,0,1)
                    index3 = index1 + sizeWithPadding;                  // + (0,0,1)

                    sw = blocks.Get(index2 - 1).Type == blockType;      // -1,1,-1
                    s_ = blocks.Get(index2).Type == blockType;          //  0,1,-1
                    se = blocks.Get(index2 + 1).Type == blockType;      //  1,1,-1
                    _w = blocks.Get(index1 - 1).Type == blockType;      // -1,1, 0
                    _e = blocks.Get(index1 + 1).Type == blockType;      //  1,1, 0
                    nw = blocks.Get(index3 - 1).Type == blockType;      // -1,1, 1
                    n_ = blocks.Get(index3).Type == blockType;          //  0,1, 1
                    ne = blocks.Get(index3 + 1).Type == blockType;      //  1,1, 1
                    break;

                case Direction.down:
                    index1 = localPosIndex - sizeWithPaddingPow2;      // - (0,1,0)
                    index2 = index1 - sizeWithPadding;                 // - (0,0,1)
                    index3 = index1 + sizeWithPadding;                 // + (0,0,1)

                    sw = blocks.Get(index2 - 1).Type == blockType;     // -1,-1,-1
                    s_ = blocks.Get(index2).Type == blockType;         //  0,-1,-1
                    se = blocks.Get(index2 + 1).Type == blockType;     //  1,-1,-1
                    _w = blocks.Get(index1 - 1).Type == blockType;     // -1,-1, 0
                    _e = blocks.Get(index1 + 1).Type == blockType;     //  1,-1, 0
                    nw = blocks.Get(index3 - 1).Type == blockType;     // -1,-1, 1
                    n_ = blocks.Get(index3).Type == blockType;         //  0,-1, 1
                    ne = blocks.Get(index3 + 1).Type == blockType;     //  1,-1, 1
                    break;

                case Direction.north:
                    index1 = localPosIndex + sizeWithPadding;       // + (0,0,1)
                    index2 = index1 - sizeWithPaddingPow2;          // - (0,1,0)
                    index3 = index1 + sizeWithPaddingPow2;          // + (0,1,0)

                    sw = blocks.Get(index2 - 1).Type == blockType;  // -1,-1,1
                    se = blocks.Get(index2 + 1).Type == blockType;  //  1,-1,1
                    _w = blocks.Get(index1 - 1).Type == blockType;  // -1, 0,1
                    _e = blocks.Get(index1 + 1).Type == blockType;  //  1, 0,1
                    nw = blocks.Get(index3 - 1).Type == blockType;  // -1, 1,1
                    s_ = blocks.Get(index2).Type == blockType;      //  0,-1,1
                    n_ = blocks.Get(index3).Type == blockType;      //  0, 1,1
                    ne = blocks.Get(index3 + 1).Type == blockType;  //  1, 1,1
                    break;

                case Direction.south:
                    index1 = localPosIndex - sizeWithPadding;       // - (0,0,1)
                    index2 = index1 - sizeWithPaddingPow2;          // - (0,1,0)
                    index3 = index1 + sizeWithPaddingPow2;          // + (0,1,0)

                    sw = blocks.Get(index2 - 1).Type == blockType;  // -1,-1,-1
                    se = blocks.Get(index2 + 1).Type == blockType;  //  1,-1,-1
                    _w = blocks.Get(index1 - 1).Type == blockType;  // -1, 0,-1
                    _e = blocks.Get(index1 + 1).Type == blockType;  //  1, 0,-1
                    nw = blocks.Get(index3 - 1).Type == blockType;  // -1, 1,-1
                    s_ = blocks.Get(index2).Type == blockType;      //  0,-1,-1
                    n_ = blocks.Get(index3).Type == blockType;      //  0, 1,-1
                    ne = blocks.Get(index3 + 1).Type == blockType;  //  1, 1,-1
                    break;

                case Direction.east:
                    index1 = localPosIndex + 1;                                  // + (1,0,0)
                    index2 = index1 - sizeWithPaddingPow2;                       // - (0,1,0)
                    index3 = index1 + sizeWithPaddingPow2;                       // + (0,1,0)

                    sw = blocks.Get(index2 - sizeWithPadding).Type == blockType; // 1,-1,-1
                    s_ = blocks.Get(index2).Type == blockType;                   // 1,-1, 0
                    se = blocks.Get(index2 + sizeWithPadding).Type == blockType; // 1,-1, 1
                    _w = blocks.Get(index1 - sizeWithPadding).Type == blockType; // 1, 0,-1
                    _e = blocks.Get(index1 + sizeWithPadding).Type == blockType; // 1, 0, 1
                    nw = blocks.Get(index3 - sizeWithPadding).Type == blockType; // 1, 1,-1
                    n_ = blocks.Get(index3).Type == blockType;                   // 1, 1, 0
                    ne = blocks.Get(index3 + sizeWithPadding).Type == blockType; // 1, 1, 1
                    break;

                default:                                                         //case Direction.west:
                    index1 = localPosIndex - 1;                                  // - (1,0,0)
                    index2 = index1 - sizeWithPaddingPow2;                       // - (0,1,0)
                    index3 = index1 + sizeWithPaddingPow2;                       // + (0,1,0)

                    sw = blocks.Get(index2 - sizeWithPadding).Type == blockType; // -1,-1,-1
                    s_ = blocks.Get(index2).Type == blockType;                   // -1,-1, 0
                    se = blocks.Get(index2 + sizeWithPadding).Type == blockType; // -1,-1, 1
                    _w = blocks.Get(index1 - sizeWithPadding).Type == blockType; // -1, 0,-1
                    _e = blocks.Get(index1 + sizeWithPadding).Type == blockType; // -1, 0, 1
                    nw = blocks.Get(index3 - sizeWithPadding).Type == blockType; // -1, 1,-1
                    n_ = blocks.Get(index3).Type == blockType;                   // -1, 1, 0
                    ne = blocks.Get(index3 + sizeWithPadding).Type == blockType; // -1, 1, 1
                    break;
                }

                int uvIndex = ConnectedTextures.GetTexture(n_, _e, s_, _w, nw, ne, se, sw);
                return(uvs[uvIndex]);
            }

            if (uvs.Count > 1)
            {
                int hash = localPos.GetHashCode();
                if (hash < 0)
                {
                    hash *= -1;
                }

                float randomNumber = (hash % 100) / 100f;
                randomNumber *= uvs.Count;

                return(uvs[(int)randomNumber]);
            }

            Debug.LogError("There were no textures for " + textureName);
            return(new Rect());
        }
        protected override void BuildBox(Chunk chunk, Block block, int minX, int minY, int minZ, int maxX, int maxY, int maxZ)
        {
            // Order of vertices when building faces:
            //     1--2
            //     |  |
            //     |  |
            //     0--3

            int sizeWithPadding     = sideSize + Env.CHUNK_PADDING_2;
            int sizeWithPaddingPow2 = sizeWithPadding * sizeWithPadding;

            LocalPools  pools  = Globals.WorkPool.GetPool(chunk.ThreadID);
            ChunkBlocks blocks = chunk.Blocks;

            Chunk[] listeners = chunk.Neighbors;

            // Custom blocks have their own rules
            if (block.custom)
            {
                for (int yy = minY; yy < maxY; yy++)
                {
                    for (int zz = minZ; zz < maxZ; zz++)
                    {
                        for (int xx = minX; xx < maxX; xx++)
                        {
                            Vector3Int pos = new Vector3Int(xx, yy, zz);
                            block.BuildBlock(chunk, ref pos, block.renderMaterialID);
                        }
                    }
                }

                return;
            }

            int        n, w, h, l, k, maskIndex;
            Vector3Int texturePos = new Vector3Int(minX, minY, minZ);

            Vector3[]   face = pools.vector3ArrayPool.PopExact(4);
            BlockFace[] mask = pools.blockFaceArrayPool.PopExact(sideSize * sideSize);

            #region Top face

            if (listeners[(int)Direction.up] != null ||
                // Don't render faces on world's edges for chunks with no neighbor
                (SideMask & Side.up) == 0 ||
                maxY != sideSize)
            {
                Array.Clear(mask, 0, mask.Length);

                // x axis - width
                // z axis - height

                int neighborIndex = Helpers.GetChunkIndex1DFrom3D(minX, maxY, minZ, pow);
                int zOffset       = sizeWithPadding - maxX + minX;

                // Build the mask
                for (int zz = minZ; zz < maxZ; ++zz, neighborIndex += zOffset)
                {
                    n = minX + zz * sideSize;
                    for (int xx = minX; xx < maxX; ++xx, ++n, ++neighborIndex)
                    {
                        int   currentIndex  = neighborIndex - sizeWithPaddingPow2; // (xx, maxY-1, zz);
                        Block neighborBlock = blocks.GetBlock(neighborIndex);

                        // Let's see whether we can merge faces
                        if (block.CanBuildFaceWith(neighborBlock))
                        {
                            mask[n] = new BlockFace
                            {
                                block      = block,
                                pos        = texturePos,
                                side       = Direction.up,
                                light      = BlockUtils.CalculateColors(chunk, currentIndex, Direction.up),
                                materialID = block.renderMaterialID
                            };
                        }
                    }
                }

                // Build faces from the mask if it's possible
                for (int zz = minZ; zz < maxZ; ++zz)
                {
                    n = minX + zz * sideSize;
                    for (int xx = minX; xx < maxX;)
                    {
                        if (mask[n].block == null)
                        {
                            ++xx;
                            ++n;
                            continue;
                        }

                        // Compute width and height
                        w = 1;
                        h = 1;

                        // Build the face
                        bool rotated = mask[n].light.FaceRotationNecessary;
                        if (!rotated)
                        {
                            face[0] = new Vector3(xx, maxY, zz) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.up][0];
                            face[1] = new Vector3(xx, maxY, zz + h) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.up][1];
                            face[2] = new Vector3(xx + w, maxY, zz + h) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.up][2];
                            face[3] = new Vector3(xx + w, maxY, zz) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.up][3];
                        }
                        else
                        {
                            face[0] = new Vector3(xx, maxY, zz + h) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.up][1];
                            face[1] = new Vector3(xx + w, maxY, zz + h) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.up][2];
                            face[2] = new Vector3(xx + w, maxY, zz) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.up][3];
                            face[3] = new Vector3(xx, maxY, zz) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.up][0];
                        }

                        block.BuildFace(chunk, face, Palette, ref mask[n], rotated);

                        // Zero out the mask. We don't need to process the same fields again
                        for (l = 0; l < h; ++l)
                        {
                            maskIndex = n + l * sideSize;
                            for (k = 0; k < w; ++k, ++maskIndex)
                            {
                                mask[maskIndex] = new BlockFace();
                            }
                        }

                        xx += w;
                        n  += w;
                    }
                }
            }

            #endregion

            #region Bottom face

            if (listeners[(int)Direction.down] != null ||
                // Don't render faces on world's edges for chunks with no neighbor
                (SideMask & Side.down) == 0 ||
                minY != 0)
            {
                Array.Clear(mask, 0, mask.Length);

                // x axis - width
                // z axis - height

                int currentIndex = Helpers.GetChunkIndex1DFrom3D(minX, minY, minZ, pow);
                int zOffset      = sizeWithPadding - maxX + minX;

                // Build the mask
                for (int zz = minZ; zz < maxZ; ++zz, currentIndex += zOffset)
                {
                    n = minX + zz * sideSize;
                    for (int xx = minX; xx < maxX; ++xx, ++n, ++currentIndex)
                    {
                        int   neighborIndex = currentIndex - sizeWithPaddingPow2;
                        Block neighborBlock = blocks.GetBlock(neighborIndex);

                        // Let's see whether we can merge faces
                        if (block.CanBuildFaceWith(neighborBlock))
                        {
                            mask[n] = new BlockFace
                            {
                                block      = block,
                                pos        = texturePos,
                                side       = Direction.down,
                                light      = BlockUtils.CalculateColors(chunk, currentIndex, Direction.down),
                                materialID = block.renderMaterialID
                            };
                        }
                    }
                }

                // Build faces from the mask if it's possible
                for (int zz = minZ; zz < maxZ; ++zz)
                {
                    n = minX + zz * sideSize;
                    for (int xx = minX; xx < maxX;)
                    {
                        if (mask[n].block == null)
                        {
                            ++xx;
                            ++n;
                            continue;
                        }

                        // Compute width and height
                        w = 1;
                        h = 1;

                        // Build the face
                        bool rotated = mask[n].light.FaceRotationNecessary;
                        if (!rotated)
                        {
                            face[0] = new Vector3(xx, minY, zz) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.down][0];
                            face[1] = new Vector3(xx, minY, zz + h) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.down][1];
                            face[2] = new Vector3(xx + w, minY, zz + h) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.down][2];
                            face[3] = new Vector3(xx + w, minY, zz) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.down][3];
                        }
                        else
                        {
                            face[0] = new Vector3(xx, minY, zz + h) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.down][1];
                            face[1] = new Vector3(xx + w, minY, zz + h) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.down][2];
                            face[2] = new Vector3(xx + w, minY, zz) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.down][3];
                            face[3] = new Vector3(xx, minY, zz) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.down][0];
                        }

                        block.BuildFace(chunk, face, Palette, ref mask[n], rotated);

                        // Zero out the mask. We don't need to process the same fields again
                        for (l = 0; l < h; ++l)
                        {
                            maskIndex = n + l * sideSize;
                            for (k = 0; k < w; ++k, ++maskIndex)
                            {
                                mask[maskIndex] = new BlockFace();
                            }
                        }

                        xx += w;
                        n  += w;
                    }
                }
            }

            #endregion

            #region Right face

            if (listeners[(int)Direction.east] != null ||
                // Don't render faces on world's edges for chunks with no neighbor
                (SideMask & Side.east) == 0 ||
                maxX != sideSize)
            {
                Array.Clear(mask, 0, mask.Length);

                // y axis - height
                // z axis - width

                int neighborIndex = Helpers.GetChunkIndex1DFrom3D(maxX, minY, minZ, pow);
                int yOffset       = sizeWithPaddingPow2 - (maxZ - minZ) * sizeWithPadding;

                // Build the mask
                for (int yy = minY; yy < maxY; ++yy, neighborIndex += yOffset)
                {
                    n = minZ + yy * sideSize;
                    for (int zz = minZ; zz < maxZ; ++zz, ++n, neighborIndex += sizeWithPadding)
                    {
                        int   currentIndex  = neighborIndex - 1;
                        Block neighborBlock = blocks.GetBlock(neighborIndex);

                        // Let's see whether we can merge faces
                        if (block.CanBuildFaceWith(neighborBlock))
                        {
                            mask[n] = new BlockFace
                            {
                                block      = block,
                                pos        = texturePos,
                                side       = Direction.east,
                                light      = BlockUtils.CalculateColors(chunk, currentIndex, Direction.east),
                                materialID = block.renderMaterialID
                            };
                        }
                    }
                }

                // Build faces from the mask if it's possible
                for (int yy = minY; yy < maxY; ++yy)
                {
                    n = minZ + yy * sideSize;
                    for (int zz = minZ; zz < maxZ;)
                    {
                        if (mask[n].block == null)
                        {
                            ++zz;
                            ++n;
                            continue;
                        }

                        // Compute width and height
                        w = 1;
                        h = 1;

                        // Build the face
                        bool rotated = mask[n].light.FaceRotationNecessary;
                        if (!rotated)
                        {
                            face[0] = new Vector3(maxX, yy, zz) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.east][0];
                            face[1] = new Vector3(maxX, yy + h, zz) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.east][1];
                            face[2] = new Vector3(maxX, yy + h, zz + w) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.east][2];
                            face[3] = new Vector3(maxX, yy, zz + w) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.east][3];
                        }
                        else
                        {
                            face[0] = new Vector3(maxX, yy + h, zz) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.east][1];
                            face[1] = new Vector3(maxX, yy + h, zz + w) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.east][2];
                            face[2] = new Vector3(maxX, yy, zz + w) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.east][3];
                            face[3] = new Vector3(maxX, yy, zz) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.east][0];
                        }

                        block.BuildFace(chunk, face, Palette, ref mask[n], rotated);

                        // Zero out the mask. We don't need to process the same fields again
                        for (l = 0; l < h; ++l)
                        {
                            maskIndex = n + l * sideSize;
                            for (k = 0; k < w; ++k, ++maskIndex)
                            {
                                mask[maskIndex] = new BlockFace();
                            }
                        }

                        zz += w;
                        n  += w;
                    }
                }
            }

            #endregion

            #region Left face

            if (listeners[(int)Direction.west] != null ||
                // Don't render faces on world's edges for chunks with no neighbor
                (SideMask & Side.west) == 0 ||
                minX != 0)
            {
                Array.Clear(mask, 0, mask.Length);

                // y axis - height
                // z axis - width

                int currentIndex = Helpers.GetChunkIndex1DFrom3D(minX, minY, minZ, pow);
                int yOffset      = sizeWithPaddingPow2 - (maxZ - minZ) * sizeWithPadding;

                // Build the mask
                for (int yy = minY; yy < maxY; ++yy, currentIndex += yOffset)
                {
                    n = minZ + yy * sideSize;
                    for (int zz = minZ; zz < maxZ; ++zz, ++n, currentIndex += sizeWithPadding)
                    {
                        int   neighborIndex = currentIndex - 1;
                        Block neighborBlock = blocks.GetBlock(neighborIndex);

                        // Let's see whether we can merge faces
                        if (block.CanBuildFaceWith(neighborBlock))
                        {
                            mask[n] = new BlockFace
                            {
                                block      = block,
                                pos        = texturePos,
                                side       = Direction.west,
                                light      = BlockUtils.CalculateColors(chunk, currentIndex, Direction.west),
                                materialID = block.renderMaterialID
                            };
                        }
                    }
                }

                // Build faces from the mask if it's possible
                for (int yy = minY; yy < maxY; ++yy)
                {
                    n = minZ + yy * sideSize;
                    for (int zz = minZ; zz < maxZ;)
                    {
                        if (mask[n].block == null)
                        {
                            ++zz;
                            ++n;
                            continue;
                        }

                        // Compute width and height
                        w = 1;
                        h = 1;

                        // Build the face
                        bool rotated = mask[n].light.FaceRotationNecessary;
                        if (!rotated)
                        {
                            face[0] = new Vector3(minX, yy, zz) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.west][0];
                            face[1] = new Vector3(minX, yy + h, zz) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.west][1];
                            face[2] = new Vector3(minX, yy + h, zz + w) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.west][2];
                            face[3] = new Vector3(minX, yy, zz + w) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.west][3];
                        }
                        else
                        {
                            face[0] = new Vector3(minX, yy + h, zz) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.west][1];
                            face[1] = new Vector3(minX, yy + h, zz + w) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.west][2];
                            face[2] = new Vector3(minX, yy, zz + w) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.west][3];
                            face[3] = new Vector3(minX, yy, zz) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.west][0];
                        }

                        block.BuildFace(chunk, face, Palette, ref mask[n], rotated);

                        // Zero out the mask. We don't need to process the same fields again
                        for (l = 0; l < h; ++l)
                        {
                            maskIndex = n + l * sideSize;
                            for (k = 0; k < w; ++k, ++maskIndex)
                            {
                                mask[maskIndex] = new BlockFace();
                            }
                        }

                        zz += w;
                        n  += w;
                    }
                }
            }

            #endregion

            #region Front face

            if (listeners[(int)Direction.north] != null ||
                // Don't render faces on world's edges for chunks with no neighbor
                (SideMask & Side.north) == 0 ||
                maxZ != sideSize)
            {
                Array.Clear(mask, 0, mask.Length);

                // x axis - width
                // y axis - height

                int neighborIndex = Helpers.GetChunkIndex1DFrom3D(minX, minY, maxZ, pow);
                int yOffset       = sizeWithPaddingPow2 - maxX + minX;

                // Build the mask
                for (int yy = minY; yy < maxY; ++yy, neighborIndex += yOffset)
                {
                    n = minX + yy * sideSize;
                    for (int xx = minX; xx < maxX; ++xx, ++n, ++neighborIndex)
                    {
                        int   currentIndex  = neighborIndex - sizeWithPadding;
                        Block neighborBlock = blocks.GetBlock(neighborIndex);

                        // Let's see whether we can merge faces
                        if (block.CanBuildFaceWith(neighborBlock))
                        {
                            mask[n] = new BlockFace
                            {
                                block      = block,
                                pos        = texturePos,
                                side       = Direction.north,
                                light      = BlockUtils.CalculateColors(chunk, currentIndex, Direction.north),
                                materialID = block.renderMaterialID
                            };
                        }
                    }
                }

                // Build faces from the mask if it's possible
                for (int yy = minY; yy < maxY; ++yy)
                {
                    n = minX + yy * sideSize;
                    for (int xx = minX; xx < maxX;)
                    {
                        if (mask[n].block == null)
                        {
                            ++xx;
                            ++n;
                            continue;
                        }

                        // Compute width and height
                        w = 1;
                        h = 1;

                        // Build the face
                        bool rotated = mask[n].light.FaceRotationNecessary;
                        if (!rotated)
                        {
                            face[0] = new Vector3(xx, yy, maxZ) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.north][0];
                            face[1] = new Vector3(xx, yy + h, maxZ) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.north][1];
                            face[2] = new Vector3(xx + w, yy + h, maxZ) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.north][2];
                            face[3] = new Vector3(xx + w, yy, maxZ) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.north][3];
                        }
                        else
                        {
                            face[0] = new Vector3(xx, yy + h, maxZ) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.north][1];
                            face[1] = new Vector3(xx + w, yy + h, maxZ) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.north][2];
                            face[2] = new Vector3(xx + w, yy, maxZ) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.north][3];
                            face[3] = new Vector3(xx, yy, maxZ) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.north][0];
                        }

                        block.BuildFace(chunk, face, Palette, ref mask[n], rotated);

                        // Zero out the mask. We don't need to process the same fields again
                        for (l = 0; l < h; ++l)
                        {
                            maskIndex = n + l * sideSize;
                            for (k = 0; k < w; ++k, ++maskIndex)
                            {
                                mask[maskIndex] = new BlockFace();
                            }
                        }

                        xx += w;
                        n  += w;
                    }
                }
            }

            #endregion

            #region Back face

            if (listeners[(int)Direction.south] != null ||
                // Don't render faces on world's edges for chunks with no neighbor
                (SideMask & Side.south) == 0 ||
                minZ != 0)
            {
                Array.Clear(mask, 0, mask.Length);

                // x axis - width
                // y axis - height

                int currentIndex = Helpers.GetChunkIndex1DFrom3D(minX, minY, minZ, pow);
                int yOffset      = sizeWithPaddingPow2 - maxX + minX;

                // Build the mask
                for (int yy = minY; yy < maxY; ++yy, currentIndex += yOffset)
                {
                    n = minX + yy * sideSize;
                    for (int xx = minX; xx < maxX; ++xx, ++n, ++currentIndex)
                    {
                        int   neighborIndex = currentIndex - sizeWithPadding;
                        Block neighborBlock = blocks.GetBlock(neighborIndex);

                        // Let's see whether we can merge faces
                        if (block.CanBuildFaceWith(neighborBlock))
                        {
                            mask[n] = new BlockFace
                            {
                                block      = block,
                                pos        = texturePos,
                                side       = Direction.south,
                                light      = BlockUtils.CalculateColors(chunk, currentIndex, Direction.south),
                                materialID = block.renderMaterialID
                            };
                        }
                    }
                }

                // Build faces from the mask if it's possible
                for (int yy = minY; yy < maxY; ++yy)
                {
                    n = minX + yy * sideSize;
                    for (int xx = minX; xx < maxX;)
                    {
                        if (mask[n].block == null)
                        {
                            ++xx;
                            ++n;
                            continue;
                        }

                        // Compute width and height
                        w = 1;
                        h = 1;

                        // Build the face
                        bool rotated = mask[n].light.FaceRotationNecessary;
                        if (!rotated)
                        {
                            face[0] = new Vector3(xx, yy, minZ) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.south][0];
                            face[1] = new Vector3(xx, yy + h, minZ) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.south][1];
                            face[2] = new Vector3(xx + w, yy + h, minZ) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.south][2];
                            face[3] = new Vector3(xx + w, yy, minZ) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.south][3];
                        }
                        else
                        {
                            face[0] = new Vector3(xx, yy + h, minZ) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.south][1];
                            face[1] = new Vector3(xx + w, yy + h, minZ) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.south][2];
                            face[2] = new Vector3(xx + w, yy, minZ) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.south][3];
                            face[3] = new Vector3(xx, yy, minZ) * scale +
                                      BlockUtils.paddingOffsets[(int)Direction.south][0];
                        }

                        block.BuildFace(chunk, face, Palette, ref mask[n], rotated);

                        // Zero out the mask. We don't need to process the same fields again
                        for (l = 0; l < h; ++l)
                        {
                            maskIndex = n + l * sideSize;
                            for (k = 0; k < w; ++k, ++maskIndex)
                            {
                                mask[maskIndex] = new BlockFace();
                            }
                        }

                        xx += w;
                        n  += w;
                    }
                }
            }

            #endregion

            pools.blockFaceArrayPool.Push(mask);
            pools.vector3ArrayPool.Push(face);
        }
Exemple #15
0
        protected override void BuildBox(Chunk chunk, Block block, int minX, int minY, int minZ, int maxX, int maxY,
                                         int maxZ)
        {
            // Order of vertices when building faces:
            //     1--2
            //     |  |
            //     |  |
            //     0--3

            int sizeWithPadding     = sideSize + Env.CHUNK_PADDING_2;
            int sizeWithPaddingPow2 = sizeWithPadding * sizeWithPadding;

            LocalPools  pools  = Globals.WorkPool.GetPool(chunk.ThreadID);
            ChunkBlocks blocks = chunk.Blocks;

            Chunk[] listeners = chunk.Neighbors;

            // Custom blocks have their own rules
            // TODO: Implement custom block colliders

            /*if (block.Custom)
             * {
             *  for (int yy = minY; yy < maxY; yy++)
             *  {
             *      for (int zz = minZ; zz < maxZ; zz++)
             *      {
             *          for (int xx = minX; xx < maxX; xx++)
             *          {
             *              ... // build collider here
             *          }
             *      }
             *  }
             *
             *  return;
             * }*/

            Vector3[] vertexData = pools.vector3ArrayPool.PopExact(4);
            bool[]    mask       = pools.boolArrayPool.PopExact(sideSize * sideSize);

            int n, w, h, l, k, maskIndex;

            #region Top face

            if (listeners[(int)Direction.up] != null ||
                // Don't render faces on world's edges for chunks with no neighbor
                maxY != sideSize)
            {
                Array.Clear(mask, 0, mask.Length);

                // x axis - width
                // z axis - height

                int neighborIndex = Helpers.GetChunkIndex1DFrom3D(minX, maxY, minZ, pow);
                int zOffset       = sizeWithPadding - maxX + minX;

                // Build the mask
                for (int zz = minZ; zz < maxZ; ++zz, neighborIndex += zOffset)
                {
                    n = minX + zz * sideSize;
                    for (int xx = minX; xx < maxX; ++xx, ++n, ++neighborIndex)
                    {
                        // Let's see whether we can merge the faces
                        if (!blocks.GetBlock(neighborIndex).CanCollide)
                        {
                            mask[n] = true;
                        }
                    }
                }

                // Build faces from the mask if it's possible
                for (int zz = minZ; zz < maxZ; ++zz)
                {
                    n = minX + zz * sideSize;
                    for (int xx = minX; xx < maxX;)
                    {
                        if (mask[n] == false)
                        {
                            ++xx;
                            ++n;
                            continue;
                        }

                        bool m = mask[n];

                        // Compute width
                        for (w = 1; xx + w < sideSize && mask[n + w] == m; w++)
                        {
                        }

                        // Compute height
                        for (h = 1; zz + h < sideSize; h++)
                        {
                            for (k = 0; k < w; k++)
                            {
                                maskIndex = n + k + h * sideSize;
                                if (mask[maskIndex] == false || mask[maskIndex] != m)
                                {
                                    goto cont;
                                }
                            }
                        }
cont:

                        // Build the face
                        {
                            vertexData[0] = new Vector3(xx, maxY, zz) * scale +
                                            BlockUtils.paddingOffsets[(int)Direction.up][0];
                            vertexData[1] = new Vector3(xx, maxY, zz + h) * scale +
                                            BlockUtils.paddingOffsets[(int)Direction.up][1];
                            vertexData[2] = new Vector3(xx + w, maxY, zz + h) * scale +
                                            BlockUtils.paddingOffsets[(int)Direction.up][2];
                            vertexData[3] = new Vector3(xx + w, maxY, zz) * scale +
                                            BlockUtils.paddingOffsets[(int)Direction.up][3];

                            chunk.ColliderGeometryHandler.Batcher.AddFace(block.physicMaterialID, vertexData, DirectionUtils.IsBackface(Direction.up));
                        }

                        // Zero out the mask. We don't need to process the same fields again
                        for (l = 0; l < h; ++l)
                        {
                            maskIndex = n + l * sideSize;
                            for (k = 0; k < w; ++k, ++maskIndex)
                            {
                                mask[maskIndex] = false;
                            }
                        }

                        xx += w;
                        n  += w;
                    }
                }
            }

            #endregion

            #region Bottom face

            if (listeners[(int)Direction.down] != null ||
                // Don't render faces on world's edges for chunks with no neighbor
                minY != 0)
            {
                Array.Clear(mask, 0, mask.Length);

                // x axis - width
                // z axis - height

                int neighborIndex = Helpers.GetChunkIndex1DFrom3D(minX, minY - 1, minZ, pow);
                int zOffset       = sizeWithPadding - maxX + minX;

                // Build the mask
                for (int zz = minZ; zz < maxZ; ++zz, neighborIndex += zOffset)
                {
                    n = minX + zz * sideSize;
                    for (int xx = minX; xx < maxX; ++xx, ++n, ++neighborIndex)
                    {
                        // Let's see whether we can merge the faces
                        if (!blocks.GetBlock(neighborIndex).CanCollide)
                        {
                            mask[n] = true;
                        }
                    }
                }

                // Build faces from the mask if it's possible
                for (int zz = minZ; zz < maxZ; ++zz)
                {
                    n = minX + zz * sideSize;
                    for (int xx = minX; xx < maxX;)
                    {
                        if (mask[n] == false)
                        {
                            ++xx;
                            ++n;
                            continue;
                        }

                        bool m = mask[n];

                        // Compute width
                        for (w = 1; xx + w < sideSize && mask[n + w] == m; w++)
                        {
                        }

                        // Compute height
                        for (h = 1; zz + h < sideSize; h++)
                        {
                            for (k = 0; k < w; k++)
                            {
                                maskIndex = n + k + h * sideSize;
                                if (mask[maskIndex] == false || mask[maskIndex] != m)
                                {
                                    goto cont;
                                }
                            }
                        }
cont:

                        // Build the face
                        {
                            vertexData[0] = new Vector3(xx, minY, zz) * scale +
                                            BlockUtils.paddingOffsets[(int)Direction.down][0];
                            vertexData[1] = new Vector3(xx, minY, zz + h) * scale +
                                            BlockUtils.paddingOffsets[(int)Direction.down][1];
                            vertexData[2] = new Vector3(xx + w, minY, zz + h) * scale +
                                            BlockUtils.paddingOffsets[(int)Direction.down][2];
                            vertexData[3] = new Vector3(xx + w, minY, zz) * scale +
                                            BlockUtils.paddingOffsets[(int)Direction.down][3];

                            chunk.ColliderGeometryHandler.Batcher.AddFace(block.physicMaterialID, vertexData, DirectionUtils.IsBackface(Direction.down));
                        }

                        // Zero out the mask. We don't need to process the same fields again
                        for (l = 0; l < h; ++l)
                        {
                            maskIndex = n + l * sideSize;
                            for (k = 0; k < w; ++k, ++maskIndex)
                            {
                                mask[maskIndex] = false;
                            }
                        }

                        xx += w;
                        n  += w;
                    }
                }
            }

            #endregion

            #region Right face

            if (listeners[(int)Direction.east] != null ||
                // Don't render faces on world's edges for chunks with no neighbor
                maxX != sideSize)
            {
                Array.Clear(mask, 0, mask.Length);

                // y axis - height
                // z axis - width

                int neighborIndex = Helpers.GetChunkIndex1DFrom3D(maxX, minY, minZ, pow);
                int yOffset       = sizeWithPaddingPow2 - (maxZ - minZ) * sizeWithPadding;

                // Build the mask
                for (int yy = minY; yy < maxY; ++yy, neighborIndex += yOffset)
                {
                    n = minZ + yy * sideSize;
                    for (int zz = minZ; zz < maxZ; ++zz, ++n, neighborIndex += sizeWithPadding)
                    {
                        // Let's see whether we can merge the faces
                        if (!blocks.GetBlock(neighborIndex).CanCollide)
                        {
                            mask[n] = true;
                        }
                    }
                }

                // Build faces from the mask if it's possible
                for (int yy = minY; yy < maxY; ++yy)
                {
                    n = minZ + yy * sideSize;
                    for (int zz = minZ; zz < maxZ;)
                    {
                        if (mask[n] == false)
                        {
                            ++zz;
                            ++n;
                            continue;
                        }

                        bool m = mask[n];

                        // Compute width
                        for (w = 1; zz + w < sideSize && mask[n + w] == m; w++)
                        {
                        }

                        // Compute height
                        for (h = 1; yy + h < sideSize; h++)
                        {
                            for (k = 0; k < w; k++)
                            {
                                maskIndex = n + k + h * sideSize;
                                if (mask[maskIndex] == false || mask[maskIndex] != m)
                                {
                                    goto cont;
                                }
                            }
                        }
cont:

                        // Build the face
                        {
                            vertexData[0] = new Vector3(maxX, yy, zz) * scale +
                                            BlockUtils.paddingOffsets[(int)Direction.east][0];
                            vertexData[1] = new Vector3(maxX, yy + h, zz) * scale +
                                            BlockUtils.paddingOffsets[(int)Direction.east][1];
                            vertexData[2] = new Vector3(maxX, yy + h, zz + w) * scale +
                                            BlockUtils.paddingOffsets[(int)Direction.east][2];
                            vertexData[3] = new Vector3(maxX, yy, zz + w) * scale +
                                            BlockUtils.paddingOffsets[(int)Direction.east][3];

                            chunk.ColliderGeometryHandler.Batcher.AddFace(block.physicMaterialID, vertexData, DirectionUtils.IsBackface(Direction.east));
                        }

                        // Zero out the mask. We don't need to process the same fields again
                        for (l = 0; l < h; ++l)
                        {
                            maskIndex = n + l * sideSize;
                            for (k = 0; k < w; ++k, ++maskIndex)
                            {
                                mask[maskIndex] = false;
                            }
                        }

                        zz += w;
                        n  += w;
                    }
                }
            }

            #endregion

            #region Left face

            if (listeners[(int)Direction.west] != null ||
                // Don't render faces on world's edges for chunks with no neighbor
                minX != 0)
            {
                Array.Clear(mask, 0, mask.Length);

                // y axis - height
                // z axis - width

                int neighborIndex = Helpers.GetChunkIndex1DFrom3D(minX - 1, minY, minZ, pow);
                int yOffset       = sizeWithPaddingPow2 - (maxZ - minZ) * sizeWithPadding;

                // Build the mask
                for (int yy = minY; yy < maxY; ++yy, neighborIndex += yOffset)
                {
                    n = minZ + yy * sideSize;
                    for (int zz = minZ; zz < maxZ; ++zz, ++n, neighborIndex += sizeWithPadding)
                    {
                        // Let's see whether we can merge the faces
                        if (!blocks.GetBlock(neighborIndex).CanCollide)
                        {
                            mask[n] = true;
                        }
                    }
                }

                // Build faces from the mask if it's possible
                for (int yy = minY; yy < maxY; ++yy)
                {
                    n = minZ + yy * sideSize;
                    for (int zz = minZ; zz < maxZ;)
                    {
                        if (mask[n] == false)
                        {
                            ++zz;
                            ++n;
                            continue;
                        }

                        bool m = mask[n];

                        // Compute width
                        for (w = 1; zz + w < sideSize && mask[n + w] == m; w++)
                        {
                        }

                        // Compute height
                        for (h = 1; yy + h < sideSize; h++)
                        {
                            for (k = 0; k < w; k++)
                            {
                                maskIndex = n + k + h * sideSize;
                                if (mask[maskIndex] == false || mask[maskIndex] != m)
                                {
                                    goto cont;
                                }
                            }
                        }
cont:

                        // Build the face
                        {
                            vertexData[0] = new Vector3(minX, yy, zz) * scale +
                                            BlockUtils.paddingOffsets[(int)Direction.west][0];
                            vertexData[1] = new Vector3(minX, yy + h, zz) * scale +
                                            BlockUtils.paddingOffsets[(int)Direction.west][1];
                            vertexData[2] = new Vector3(minX, yy + h, zz + w) * scale +
                                            BlockUtils.paddingOffsets[(int)Direction.west][2];
                            vertexData[3] = new Vector3(minX, yy, zz + w) * scale +
                                            BlockUtils.paddingOffsets[(int)Direction.west][3];

                            chunk.ColliderGeometryHandler.Batcher.AddFace(block.physicMaterialID, vertexData, DirectionUtils.IsBackface(Direction.west));
                        }

                        // Zero out the mask. We don't need to process the same fields again
                        for (l = 0; l < h; ++l)
                        {
                            maskIndex = n + l * sideSize;
                            for (k = 0; k < w; ++k, ++maskIndex)
                            {
                                mask[maskIndex] = false;
                            }
                        }

                        zz += w;
                        n  += w;
                    }
                }
            }

            #endregion

            #region Front face

            if (listeners[(int)Direction.north] != null ||
                // Don't render faces on world's edges for chunks with no neighbor
                maxZ != sideSize)
            {
                Array.Clear(mask, 0, mask.Length);

                // x axis - width
                // y axis - height

                int neighborIndex = Helpers.GetChunkIndex1DFrom3D(minX, minY, maxZ, pow);
                int yOffset       = sizeWithPaddingPow2 - maxX + minX;

                // Build the mask
                for (int yy = minY; yy < maxY; ++yy, neighborIndex += yOffset)
                {
                    n = minX + yy * sideSize;
                    for (int xx = minX; xx < maxX; ++xx, ++n, ++neighborIndex)
                    {
                        // Let's see whether we can merge the faces
                        if (!blocks.GetBlock(neighborIndex).CanCollide)
                        {
                            mask[n] = true;
                        }
                    }
                }

                // Build faces from the mask if it's possible
                for (int yy = minY; yy < maxY; ++yy)
                {
                    n = minX + yy * sideSize;
                    for (int xx = minX; xx < maxX;)
                    {
                        if (mask[n] == false)
                        {
                            ++xx;
                            ++n;
                            continue;
                        }

                        bool m = mask[n];

                        // Compute width
                        for (w = 1; xx + w < sideSize && mask[n + w] == m; w++)
                        {
                        }

                        // Compute height
                        for (h = 1; yy + h < sideSize; h++)
                        {
                            for (k = 0; k < w; k++)
                            {
                                maskIndex = n + k + h * sideSize;
                                if (mask[maskIndex] == false || mask[maskIndex] != m)
                                {
                                    goto cont;
                                }
                            }
                        }
cont:

                        // Build the face
                        {
                            vertexData[0] = new Vector3(xx, yy, maxZ) * scale +
                                            BlockUtils.paddingOffsets[(int)Direction.north][0];
                            vertexData[1] = new Vector3(xx, yy + h, maxZ) * scale +
                                            BlockUtils.paddingOffsets[(int)Direction.north][1];
                            vertexData[2] = new Vector3(xx + w, yy + h, maxZ) * scale +
                                            BlockUtils.paddingOffsets[(int)Direction.north][2];
                            vertexData[3] = new Vector3(xx + w, yy, maxZ) * scale +
                                            BlockUtils.paddingOffsets[(int)Direction.north][3];

                            chunk.ColliderGeometryHandler.Batcher.AddFace(block.physicMaterialID, vertexData, DirectionUtils.IsBackface(Direction.north));
                        }

                        // Zero out the mask. We don't need to process the same fields again
                        for (l = 0; l < h; ++l)
                        {
                            maskIndex = n + l * sideSize;
                            for (k = 0; k < w; ++k, ++maskIndex)
                            {
                                mask[maskIndex] = false;
                            }
                        }

                        xx += w;
                        n  += w;
                    }
                }
            }

            #endregion

            #region Back face

            if (listeners[(int)Direction.south] != null ||
                // Don't render faces on world's edges for chunks with no neighbor
                minZ != 0)
            {
                Array.Clear(mask, 0, mask.Length);

                // x axis - width
                // y axis - height

                int neighborIndex = Helpers.GetChunkIndex1DFrom3D(minX, minY, minZ - 1, pow);
                int yOffset       = sizeWithPaddingPow2 - maxX + minX;

                // Build the mask
                for (int yy = minY; yy < maxY; ++yy, neighborIndex += yOffset)
                {
                    n = minX + yy * sideSize;
                    for (int xx = minX; xx < maxX; ++xx, ++n, ++neighborIndex)
                    {
                        // Let's see whether we can merge the faces
                        if (!blocks.GetBlock(neighborIndex).CanCollide)
                        {
                            mask[n] = true;
                        }
                    }
                }

                // Build faces from the mask if it's possible
                for (int yy = minY; yy < maxY; ++yy)
                {
                    n = minX + yy * sideSize;
                    for (int xx = minX; xx < maxX;)
                    {
                        if (mask[n] == false)
                        {
                            ++xx;
                            ++n;
                            continue;
                        }

                        bool m = mask[n];

                        // Compute width
                        for (w = 1; xx + w < sideSize && mask[n + w] == m; w++)
                        {
                        }

                        // Compute height
                        for (h = 1; yy + h < sideSize; h++)
                        {
                            for (k = 0; k < w; k++)
                            {
                                maskIndex = n + k + h * sideSize;
                                if (mask[maskIndex] == false || mask[maskIndex] != m)
                                {
                                    goto cont;
                                }
                            }
                        }
cont:

                        // Build the face
                        {
                            vertexData[0] = new Vector3(xx, yy, minZ) * scale +
                                            BlockUtils.paddingOffsets[(int)Direction.south][0];
                            vertexData[1] = new Vector3(xx, yy + h, minZ) * scale +
                                            BlockUtils.paddingOffsets[(int)Direction.south][1];
                            vertexData[2] = new Vector3(xx + w, yy + h, minZ) * scale +
                                            BlockUtils.paddingOffsets[(int)Direction.south][2];
                            vertexData[3] = new Vector3(xx + w, yy, minZ) * scale +
                                            BlockUtils.paddingOffsets[(int)Direction.south][3];

                            chunk.ColliderGeometryHandler.Batcher.AddFace(block.physicMaterialID, vertexData, DirectionUtils.IsBackface(Direction.south));
                        }

                        // Zero out the mask. We don't need to process the same fields again
                        for (l = 0; l < h; ++l)
                        {
                            maskIndex = n + l * sideSize;
                            for (k = 0; k < w; ++k, ++maskIndex)
                            {
                                mask[maskIndex] = false;
                            }
                        }

                        xx += w;
                        n  += w;
                    }
                }
            }

            #endregion

            pools.boolArrayPool.Push(mask);
            pools.vector3ArrayPool.Push(vertexData);
        }
Exemple #16
0
        public override void Build(Chunk chunk, int id, ref Vector3Int worldPos, TerrainLayer layer)
        {
            World world = chunk.World;

            int noise =
                Helpers.FastFloor(NoiseUtils.GetNoise(layer.Noise.Noise, worldPos.x, worldPos.y, worldPos.z, 1f, 3, 1f));
            int leavesRange  = MIN_CROWN_SIZE + noise;
            int leavesRange1 = leavesRange - 1;
            int trunkHeight  = MIN_TRUNK_SIZE + noise;

            // Make the crown an ellipsoid flattened on the y axis
            float a2inv = 1.0f / (leavesRange * leavesRange);
            float b2inv = 1.0f / (leavesRange1 * leavesRange1);

            int x1 = worldPos.x - leavesRange;
            int x2 = worldPos.x + leavesRange;
            int y1 = worldPos.y + 1 + trunkHeight;
            int y2 = y1 + 1 + 2 * leavesRange1;
            int z1 = worldPos.z - leavesRange;
            int z2 = worldPos.z + leavesRange;

            int cx, cy, cz;
            int minX, minY, minZ;
            int maxX, maxY, maxZ;

            AABBInt       bounds   = new AABBInt(x1, worldPos.y, z1, x2, y2, z2);
            Vector3Int    chunkPos = chunk.Pos;
            StructureInfo info     = null;

            // Generate the crown
            Vector3Int posFrom      = new Vector3Int(x1, y1, z1);
            Vector3Int posTo        = new Vector3Int(x2, y2, z2);
            Vector3Int chunkPosFrom = Helpers.ContainingChunkPos(ref posFrom);
            Vector3Int chunkPosTo   = Helpers.ContainingChunkPos(ref posTo);

            minY = Helpers.Mod(posFrom.y, Env.CHUNK_SIZE);
            for (cy = chunkPosFrom.y; cy <= chunkPosTo.y; cy += Env.CHUNK_SIZE, minY = 0)
            {
                maxY = System.Math.Min(posTo.y - cy, Env.CHUNK_SIZE_1);
                minZ = Helpers.Mod(posFrom.z, Env.CHUNK_SIZE);
                for (cz = chunkPosFrom.z; cz <= chunkPosTo.z; cz += Env.CHUNK_SIZE, minZ = 0)
                {
                    maxZ = System.Math.Min(posTo.z - cz, Env.CHUNK_SIZE_1);
                    minX = Helpers.Mod(posFrom.x, Env.CHUNK_SIZE);
                    for (cx = chunkPosFrom.x; cx <= chunkPosTo.x; cx += Env.CHUNK_SIZE, minX = 0)
                    {
                        maxX = System.Math.Min(posTo.x - cx, Env.CHUNK_SIZE_1);

                        int xOff = cx - worldPos.x;
                        int yOff = cy - y1 - leavesRange1;
                        int zOff = cz - worldPos.z;

                        if (cx != chunk.Pos.x || cy != chunk.Pos.y || cz != chunk.Pos.z)
                        {
                            Vector3Int pos = new Vector3Int(cx, cy, cz);
                            Vector3Int min = new Vector3Int(minX, minY, minZ);
                            Vector3Int max = new Vector3Int(maxX, maxY, maxZ);

                            if (info == null)
                            {
                                info = new StructureInfo(id, ref chunkPos, ref bounds);
                            }

                            world.RegisterPendingStructure(info, new StructureContextTreeCrown(id, ref pos, ref worldPos, ref min, ref max, noise));

                            continue;
                        }

                        // Actual crown construction
                        ChunkBlocks blocks  = chunk.Blocks;
                        int         index   = Helpers.GetChunkIndex1DFrom3D(minX, minY, minZ);
                        int         yOffset = Env.CHUNK_SIZE_WITH_PADDING_POW_2 - (maxZ - minZ + 1) * Env.CHUNK_SIZE_WITH_PADDING;
                        int         zOffset = Env.CHUNK_SIZE_WITH_PADDING - (maxX - minX + 1);
                        for (int y = minY; y <= maxY; ++y, index += yOffset)
                        {
                            for (int z = minZ; z <= maxZ; ++z, index += zOffset)
                            {
                                for (int x = minX; x <= maxX; ++x, ++index)
                                {
                                    int xx = x + xOff;
                                    int yy = y + yOff;
                                    int zz = z + zOff;

                                    float _x = xx * xx * a2inv;
                                    float _y = yy * yy * b2inv;
                                    float _z = zz * zz * a2inv;
                                    if (_x + _y + _z <= 1.0f)
                                    {
                                        blocks.SetRaw(index, leaves);
                                    }
                                }
                            }
                        }
                    }
                }
            }

            // Generate the trunk
            posFrom      = new Vector3Int(worldPos.x, worldPos.y, worldPos.z);
            posTo        = new Vector3Int(worldPos.x, worldPos.y + trunkHeight, worldPos.z);
            chunkPosFrom = Helpers.ContainingChunkPos(ref posFrom);
            chunkPosTo   = Helpers.ContainingChunkPos(ref posTo);

            cx = Helpers.MakeChunkCoordinate(worldPos.x);
            cz = Helpers.MakeChunkCoordinate(worldPos.z);

            int tx = Helpers.Mod(worldPos.x, Env.CHUNK_SIZE);
            int tz = Helpers.Mod(worldPos.z, Env.CHUNK_SIZE);

            minY = Helpers.Mod(posFrom.y, Env.CHUNK_SIZE);
            for (cy = chunkPosFrom.y; cy <= chunkPosTo.y; cy += Env.CHUNK_SIZE, minY = 0)
            {
                maxY = System.Math.Min(posTo.y - cy, Env.CHUNK_SIZE_1);

                if (cx != chunk.Pos.x || cy != chunk.Pos.y || cz != chunk.Pos.z)
                {
                    Vector3Int pos = new Vector3Int(cx, cy, cz);
                    Vector3Int min = new Vector3Int(tx, minY, tz);
                    Vector3Int max = new Vector3Int(tx, maxY, tz);

                    if (info == null)
                    {
                        info = new StructureInfo(id, ref chunkPos, ref bounds);
                    }

                    world.RegisterPendingStructure(info, new StructureContextTreeTrunk(id, ref pos, ref min, ref max));

                    continue;
                }

                // Actual trunk construction
                ChunkBlocks blocks = chunk.Blocks;
                int         index  = Helpers.GetChunkIndex1DFrom3D(tx, minY, tz);
                for (int y = minY; y <= maxY; ++y, index += Env.CHUNK_SIZE_WITH_PADDING_POW_2)
                {
                    blocks.SetRaw(index, log);
                }
            }
        }
Exemple #17
0
        public BlockData Get(ref Vector3Int pos)
        {
            int index = Helpers.GetChunkIndex1DFrom3D(pos.x, pos.y, pos.z, pow);

            return(this[index]);
        }
Exemple #18
0
        public Block GetBlock(ref Vector3Int pos)
        {
            int index = Helpers.GetChunkIndex1DFrom3D(pos.x, pos.y, pos.z, pow);

            return(blockTypes[this[index].Type]);
        }