Example #1
0
            public void Execute(int index)
            {
                int x = JobA.Row(index, tDim);
                int y = JobA.Col(index, tDim);

                // Assign tile data to tilemap
                Color32 tileColor = new Color32(0, 0, 0, 0);

                // Get sample tile data
                byte tile = tilemapData[JobA.Idx(x, y, tDim)];

                // Convert from [flip,rotate,6bit-record] => [6bit-record,flip,rotate]
                int record;

                if (tile == byte.MaxValue)
                {   // Zeros are converted to FF so assign tiles doesn't overwrite location tiles, convert back.
                    record = 0;
                }
                else
                {
                    record = tile * 4;
                    if ((tile & rotBit) != 0)
                    {
                        record += 1;
                    }
                    if ((tile & flipBit) != 0)
                    {
                        record += 2;
                    }
                }

                // Assign to tileMap
                tileColor.r           = tileColor.a = (byte)record;
                tileMap[y * tDim + x] = tileColor;
            }
        /// <summary>
        /// Complete terrain data update using jobs system. (second of a two stage process)
        /// </summary>
        /// <param name="terrainTexturing">Instance of ITerrainTexturing implementation class to use.</param>
        public void CompleteMapPixelDataUpdate(ITerrainTexturing terrainTexturing = null)
        {
            // Convert heightmap data back to standard managed 2d array.
            MapData.heightmapSamples = new float[heightmapDim, heightmapDim];
            for (int i = 0; i < MapData.heightmapData.Length; i++)
            {
                MapData.heightmapSamples[JobA.Row(i, heightmapDim), JobA.Col(i, heightmapDim)] = MapData.heightmapData[i];
            }

            // Convert tilemap data back to standard managed 2d array.
            // (Still needed for nature layout so it can be called again without requiring terrain data generation)
            MapData.tilemapSamples = new byte[tilemapDim, tilemapDim];
            for (int i = 0; i < MapData.tilemapData.Length; i++)
            {
                byte tile = MapData.tilemapData[i];
                if (tile == byte.MaxValue)
                {
                    tile = 0;
                }
                MapData.tilemapSamples[JobA.Row(i, tilemapDim), JobA.Col(i, tilemapDim)] = tile;
            }

            // Create tileMap array or resize if needed and copy native array.
            if (TileMap == null || TileMap.Length != MapData.tileMap.Length)
            {
                TileMap = new Color32[MapData.tileMap.Length];
            }
            MapData.tileMap.CopyTo(TileMap);

            // Copy max and avg heights. (TODO: Are these needed? Seem to not be used anywhere)
            MapData.averageHeight = MapData.avgMaxHeight[TerrainHelper.avgHeightIdx];
            MapData.maxHeight     = MapData.avgMaxHeight[TerrainHelper.maxHeightIdx];

            DisposeNativeMemory();
        }
            public void Execute(int index)
            {
                int x = JobA.Row(index, tdDim);
                int y = JobA.Col(index, tdDim);

                // Height sample for ocean and beach tiles
                int   hx     = (int)Mathf.Clamp(hDim * ((float)x / (float)tdDim), 0, hDim - 1);
                int   hy     = (int)Mathf.Clamp(hDim * ((float)y / (float)tdDim), 0, hDim - 1);
                float height = heightmapData[JobA.Idx(hy, hx, hDim)] * maxTerrainHeight;  // x & y swapped in heightmap for TerrainData.SetHeights()

                // Ocean texture
                if (height <= oceanElevation)
                {
                    tileData[index] = water;
                    return;
                }
                // Beach texture
                // Adds a little +/- randomness to threshold so beach line isn't too regular
                if (height <= beachElevation + (JobRand.Next(-15000000, 15000000) / 10000000f))
                {
                    tileData[index] = dirt;
                    return;
                }

                // Get latitude and longitude of this tile
                int latitude  = (int)(mapPixelX * MapsFile.WorldMapTileDim + x);
                int longitude = (int)(MapsFile.MaxWorldTileCoordZ - mapPixelY * MapsFile.WorldMapTileDim + y);

                // Set texture tile using weighted noise
                float weight = 0;

                weight += NoiseWeight(latitude, longitude);
                // TODO: Add other weights to influence texture tile generation
                tileData[index] = GetWeightedRecord(weight);
            }
            public void Execute(int index)
            {
                int x = JobA.Row(index, tDim);
                int y = JobA.Col(index, tDim);

                // Do nothing if in location rect as texture already set, to 0xFF if zero
                if (tilemapData[index] != 0)
                {
                    return;
                }

                // Assign tile texture
                if (march)
                {
                    // Get sample points
                    int tdIdx = JobA.Idx(x, y, tdDim);
                    int b0    = tileData[tdIdx];             // tileData[x, y]
                    int b1    = tileData[tdIdx + 1];         // tileData[x + 1, y]
                    int b2    = tileData[tdIdx + tdDim];     // tileData[x, y + 1]
                    int b3    = tileData[tdIdx + tdDim + 1]; // tileData[x + 1, y + 1]

                    int shape  = (b0 & 1) | (b1 & 1) << 1 | (b2 & 1) << 2 | (b3 & 1) << 3;
                    int ring   = (b0 + b1 + b2 + b3) >> 2;
                    int tileID = shape | ring << 4;

                    tilemapData[index] = lookupTable[tileID];
                }
                else
                {
                    tilemapData[index] = tileData[JobA.Idx(x, y, tdDim)];
                }
            }
            public void Execute(int index)
            {
                // Use cols=x and rows=y for height data
                int x = JobA.Col(index, hDim);
                int y = JobA.Row(index, hDim);

                float rx           = (float)x / div;
                float ry           = (float)y / div;
                int   ix           = Mathf.FloorToInt(rx);
                int   iy           = Mathf.FloorToInt(ry);
                float sfracx       = (float)x / (float)(hDim - 1);
                float sfracy       = (float)y / (float)(hDim - 1);
                float fracx        = (float)(x - ix * div) / div;
                float fracy        = (float)(y - iy * div) / div;
                float scaledHeight = 0;

                // Bicubic sample small height map for base terrain elevation
                x1            = TerrainHelper.CubicInterpolator(shm[JobA.Idx(0, 3, sd)], shm[JobA.Idx(1, 3, sd)], shm[JobA.Idx(2, 3, sd)], shm[JobA.Idx(3, 3, sd)], sfracx);
                x2            = TerrainHelper.CubicInterpolator(shm[JobA.Idx(0, 2, sd)], shm[JobA.Idx(1, 2, sd)], shm[JobA.Idx(2, 2, sd)], shm[JobA.Idx(3, 2, sd)], sfracx);
                x3            = TerrainHelper.CubicInterpolator(shm[JobA.Idx(0, 1, sd)], shm[JobA.Idx(1, 1, sd)], shm[JobA.Idx(2, 1, sd)], shm[JobA.Idx(3, 1, sd)], sfracx);
                x4            = TerrainHelper.CubicInterpolator(shm[JobA.Idx(0, 0, sd)], shm[JobA.Idx(1, 0, sd)], shm[JobA.Idx(2, 0, sd)], shm[JobA.Idx(3, 0, sd)], sfracx);
                baseHeight    = TerrainHelper.CubicInterpolator(x1, x2, x3, x4, sfracy);
                scaledHeight += baseHeight * baseHeightScale;

                // Bicubic sample large height map for noise mask over terrain features
                x1            = TerrainHelper.CubicInterpolator(lhm[JobA.Idx(ix, iy + 0, ld)], lhm[JobA.Idx(ix + 1, iy + 0, ld)], lhm[JobA.Idx(ix + 2, iy + 0, ld)], lhm[JobA.Idx(ix + 3, iy + 0, ld)], fracx);
                x2            = TerrainHelper.CubicInterpolator(lhm[JobA.Idx(ix, iy + 1, ld)], lhm[JobA.Idx(ix + 1, iy + 1, ld)], lhm[JobA.Idx(ix + 2, iy + 1, ld)], lhm[JobA.Idx(ix + 3, iy + 1, ld)], fracx);
                x3            = TerrainHelper.CubicInterpolator(lhm[JobA.Idx(ix, iy + 2, ld)], lhm[JobA.Idx(ix + 1, iy + 2, ld)], lhm[JobA.Idx(ix + 2, iy + 2, ld)], lhm[JobA.Idx(ix + 3, iy + 2, ld)], fracx);
                x4            = TerrainHelper.CubicInterpolator(lhm[JobA.Idx(ix, iy + 3, ld)], lhm[JobA.Idx(ix + 1, iy + 3, ld)], lhm[JobA.Idx(ix + 2, iy + 3, ld)], lhm[JobA.Idx(ix + 3, iy + 3, ld)], fracx);
                noiseHeight   = TerrainHelper.CubicInterpolator(x1, x2, x3, x4, fracy);
                scaledHeight += noiseHeight * noiseMapScale;

                // Additional noise mask for small terrain features at ground level
                int   noisex   = mapPixelX * (hDim - 1) + x;
                int   noisey   = (MapsFile.MaxMapPixelY - mapPixelY) * (hDim - 1) + y;
                float lowFreq  = TerrainHelper.GetNoise(noisex, noisey, 0.3f, 0.5f, 0.5f, 1);
                float highFreq = TerrainHelper.GetNoise(noisex, noisey, 0.9f, 0.5f, 0.5f, 1);

                scaledHeight += (lowFreq * highFreq) * extraNoiseScale;

                // Clamp lower values to ocean elevation
                if (scaledHeight < scaledOceanElevation)
                {
                    scaledHeight = scaledOceanElevation;
                }

                // Set sample
                float height = Mathf.Clamp01(scaledHeight / maxTerrainHeight);

                heightmapData[index] = height;
            }
