summaryrefslogtreecommitdiffstats
path: root/src/view/map.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/map.ts')
-rw-r--r--src/view/map.ts73
1 files changed, 73 insertions, 0 deletions
diff --git a/src/view/map.ts b/src/view/map.ts
new file mode 100644
index 0000000..954e39e
--- /dev/null
+++ b/src/view/map.ts
@@ -0,0 +1,73 @@
+import MapData from '../model/data/MapData';
+import { mapValues, nextPowerOf2 } from '../util';
+
+import Renderer from './renderer/Renderer';
+import { TileCoords, TileView, TileViewBuilder } from './tile';
+import { loadImages, mkTexture } from './util/image';
+
+interface TileMap {
+ texture: WebGLTexture;
+ tiles: Map<string, TileCoords>;
+}
+
+function loadTiles(tiles: Map<string, string>): Promise<Map<string, HTMLImageElement>> {
+ return loadImages(mapValues((t) => `resources/sprite/tile/${t}.png`, tiles));
+}
+
+function mkTileMap(
+ gl: WebGLRenderingContext,
+ tiles: Map<string, HTMLImageElement>,
+): TileMap {
+ const tileSize = 32;
+
+ const canvasDim = nextPowerOf2(Math.sqrt(tiles.size));
+ const canvasSize = canvasDim * tileSize;
+
+ const canvas = document.createElement('canvas');
+ canvas.width = canvas.height = canvasSize;
+
+ let x = 0, y = 0;
+ const map: Map<string, TileCoords> = new Map();
+ const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
+
+ for (const [k, tile] of tiles) {
+ ctx.drawImage(tile, x * tileSize, y * tileSize);
+ map.set(k, [x / canvasDim, y / canvasDim, (x + 1) / canvasDim, (y + 1) / canvasDim]);
+
+ x++;
+ if (x === canvasDim) {
+ x = 0;
+ y++;
+ }
+ }
+
+ return {
+ texture: mkTexture(gl, canvas),
+ tiles: map,
+ };
+}
+
+function addTile(builder: TileViewBuilder, tileMap: TileMap, x: number, y: number, tile: string) {
+ if (tile === ' ')
+ return;
+
+ const tilePos = tileMap.tiles.get(tile);
+ if (!tilePos)
+ throw new Error('invalid tile specifier in map data');
+
+ builder.addTile([x, y, x + 1, y + 1], tilePos);
+}
+
+export async function loadMap(r: Renderer, map: MapData): Promise<TileView> {
+ const tiles = await loadTiles(map.tiles);
+ const tileMap = mkTileMap(r.getContext(), tiles);
+
+ const builder = new TileViewBuilder(r, tileMap.texture);
+
+ for (const layer of map.layers)
+ for (let x = 0; x < map.width; x++)
+ for (let y = 0; y < map.height; y++)
+ addTile(builder, tileMap, x, y, layer[y][x]);
+
+ return builder.build();
+}