Example #1
0
        public IEnumerable <ushort> GetAllData()
        {
            int size = _Extent << 1;

            for (int index = 0; index < Length; index++)
            {
                yield return(GetPoint(WydMath.IndexTo3D(index, size)));
            }
        }
Example #2
0
        private void GenerateIndex(int index)
        {
            int3 localPosition  = WydMath.IndexTo3D(index, GenerationConstants.CHUNK_SIZE);
            int  heightmapIndex = WydMath.PointToIndex(localPosition.xz, GenerationConstants.CHUNK_SIZE);

            int noiseHeight = _Heightmap[heightmapIndex];

            if (noiseHeight < _OriginPoint.y)
            {
                return;
            }

            int globalPositionY = _OriginPoint.y + localPosition.y;

            if ((globalPositionY < 4) && (globalPositionY <= _SeededRandom.Next(0, 4)))
            {
                _Blocks.SetPoint(localPosition, GetCachedBlockID("bedrock"));
                return;
            }
            else if (_CaveNoise[index] < 0.000225f)
            {
                return;
            }

            if (globalPositionY == noiseHeight)
            {
                _Blocks.SetPoint(localPosition, GetCachedBlockID("grass"));
            }
            else if ((globalPositionY < noiseHeight) && (globalPositionY >= (noiseHeight - 3))) // lay dirt up to 3 blocks below noise height
            {
                _Blocks.SetPoint(localPosition, _SeededRandom.Next(0, 8) == 0
                    ? GetCachedBlockID("dirt_coarse")
                    : GetCachedBlockID("dirt"));
            }
            else if (globalPositionY < (noiseHeight - 3))
            {
                if (_SeededRandom.Next(0, 100) == 0)
                {
                    _Blocks.SetPoint(localPosition, GetCachedBlockID("coal_ore"));
                }
                else
                {
                    _Blocks.SetPoint(localPosition, GetCachedBlockID("stone"));
                }
            }
        }
