void CacheTileData(ITerrainSampler terrainSampler, ref MapPixelData mapData) { // Create array if required int dim = MapsFile.WorldMapTileDim + 1; if (tileData == null) { tileData = new int[dim, dim]; } // Populate array with tile metadata for (int y = 0; y < dim; y++) { for (int x = 0; x < dim; x++) { // Height sample for ocean and beach tiles float height = TerrainHelper.GetClampedHeight( ref mapData, terrainSampler.HeightmapDimension, (float)x / (float)dim, (float)y / (float)dim) * terrainSampler.MaxTerrainHeight; // Ocean texture if (height <= terrainSampler.OceanElevation) { tileData[x, y] = water; continue; } // Get latitude and longitude of this tile int latitude = (int)(mapData.mapPixelX * MapsFile.WorldMapTileDim + x); int longitude = (int)(MapsFile.MaxWorldTileCoordZ - mapData.mapPixelY * MapsFile.WorldMapTileDim + y); // Beach texture // Adds a little +/- randomness to threshold so beach line isn't too regular if (height <= terrainSampler.BeachElevation + UnityEngine.Random.Range(-1.5f, 1.5f)) { tileData[x, y] = dirt; continue; } // Set texture tile using weighted noise float weight = 0; weight += NoiseWeight(latitude, longitude); // TODO: Add other weights to influence texture tile generation tileData[x, y] = GetWeightedRecord(weight); } } }
/// <summary> /// Works exactly like the default TerrainTexturer, except that it skips the GenerateTileDataJob /// and uses the tileData generated during terrain sampling instead. /// Use the mod messaging system to obtain tileData for a map pixel in a custom TerrainTexturer. /// </summary> /// /// To access tileData in a separate mod, you can use this code: /// <code> /// byte[] tData = null; /// ModManager.Instance.SendModMessage("Interesting Terrains", "getTileData", new int[] { mapData.mapPixelX, mapData.mapPixelY }, (string message, object data) => /// { /// if (message == "error") /// Debug.LogError(data as string); /// else /// tData = data as byte[]; /// }); /// </code> public override JobHandle ScheduleAssignTilesJob(ITerrainSampler terrainSampler, ref MapPixelData mapData, JobHandle dependencies, bool march = true) { // Load tile data generated by the Terrain Sampler var tData = InterestingTerrains.tileDataCache.Get(mapData.mapPixelX, mapData.mapPixelY); NativeArray <byte> tileData = new NativeArray <byte>(tData, Allocator.TempJob); // Schedule the paint roads jobs if basic roads mod is enabled JobHandle preAssignTilesHandle = dependencies; if (CompatibilityUtils.BasicRoadsLoaded) { ModManager.Instance.SendModMessage("BasicRoads", "scheduleRoadsJob", new object[] { mapData, tileData, dependencies }, (string message, object data) => { if (message == "error") { Debug.LogError(data as string); } else { preAssignTilesHandle = (JobHandle)data; } }); } // Assign tile data to terrain NativeArray <byte> lookupData = new NativeArray <byte>(lookupTable, Allocator.TempJob); AssignTilesJob assignTilesJob = new AssignTilesJob { lookupTable = lookupData, tileData = tileData, tilemapData = mapData.tilemapData, tdDim = tileDataDim, tDim = assignTilesDim, march = march, locationRect = mapData.locationRect, }; JobHandle assignTilesHandle = assignTilesJob.Schedule(assignTilesDim * assignTilesDim, 64, preAssignTilesHandle); // Add both working native arrays to disposal list. mapData.nativeArrayList.Add(tileData); mapData.nativeArrayList.Add(lookupData); return(assignTilesHandle); }
// Very basic marching squares for water > dirt > grass > stone transitions. // Cannot handle water > grass or water > stone, etc. // Will improve this at later date to use a wider range of transitions. public void AssignTiles(ITerrainSampler terrainSampler, ref MapPixelData mapData, bool march = true) { // Cache tile data to minimise noise sampling CacheTileData(terrainSampler, ref mapData); // Assign tile data to terrain int dim = TerrainHelper.terrainSampleDim; for (int y = 0; y < dim; y++) { for (int x = 0; x < dim; x++) { int offset = y * dim + x; // Do nothing if location tile as texture already set if (mapData.samples[offset].location) { continue; } // Assign tile texture if (march) { // Get sample points int b0 = tileData[x, y]; int b1 = tileData[x + 1, y]; int b2 = tileData[x, y + 1]; int b3 = 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; byte val = lookupTable[tileID]; mapData.samples[offset].record = val & 63; mapData.samples[offset].rotate = ((val & 64) == 64); mapData.samples[offset].flip = ((val & 128) == 128); } else { mapData.samples[offset].record = tileData[x, y]; } } } }
// Very basic marching squares for water > dirt > grass > stone transitions. // Cannot handle water > grass or water > stone, etc. // Will improve this at later date to use a wider range of transitions. public void AssignTiles(ITerrainSampler terrainSampler, ref MapPixelData mapData, bool march = true) { // Cache tile data to minimise noise sampling CacheTileData(terrainSampler, ref mapData); // Assign tile data to terrain int dim = TerrainHelper.terrainSampleDim; for (int y = 0; y < dim; y++) { for (int x = 0; x < dim; x++) { int offset = y * dim + x; // Do nothing if location tile as texture already set if (mapData.samples[offset].location) continue; // Assign tile texture if (march) { // Get sample points int b0 = tileData[x, y]; int b1 = tileData[x + 1, y]; int b2 = tileData[x, y + 1]; int b3 = 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; byte val = lookupTable[tileID]; mapData.samples[offset].record = val & 63; mapData.samples[offset].rotate = ((val & 64) == 64); mapData.samples[offset].flip = ((val & 128) == 128); } else { mapData.samples[offset].record = tileData[x, y]; } } } }
public override JobHandle ScheduleAssignTilesJob(ITerrainSampler terrainSampler, ref MapPixelData mapData, JobHandle dependencies, bool march = true) { // Cache tile data to minimise noise sampling during march (using default job) NativeArray <byte> tileData = new NativeArray <byte>(tileDataDim * tileDataDim, Allocator.TempJob); GenerateTileDataJob tileDataJob = new GenerateTileDataJob { heightmapData = mapData.heightmapData, tileData = tileData, tdDim = tileDataDim, hDim = terrainSampler.HeightmapDimension, maxTerrainHeight = terrainSampler.MaxTerrainHeight, oceanElevation = terrainSampler.OceanElevation, beachElevation = terrainSampler.BeachElevation, mapPixelX = mapData.mapPixelX, mapPixelY = mapData.mapPixelY, }; JobHandle tileDataHandle = tileDataJob.Schedule(tileDataDim * tileDataDim, 64, dependencies); // Schedule painting of roads, including smoothing if enabled JobHandle paintRoadsHandle = SchedulePaintRoadsJob(ref mapData, ref tileData, tileDataHandle); // Assign tile data to terrain (using default job) NativeArray <byte> lookupData = new NativeArray <byte>(lookupTable, Allocator.TempJob); AssignTilesJob assignTilesJob = new AssignTilesJob { lookupTable = lookupData, tileData = tileData, tilemapData = mapData.tilemapData, tdDim = tileDataDim, tDim = assignTilesDim, march = march, locationRect = mapData.locationRect, }; JobHandle assignTilesHandle = assignTilesJob.Schedule(assignTilesDim * assignTilesDim, 64, paintRoadsHandle); // Add both working native arrays to disposal list. mapData.nativeArrayList.Add(tileData); mapData.nativeArrayList.Add(lookupData); return(assignTilesHandle); }
void CacheTileData(ITerrainSampler terrainSampler, ref MapPixelData mapData) { // Create array if required int dim = MapsFile.WorldMapTileDim + 1; if (tileData == null) tileData = new int[dim, dim]; // Populate array with tile metadata for (int y = 0; y < dim; y++) { for (int x = 0; x < dim; x++) { // Height sample for ocean and beach tiles float height = TerrainHelper.GetClampedHeight( ref mapData, terrainSampler.HeightmapDimension, (float)x / (float)dim, (float)y / (float)dim) * terrainSampler.MaxTerrainHeight; // Ocean texture if (height <= terrainSampler.OceanElevation) { tileData[x, y] = water; continue; } // Get latitude and longitude of this tile int latitude = (int)(mapData.mapPixelX * MapsFile.WorldMapTileDim + x); int longitude = (int)(MapsFile.MaxWorldTileCoordZ - mapData.mapPixelY * MapsFile.WorldMapTileDim + y); // Beach texture // Adds a little +/- randomness to threshold so beach line isn't too regular if (height <= terrainSampler.BeachElevation + UnityEngine.Random.Range(-1.5f, 1.5f)) { tileData[x, y] = dirt; continue; } // Set texture tile using weighted noise float weight = 0; weight += NoiseWeight(latitude, longitude); // TODO: Add other weights to influence texture tile generation tileData[x, y] = GetWeightedRecord(weight); } } }
public override JobHandle ScheduleAssignTilesJob(ITerrainSampler terrainSampler, ref MapPixelData mapData, JobHandle dependencies, bool march = true) { // Cache tile data to minimise noise sampling during march. NativeArray <byte> tileData = new NativeArray <byte>(tileDataDim * tileDataDim, Allocator.TempJob); GenerateTileDataJob tileDataJob = new GenerateTileDataJob { heightmapData = mapData.heightmapData, tileData = tileData, tdDim = tileDataDim, hDim = terrainSampler.HeightmapDimension, maxTerrainHeight = terrainSampler.MaxTerrainHeight, oceanElevation = terrainSampler.OceanElevation, beachElevation = terrainSampler.BeachElevation, mapPixelX = mapData.mapPixelX, mapPixelY = mapData.mapPixelY, }; JobHandle tileDataHandle = tileDataJob.Schedule(tileDataDim * tileDataDim, 64, dependencies); // Assign tile data to terrain, painting paths in the process int pathsIndex = mapData.mapPixelX + (mapData.mapPixelY * MapsFile.MaxMapPixelX); byte roadDataPt = pathsData[roads][pathsIndex]; byte roadCorners = (byte)(InRange(pathsIndex) ? (pathsData[roads][pathsIndex + 1] & 0x5) | (pathsData[roads][pathsIndex - 1] & 0x50) : 0); byte trackDataPt = pathsData[tracks][pathsIndex]; byte trackCorners = (byte)(InRange(pathsIndex) ? (pathsData[tracks][pathsIndex + 1] & 0x5) | (pathsData[tracks][pathsIndex - 1] & 0x50) : 0); if (editorEnabled) { roadDataPt = BasicRoadsPathEditor.pathsData[roads][pathsIndex]; roadCorners = (byte)(InRange(pathsIndex) ? (BasicRoadsPathEditor.pathsData[roads][pathsIndex + 1] & 0x5) | (BasicRoadsPathEditor.pathsData[roads][pathsIndex - 1] & 0x50) : 0); trackDataPt = BasicRoadsPathEditor.pathsData[tracks][pathsIndex]; trackCorners = (byte)(InRange(pathsIndex) ? (BasicRoadsPathEditor.pathsData[tracks][pathsIndex + 1] & 0x5) | (BasicRoadsPathEditor.pathsData[tracks][pathsIndex - 1] & 0x50) : 0); } NativeArray <byte> lookupData = new NativeArray <byte>(lookupTable, Allocator.TempJob); AssignTilesWithRoadsJob assignTilesJob = new AssignTilesWithRoadsJob { lookupTable = lookupData, tileData = tileData, tilemapData = mapData.tilemapData, tdDim = tileDataDim, tDim = assignTilesDim, hDim = terrainSampler.HeightmapDimension, march = march, locationRect = mapData.locationRect, midLo = (assignTilesDim / 2) - 1, midHi = assignTilesDim / 2, roadDataPt = roadDataPt, roadCorners = roadCorners, trackDataPt = trackDataPt, trackCorners = trackCorners, }; JobHandle assignTilesHandle = assignTilesJob.Schedule(assignTilesDim * assignTilesDim, 64, tileDataHandle); JobHandle returnHandle = assignTilesHandle; if (smoothPaths) { SmoothRoadsTerrainJob smoothRoadTerrainJob = new SmoothRoadsTerrainJob() { heightmapData = mapData.heightmapData, tilemapData = mapData.tilemapData, hDim = DaggerfallUnity.Instance.TerrainSampler.HeightmapDimension, tDim = assignTilesDim, locationRect = mapData.locationRect, }; JobHandle smoothRoadHandle = smoothRoadTerrainJob.Schedule(assignTilesHandle); returnHandle = smoothRoadHandle; } // Add both working native arrays to disposal list. mapData.nativeArrayList.Add(tileData); mapData.nativeArrayList.Add(lookupData); return(returnHandle); }
public virtual JobHandle ScheduleAssignTilesJob(ITerrainSampler terrainSampler, ref MapPixelData mapData, JobHandle dependencies, bool march = true) { // Cache tile data to minimise noise sampling during march. NativeArray <byte> tileData = new NativeArray <byte>(tileDataDim * tileDataDim, Allocator.TempJob); currentMapData = mapData; GenerateTileDataJob tileDataJob = new GenerateTileDataJob { heightmapData = mapData.heightmapData, tileData = tileData, tdDim = tileDataDim, hDim = terrainSampler.HeightmapDimension, maxTerrainHeight = terrainSampler.MaxTerrainHeight, oceanElevation = terrainSampler.OceanElevation, beachElevation = terrainSampler.BeachElevation, mapPixelX = mapData.mapPixelX, mapPixelY = mapData.mapPixelY, worldClimate = mapData.worldClimate, }; JobHandle tileDataHandle = tileDataJob.Schedule(tileDataDim * tileDataDim, 64, dependencies); // Schedule the paint roads jobs if basic roads mod is enabled JobHandle preAssignTilesHandle = tileDataHandle; if (basicRoadsEnabled) { ModManager.Instance.SendModMessage("BasicRoads", "scheduleRoadsJob", new object[] { mapData, tileData, tileDataHandle }, (string message, object data) => { if (message == "error") { Debug.LogError(data as string); } else { preAssignTilesHandle = (JobHandle)data; } }); } // Assign tile data to terrain NativeArray <byte> lookupData = new NativeArray <byte>(lookupTable, Allocator.TempJob); AssignTilesJob assignTilesJob = new AssignTilesJob { lookupTable = lookupData, tileData = tileData, tilemapData = mapData.tilemapData, tdDim = tileDataDim, tDim = assignTilesDim, march = march, locationRect = mapData.locationRect, }; JobHandle assignTilesHandle = assignTilesJob.Schedule(assignTilesDim * assignTilesDim, 64, preAssignTilesHandle); // Add both working native arrays to disposal list. mapData.nativeArrayList.Add(tileData); mapData.nativeArrayList.Add(lookupData); return(assignTilesHandle); }