Anpassung der KArte

This commit is contained in:
2026-09-03 10:44:59 +02:00
parent abf56f81b6
commit 0bf7725051

View File

@@ -1228,17 +1228,17 @@ public final class WorldMapRenderer {
int[] tileAvg = computeTileAvgColors(tilePixels);
int[] slotTypes = computeSlotTileTypes(m, slotColors);
float cellW = WORLD_SIZE / (SIZE - 1);
int[] result = new int[SIZE * SIZE];
int[] terrainRGB = new int[SIZE * SIZE];
float[] cliffMask = new float[SIZE * SIZE];
for (int py = 0; py < SIZE; py++) {
float wz = -WORLD_HALF + py * cellW;
for (int px = 0; px < SIZE; px++) {
float wx = -WORLD_HALF + px * cellW;
int idx = py * SIZE + px;
float h = heights[idx];
int rgb;
if (h < 0f || (waterH[idx] > 0f && waterH[idx] > h)) {
int[] wc = TILE_FALLBACK_RGB[TILE_WATER];
rgb = (wc[0]<<16)|(wc[1]<<8)|wc[2];
terrainRGB[idx] = (wc[0]<<16)|(wc[1]<<8)|wc[2];
} else {
int dPx = Math.max(1, (int)(1.5f / cellW));
float hR = heights[py * SIZE + Math.min(SIZE-1, px+dPx)];
@@ -1248,14 +1248,23 @@ public final class WorldMapRenderer {
float dist = dPx * cellW;
double slope = Math.toDegrees(Math.atan(Math.sqrt(
Math.pow((hR-hL)/(2*dist),2) + Math.pow((hD-hU)/(2*dist),2))));
if (slope > 30.0) {
rgb = tileAvg[Math.min(TILE_CLIFF, tileAvg.length-1)];
} else {
rgb = blendTileAvgColors(m, SS, wx, wz, tileAvg, slotTypes);
cliffMask[idx] = (slope > 30.0) ? 1f : 0f;
terrainRGB[idx] = blendTileAvgColors(m, SS, wx, wz, tileAvg, slotTypes);
}
}
result[idx] = rgb;
}
// Cliff-Maske weichzeichnen → weiche Klippen-Kanten ohne Änderung der Schwellwert-Logik
float[] softMask = boxBlurFloat(cliffMask, SIZE, 3);
int cliffRgb = tileAvg[Math.min(TILE_CLIFF, tileAvg.length-1)];
int cr = (cliffRgb>>16)&0xFF, cg = (cliffRgb>>8)&0xFF, cb = cliffRgb&0xFF;
int[] result = new int[SIZE * SIZE];
for (int i = 0; i < SIZE * SIZE; i++) {
float t = softMask[i];
int tc = terrainRGB[i];
int r = (tc>>16)&0xFF, g = (tc>>8)&0xFF, b = tc&0xFF;
result[i] = (clamp((int)(r + (cr-r)*t)) << 16)
| (clamp((int)(g + (cg-g)*t)) << 8)
| clamp((int)(b + (cb-b)*t));
}
return boxBlur(result, SIZE, 2);
}
@@ -1295,38 +1304,67 @@ public final class WorldMapRenderer {
float cellW = WORLD_SIZE / (SIZE - 1);
int written = 0;
final int CLIFF_BLUR_R = 4; // Blur-Radius für weiche Klippen-Kanten
final int EXT = CLIFF_BLUR_R;
final int EXTW = CS + 2 * EXT; // erweitertes Fenster inkl. Rand für nahtlosen Blur
int dPxHires = Math.max(1, (int)(1.5f / cellW));
for (int cy = 0; cy < COLS; cy++) {
for (int cx = 0; cx < COLS; cx++) {
java.nio.file.Path p = chunkPath(cacheDir, cx, cy);
if (!forceRegen && Files.exists(p)) continue;
// Chunk-Pixel berechnen
// Erweiterte Cliff-Maske + Terrain-Farben (mit Rand über Chunk-Grenze)
float[] cliffMaskExt = new float[EXTW * EXTW];
boolean[] isWaterExt = new boolean[EXTW * EXTW];
int[] terrainColExt = new int[EXTW * EXTW];
for (int ely = 0; ely < EXTW; ely++) {
int gy = cy * CS + ely - EXT;
int gyC = Math.max(0, Math.min(SIZE-1, gy));
float wz = -WORLD_HALF + gyC * cellW;
for (int elx = 0; elx < EXTW; elx++) {
int gx = cx * CS + elx - EXT;
int gxC = Math.max(0, Math.min(SIZE-1, gx));
float wx = -WORLD_HALF + gxC * cellW;
int eidx = ely * EXTW + elx;
int hidx = gyC * SIZE + gxC;
float h = heights[hidx];
if (h < 0f || (waterH[hidx] > 0f && waterH[hidx] > h)) {
isWaterExt[eidx] = true;
} else {
float hR = heights[gyC * SIZE + Math.min(SIZE-1, gxC+dPxHires)];
float hL = heights[gyC * SIZE + Math.max(0, gxC-dPxHires)];
float hD = heights[Math.min(SIZE-1, gyC+dPxHires) * SIZE + gxC];
float hU = heights[Math.max(0, gyC-dPxHires) * SIZE + gxC];
float dist = dPxHires * cellW;
double slope = Math.toDegrees(Math.atan(Math.sqrt(
Math.pow((hR-hL)/(2*dist),2) + Math.pow((hD-hU)/(2*dist),2))));
cliffMaskExt[eidx] = (slope > 30.0) ? 1f : 0f;
terrainColExt[eidx] = blendTileAvgColors(m, SS, wx, wz, tileAvg, slotTypes);
}
}
}
float[] softMaskExt = boxBlurFloat(cliffMaskExt, EXTW, CLIFF_BLUR_R);
int cliffRgb = tileAvg[Math.min(TILE_CLIFF, tileAvg.length-1)];
int cr = (cliffRgb>>16)&0xFF, cg = (cliffRgb>>8)&0xFF, cb = cliffRgb&0xFF;
// Chunk-Pixel aus dem inneren Bereich der erweiterten Maske zusammensetzen
int[] chunk = new int[CS * CS];
for (int ly = 0; ly < CS; ly++) {
int gy = cy * CS + ly; // globaler Y-Index in der HIRES-Karte
float wz = -WORLD_HALF + gy * cellW;
for (int lx = 0; lx < CS; lx++) {
int gx = cx * CS + lx;
float wx = -WORLD_HALF + gx * cellW;
int idx = gy * SIZE + gx;
float h = heights[idx];
int extIdx = (ly + EXT) * EXTW + (lx + EXT);
int tr, tg, tb;
if (h < 0f || (waterH[idx] > 0f && waterH[idx] > h)) {
if (isWaterExt[extIdx]) {
tr = (WATER_COLOR >> 16) & 0xFF;
tg = (WATER_COLOR >> 8) & 0xFF;
tb = WATER_COLOR & 0xFF;
} else {
int dPx = Math.max(1, (int)(1.5f / cellW));
float hR = heights[gy * SIZE + Math.min(SIZE-1, gx+dPx)];
float hL = heights[gy * SIZE + Math.max(0, gx-dPx)];
float hD = heights[Math.min(SIZE-1, gy+dPx) * SIZE + gx];
float hU = heights[Math.max(0, gy-dPx) * SIZE + gx];
float dist = dPx * cellW;
double slope = Math.toDegrees(Math.atan(Math.sqrt(
Math.pow((hR-hL)/(2*dist),2) + Math.pow((hD-hU)/(2*dist),2))));
int rgb = (slope > 30.0)
? tileAvg[Math.min(TILE_CLIFF, tileAvg.length-1)]
: blendTileAvgColors(m, SS, wx, wz, tileAvg, slotTypes);
tr = (rgb>>16)&0xFF; tg = (rgb>>8)&0xFF; tb = rgb&0xFF;
float t = softMaskExt[extIdx];
int tc = terrainColExt[extIdx];
int r2 = (tc>>16)&0xFF, g2 = (tc>>8)&0xFF, b2 = tc&0xFF;
tr = clamp((int)(r2 + (cr-r2)*t));
tg = clamp((int)(g2 + (cg-g2)*t));
tb = clamp((int)(b2 + (cb-b2)*t));
}
chunk[ly * CS + lx] = (0xFF << 24) | (tr << 16) | (tg << 8) | tb;
}
@@ -1360,6 +1398,32 @@ public final class WorldMapRenderer {
return dir.resolve(String.format("chunk_%02x_%02x.png", cx, cy));
}
/** Separabler Box-Blur auf float-Array (horizontal + vertikal), Radius in Pixeln. */
private static float[] boxBlurFloat(float[] src, int size, int radius) {
float[] tmp = new float[size * size];
float[] dst = new float[size * size];
float inv = 1f / (radius * 2 + 1);
for (int py = 0; py < size; py++) {
for (int px = 0; px < size; px++) {
float sum = 0;
for (int dx = -radius; dx <= radius; dx++) {
sum += src[py * size + Math.max(0, Math.min(size-1, px+dx))];
}
tmp[py * size + px] = sum * inv;
}
}
for (int py = 0; py < size; py++) {
for (int px = 0; px < size; px++) {
float sum = 0;
for (int dz = -radius; dz <= radius; dz++) {
sum += tmp[Math.max(0, Math.min(size-1, py+dz)) * size + px];
}
dst[py * size + px] = sum * inv;
}
}
return dst;
}
/** Separabler Box-Blur (horizontal + vertikal), Radius in Pixeln. */
private static int[] boxBlur(int[] src, int size, int radius) {
int[] tmp = new int[size * size];