Example #3
0
        public T GetPoint(int3 point)
        {
            int index = WydMath.PointToIndex(point, GenerationConstants.CHUNK_SIZE);
            LinkedListNode <RLENode <T> > currentNode = _RLENodes.First;

            for (uint i = 0; (i < index) && ((currentNode = currentNode.Next) != null);)
            {
                uint totalRunLength = i + currentNode.Value.RunLength;

                if (totalRunLength >= index)
                {
                    return(currentNode.Value.Value);
                }
                else
                {
                    i = totalRunLength;
                }
            }

            return(default);
Example #4
0
        protected override Task ProcessIndex(int index)
        {
            if (_CancellationToken.IsCancellationRequested)
            {
                return(Task.CompletedTask);
            }

            ushort currentBlockId = _MeshingBlocks[index].ID;
            int    localPosition  = CompressVertex(WydMath.IndexTo3D(index, GenerationConstants.CHUNK_SIZE));

            if (currentBlockId == BlockController.AirID)
            {
                return(Task.CompletedTask);
            }

            bool transparentTraversal = BlockController.Current.CheckBlockHasProperty(currentBlockId, BlockDefinition.Property.Transparent);

            NaiveMeshIndex(index, localPosition, currentBlockId, transparentTraversal);

            return(Task.CompletedTask);
        }
Example #5
0
        public void CopyTo(ushort[] destinationArray)
        {
            if (destinationArray == null)
            {
                throw new NullReferenceException(nameof(destinationArray));
            }
            else if (destinationArray.Rank != 1)
            {
                throw new RankException("Only single dimension arrays are supported here.");
            }
            else if (destinationArray.Length < Length)
            {
                throw new ArgumentOutOfRangeException(nameof(destinationArray), "Destination array was not long enough.");
            }

            int size = _Extent << 1;

            for (int index = 0; index < destinationArray.Length; index++)
            {
                destinationArray[index] = GetPoint(WydMath.IndexTo3D(index, size));
            }
        }
Example #6
0
        private async Task GenerateNoise()
        {
            // SIZE_SQUARED + 1 to facilitate compute shader's above-y-value count
            _Heightmap = _HeightmapPool.Retrieve() ?? new int[GenerationConstants.CHUNK_SIZE_SQUARED];
            _CaveNoise = _CaveNoisePool.Retrieve() ?? new float[GenerationConstants.CHUNK_SIZE_CUBED];

            if ((_HeightmapBuffer == null) || (_CaveNoiseBuffer == null))
            {
                for (int x = 0; x < GenerationConstants.CHUNK_SIZE; x++)
                {
                    for (int z = 0; z < GenerationConstants.CHUNK_SIZE; z++)
                    {
                        int2 xzCoords       = new int2(x, z);
                        int  heightmapIndex = WydMath.PointToIndex(xzCoords, GenerationConstants.CHUNK_SIZE);
                        _Heightmap[heightmapIndex] = GetHeightByGlobalPosition(_OriginPoint.xz + xzCoords);

                        for (int y = 0; y < GenerationConstants.CHUNK_SIZE; y++)
                        {
                            int3 localPosition  = new int3(x, y, z);
                            int3 globalPosition = _OriginPoint + localPosition;
                            int  caveNoiseIndex = WydMath.PointToIndex(localPosition, GenerationConstants.CHUNK_SIZE);

                            _CaveNoise[caveNoiseIndex] = GetCaveNoiseByGlobalPosition(globalPosition);
                        }
                    }
                }
            }
            else
            {
                // ReSharper disable once ConvertToUsingDeclaration
                // .... because Rider doesn't actually consider language feature version
                // remark: thanks JetBrains
                using (SemaphoreSlim semaphoreReset = MainThreadActionsController.Current.QueueAction(GetComputeBufferData))
                {
                    await semaphoreReset.WaitAsync(_CancellationToken);
                }
            }
        }
Example #7
0
        private void NaiveMeshIndex(int index, int localPosition, ushort currentBlockId, bool isCurrentBlockTransparent)
        {
            Debug.Assert(currentBlockId != BlockController.AirID, $"{nameof(TraverseIndex)} should not run on air blocks.");
            Debug.Assert((index >= 0) && (index < GenerationConstants.CHUNK_SIZE_CUBED), $"{nameof(index)} is not within chunk bounds.");
            Debug.Assert(WydMath.PointToIndex(DecompressVertex(localPosition), GenerationConstants.CHUNK_SIZE) == index,
                         $"{nameof(localPosition)} does not match given {nameof(index)}.");
            Debug.Assert(_MeshingBlocks[index].ID == currentBlockId, $"{currentBlockId} is not equal to block ID at given index.");
            Debug.Assert(
                BlockController.Current.CheckBlockHasProperty(currentBlockId, BlockDefinition.Property.Transparent) == isCurrentBlockTransparent,
                $"Given transparency state for {nameof(currentBlockId)} does not match actual block transparency.");

            // iterate once over all 6 faces of given cubic space
            for (int normalIndex = 0; normalIndex < 6; normalIndex++)
            {
                // face direction always exists on a single bit, so shift 1 by the current normalIndex (0-5)
                Direction faceDirection = (Direction)(1 << normalIndex);

                // check if current index has face already
                if (_MeshingBlocks[index].HasFace(faceDirection))
                {
                    continue;
                }

                // indicates whether the current face checking direction is negative or positive
                bool isNegativeFace = (normalIndex - 3) >= 0;
                // normalIndex constrained to represent the 3 axes
                int iModulo3      = normalIndex % 3;
                int iModulo3Shift = GenerationConstants.CHUNK_SIZE_BIT_SHIFT * iModulo3;
                // axis value of the current face check direction
                // example: for iteration normalIndex == 0—which is positive X—it'd be equal to localPosition.x
                int faceCheckAxisValue = (localPosition >> iModulo3Shift) & GenerationConstants.CHUNK_SIZE_BIT_MASK;
                // indicates whether or not the face check is within the current chunk bounds
                bool isFaceCheckOutOfBounds = (!isNegativeFace && (faceCheckAxisValue == (GenerationConstants.CHUNK_SIZE - 1))) ||
                                              (isNegativeFace && (faceCheckAxisValue == 0));

                if (!isFaceCheckOutOfBounds)
                {
                    // amount by integer to add to current traversal index to get 3D->1D position of facing block
                    int facedBlockIndex = index + GenerationConstants.IndexStepByNormalIndex[normalIndex];
                    // if so, index into block ids and set facingBlockId
                    ushort facedBlockId = _MeshingBlocks[facedBlockIndex].ID;

                    // if transparent, traverse so long as facing block is not the same block id
                    // if opaque, traverse so long as facing block is transparent
                    if (isCurrentBlockTransparent)
                    {
                        if (currentBlockId != facedBlockId)
                        {
                            continue;
                        }
                    }
                    else if (!BlockController.Current.CheckBlockHasProperty(facedBlockId, BlockDefinition.Property.Transparent))
                    {
                        if (!isNegativeFace)
                        {
                            Direction inverseFaceDirection = (Direction)(1 << ((normalIndex + 3) % 6));
                            _MeshingBlocks[facedBlockIndex].SetFace(inverseFaceDirection);
                        }

                        continue;
                    }
                }
                else
                {
                    // this block of code translates the integer local position to the local position of the neighbor at [normalIndex]
                    int sign = isNegativeFace ? -1 : 1;
                    int iModuloComponentMask = GenerationConstants.CHUNK_SIZE_BIT_MASK << iModulo3Shift;
                    int finalLocalPosition   = (~iModuloComponentMask & localPosition)
                                               | (WydMath.Wrap(((localPosition & iModuloComponentMask) >> iModulo3Shift) + sign,
                                                               GenerationConstants.CHUNK_SIZE, 0, GenerationConstants.CHUNK_SIZE - 1)
                                                << iModulo3Shift);

                    // index into neighbor blocks collections, call .GetPoint() with adjusted local position
                    // remark: if there's no neighbor at the index given, then no chunk exists there (for instance,
                    //     chunks at the edge of render distance). In this case, return NullID so no face is rendered on edges.
                    ushort facedBlockId = _NeighborBlocksCollections[normalIndex]?.GetPoint(DecompressVertex(finalLocalPosition))
                                          ?? BlockController.NullID;

                    if (isCurrentBlockTransparent)
                    {
                        if (currentBlockId != facedBlockId)
                        {
                            continue;
                        }
                    }
                    else if (!BlockController.Current.CheckBlockHasProperty(facedBlockId, BlockDefinition.Property.Transparent))

                    {
                        continue;
                    }
                }

                _MeshingBlocks[index].SetFace(faceDirection);

                if (BlockController.Current.GetUVs(currentBlockId, faceDirection, out ushort textureId))
                {
                    int compressedUv = (textureId << (GenerationConstants.CHUNK_SIZE_BIT_SHIFT * 2))
                                       ^ (1 << GenerationConstants.CHUNK_SIZE_BIT_SHIFT)
                                       ^ 1;

                    int   normals            = GenerationConstants.NormalByIteration[normalIndex];
                    int[] compressedVertices = GenerationConstants.VerticesByIteration[normalIndex];

                    _MeshData.AddVertex((localPosition + compressedVertices[3]) | normals);
                    _MeshData.AddVertex(compressedUv & (int.MaxValue << (GenerationConstants.CHUNK_SIZE_BIT_SHIFT * 2)));

                    _MeshData.AddVertex((localPosition + compressedVertices[2]) | normals);
                    _MeshData.AddVertex(compressedUv & (int.MaxValue << GenerationConstants.CHUNK_SIZE_BIT_SHIFT));

                    _MeshData.AddVertex((localPosition + compressedVertices[1]) | normals);
                    _MeshData.AddVertex(compressedUv & ~(GenerationConstants.CHUNK_SIZE_BIT_MASK << GenerationConstants.CHUNK_SIZE_BIT_SHIFT));

                    _MeshData.AddVertex((localPosition + compressedVertices[0]) | normals);
                    _MeshData.AddVertex(compressedUv & int.MaxValue);


                    int verticesCount    = _MeshData.VerticesCount / 2;
                    int transparentAsInt = Convert.ToInt32(isCurrentBlockTransparent);

                    _MeshData.AddTriangle(transparentAsInt, 0 + verticesCount);
                    _MeshData.AddTriangle(transparentAsInt, 2 + verticesCount);
                    _MeshData.AddTriangle(transparentAsInt, 1 + verticesCount);
                    _MeshData.AddTriangle(transparentAsInt, 2 + verticesCount);
                    _MeshData.AddTriangle(transparentAsInt, 3 + verticesCount);
                    _MeshData.AddTriangle(transparentAsInt, 1 + verticesCount);
                }
                else
                {
                }
            }
        }
Example #8
0
        /// <summary>
        ///     Traverse given index of <see cref="_MeshingBlocks" /> to conditionally emit vertex data for each face.
        /// </summary>
        /// <param name="index">Current working index.</param>
        /// <param name="localPosition">3D projected local position of the current working index.</param>
        /// <param name="currentBlockId">Block ID present at the current working index.</param>
        /// <param name="isCurrentBlockTransparent">Whether or not this traversal uses transparent-specific conditionals.</param>
        private void TraverseIndex(int index, int localPosition, ushort currentBlockId, bool isCurrentBlockTransparent)
        {
            Debug.Assert(currentBlockId != BlockController.AirID, $"{nameof(TraverseIndex)} should not run on air blocks.");
            Debug.Assert((index >= 0) && (index < GenerationConstants.CHUNK_SIZE_CUBED), $"{nameof(index)} is not within chunk bounds.");
            Debug.Assert(WydMath.PointToIndex(DecompressVertex(localPosition), GenerationConstants.CHUNK_SIZE) == index,
                         $"{nameof(localPosition)} does not match given {nameof(index)}.");
            Debug.Assert(_MeshingBlocks[index].ID == currentBlockId, $"{currentBlockId} is not equal to block ID at given index.");
            Debug.Assert(
                BlockController.Current.CheckBlockHasProperty(currentBlockId, BlockDefinition.Property.Transparent) == isCurrentBlockTransparent,
                $"Given transparency state for {nameof(currentBlockId)} does not match actual block transparency.");

            // iterate once over all 6 faces of given cubic space
            for (int normalIndex = 0; normalIndex < 6; normalIndex++)
            {
                // face direction always exists on a single bit, so shift 1 by the current normalIndex (0-5)
                Direction faceDirection = (Direction)(1 << normalIndex);

                // check if current index has face already
                if (_MeshingBlocks[index].HasFace(faceDirection))
                {
                    continue;
                }

                // indicates whether the current face checking direction is negative or positive
                bool isNegativeFace = (normalIndex - 3) >= 0;
                // normalIndex constrained to represent the 3 axes
                int iModulo3      = normalIndex % 3;
                int iModulo3Shift = GenerationConstants.CHUNK_SIZE_BIT_SHIFT * iModulo3;
                // axis value of the current face check direction
                // example: for iteration normalIndex == 0—which is positive X—it'd be equal to localPosition.x
                int faceCheckAxisValue = (localPosition >> iModulo3Shift) & GenerationConstants.CHUNK_SIZE_BIT_MASK;
                // indicates whether or not the face check is within the current chunk bounds
                bool isFaceCheckOutOfBounds = (!isNegativeFace && (faceCheckAxisValue == (GenerationConstants.CHUNK_SIZE - 1))) ||
                                              (isNegativeFace && (faceCheckAxisValue == 0));
                // total number of successful traversals
                int traversals = 0;

                for (int perpendicularNormalIndex = 1; perpendicularNormalIndex < 3; perpendicularNormalIndex++)
                {
                    // the index of the int3 traversalNormal to traverse on
                    int traversalNormalIndex = (iModulo3 + perpendicularNormalIndex) % 3;
                    int traversalNormalShift = GenerationConstants.CHUNK_SIZE_BIT_SHIFT * traversalNormalIndex;

                    // current value of the local position by traversal direction
                    int traversalNormalAxisValue = (localPosition >> traversalNormalShift) & GenerationConstants.CHUNK_SIZE_BIT_MASK;
                    // amount by integer to add to current index to get 3D->1D position of traversal position
                    int traversalIndexStep = GenerationConstants.IndexStepByNormalIndex[traversalNormalIndex];
                    // current traversal index, which is increased by traversalIndexStep every iteration the for loop below
                    int traversalIndex = index + (traversals * traversalIndexStep);
                    // local start axis position + traversals
                    int totalTraversalLength = traversalNormalAxisValue + traversals;

                    for (;
                         (totalTraversalLength < GenerationConstants.CHUNK_SIZE) &&
                         !_MeshingBlocks[traversalIndex].HasFace(faceDirection) &&
                         (_MeshingBlocks[traversalIndex].ID == currentBlockId);
                         totalTraversalLength++,
                         traversals++,                         // increment traversals
                         traversalIndex += traversalIndexStep) // increment traversal index by index step to adjust local working position
                    {
                        // check if current facing block axis value is within the local chunk
                        if (!isFaceCheckOutOfBounds)
                        {
                            // amount by integer to add to current traversal index to get 3D->1D position of facing block
                            int facedBlockIndex = traversalIndex + GenerationConstants.IndexStepByNormalIndex[normalIndex];
                            // if so, index into block ids and set facingBlockId
                            ushort facedBlockId = _MeshingBlocks[facedBlockIndex].ID;

                            // if transparent, traverse so long as facing block is not the same block id
                            // if opaque, traverse so long as facing block is transparent
                            if (isCurrentBlockTransparent)
                            {
                                if (currentBlockId != facedBlockId)
                                {
                                    break;
                                }
                            }
                            else if (!BlockController.Current.CheckBlockHasProperty(facedBlockId, BlockDefinition.Property.Transparent))
                            {
                                if (!isNegativeFace)
                                {
                                    // we've culled this face, and faced block is opaque as well, so cull it's face inverse to the current.
                                    Direction inverseFaceDirection = (Direction)(1 << ((normalIndex + 3) % 6));
                                    _MeshingBlocks[facedBlockIndex].SetFace(inverseFaceDirection);
                                }

                                break;
                            }
                        }
                        else
                        {
                            // this block of code translates the integer local position to the local position of the neighbor at [normalIndex]
                            int sign = isNegativeFace ? -1 : 1;
                            int iModuloComponentMask    = GenerationConstants.CHUNK_SIZE_BIT_MASK << iModulo3Shift;
                            int translatedLocalPosition = localPosition + (traversals << traversalNormalShift);
                            int finalLocalPosition      = (~iModuloComponentMask & translatedLocalPosition)
                                                          | (WydMath.Wrap(((translatedLocalPosition & iModuloComponentMask) >> iModulo3Shift) + sign,
                                                                          GenerationConstants.CHUNK_SIZE, 0, GenerationConstants.CHUNK_SIZE - 1)
                                                        << iModulo3Shift);

                            // index into neighbor blocks collections, call .GetPoint() with adjusted local position
                            // remark: if there's no neighbor at the index given, then no chunk exists there (for instance,
                            //     chunks at the edge of render distance). In this case, return NullID so no face is rendered on edges.
                            ushort facedBlockId = _NeighborBlocksCollections[normalIndex]?.GetPoint(DecompressVertex(finalLocalPosition))
                                                  ?? BlockController.NullID;

                            if (isCurrentBlockTransparent)
                            {
                                if (currentBlockId != facedBlockId)
                                {
                                    break;
                                }
                            }
                            else if (!BlockController.Current.CheckBlockHasProperty(facedBlockId, BlockDefinition.Property.Transparent))
                            {
                                break;
                            }
                        }

                        _MeshingBlocks[traversalIndex].SetFace(faceDirection);
                    }

                    // if it's the first traversal and we've only made a 1x1x1 face, continue to test next axis
                    if ((traversals == 1) && (perpendicularNormalIndex == 1))
                    {
                        continue;
                    }

                    if ((traversals == 0) || !BlockController.Current.GetUVs(currentBlockId, faceDirection, out ushort textureId))
                    {
                        break;
                    }

                    // add triangles
                    int verticesCount    = _MeshData.VerticesCount / 2;
                    int transparentAsInt = Convert.ToInt32(isCurrentBlockTransparent);

                    _MeshData.AddTriangle(transparentAsInt, 0 + verticesCount);
                    _MeshData.AddTriangle(transparentAsInt, 2 + verticesCount);
                    _MeshData.AddTriangle(transparentAsInt, 1 + verticesCount);
                    _MeshData.AddTriangle(transparentAsInt, 2 + verticesCount);
                    _MeshData.AddTriangle(transparentAsInt, 3 + verticesCount);
                    _MeshData.AddTriangle(transparentAsInt, 1 + verticesCount);

                    int uvShift      = (iModulo3 + traversalNormalIndex) % 2;
                    int compressedUv = (textureId << (GenerationConstants.CHUNK_SIZE_BIT_SHIFT * 2))
                                       | (1 << (GenerationConstants.CHUNK_SIZE_BIT_SHIFT * ((uvShift + 1) % 2)))
                                       | (traversals << (GenerationConstants.CHUNK_SIZE_BIT_SHIFT * uvShift));

                    int traversalShiftedMask      = GenerationConstants.CHUNK_SIZE_BIT_MASK << traversalNormalShift;
                    int unaryTraversalShiftedMask = ~traversalShiftedMask;

                    int   aggregatePositionNormal = localPosition | GenerationConstants.NormalByIteration[normalIndex];
                    int[] compressedVertices      = GenerationConstants.VerticesByIteration[normalIndex];


                    _MeshData.AddVertex(aggregatePositionNormal
                                        + ((unaryTraversalShiftedMask & compressedVertices[3])
                                           | ((((compressedVertices[3] >> traversalNormalShift) * traversals) << traversalNormalShift)
                                              & traversalShiftedMask)));
                    _MeshData.AddVertex(compressedUv & (int.MaxValue << (GenerationConstants.CHUNK_SIZE_BIT_SHIFT * 2)));


                    _MeshData.AddVertex(aggregatePositionNormal
                                        + ((unaryTraversalShiftedMask & compressedVertices[2])
                                           | ((((compressedVertices[2] >> traversalNormalShift) * traversals) << traversalNormalShift)
                                              & traversalShiftedMask)));
                    _MeshData.AddVertex(compressedUv & (int.MaxValue << GenerationConstants.CHUNK_SIZE_BIT_SHIFT));


                    _MeshData.AddVertex(aggregatePositionNormal
                                        + ((unaryTraversalShiftedMask & compressedVertices[1])
                                           | ((((compressedVertices[1] >> traversalNormalShift) * traversals) << traversalNormalShift)
                                              & traversalShiftedMask)));
                    _MeshData.AddVertex(compressedUv & ~(GenerationConstants.CHUNK_SIZE_BIT_MASK << GenerationConstants.CHUNK_SIZE_BIT_SHIFT));


                    _MeshData.AddVertex(aggregatePositionNormal
                                        + ((unaryTraversalShiftedMask & compressedVertices[0])
                                           | ((((compressedVertices[0] >> traversalNormalShift) * traversals) << traversalNormalShift)
                                              & traversalShiftedMask)));
                    _MeshData.AddVertex(compressedUv & int.MaxValue);

                    break;
                }
            }
        }