summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2018-10-26 23:11:14 +0200
committerMatthias Schiffer <mschiffer@universe-factory.net>2018-10-26 23:11:14 +0200
commit4b680776a3c0896a7dbe9943e1fa5c8bed0109b0 (patch)
treef8b71be4e70f93cdc66958a49cd5e4a5171377e1 /src
parentbc6d79b088154e2fca56b9c18ee5ea0bf17875f8 (diff)
downloadrpgedit-4b680776a3c0896a7dbe9943e1fa5c8bed0109b0.tar
rpgedit-4b680776a3c0896a7dbe9943e1fa5c8bed0109b0.zip
MapLoader: use square tile texture rather than long Nx1 rectangle
By placing the tiles in a square texture, the dimensions are bounded by the square root of the dimension in the old solution. This way we can fit a significantly higher number of tiles into it without using up all the accuracy of the coordinates.
Diffstat (limited to 'src')
-rw-r--r--src/view/MapLoader.ts42
-rw-r--r--src/view/MapView.ts43
2 files changed, 50 insertions, 35 deletions
diff --git a/src/view/MapLoader.ts b/src/view/MapLoader.ts
index 290f095..6953321 100644
--- a/src/view/MapLoader.ts
+++ b/src/view/MapLoader.ts
@@ -4,6 +4,11 @@ import MapState from '../model/state/MapState';
import MapView from './MapView';
import Renderer from './renderer/Renderer';
+export interface TileMap {
+ texture: WebGLTexture;
+ tiles: Map<string, [number, number, number, number]>;
+}
+
function loadImage(url: string): Promise<HTMLImageElement> {
return new Promise((resolve, reject) => {
const img = new Image();
@@ -36,27 +41,42 @@ function mkTexture(gl: WebGLRenderingContext, src: HTMLCanvasElement|HTMLImageEl
return texture;
}
-function mkTileTexture(gl: WebGLRenderingContext, tiles: Map<string, HTMLImageElement>):
-[WebGLTexture, Map<string, number>] {
+function mkTileMap(
+ gl: WebGLRenderingContext,
+ tiles: Map<string, HTMLImageElement>,
+): TileMap {
+ const tileSize = MapView.tileSize;
+
+ const canvasDim = nextPowerOf2(Math.sqrt(tiles.size));
+ const canvasSize = canvasDim * tileSize;
+
const canvas = document.createElement('canvas');
- canvas.width = nextPowerOf2(tiles.size) * MapView.tileSize;
- canvas.height = MapView.tileSize;
+ canvas.width = canvas.height = canvasSize;
- let i = 0;
- const ret: Map<string, number> = new Map();
+ let x = 0, y = 0;
+ const map: Map<string, [number, number, number, number]> = new Map();
const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
for (const [k, tile] of tiles) {
- ctx.drawImage(tile, i * MapView.tileSize, 0);
- ret.set(k, i++);
+ 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 [mkTexture(gl, canvas), ret];
+ return {
+ texture: mkTexture(gl, canvas),
+ tiles: map,
+ };
}
export async function loadMap(r: Renderer, map: MapState): Promise<MapView> {
const tiles = await loadTiles(map.data.tiles);
- const [tileTexture, tileMap] = mkTileTexture(r.getContext(), tiles);
+ const tileMap = mkTileMap(r.getContext(), tiles);
- return new MapView(r, map, tileTexture, tileMap);
+ return new MapView(r, map, tileMap);
}
diff --git a/src/view/MapView.ts b/src/view/MapView.ts
index 92784b7..5c30f20 100644
--- a/src/view/MapView.ts
+++ b/src/view/MapView.ts
@@ -1,6 +1,5 @@
-import {nextPowerOf2} from '../util';
-
import MapState from '../model/state/MapState';
+import {TileMap} from './MapLoader';
import Renderer from './renderer/Renderer';
export default class MapView {
@@ -14,17 +13,14 @@ export default class MapView {
constructor(
private readonly r: Renderer,
private readonly map: MapState,
- private readonly tileTexture: WebGLTexture,
- private readonly tileMap: Map<string, number>,
+ private readonly tileMap: TileMap,
) {
const vertexData: number[] = [];
const textureData: number[] = [];
- const tileCount = nextPowerOf2(tileMap.size);
-
for (let x = 0; x < map.data.width; x++)
for (let y = 0; y < map.data.height; y++)
- this.addTile(vertexData, textureData, x, y, map.data.layers[0][y][x], tileCount);
+ this.addTile(vertexData, textureData, x, y, map.data.layers[0][y][x]);
const gl = r.getContext();
@@ -43,7 +39,7 @@ export default class MapView {
gl.clear(gl.COLOR_BUFFER_BIT);
gl.activeTexture(gl.TEXTURE0);
- gl.bindTexture(gl.TEXTURE_2D, this.tileTexture);
+ gl.bindTexture(gl.TEXTURE_2D, this.tileMap.texture);
gl.uniform1i(this.r.getSamplerLoc(), 0);
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
@@ -55,25 +51,24 @@ export default class MapView {
gl.drawArrays(gl.TRIANGLES, 0, 6 * this.map.data.width * this.map.data.height);
}
- private addTile(vertexData: number[], textureData: number[], x: number, y: number, tile: string, tileCount: number) {
- const tileID = this.tileMap.get(tile);
- if (tileID === undefined)
- throw new Error('invalid tile specifier in map data');
+ private pushTile(buf: number[], coords: [number, number, number, number]) {
+ const [x1, y1, x2, y2] = coords;
- vertexData.push(x); vertexData.push(y);
- vertexData.push(x + 1); vertexData.push(y);
- vertexData.push(x); vertexData.push(y + 1);
+ buf.push(x1); buf.push(y1);
+ buf.push(x2); buf.push(y1);
+ buf.push(x1); buf.push(y2);
- vertexData.push(x); vertexData.push(y + 1);
- vertexData.push(x + 1); vertexData.push(y);
- vertexData.push(x + 1); vertexData.push(y + 1);
+ buf.push(x1); buf.push(y2);
+ buf.push(x2); buf.push(y1);
+ buf.push(x2); buf.push(y2);
+ }
- textureData.push(tileID / tileCount); textureData.push(0);
- textureData.push((tileID + 1) / tileCount); textureData.push(0);
- textureData.push(tileID / tileCount); textureData.push(1);
+ private addTile(vertexData: number[], textureData: number[], x: number, y: number, tile: string) {
+ const tilePos = this.tileMap.tiles.get(tile);
+ if (!tilePos)
+ throw new Error('invalid tile specifier in map data');
- textureData.push(tileID / tileCount); textureData.push(1);
- textureData.push((tileID + 1) / tileCount); textureData.push(0);
- textureData.push((tileID + 1) / tileCount); textureData.push(1);
+ this.pushTile(vertexData, [x, y, x + 1, y + 1]);
+ this.pushTile(textureData, tilePos);
}
}