summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2018-11-10 20:24:25 +0100
committerMatthias Schiffer <mschiffer@universe-factory.net>2018-11-10 20:24:25 +0100
commitc9000b7c385b530bddf87cfed4b580b5d1a2d6d2 (patch)
tree7afdbdf1435c20f694c1eaeca6d7aa54c62d8e64
parentfa3dad090c7abd8b13ad107e4dcb406012b63243 (diff)
downloadrpgedit-c9000b7c385b530bddf87cfed4b580b5d1a2d6d2.tar
rpgedit-c9000b7c385b530bddf87cfed4b580b5d1a2d6d2.zip
view: add support for non-square, non-power-of-2 sprites
-rw-r--r--dist/resources/entity/red_ellipse.json3
-rw-r--r--dist/resources/sprite/entity/red_ellipse.pngbin0 -> 255 bytes
-rw-r--r--src/view/entity.ts18
-rw-r--r--src/view/map.ts8
-rw-r--r--src/view/renderer/renderer.ts11
-rw-r--r--src/view/util/image.ts31
6 files changed, 57 insertions, 14 deletions
diff --git a/dist/resources/entity/red_ellipse.json b/dist/resources/entity/red_ellipse.json
new file mode 100644
index 0000000..e8ce5e6
--- /dev/null
+++ b/dist/resources/entity/red_ellipse.json
@@ -0,0 +1,3 @@
+{
+ "sprite": "red_ellipse"
+}
diff --git a/dist/resources/sprite/entity/red_ellipse.png b/dist/resources/sprite/entity/red_ellipse.png
new file mode 100644
index 0000000..48fc2c0
--- /dev/null
+++ b/dist/resources/sprite/entity/red_ellipse.png
Binary files differ
diff --git a/src/view/entity.ts b/src/view/entity.ts
index 421a238..b59bf92 100644
--- a/src/view/entity.ts
+++ b/src/view/entity.ts
@@ -1,18 +1,28 @@
import { EntityData } from '../model/data/entity';
import { Renderer } from './renderer/renderer';
-import { SpriteView, SpriteViewBuilder } from './sprite';
+import { SpriteCoords, SpriteView, SpriteViewBuilder } from './sprite';
import { loadImage, mkTexture } from './util/image';
+import { vec2 } from 'gl-matrix';
+
export async function loadEntity(
r: Renderer,
data: EntityData,
): Promise<SpriteView> {
const tile = await loadImage(`resources/sprite/entity/${data.sprite}.png`);
- const texture = mkTexture(r.getContext(), tile);
+ const [texture, size, coords] = mkTexture(r, tile);
+
+ const offset = vec2.mul(vec2.create(), data.anchor, size);
+ r.snapToGrid(offset, offset);
- const [x, y] = data.anchor;
+ const anchorCoords: SpriteCoords = [
+ coords[0] - offset[0],
+ coords[1] - offset[1],
+ coords[2] - offset[0],
+ coords[3] - offset[1],
+ ];
const builder = new SpriteViewBuilder(r, texture);
- builder.addSprite([-x, -y, -x + 1, -y + 1], [0, 0, 1, 1]);
+ builder.addSprite(anchorCoords, [0, 0, 1, 1]);
return builder.build();
}
diff --git a/src/view/map.ts b/src/view/map.ts
index ff37737..9bdbd30 100644
--- a/src/view/map.ts
+++ b/src/view/map.ts
@@ -16,7 +16,7 @@ function loadTiles(tiles: string[]): Promise<HTMLImageElement[]> {
}
function mkTileset(
- gl: WebGLRenderingContext,
+ r: Renderer,
tiles: HTMLImageElement[],
): Tileset {
const tileSize = 32;
@@ -42,8 +42,10 @@ function mkTileset(
}
}
+ const [texture] = mkTexture(r, canvas);
+
return {
- texture: mkTexture(gl, canvas),
+ texture,
tiles: tileCoords,
};
}
@@ -58,7 +60,7 @@ function addSprite(builder: SpriteViewBuilder, tileset: Tileset, x: number, y: n
export async function loadMap(r: Renderer, map: MapData): Promise<SpriteView> {
const tiles = await loadTiles(map.tiles);
- const tileset = mkTileset(r.getContext(), tiles);
+ const tileset = mkTileset(r, tiles);
const builder = new SpriteViewBuilder(r, tileset.texture);
diff --git a/src/view/renderer/renderer.ts b/src/view/renderer/renderer.ts
index 062c868..93f8589 100644
--- a/src/view/renderer/renderer.ts
+++ b/src/view/renderer/renderer.ts
@@ -3,7 +3,8 @@ import { Shaders } from './shaders';
import { mat4, vec2 } from 'gl-matrix';
export class Renderer {
- private readonly viewScale = 64;
+ public readonly coordScale = 32;
+ private readonly viewScale = 2;
private readonly gl: WebGLRenderingContext;
private readonly shaders: Shaders;
@@ -67,9 +68,9 @@ export class Renderer {
}
public snapToGrid(out: vec2, a: vec2|number[]): void {
- vec2.scale(out, a, this.viewScale);
+ vec2.scale(out, a, this.coordScale);
vec2.round(out, out);
- vec2.scale(out, out, 1 / this.viewScale);
+ vec2.scale(out, out, 1 / this.coordScale);
}
private mkContext(): WebGLRenderingContext {
@@ -89,8 +90,10 @@ export class Renderer {
this.gl.viewport(0, 0, w, h);
this.clear();
+ const scale = this.viewScale * this.coordScale;
+
mat4.identity(this.viewport);
- mat4.scale(this.viewport, this.viewport, [2 * this.viewScale / w, -2 * this.viewScale / h, 1.0]);
+ mat4.scale(this.viewport, this.viewport, [2 * scale / w, -2 * scale / h, 1.0]);
this.gl.uniformMatrix4fv(this.shaders.viewportLoc, false, this.viewport);
}
}
diff --git a/src/view/util/image.ts b/src/view/util/image.ts
index 73edbba..e01246c 100644
--- a/src/view/util/image.ts
+++ b/src/view/util/image.ts
@@ -1,3 +1,7 @@
+import { nextPowerOf2 } from '../../util';
+import { Renderer } from '../renderer/renderer';
+import { SpriteCoords } from '../sprite';
+
export function loadImage(url: string): Promise<HTMLImageElement> {
return new Promise((resolve, reject) => {
const img = new Image();
@@ -7,17 +11,38 @@ export function loadImage(url: string): Promise<HTMLImageElement> {
});
}
-export function mkTexture(gl: WebGLRenderingContext, src: HTMLCanvasElement|HTMLImageElement): WebGLTexture {
+export function mkTexture(
+ r: Renderer,
+ src: HTMLCanvasElement|HTMLImageElement,
+): [WebGLTexture, [number, number], SpriteCoords] {
+ const gl = r.getContext();
const texture = gl.createTexture();
if (!texture)
throw new Error('unable to create texture');
+ const w = src.width, h = src.height;
+ const w2 = nextPowerOf2(w), h2 = nextPowerOf2(h);
+
+ const canvas = document.createElement('canvas');
+ canvas.width = w2;
+ canvas.height = h2;
+
+ const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
+ ctx.drawImage(src, 0, 0);
+
gl.bindTexture(gl.TEXTURE_2D, texture);
- gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, src);
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, canvas);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
- return texture;
+ const size: [number, number] = [
+ w / r.coordScale, h / r.coordScale,
+ ];
+ const coords: SpriteCoords = [
+ 0, 0, w2 / r.coordScale, h2 / r.coordScale,
+ ];
+
+ return [texture, size, coords];
}