Example #6
0
        // Makes terrain sampler implementations backwards compatible with jobs system terrain data generation.
        public virtual JobHandle ScheduleGenerateSamplesJob(ref MapPixelData mapPixel)
        {
            GenerateSamples(ref mapPixel);

            // Convert generated samples to the flattened native array used by jobs.
            int hDim = HeightmapDimension;

            for (int y = 0; y < hDim; y++)
            {
                for (int x = 0; x < hDim; x++)
                {
                    mapPixel.heightmapData[JobA.Idx(y, x, hDim)] = mapPixel.heightmapSamples[y, x];
                }
            }
            return(new JobHandle());
        }
Example #7
0
            public void Execute()
            {
                // Convert from rect in tilemap space to interior corners in 0-1 range
                float xMin = locationRect.xMin / MapsFile.WorldMapTileDim;
                float xMax = locationRect.xMax / MapsFile.WorldMapTileDim;
                float yMin = locationRect.yMin / MapsFile.WorldMapTileDim;
                float yMax = locationRect.yMax / MapsFile.WorldMapTileDim;

                // Scale values for converting blend space into 0-1 range
                float leftScale   = 1 / xMin;
                float rightScale  = 1 / (1 - xMax);
                float topScale    = 1 / yMin;
                float bottomScale = 1 / (1 - yMax);

                // Flatten location area and blend with surrounding heights
                float strength     = 0;
                float targetHeight = avgMaxHeight[avgHeightIdx];

                for (int y = 0; y < hDim; y++)
                {
                    float v       = (float)y / (float)(hDim - 1);
                    bool  insideY = (v >= yMin && v <= yMax);

                    for (int x = 0; x < hDim; x++)
                    {
                        float u       = (float)x / (float)(hDim - 1);
                        bool  insideX = (u >= xMin && u <= xMax);


                        if (insideX || insideY)
                        {
                            if (insideY && u <= xMin)
                            {
                                strength = u * leftScale;
                            }
                            else if (insideY && u >= xMax)
                            {
                                strength = (1 - u) * rightScale;
                            }
                            else if (insideX && v <= yMin)
                            {
                                strength = v * topScale;
                            }
                            else if (insideX && v >= yMax)
                            {
                                strength = (1 - v) * bottomScale;
                            }
                        }
                        else
                        {
                            float xs = 0, ys = 0;
                            if (u <= xMin)
                            {
                                xs = u * leftScale;
                            }
                            else if (u >= xMax)
                            {
                                xs = (1 - u) * rightScale;
                            }
                            if (v <= yMin)
                            {
                                ys = v * topScale;
                            }
                            else if (v >= yMax)
                            {
                                ys = (1 - v) * bottomScale;
                            }
                            strength = TerrainHelper.BilinearInterpolator(0, 0, 0, 1, xs, ys);
                        }

                        int   idx    = JobA.Idx(y, x, hDim);
                        float height = heightmapData[idx];

                        if (insideX && insideY)
                        {
                            height = targetHeight;
                        }
                        else
                        {
                            height = Mathf.Lerp(height, targetHeight, strength);
                        }

                        heightmapData[idx] = height;
                    }
                }
            }
