/// <summary> /// Adds highlights and shadows to the solid stone color in the texture /// </summary> private static void AddBevelToSolidStone(ThreadableTexture tex) { for (int x = 0; x < tex.width; x++) { for (int y = 0; y < tex.height; y++) { var isStone = tex.GetPixel(x, y) == solidStoneColor; if (isStone) { var colorBelow = y > 0 ? tex.GetPixel(x, y - 1) : Color.clear; var isStoneBelow = colorBelow == solidStoneColor || colorBelow == solidStoneHighlightColor || colorBelow == solidStoneShadowColor; var isStoneAbove = y < tex.height - 1 && tex.GetPixel(x, y + 1) == solidStoneColor; if (!isStoneAbove) { tex.SetPixel(x, y, solidStoneHighlightColor); } else if (!isStoneBelow) { tex.SetPixel(x, y, solidStoneShadowColor); } } } } }
private void DoThreadWork() { QueuedPreviewRequest request = null; try { while (queuedRequests.Count > 0 || WaitHandle.WaitAny(new WaitHandle[] { workHandle, disposeHandle }) == 0) { Exception rejectException = null; if (queuedRequests.Count > 0) { var req = queuedRequests.Dequeue(); request = req; Texture2D texture = null; int width = 0, height = 0; WaitForExecutionInMainThread(() => { // textures must be instantiated in the main thread texture = new Texture2D(req.MapSize, req.MapSize, TextureFormat.RGB24, false); width = texture.width; height = texture.height; }); ThreadableTexture placeholderTex = null; try { if (texture == null) { throw new Exception("Could not create required texture."); } placeholderTex = new ThreadableTexture(width, height); GeneratePreviewForSeed(req.Seed, req.MapTile, req.MapSize, req.RevealCaves, placeholderTex); } catch (Exception e) { MapRerollController.Instance.Logger.Error("Failed to generate map preview: " + e); rejectException = e; texture = null; } if (texture != null && placeholderTex != null) { WaitForExecutionInMainThread(() => { // upload in main thread placeholderTex.CopyToTexture(texture); texture.Apply(); }); } WaitForExecutionInMainThread(() => { if (texture == null) { req.Promise.Reject(rejectException); } else { req.Promise.Resolve(texture); } }); } } workHandle.Close(); mainThreadHandle.Close(); mainThreadHandle = disposeHandle = workHandle = null; } catch (Exception e) { MapRerollController.Instance.Logger.Error("Exception in preview generator thread: " + e); if (request != null) { request.Promise.Reject(e); } } }
private static void GeneratePreviewForSeed(string seed, int mapTile, int mapSize, bool revealCaves, ThreadableTexture texture) { var prevSeed = Find.World.info.seedString; try { MapRerollController.HasCavesOverride.HasCaves = Find.World.HasCaves(mapTile); MapRerollController.HasCavesOverride.OverrideEnabled = true; Find.World.info.seedString = seed; MapRerollController.RandStateStackCheckingPaused = true; var grids = GenerateMapGrids(mapTile, mapSize, revealCaves); DeepProfiler.Start("generateMapPreviewTexture"); const string terrainGenStepName = "Terrain"; var terrainGenStepDef = DefDatabase <GenStepDef> .GetNamedSilentFail(terrainGenStepName); if (terrainGenStepDef == null) { throw new Exception("Named GenStepDef not found: " + terrainGenStepName); } var terrainGenstep = terrainGenStepDef.genStep; var riverMaker = ReflectionCache.GenStepTerrain_GenerateRiver.Invoke(terrainGenstep, new object[] { grids.Map }); var beachTerrainAtDelegate = (BeachMakerBeachTerrainAt)Delegate.CreateDelegate(typeof(BeachMakerBeachTerrainAt), null, ReflectionCache.BeachMaker_BeachTerrainAt); var riverTerrainAtDelegate = riverMaker == null ? null : (RiverMakerTerrainAt)Delegate.CreateDelegate(typeof(RiverMakerTerrainAt), riverMaker, ReflectionCache.RiverMaker_TerrainAt); ReflectionCache.BeachMaker_Init.Invoke(null, new object[] { grids.Map }); var mapBounds = CellRect.WholeMap(grids.Map); foreach (var cell in mapBounds) { const float rockCutoff = .7f; var terrainDef = TerrainFrom(cell, grids.Map, grids.ElevationGrid[cell], grids.FertilityGrid[cell], riverTerrainAtDelegate, beachTerrainAtDelegate, false); if (!terrainColors.TryGetValue(terrainDef.defName, out Color pixelColor)) { pixelColor = missingTerrainColor; } if (grids.ElevationGrid[cell] > rockCutoff && !terrainDef.IsRiver) { pixelColor = solidStoneColor; if (grids.CavesGrid[cell] > 0) { pixelColor = caveColor; } } texture.SetPixel(cell.x, cell.z, pixelColor); } AddBevelToSolidStone(texture); foreach (var terrainPatchMaker in grids.Map.Biome.terrainPatchMakers) { terrainPatchMaker.Cleanup(); } } catch (Exception e) { MapRerollController.Instance.Logger.ReportException(e, null, false, "preview generation"); } finally { RockNoises.Reset(); DeepProfiler.End(); Find.World.info.seedString = prevSeed; MapRerollController.RandStateStackCheckingPaused = false; MapRerollController.HasCavesOverride.OverrideEnabled = false; try { ReflectionCache.BeachMaker_Cleanup.Invoke(null, null); } catch (Exception e) { MapRerollController.Instance.Logger.ReportException(e, null, false, "BeachMaker preview cleanup"); } } }