Weltkarte: tile-basiertes Rendering, Hires-Chunks, 5 Zoom-Stufen

- Durchschnittliche Kachel-Farben (terrainColorMap, 2048px) als Basis für Low-Res-Ansicht
- Bilineares Splatmap-Blending (blendTileAvgColors) statt Nearest-Neighbor
- Chunk-basierte Hires-Karte (8192px, 256 Chunks à 512px) auf Disk gecacht
- Zoom-Stufen 0–2: Overview-Bild; Stufen 3–4: Hires-Chunks per LRU-Cache
- 5 geometrisch verteilte Zoom-Stufen (Fit-All bis 0,25m/Pixel)
- Klippen-Erkennung per Steigungswinkel (1,5m Sampling-Distanz, harter 30°-Schwellwert)
- Leichter Box-Blur (Radius 2) über Terrain-Layer
- Wasserfarbe in Hires-Chunks vereinheitlicht (WATER_COLOR)
- Kein Hillshading

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-09-03 10:39:23 +02:00
parent 43829a42f3
commit abf56f81b6
5 changed files with 477 additions and 413 deletions

View File

@@ -40,7 +40,9 @@ import de.blight.common.PlacedLocationZone;
import de.blight.common.PlacedModel;
import de.blight.common.PlacedModelIO;
import de.blight.common.PlacedWater;
import de.blight.common.PlacedWaterfall;
import de.blight.common.WaterBodyIO;
import de.blight.common.WaterfallIO;
import de.blight.common.map.WorldMapRenderer;
import de.blight.common.map.WorldMapRenderer.RenderInput;
import de.blight.common.map.WorldMapRenderer.RenderOptions;
@@ -546,30 +548,22 @@ public class MinimapState extends BaseAppState {
List<Location> locs = LocationIO.load();
List<PlacedWater> waters = WaterBodyIO.load();
List<PlacedModel> models = PlacedModelIO.load();
List<PlacedWaterfall> waterfalls = WaterfallIO.load();
int[] slotColors = computeSlotColors(mapData, root);
int[][] tilePixels = WorldMapRenderer.loadMapTiles(root);
renderInput = new RenderInput(mapData, areas, zones, locs, waters, models, slotColors);
de.blight.common.map.WorldMapRenderModel renderModel = new de.blight.common.map.WorldMapRenderModel(
mapData, areas, zones, locs, waters, models, waterfalls,
slotColors, null, null, null, null, null, tilePixels, null);
log.debug("[Minimap] Render-Modell bereit – {} Areas, {} Orte, {} Wasser ({} ms)",
areas.size(), locs.size(), waters.size(), System.currentTimeMillis() - t0);
boolean needsRender = !Files.exists(png);
if (!needsRender) {
// Cache ungültig wenn Karte neuer als das PNG
try {
long pngMod = Files.getLastModifiedTime(png).toMillis();
long mapMod = Files.getLastModifiedTime(MapIO.getMapPath()).toMillis();
if (mapMod > pngMod) { needsRender = true; }
} catch (Exception ignored) { needsRender = true; }
}
if (needsRender) {
log.info("[Minimap] Rendere Weltkarte {}×{}…", TEXTURE_SIZE, TEXTURE_SIZE);
long t1 = System.currentTimeMillis();
BufferedImage bi = WorldMapRenderer.render(renderInput, TEXTURE_SIZE, RenderOptions.all());
ImageIO.write(bi, "PNG", png.toFile());
log.debug("[Minimap] Weltkarte gerendert und gespeichert ({} ms): {}",
System.currentTimeMillis() - t1, png);
} else {
log.info("[Minimap] Gecachte Weltkarte: {}", png);
}
log.info("[Minimap] Rendere Weltkarte {}×{}…", TEXTURE_SIZE, TEXTURE_SIZE);
long t1 = System.currentTimeMillis();
BufferedImage bi = WorldMapRenderer.render(renderModel, TEXTURE_SIZE, RenderOptions.all());
ImageIO.write(bi, "PNG", png.toFile());
log.debug("[Minimap] Weltkarte gerendert und gespeichert ({} ms): {}",
System.currentTimeMillis() - t1, png);
app.enqueue(() -> { onTextureReady(); return null; });
} catch (Exception e) {