diff options
Diffstat (limited to 'src/view/map.ts')
-rw-r--r-- | src/view/map.ts | 73 |
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(); +} |