Example #8
0
        // Set location tilemap data
        public static void SetLocationTiles(ref MapPixelData mapPixel)
        {
            // Get location
            DaggerfallUnity dfUnity  = DaggerfallUnity.Instance;
            DFLocation      location = dfUnity.ContentReader.MapFileReader.GetLocation(mapPixel.mapRegionIndex, mapPixel.mapLocationIndex);

            // Position tiles inside terrain area
            DFPosition tilePos = TerrainHelper.GetLocationTerrainTileOrigin(location);

            // Full 8x8 locations have "terrain blend space" around walls to smooth down random terrain towards flat area.
            // This is indicated by texture index > 55 (ground texture range is 0-55), larger values indicate blend space.
            // We need to know rect of actual city area so we can use blend space outside walls.
            int xmin = int.MaxValue, ymin = int.MaxValue;
            int xmax = 0, ymax = 0;

            // Iterate blocks of this location
            for (int blockY = 0; blockY < location.Exterior.ExteriorData.Height; blockY++)
            {
                for (int blockX = 0; blockX < location.Exterior.ExteriorData.Width; blockX++)
                {
                    // Get block data
                    DFBlock block;
                    string  blockName = dfUnity.ContentReader.MapFileReader.GetRmbBlockName(ref location, blockX, blockY);
                    if (!dfUnity.ContentReader.GetBlock(blockName, out block))
                    {
                        continue;
                    }

                    // Copy ground tile info
                    for (int tileY = 0; tileY < RMBLayout.RMBTilesPerBlock; tileY++)
                    {
                        for (int tileX = 0; tileX < RMBLayout.RMBTilesPerBlock; tileX++)
                        {
                            DFBlock.RmbGroundTiles tile = block.RmbBlock.FldHeader.GroundData.GroundTiles[tileX, (RMBLayout.RMBTilesPerBlock - 1) - tileY];
                            int xpos = tilePos.X + blockX * RMBLayout.RMBTilesPerBlock + tileX;
                            int ypos = tilePos.Y + blockY * RMBLayout.RMBTilesPerBlock + tileY;

                            if (tile.TextureRecord < 56)
                            {
                                // Track interior bounds of location tiled area
                                if (xpos < xmin)
                                {
                                    xmin = xpos;
                                }
                                if (xpos > xmax)
                                {
                                    xmax = xpos;
                                }
                                if (ypos < ymin)
                                {
                                    ymin = ypos;
                                }
                                if (ypos > ymax)
                                {
                                    ymax = ypos;
                                }

                                // Store texture data from block
                                mapPixel.tilemapData[JobA.Idx(xpos, ypos, MapsFile.WorldMapTileDim)] = tile.TileBitfield == 0 ? byte.MaxValue : tile.TileBitfield;
                            }
                        }
                    }
                }
            }

            // Update location rect with extra clearance
            int  extraClearance = location.MapTableData.LocationType == DFRegion.LocationTypes.TownCity ? 3 : 2;
            Rect locationRect   = new Rect();

            locationRect.xMin     = xmin - extraClearance;
            locationRect.xMax     = xmax + extraClearance;
            locationRect.yMin     = ymin - extraClearance;
            locationRect.yMax     = ymax + extraClearance;
            mapPixel.locationRect = locationRect;
        }