mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2026-03-22 15:17:23 +01:00
fix: streamline texture loading and preload logic in WebGL renderer
This commit is contained in:
parent
4515232e93
commit
dc06f3d65c
3 changed files with 130 additions and 147 deletions
106
src/config/relief-config.ts
Normal file
106
src/config/relief-config.ts
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
export const RELIEF_SYMBOLS: Record<string, string[]> = {
|
||||
simple: [
|
||||
"relief-mount-1",
|
||||
"relief-hill-1",
|
||||
"relief-conifer-1",
|
||||
"relief-deciduous-1",
|
||||
"relief-acacia-1",
|
||||
"relief-palm-1",
|
||||
"relief-grass-1",
|
||||
"relief-swamp-1",
|
||||
"relief-dune-1",
|
||||
],
|
||||
gray: [
|
||||
"relief-mount-2-bw",
|
||||
"relief-mount-3-bw",
|
||||
"relief-mount-4-bw",
|
||||
"relief-mount-5-bw",
|
||||
"relief-mount-6-bw",
|
||||
"relief-mount-7-bw",
|
||||
"relief-mountSnow-1-bw",
|
||||
"relief-mountSnow-2-bw",
|
||||
"relief-mountSnow-3-bw",
|
||||
"relief-mountSnow-4-bw",
|
||||
"relief-mountSnow-5-bw",
|
||||
"relief-mountSnow-6-bw",
|
||||
"relief-hill-2-bw",
|
||||
"relief-hill-3-bw",
|
||||
"relief-hill-4-bw",
|
||||
"relief-hill-5-bw",
|
||||
"relief-conifer-2-bw",
|
||||
"relief-coniferSnow-1-bw",
|
||||
"relief-swamp-2-bw",
|
||||
"relief-swamp-3-bw",
|
||||
"relief-cactus-1-bw",
|
||||
"relief-cactus-2-bw",
|
||||
"relief-cactus-3-bw",
|
||||
"relief-deadTree-1-bw",
|
||||
"relief-deadTree-2-bw",
|
||||
"relief-vulcan-1-bw",
|
||||
"relief-vulcan-2-bw",
|
||||
"relief-vulcan-3-bw",
|
||||
"relief-dune-2-bw",
|
||||
"relief-grass-2-bw",
|
||||
"relief-acacia-2-bw",
|
||||
"relief-palm-2-bw",
|
||||
"relief-deciduous-2-bw",
|
||||
"relief-deciduous-3-bw",
|
||||
],
|
||||
colored: [
|
||||
"relief-mount-2",
|
||||
"relief-mount-3",
|
||||
"relief-mount-4",
|
||||
"relief-mount-5",
|
||||
"relief-mount-6",
|
||||
"relief-mount-7",
|
||||
"relief-mountSnow-1",
|
||||
"relief-mountSnow-2",
|
||||
"relief-mountSnow-3",
|
||||
"relief-mountSnow-4",
|
||||
"relief-mountSnow-5",
|
||||
"relief-mountSnow-6",
|
||||
"relief-hill-2",
|
||||
"relief-hill-3",
|
||||
"relief-hill-4",
|
||||
"relief-hill-5",
|
||||
"relief-conifer-2",
|
||||
"relief-coniferSnow-1",
|
||||
"relief-swamp-2",
|
||||
"relief-swamp-3",
|
||||
"relief-cactus-1",
|
||||
"relief-cactus-2",
|
||||
"relief-cactus-3",
|
||||
"relief-deadTree-1",
|
||||
"relief-deadTree-2",
|
||||
"relief-vulcan-1",
|
||||
"relief-vulcan-2",
|
||||
"relief-vulcan-3",
|
||||
"relief-dune-2",
|
||||
"relief-grass-2",
|
||||
"relief-acacia-2",
|
||||
"relief-palm-2",
|
||||
"relief-deciduous-2",
|
||||
"relief-deciduous-3",
|
||||
],
|
||||
};
|
||||
|
||||
export const VARIANT_RANGES: Record<string, [number, number]> = {
|
||||
mount: [2, 7],
|
||||
mountSnow: [1, 6],
|
||||
hill: [2, 5],
|
||||
conifer: [2, 2],
|
||||
coniferSnow: [1, 1],
|
||||
swamp: [2, 3],
|
||||
cactus: [1, 3],
|
||||
deadTree: [1, 2],
|
||||
vulcan: [1, 3],
|
||||
deciduous: [2, 3],
|
||||
};
|
||||
|
||||
export const COLORED_TO_SIMPLE_MAP: Record<string, string> = {
|
||||
mountSnow: "mount",
|
||||
vulcan: "mount",
|
||||
coniferSnow: "conifer",
|
||||
cactus: "dune",
|
||||
deadTree: "dune",
|
||||
};
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
import { extent, polygonContains } from "d3";
|
||||
import { COLORED_TO_SIMPLE_MAP, VARIANT_RANGES } from "../config/relief-config";
|
||||
import {
|
||||
byId,
|
||||
getPackPolygon,
|
||||
|
|
@ -118,127 +119,6 @@ export function generateRelief(): ReliefIcon[] {
|
|||
}
|
||||
}
|
||||
|
||||
// ── Utilities ─────────────────────────────────────────────────────────
|
||||
export const RELIEF_SYMBOLS: Record<string, string[]> = {
|
||||
simple: [
|
||||
"relief-mount-1",
|
||||
"relief-hill-1",
|
||||
"relief-conifer-1",
|
||||
"relief-deciduous-1",
|
||||
"relief-acacia-1",
|
||||
"relief-palm-1",
|
||||
"relief-grass-1",
|
||||
"relief-swamp-1",
|
||||
"relief-dune-1",
|
||||
],
|
||||
gray: [
|
||||
"relief-mount-2-bw",
|
||||
"relief-mount-3-bw",
|
||||
"relief-mount-4-bw",
|
||||
"relief-mount-5-bw",
|
||||
"relief-mount-6-bw",
|
||||
"relief-mount-7-bw",
|
||||
"relief-mountSnow-1-bw",
|
||||
"relief-mountSnow-2-bw",
|
||||
"relief-mountSnow-3-bw",
|
||||
"relief-mountSnow-4-bw",
|
||||
"relief-mountSnow-5-bw",
|
||||
"relief-mountSnow-6-bw",
|
||||
"relief-hill-2-bw",
|
||||
"relief-hill-3-bw",
|
||||
"relief-hill-4-bw",
|
||||
"relief-hill-5-bw",
|
||||
"relief-conifer-2-bw",
|
||||
"relief-coniferSnow-1-bw",
|
||||
"relief-swamp-2-bw",
|
||||
"relief-swamp-3-bw",
|
||||
"relief-cactus-1-bw",
|
||||
"relief-cactus-2-bw",
|
||||
"relief-cactus-3-bw",
|
||||
"relief-deadTree-1-bw",
|
||||
"relief-deadTree-2-bw",
|
||||
"relief-vulcan-1-bw",
|
||||
"relief-vulcan-2-bw",
|
||||
"relief-vulcan-3-bw",
|
||||
"relief-dune-2-bw",
|
||||
"relief-grass-2-bw",
|
||||
"relief-acacia-2-bw",
|
||||
"relief-palm-2-bw",
|
||||
"relief-deciduous-2-bw",
|
||||
"relief-deciduous-3-bw",
|
||||
],
|
||||
colored: [
|
||||
"relief-mount-2",
|
||||
"relief-mount-3",
|
||||
"relief-mount-4",
|
||||
"relief-mount-5",
|
||||
"relief-mount-6",
|
||||
"relief-mount-7",
|
||||
"relief-mountSnow-1",
|
||||
"relief-mountSnow-2",
|
||||
"relief-mountSnow-3",
|
||||
"relief-mountSnow-4",
|
||||
"relief-mountSnow-5",
|
||||
"relief-mountSnow-6",
|
||||
"relief-hill-2",
|
||||
"relief-hill-3",
|
||||
"relief-hill-4",
|
||||
"relief-hill-5",
|
||||
"relief-conifer-2",
|
||||
"relief-coniferSnow-1",
|
||||
"relief-swamp-2",
|
||||
"relief-swamp-3",
|
||||
"relief-cactus-1",
|
||||
"relief-cactus-2",
|
||||
"relief-cactus-3",
|
||||
"relief-deadTree-1",
|
||||
"relief-deadTree-2",
|
||||
"relief-vulcan-1",
|
||||
"relief-vulcan-2",
|
||||
"relief-vulcan-3",
|
||||
"relief-dune-2",
|
||||
"relief-grass-2",
|
||||
"relief-acacia-2",
|
||||
"relief-palm-2",
|
||||
"relief-deciduous-2",
|
||||
"relief-deciduous-3",
|
||||
],
|
||||
};
|
||||
|
||||
// map a symbol href to its atlas set and tile index
|
||||
export function resolveSprite(symbolHref: string): {
|
||||
set: string;
|
||||
tileIndex: number;
|
||||
} {
|
||||
const id = symbolHref.startsWith("#") ? symbolHref.slice(1) : symbolHref;
|
||||
for (const [set, ids] of Object.entries(RELIEF_SYMBOLS)) {
|
||||
const idx = ids.indexOf(id);
|
||||
if (idx !== -1) return { set, tileIndex: idx };
|
||||
}
|
||||
throw new Error(`Relief: unknown symbol href "${symbolHref}"`);
|
||||
}
|
||||
|
||||
const VARIANT_RANGES: Record<string, [number, number]> = {
|
||||
mount: [2, 7],
|
||||
mountSnow: [1, 6],
|
||||
hill: [2, 5],
|
||||
conifer: [2, 2],
|
||||
coniferSnow: [1, 1],
|
||||
swamp: [2, 3],
|
||||
cactus: [1, 3],
|
||||
deadTree: [1, 2],
|
||||
vulcan: [1, 3],
|
||||
deciduous: [2, 3],
|
||||
};
|
||||
|
||||
const COLORED_TO_SIMPLE_MAP: Record<string, string> = {
|
||||
mountSnow: "mount",
|
||||
vulcan: "mount",
|
||||
coniferSnow: "conifer",
|
||||
cactus: "dune",
|
||||
deadTree: "dune",
|
||||
};
|
||||
|
||||
function getVariant(type: string): number {
|
||||
const range = VARIANT_RANGES[type];
|
||||
return range ? rand(...range) : 2;
|
||||
|
|
|
|||
|
|
@ -1,13 +1,9 @@
|
|||
import * as THREE from "three";
|
||||
import { RELIEF_SYMBOLS } from "../config/relief-config";
|
||||
import type { ReliefIcon } from "../modules/relief-generator";
|
||||
import {
|
||||
generateRelief,
|
||||
RELIEF_SYMBOLS,
|
||||
resolveSprite,
|
||||
} from "../modules/relief-generator";
|
||||
import { generateRelief } from "../modules/relief-generator";
|
||||
import { byId } from "../utils";
|
||||
|
||||
// ── Module state ───────────────────────────────────────────────────────────────
|
||||
let fo: SVGForeignObjectElement | null = null;
|
||||
let renderer: any = null; // THREE.WebGLRenderer
|
||||
let camera: any = null; // THREE.OrthographicCamera
|
||||
|
|
@ -15,7 +11,9 @@ let scene: any = null; // THREE.Scene
|
|||
|
||||
const textureCache = new Map<string, any>(); // set name → THREE.Texture
|
||||
|
||||
// ── Texture ────────────────────────────────────────────────────────────────────
|
||||
function preloadTextures(): void {
|
||||
for (const set of Object.keys(RELIEF_SYMBOLS)) loadTexture(set);
|
||||
}
|
||||
|
||||
function loadTexture(set: string): Promise<any> {
|
||||
if (textureCache.has(set)) return Promise.resolve(textureCache.get(set));
|
||||
|
|
@ -30,7 +28,8 @@ function loadTexture(set: string): Promise<any> {
|
|||
texture.minFilter = THREE.LinearMipmapLinearFilter;
|
||||
texture.magFilter = THREE.LinearFilter;
|
||||
texture.generateMipmaps = true;
|
||||
texture.anisotropy = renderer.capabilities.getMaxAnisotropy();
|
||||
if (renderer)
|
||||
texture.anisotropy = renderer.capabilities.getMaxAnisotropy();
|
||||
textureCache.set(set, texture);
|
||||
resolve(texture);
|
||||
},
|
||||
|
|
@ -43,8 +42,6 @@ function loadTexture(set: string): Promise<any> {
|
|||
});
|
||||
}
|
||||
|
||||
// ── WebGL bootstrap ────────────────────────────────────────────────────────────
|
||||
|
||||
function ensureRenderer(): boolean {
|
||||
const terrainEl = byId("terrain");
|
||||
if (!terrainEl) return false;
|
||||
|
|
@ -58,7 +55,6 @@ function ensureRenderer(): boolean {
|
|||
camera = null;
|
||||
scene = null;
|
||||
disposeTextureCache();
|
||||
// fall through to recreate
|
||||
} else {
|
||||
if (fo && !fo.isConnected) terrainEl.appendChild(fo);
|
||||
return true;
|
||||
|
|
@ -66,10 +62,7 @@ function ensureRenderer(): boolean {
|
|||
}
|
||||
|
||||
// foreignObject hosts the WebGL canvas inside the SVG.
|
||||
fo = document.createElementNS(
|
||||
"http://www.w3.org/2000/svg",
|
||||
"foreignObject",
|
||||
) as unknown as SVGForeignObjectElement;
|
||||
fo = document.createElementNS("http://www.w3.org/2000/svg", "foreignObject");
|
||||
fo.id = "terrainFo";
|
||||
fo.setAttribute("x", "0");
|
||||
fo.setAttribute("y", "0");
|
||||
|
|
@ -102,19 +95,25 @@ function ensureRenderer(): boolean {
|
|||
// Camera in SVG coordinate space: top=0, bottom=H puts map y=0 at screen-top.
|
||||
camera = new THREE.OrthographicCamera(0, graphWidth, 0, graphHeight, -1, 1);
|
||||
scene = new THREE.Scene();
|
||||
|
||||
preloadTextures();
|
||||
return true;
|
||||
}
|
||||
|
||||
// ── Scene / geometry ───────────────────────────────────────────────────────────
|
||||
// map a symbol href to its atlas set and tile index
|
||||
function resolveSprite(symbolHref: string): {
|
||||
set: string;
|
||||
tileIndex: number;
|
||||
} {
|
||||
const id = symbolHref.startsWith("#") ? symbolHref.slice(1) : symbolHref;
|
||||
for (const [set, ids] of Object.entries(RELIEF_SYMBOLS)) {
|
||||
const idx = ids.indexOf(id);
|
||||
if (idx !== -1) return { set, tileIndex: idx };
|
||||
}
|
||||
throw new Error(`Relief: unknown symbol href "${symbolHref}"`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a BufferGeometry with all icon quads for one atlas set.
|
||||
* Geometry is painter's-order sorted so depth is correct without depth testing.
|
||||
*
|
||||
* UV layout (texture.flipY = false — v=0 is top of image):
|
||||
* u = col/cols … (col+1)/cols
|
||||
* v = row/rows … (row+1)/rows
|
||||
*/
|
||||
// Build a BufferGeometry with all icon quads for one atlas set.
|
||||
function buildSetMesh(icons: ReliefIcon[], set: string, texture: any): any {
|
||||
const ids = RELIEF_SYMBOLS[set] ?? [];
|
||||
const n = ids.length || 1;
|
||||
|
|
@ -233,8 +232,6 @@ function renderFrame(): void {
|
|||
renderer.render(scene, camera);
|
||||
}
|
||||
|
||||
// ── Private draw / clear ───────────────────────────────────────────────────────
|
||||
|
||||
function drawWebGl(icons: ReliefIcon[]): void {
|
||||
const terrainEl = byId("terrain");
|
||||
if (!terrainEl) return;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue