From af04cbe3592656cf6981232550a460f1b10e2560 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Wed, 31 Oct 2018 14:24:38 +0100 Subject: view: refactor generic parts of MapView into a TileView --- src/index.ts | 2 +- src/view/MapLoader.ts | 8 ++++-- src/view/MapView.ts | 80 ++++++++++++++------------------------------------- src/view/tile.ts | 74 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 102 insertions(+), 62 deletions(-) create mode 100644 src/view/tile.ts (limited to 'src') diff --git a/src/index.ts b/src/index.ts index 033e4ea..e21b006 100644 --- a/src/index.ts +++ b/src/index.ts @@ -18,7 +18,7 @@ window.onload = () => { const map = new MapState(mapData); const mapView = await loadMap(renderer, map); - mapView.draw(); + mapView.render(); }); xhr.open('GET', 'resources/map/test.json', true); diff --git a/src/view/MapLoader.ts b/src/view/MapLoader.ts index 878fef4..a35eeec 100644 --- a/src/view/MapLoader.ts +++ b/src/view/MapLoader.ts @@ -1,4 +1,6 @@ -import {mapValues, mapValuesAsync, nextPowerOf2} from '../util'; +import { mapValues, mapValuesAsync, nextPowerOf2 } from '../util'; + +import { TileCoords } from './tile'; import MapState from '../model/state/MapState'; import MapView from './MapView'; @@ -6,7 +8,7 @@ import Renderer from './renderer/Renderer'; export interface TileMap { texture: WebGLTexture; - tiles: Map; + tiles: Map; } function loadImage(url: string): Promise { @@ -54,7 +56,7 @@ function mkTileMap( canvas.width = canvas.height = canvasSize; let x = 0, y = 0; - const map: Map = new Map(); + const map: Map = new Map(); const ctx = canvas.getContext('2d') as CanvasRenderingContext2D; for (const [k, tile] of tiles) { diff --git a/src/view/MapView.ts b/src/view/MapView.ts index 1061196..a5af8f7 100644 --- a/src/view/MapView.ts +++ b/src/view/MapView.ts @@ -1,74 +1,38 @@ import MapState from '../model/state/MapState'; -import {TileMap} from './MapLoader'; +import { TileMap } from './MapLoader'; import Renderer from './renderer/Renderer'; +import { TileView, TileViewBuilder } from './tile'; export default class MapView { - private readonly vertexBuffer: WebGLBuffer; - private readonly textureBuffer: WebGLBuffer; + private static 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); + } + + private readonly tileView: TileView; constructor( - private readonly r: Renderer, - private readonly map: MapState, - private readonly tileMap: TileMap, + r: Renderer, + map: MapState, + tileMap: TileMap, ) { - const vertexData: number[] = []; - const textureData: number[] = []; + const builder = new TileViewBuilder(r, tileMap.texture); for (let x = 0; x < map.data.width; x++) for (let y = 0; y < map.data.height; y++) for (const layer of map.data.layers) - this.addTile(vertexData, textureData, x, y, layer[y][x]); - - const gl = r.getContext(); + MapView.addTile(builder, tileMap, x, y, layer[y][x]); - this.vertexBuffer = r.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW); - - this.textureBuffer = r.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER, this.textureBuffer); - gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureData), gl.STATIC_DRAW); + this.tileView = builder.build(); } - public draw(): void { - const gl = this.r.getContext(); - - gl.clear(gl.COLOR_BUFFER_BIT); - - gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, this.tileMap.texture); - gl.uniform1i(this.r.getSamplerLoc(), 0); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - gl.vertexAttribPointer(this.r.getVertexPosLoc(), 2, gl.FLOAT, false, 0, 0); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.textureBuffer); - gl.vertexAttribPointer(this.r.getTextureCoordLoc(), 2, gl.FLOAT, false, 0, 0); - - gl.drawArrays(gl.TRIANGLES, 0, 6 * this.map.data.width * this.map.data.height); - } - - private pushTile(buf: number[], coords: [number, number, number, number]) { - const [x1, y1, x2, y2] = coords; - - buf.push(x1); buf.push(y1); - buf.push(x2); buf.push(y1); - buf.push(x1); buf.push(y2); - - buf.push(x1); buf.push(y2); - buf.push(x2); buf.push(y1); - buf.push(x2); buf.push(y2); - } - - private addTile(vertexData: number[], textureData: number[], x: number, y: number, tile: string) { - if (tile === ' ') - return; - - const tilePos = this.tileMap.tiles.get(tile); - if (!tilePos) - throw new Error('invalid tile specifier in map data'); - - this.pushTile(vertexData, [x, y, x + 1, y + 1]); - this.pushTile(textureData, tilePos); + public render(): void { + this.tileView.render(); } } diff --git a/src/view/tile.ts b/src/view/tile.ts new file mode 100644 index 0000000..d748ec9 --- /dev/null +++ b/src/view/tile.ts @@ -0,0 +1,74 @@ +import Renderer from './renderer/Renderer'; + +export type TileCoords = [number, number, number, number]; + +export class TileViewBuilder { + private static pushTile(buf: number[], coords: TileCoords): void { + const [x1, y1, x2, y2] = coords; + + buf.push(x1); buf.push(y1); + buf.push(x2); buf.push(y1); + buf.push(x1); buf.push(y2); + + buf.push(x1); buf.push(y2); + buf.push(x2); buf.push(y1); + buf.push(x2); buf.push(y2); + } + + private readonly vertexData: number[] = []; + private readonly textureData: number[] = []; + + constructor(private readonly r: Renderer, private readonly texture: WebGLTexture) {} + + public addTile(vertexCoords: TileCoords, texCoords: TileCoords): void { + TileViewBuilder.pushTile(this.vertexData, vertexCoords); + TileViewBuilder.pushTile(this.textureData, texCoords); + } + + public build(): TileView { + return new TileView(this.r, this.texture, this.vertexData, this.textureData); + } +} + +export class TileView { + private readonly primitiveCount: number; + private readonly vertexBuffer: WebGLBuffer; + private readonly textureBuffer: WebGLBuffer; + + constructor( + private readonly r: Renderer, + private readonly texture: WebGLTexture, + vertexData: number[], + textureData: number[], + ) { + const gl = r.getContext(); + + this.vertexBuffer = r.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW); + + this.textureBuffer = r.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, this.textureBuffer); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureData), gl.STATIC_DRAW); + + this.primitiveCount = vertexData.length / 3; + } + + public render(): void { + const gl = this.r.getContext(); + + gl.clear(gl.COLOR_BUFFER_BIT); + + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, this.texture); + gl.uniform1i(this.r.getSamplerLoc(), 0); + + gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); + gl.vertexAttribPointer(this.r.getVertexPosLoc(), 2, gl.FLOAT, false, 0, 0); + + gl.bindBuffer(gl.ARRAY_BUFFER, this.textureBuffer); + gl.vertexAttribPointer(this.r.getTextureCoordLoc(), 2, gl.FLOAT, false, 0, 0); + + gl.drawArrays(gl.TRIANGLES, 0, this.primitiveCount); + } +} -- cgit v1.2.3