Compare commits

..

No commits in common. "2e9ec2565bef832acb52c5771d8964120f9eeb84" and "14d5db166e1435c667f3a05f1e2a3a3250c77fda" have entirely different histories.

12 changed files with 445 additions and 536 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 511 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -26,10 +26,12 @@ export class Assets {
throw new Error("Tried to assess assets without loading them!"); throw new Error("Tried to assess assets without loading them!");
return this.assets.get(name); return this.assets.get(name);
} }
async load(gfx) { async load(ctx) {
assets.push("grass", await Texture.load(gfx, "../../assets/grass2.png")); assets.push("city", await Texture.load(ctx, "../../assets/genetica/rt/City Night.jpg"));
assets.push("leaves", await Texture.load(gfx, "../../assets/greenary.png")); assets.push("wall", await Texture.load(ctx, "../../assets/wall.png"));
assets.push("log", await Texture.load(gfx, "../../assets/log.png")); assets.push("grass", await Texture.load(ctx, "../../assets/grass.png"));
assets.push("leaves", await Texture.load(ctx, "../../assets/greenary.png"));
assets.push("log", await Texture.load(ctx, "../../assets/log.png"));
this.loaded = true; this.loaded = true;
} }
} }

View File

@ -1,4 +1,4 @@
import {Graphics, Texture} from "./graphics.js"; import {Texture} from "./graphics.js";
import {TileFill} from "./world.js"; import {TileFill} from "./world.js";
export type Color = [number, number, number, number] export type Color = [number, number, number, number]
@ -40,11 +40,12 @@ export class Assets {
return this.assets.get(name)!; return this.assets.get(name)!;
} }
async load(gfx: Graphics) { async load(ctx: WebGL2RenderingContext) {
assets.push("grass", await Texture.load(gfx, "../../assets/grass2.png")); assets.push("city", await Texture.load(ctx, "../../assets/genetica/rt/City Night.jpg"));
assets.push("leaves", await Texture.load(gfx, "../../assets/greenary.png")); assets.push("wall", await Texture.load(ctx, "../../assets/wall.png"));
assets.push("log", await Texture.load(gfx, "../../assets/log.png")); assets.push("grass", await Texture.load(ctx, "../../assets/grass.png"));
assets.push("leaves", await Texture.load(ctx, "../../assets/greenary.png"));
assets.push("log", await Texture.load(ctx, "../../assets/log.png"));
this.loaded = true; this.loaded = true;
} }
} }

View File

@ -267,14 +267,6 @@ class Mat4 {
} }
this.data = new Float32Array(16); this.data = new Float32Array(16);
} }
static IDENTITY() {
return new Mat4(new Float32Array([
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
]));
}
static orthographic(left, right, bottom, top, near, far) { static orthographic(left, right, bottom, top, near, far) {
let data = new Float32Array([ let data = new Float32Array([
2 / (right - left), 0, 0, 0, 2 / (right - left), 0, 0, 0,
@ -338,14 +330,6 @@ class Mat4 {
t.x, t.y, t.z, 1, t.x, t.y, t.z, 1,
])); ]));
} }
static scale(scales) {
return new Mat4(new Float32Array([
scales.x, 0, 0, 0,
0, scales.y, 0, 0,
0, 0, scales.z, 0,
0, 0, 0, 1,
]));
}
x(n) { x(n) {
return this.data[n]; return this.data[n];
} }

View File

@ -379,15 +379,6 @@ class Mat4 {
this.data = new Float32Array(16); this.data = new Float32Array(16);
} }
static IDENTITY(): Mat4 {
return new Mat4(new Float32Array([
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
]));
}
static orthographic(left: number, right: number, bottom: number, top: number, near: number, far: number): Mat4 { static orthographic(left: number, right: number, bottom: number, top: number, near: number, far: number): Mat4 {
let data = new Float32Array([ let data = new Float32Array([
2 / (right - left), 0, 0, 0, 2 / (right - left), 0, 0, 0,
@ -463,15 +454,6 @@ class Mat4 {
])); ]));
} }
static scale(scales: Vec3) {
return new Mat4(new Float32Array([
scales.x, 0, 0, 0,
0, scales.y, 0, 0,
0, 0, scales.z, 0,
0, 0, 0, 1,
]));
}
x(n: Mat4X) { x(n: Mat4X) {
return this.data[n]; return this.data[n];
} }

View File

@ -1,5 +1,5 @@
import { Vec3 } from "./common.js"; import { Vec3, Vec2, Vec4 } from "./common.js";
import { Texture, DrawTag } from "./graphics.js"; import { Texture } from "./graphics.js";
import { TileEdge } from "./world.js"; import { TileEdge } from "./world.js";
// TODO: Don't assume tile size is same in all directions // TODO: Don't assume tile size is same in all directions
function cull(point, screen, tileSize) { function cull(point, screen, tileSize) {
@ -13,80 +13,76 @@ function cull(point, screen, tileSize) {
return true; return true;
return false; return false;
} }
// Attrib format export function drawTriangle(gfx, positions, color) {
// position color uv const a_position = gfx.getAttribute("a_position");
// (3) (4) (2) => 3 + 4 + 2 = 9 <=> data.len % 9 == 0 const a_color = gfx.getAttribute("a_color");
export class Rectangle { const points = [
fill; positions[0].x, positions[0].y,
attribs = ["a_position", "a_color", "a_tex_position"]; positions[1].x, positions[1].y,
tags = []; positions[2].x, positions[2].y,
data = []; ];
stride = 0; const colors = [
vertexStride = 0; color,
constructor(fill, tags, attribs) { color,
this.fill = fill; color,
if (attribs !== undefined) { ];
this.attribs = attribs; a_position.data(gfx.ctx, points, gfx.ctx.STATIC_DRAW);
} a_color.data(gfx.ctx, colors.flat(), gfx.ctx.STATIC_DRAW);
if (tags !== undefined) { gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 3);
this.tags = tags; }
} export function drawTriangleExts(gfx, position, exts, color) {
const a_position = gfx.getAttribute("a_position");
const a_color = gfx.getAttribute("a_color");
const points = [
position.x, position.y, position.z,
position.x + exts.x, position.y, position.z,
position.x, position.y + exts.y, position.z,
];
const colors = [
color,
color,
color,
];
a_position.data(gfx.ctx, points, gfx.ctx.STATIC_DRAW);
a_color.data(gfx.ctx, colors.flat(), gfx.ctx.STATIC_DRAW);
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 3);
}
export function drawRectangle(gfx, corners, color) {
const a_position = gfx.getAttribute("a_position");
const points = [
corners[0].x, corners[0].y, corners[0].z,
corners[1].x, corners[1].y, corners[1].z,
corners[3].x, corners[3].y, corners[3].z,
corners[2].x, corners[2].y, corners[2].z,
corners[1].x, corners[1].y, corners[1].z,
corners[3].x, corners[3].y, corners[3].z,
];
if (color instanceof Texture) {
const a_tex_position = gfx.getAttribute("a_tex_position");
const uv = [
0.0, 0.0,
-1.0, 0.0,
0.0, -1.0,
-1.0, -1.0,
-1.0, 0.0,
0.0, -1.0,
];
a_position.data(gfx.ctx, points, gfx.ctx.STATIC_DRAW);
a_tex_position.data(gfx.ctx, uv, gfx.ctx.STATIC_DRAW);
color.bind(gfx);
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 6);
color.unbind(gfx);
} }
overrideDraw(draw) { else {
this.draw = draw; const a_color = gfx.getAttribute("a_color");
} const colors = new Array(6);
draw(gfx, corners) { colors.fill(color);
if (this.fill instanceof Texture) { a_position.data(gfx.ctx, points, gfx.ctx.STATIC_DRAW);
this.data = [ a_color.data(gfx.ctx, colors.flat(), gfx.ctx.STATIC_DRAW);
corners[0].x, corners[0].y, corners[0].z, 0, 0, 0, 0, 0, 0, gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 6);
corners[1].x, corners[1].y, corners[1].z, 0, 0, 0, 0, -1, 0,
corners[3].x, corners[3].y, corners[3].z, 0, 0, 0, 0, 0, -1,
corners[2].x, corners[2].y, corners[2].z, 0, 0, 0, 0, -1, -1,
corners[1].x, corners[1].y, corners[1].z, 0, 0, 0, 0, -1, 0,
corners[3].x, corners[3].y, corners[3].z, 0, 0, 0, 0, 0, -1,
];
}
else {
this.data = [
corners[0].x, corners[0].y, corners[0].z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
corners[1].x, corners[1].y, corners[1].z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
corners[3].x, corners[3].y, corners[3].z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
corners[2].x, corners[2].y, corners[2].z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
corners[1].x, corners[1].y, corners[1].z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
corners[3].x, corners[3].y, corners[3].z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
];
}
this.vertexStride = 9;
this.stride = this.vertexStride * 4;
gfx.toRender.push({ ...this });
}
drawExts(gfx, position, exts) {
if (this.fill instanceof Texture) {
this.data = [
position.x, position.y, position.z, 0, 0, 0, 0, 0, 0,
position.x + exts.x, position.y, position.z, 0, 0, 0, 0, -1, 0,
position.x, position.y + exts.y, position.z, 0, 0, 0, 0, 0, -1,
position.x + exts.x, position.y + exts.y, position.z, 0, 0, 0, 0, -1, -1,
position.x + exts.x, position.y, position.z, 0, 0, 0, 0, -1, 0,
position.x, position.y + exts.y, position.z, 0, 0, 0, 0, 0, -1,
];
}
else {
this.data = [
position.x, position.y, position.z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
position.x + exts.x, position.y, position.z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
position.x, position.y + exts.y, position.z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
position.x + exts.x, position.y + exts.y, position.z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
position.x + exts.x, position.y, position.z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
position.x, position.y + exts.y, position.z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
];
}
this.vertexStride = 9;
this.stride = this.vertexStride * 4;
gfx.toRender.push(this);
} }
} }
export function drawIsometricCube(gfx, position, exts, color, edge) { export function drawIsometricCube(gfx, camera, position, exts, color, edge) {
let points = [ let points = [
// Left Top // Left Top
position, position,
@ -101,58 +97,52 @@ export function drawIsometricCube(gfx, position, exts, color, edge) {
new Vec3(position.x + 1.5 * exts.x, position.y + 0.5 * exts.y, position.z + 0.25 * exts.z), new Vec3(position.x + 1.5 * exts.x, position.y + 0.5 * exts.y, position.z + 0.25 * exts.z),
new Vec3(position.x + 0.5 * exts.x, position.y - 0.5 * exts.y, position.z + 0.25 * exts.z), new Vec3(position.x + 0.5 * exts.x, position.y - 0.5 * exts.y, position.z + 0.25 * exts.z),
]; ];
let r = new Rectangle(color.top, [ let screen = new Vec4(-camera.position.x, -camera.position.y, gfx.ctx.canvas.width, gfx.ctx.canvas.height);
DrawTag.ISO, gfx.ctx.uniform1i(gfx.getUniform("u_isIso"), 1);
]);
// Top // Top
r.draw(gfx, [ drawRectangle(gfx, [
points[0], points[0],
points[1], points[1],
points[3], points[3],
points[2], points[2],
]); ], color.top);
// Right Edge // Right Edge
if (edge == TileEdge.Right || edge == TileEdge.Both) { if (edge == TileEdge.Right || edge == TileEdge.Both) {
r.fill = color.right; drawRectangle(gfx, [
r.draw(gfx, [
points[3], points[3],
points[2], points[2],
points[4], points[4],
points[5], points[5],
]); ], color.right);
} }
// Left Edge // Left Edge
if (edge == TileEdge.Left || edge == TileEdge.Both) { if (edge == TileEdge.Left || edge == TileEdge.Both) {
r.fill = color.left; drawRectangle(gfx, [
r.draw(gfx, [
points[0], points[0],
points[2], points[2],
points[4], points[4],
points[6], points[6],
]); ], color.left);
} }
gfx.ctx.uniform1i(gfx.getUniform("u_isIso"), 0);
} }
export function drawIsometricGrid(gfx, grid) { export function drawIsometricGrid(gfx, camera, grid) {
let position = { ...grid.position }; let position = { ...grid.position };
let exts = new Vec3(grid.tileSize, grid.tileSize, 0); let exts = new Vec3(grid.tileSize, grid.tileSize, 0);
let tileCoord = new Vec3(0, 0, 0); let tileCoord = new Vec3(0, 0, 0);
// TODO: Optimize this // TODO: Optimize this
// 1. Grid based occlusion culling
// 2. frustum culling
for (let k = 0; k < grid.height; ++k) { for (let k = 0; k < grid.height; ++k) {
for (let j = 0; j < grid.length; ++j) { for (let j = 0; j < grid.length; ++j) {
for (let i = 0; i < grid.width; ++i) { for (let i = 0; i < grid.width; ++i) {
tileCoord.x = i; tileCoord.x = i;
tileCoord.y = j; tileCoord.y = j;
tileCoord.z = k; tileCoord.z = k;
// getTile is sus (it uses a lot of time in the profiler) (i don't know why, it is a pretty simple function)
// (Prolly cuz i call it a lot) (Maybe change grid to use spatial hashmap?)
let tile = grid.getTile(tileCoord); let tile = grid.getTile(tileCoord);
if (tile === null) { if (tile === null) {
position.x += grid.tileSize; position.x += grid.tileSize;
continue; continue;
} }
drawIsometricCube(gfx, new Vec3(position.x - grid.tileSize / 2 * k, position.y + grid.tileSize / 2 * k, position.z), exts, tile.fill, tile.edge); drawIsometricCube(gfx, camera, new Vec3(position.x - grid.tileSize / 2 * k, position.y + grid.tileSize / 2 * k, position.z), exts, tile.fill, tile.edge);
position.x += grid.tileSize; position.x += grid.tileSize;
} }
position.y -= grid.tileSize; position.y -= grid.tileSize;
@ -161,3 +151,71 @@ export function drawIsometricGrid(gfx, grid) {
position.y = grid.position.y; position.y = grid.position.y;
} }
} }
export function drawRectangleExts(gfx, position, exts, color) {
const a_position = gfx.getAttribute("a_position");
const points = [
position.x, position.y, position.z,
position.x + exts.x, position.y, position.z,
position.x, position.y + exts.y, position.z,
position.x + exts.x, position.y + exts.y, position.z,
position.x + exts.x, position.y, position.z,
position.x, position.y + exts.y, position.z,
];
if (color instanceof Texture) {
const a_tex_position = gfx.getAttribute("a_tex_position");
const uv = [
0.0, 0.0,
-1.0, 0.0,
0.0, -1.0,
-1.0, -1.0,
-1.0, 0.0,
0.0, -1.0,
];
a_position.data(gfx.ctx, points, gfx.ctx.STATIC_DRAW);
a_tex_position.data(gfx.ctx, uv, gfx.ctx.STATIC_DRAW);
color.bind(gfx);
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 6);
color.unbind(gfx);
}
else {
const a_color = gfx.getAttribute("a_color");
const colors = new Array(6);
colors.fill(color);
a_position.data(gfx.ctx, points, gfx.ctx.STATIC_DRAW);
a_color.data(gfx.ctx, colors.flat(), gfx.ctx.STATIC_DRAW);
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 6);
}
}
export function drawCircle(gfx, position, radius, color) {
const points = new Array();
const precision = 40;
const angle = 2.0 * Math.PI / precision;
let a = 0;
for (let i = 0; i < precision; ++i) {
var vec = Vec2.angle(a);
vec.multScalar(radius);
a += angle;
points.push(vec);
}
for (let i = 0; i < points.length; i++) {
const current = points[i];
const next = points[(i + 1) % points.length];
let center = position;
drawTriangle(gfx, [center, center.addNew(current), center.addNew(next)], color);
}
}
export function drawLine(gfx, A, B, color) {
const a_position = gfx.getAttribute("a_position");
const a_color = gfx.getAttribute("a_color");
let points = [
A.x, A.y,
B.x, B.y,
];
const colors = [
color,
color,
];
a_position.data(gfx.ctx, points, gfx.ctx.STATIC_DRAW);
a_color.data(gfx.ctx, colors.flat(), gfx.ctx.STATIC_DRAW);
gfx.ctx.drawArrays(gfx.ctx.LINES, 0, 2);
}

View File

@ -1,6 +1,6 @@
import { Vec3, Vec2, Vec4 } from "./common.js" import { Vec3, Vec2, Vec4, Mat4 } from "./common.js"
import { Graphics, Texture, Drawable, DrawTag } from "./graphics.js"; import { Camera, Graphics, Texture } from "./graphics.js";
import { TileEdge, TileFill, Grid } from "./world.js"; import {Grid, TileEdge, TileFill} from "./world.js";
import * as Assets from "./assets.js"; import * as Assets from "./assets.js";
// TODO: Don't assume tile size is same in all directions // TODO: Don't assume tile size is same in all directions
@ -20,93 +20,93 @@ function cull(point: Vec3, screen: Vec4, tileSize: number): boolean {
return false; return false;
} }
// Attrib format export function drawTriangle(gfx: Graphics, positions: [Vec2, Vec2, Vec2], color: Assets.Color) {
// position color uv const a_position = gfx.getAttribute("a_position");
// (3) (4) (2) => 3 + 4 + 2 = 9 <=> data.len % 9 == 0 const a_color = gfx.getAttribute("a_color");
export class Rectangle implements Drawable { const points: Array<number> = [
fill: Texture | Assets.Color; positions[0].x, positions[0].y,
attribs: string[] = ["a_position", "a_color", "a_tex_position"]; positions[1].x, positions[1].y,
tags: Array<DrawTag> = []; positions[2].x, positions[2].y,
]
data: number[] = []; const colors: Array<number[]> = [
stride: number = 0; color,
vertexStride: number = 0; color,
color,
];
constructor(fill: Texture | Assets.Color, tags?: Array<DrawTag>, attribs?: string[]) { a_position.data(gfx.ctx, points, gfx.ctx.STATIC_DRAW);
this.fill = fill; a_color.data(gfx.ctx, colors.flat(), gfx.ctx.STATIC_DRAW);
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 3);
if (attribs !== undefined) {
this.attribs = attribs;
}
if (tags !== undefined) {
this.tags = tags;
}
}
overrideDraw(draw: (...args: any[]) => void) {
this.draw = draw;
}
draw(gfx: Graphics, corners: [Vec3, Vec3, Vec3, Vec3]) {
if (this.fill instanceof Texture) {
this.data = [
corners[0].x, corners[0].y, corners[0].z, 0, 0, 0, 0, 0, 0,
corners[1].x, corners[1].y, corners[1].z, 0, 0, 0, 0, -1, 0,
corners[3].x, corners[3].y, corners[3].z, 0, 0, 0, 0, 0, -1,
corners[2].x, corners[2].y, corners[2].z, 0, 0, 0, 0, -1, -1,
corners[1].x, corners[1].y, corners[1].z, 0, 0, 0, 0, -1, 0,
corners[3].x, corners[3].y, corners[3].z, 0, 0, 0, 0, 0, -1,
]
} else {
this.data = [
corners[0].x, corners[0].y, corners[0].z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
corners[1].x, corners[1].y, corners[1].z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
corners[3].x, corners[3].y, corners[3].z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
corners[2].x, corners[2].y, corners[2].z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
corners[1].x, corners[1].y, corners[1].z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
corners[3].x, corners[3].y, corners[3].z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
]
}
this.vertexStride = 9;
this.stride = this.vertexStride * 4
gfx.toRender.push({...this});
}
drawExts(gfx: Graphics, position: Vec3, exts: Vec2) {
if (this.fill instanceof Texture) {
this.data = [
position.x, position.y, position.z, 0, 0, 0, 0, 0, 0,
position.x + exts.x, position.y, position.z, 0, 0, 0, 0, -1, 0,
position.x, position.y + exts.y, position.z, 0, 0, 0, 0, 0, -1,
position.x + exts.x, position.y + exts.y, position.z, 0, 0, 0, 0, -1, -1,
position.x + exts.x, position.y, position.z, 0, 0, 0, 0, -1, 0,
position.x, position.y + exts.y, position.z, 0, 0, 0, 0, 0, -1,
]
} else {
this.data = [
position.x, position.y, position.z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
position.x + exts.x, position.y, position.z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
position.x, position.y + exts.y, position.z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
position.x + exts.x, position.y + exts.y, position.z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
position.x + exts.x, position.y, position.z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
position.x, position.y + exts.y, position.z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
]
}
this.vertexStride = 9;
this.stride = this.vertexStride * 4
gfx.toRender.push(this);
}
} }
export function drawIsometricCube(gfx: Graphics, position: Vec3, exts: Vec3, color: TileFill, edge: TileEdge) { export function drawTriangleExts(gfx: Graphics, position: Vec3, exts: Vec2, color: Assets.Color) {
const a_position = gfx.getAttribute("a_position");
const a_color = gfx.getAttribute("a_color");
const points: Array<number> = [
position.x, position.y, position.z,
position.x + exts.x, position.y, position.z,
position.x, position.y + exts.y, position.z,
]
const colors: Array<number[]> = [
color,
color,
color,
];
a_position.data(gfx.ctx, points, gfx.ctx.STATIC_DRAW);
a_color.data(gfx.ctx, colors.flat(), gfx.ctx.STATIC_DRAW);
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 3);
}
export function drawRectangle(gfx: Graphics, corners: [Vec3, Vec3, Vec3, Vec3], color: Assets.Color | Texture) {
const a_position = gfx.getAttribute("a_position");
const points: Array<number> = [
corners[0].x, corners[0].y, corners[0].z,
corners[1].x, corners[1].y, corners[1].z,
corners[3].x, corners[3].y, corners[3].z,
corners[2].x, corners[2].y, corners[2].z,
corners[1].x, corners[1].y, corners[1].z,
corners[3].x, corners[3].y, corners[3].z,
]
if (color instanceof Texture) {
const a_tex_position = gfx.getAttribute("a_tex_position");
const uv: Array<number> = [
0.0, 0.0,
-1.0, 0.0,
0.0, -1.0,
-1.0, -1.0,
-1.0, 0.0,
0.0, -1.0,
];
a_position.data(gfx.ctx, points, gfx.ctx.STATIC_DRAW);
a_tex_position.data(gfx.ctx, uv, gfx.ctx.STATIC_DRAW);
color.bind(gfx);
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 6);
color.unbind(gfx);
} else {
const a_color = gfx.getAttribute("a_color");
const colors: Array<number[]> = new Array(6);
colors.fill(color);
a_position.data(gfx.ctx, points, gfx.ctx.STATIC_DRAW);
a_color.data(gfx.ctx, colors.flat(), gfx.ctx.STATIC_DRAW);
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 6);
}
}
export function drawIsometricCube(gfx: Graphics, camera: Camera, position: Vec3, exts: Vec3, color: TileFill, edge: TileEdge) {
let points = [ let points = [
// Left Top // Left Top
position, position,
@ -122,12 +122,16 @@ export function drawIsometricCube(gfx: Graphics, position: Vec3, exts: Vec3, col
new Vec3(position.x + 0.5 * exts.x, position.y - 0.5 * exts.y, position.z + 0.25 * exts.z), new Vec3(position.x + 0.5 * exts.x, position.y - 0.5 * exts.y, position.z + 0.25 * exts.z),
]; ];
let r = new Rectangle(color.top, [ let screen = new Vec4(
DrawTag.ISO, -camera.position.x,
]); -camera.position.y,
gfx.ctx.canvas.width,
gfx.ctx.canvas.height);
gfx.ctx.uniform1i(gfx.getUniform("u_isIso"), 1);
// Top // Top
r.draw( drawRectangle(
gfx, gfx,
[ [
points[0], points[0],
@ -135,48 +139,44 @@ export function drawIsometricCube(gfx: Graphics, position: Vec3, exts: Vec3, col
points[3], points[3],
points[2], points[2],
], ],
); color.top);
// Right Edge // Right Edge
if (edge == TileEdge.Right || edge == TileEdge.Both) { if (edge == TileEdge.Right || edge == TileEdge.Both) {
r.fill = color.right; drawRectangle(
r.draw(
gfx, gfx,
[ [
points[3], points[3],
points[2], points[2],
points[4], points[4],
points[5], points[5],
] ],
); color.right);
} }
// Left Edge // Left Edge
if (edge == TileEdge.Left || edge == TileEdge.Both) { if (edge == TileEdge.Left || edge == TileEdge.Both) {
r.fill = color.left; drawRectangle(
r.draw(
gfx, gfx,
[ [
points[0], points[0],
points[2], points[2],
points[4], points[4],
points[6], points[6],
] ],
); color.left);
} }
gfx.ctx.uniform1i(gfx.getUniform("u_isIso"), 0);
} }
export function drawIsometricGrid(gfx: Graphics, grid: Grid) { export function drawIsometricGrid(gfx: Graphics, camera: Camera, grid: Grid) {
let position = {...grid.position} as Vec3; let position = {...grid.position} as Vec3;
let exts = new Vec3(grid.tileSize, grid.tileSize, 0); let exts = new Vec3(grid.tileSize, grid.tileSize, 0);
let tileCoord = new Vec3(0, 0, 0); let tileCoord = new Vec3(0, 0, 0);
// TODO: Optimize this // TODO: Optimize this
// 1. Grid based occlusion culling
// 2. frustum culling
for (let k = 0; k < grid.height; ++k) { for (let k = 0; k < grid.height; ++k) {
for (let j = 0; j < grid.length; ++j) { for (let j = 0; j < grid.length; ++j) {
for (let i = 0; i < grid.width; ++i) { for (let i = 0; i < grid.width; ++i) {
@ -184,8 +184,6 @@ export function drawIsometricGrid(gfx: Graphics, grid: Grid) {
tileCoord.y = j; tileCoord.y = j;
tileCoord.z = k; tileCoord.z = k;
// getTile is sus (it uses a lot of time in the profiler) (i don't know why, it is a pretty simple function)
// (Prolly cuz i call it a lot) (Maybe change grid to use spatial hashmap?)
let tile = grid.getTile(tileCoord); let tile = grid.getTile(tileCoord);
if (tile === null) { if (tile === null) {
@ -193,7 +191,7 @@ export function drawIsometricGrid(gfx: Graphics, grid: Grid) {
continue; continue;
} }
drawIsometricCube(gfx, new Vec3(position.x - grid.tileSize / 2 * k, position.y + grid.tileSize / 2 * k, position.z), exts, tile.fill, tile.edge); drawIsometricCube(gfx, camera, new Vec3(position.x - grid.tileSize / 2 * k, position.y + grid.tileSize / 2 * k, position.z), exts, tile.fill, tile.edge);
position.x += grid.tileSize; position.x += grid.tileSize;
} }
@ -203,3 +201,86 @@ export function drawIsometricGrid(gfx: Graphics, grid: Grid) {
position.y = grid.position.y; position.y = grid.position.y;
} }
} }
export function drawRectangleExts(gfx: Graphics, position: Vec3, exts: Vec2, color: Assets.Color | Texture) {
const a_position = gfx.getAttribute("a_position");
const points: Array<number> = [
position.x, position.y, position.z,
position.x + exts.x, position.y, position.z,
position.x, position.y + exts.y, position.z,
position.x + exts.x, position.y + exts.y, position.z,
position.x + exts.x, position.y, position.z,
position.x, position.y + exts.y, position.z,
]
if (color instanceof Texture) {
const a_tex_position = gfx.getAttribute("a_tex_position");
const uv: Array<number> = [
0.0, 0.0,
-1.0, 0.0,
0.0, -1.0,
-1.0, -1.0,
-1.0, 0.0,
0.0, -1.0,
];
a_position.data(gfx.ctx, points, gfx.ctx.STATIC_DRAW);
a_tex_position.data(gfx.ctx, uv, gfx.ctx.STATIC_DRAW);
color.bind(gfx);
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 6);
color.unbind(gfx);
} else {
const a_color = gfx.getAttribute("a_color");
const colors: Array<number[]> = new Array(6);
colors.fill(color);
a_position.data(gfx.ctx, points, gfx.ctx.STATIC_DRAW);
a_color.data(gfx.ctx, colors.flat(), gfx.ctx.STATIC_DRAW);
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 6);
}
}
export function drawCircle(gfx: Graphics, position: Vec2, radius: number, color: Assets.Color) {
const points: Array<Vec2> = new Array<Vec2>();
const precision = 40;
const angle = 2.0*Math.PI/precision;
let a = 0;
for (let i = 0; i < precision; ++i) {
var vec = Vec2.angle(a);
vec.multScalar(radius);
a += angle;
points.push(vec);
}
for (let i = 0; i < points.length; i++) {
const current = points[i];
const next = points[(i + 1) % points.length];
let center = position;
drawTriangle(gfx, [center, center.addNew(current), center.addNew(next)], color);
}
}
export function drawLine(gfx: Graphics, A: Vec2, B: Vec2, color: Assets.Color) {
const a_position = gfx.getAttribute("a_position");
const a_color = gfx.getAttribute("a_color");
let points: Array<number> = [
A.x, A.y,
B.x, B.y,
];
const colors: Array<number[]> = [
color,
color,
];
a_position.data(gfx.ctx, points, gfx.ctx.STATIC_DRAW);
a_color.data(gfx.ctx, colors.flat(), gfx.ctx.STATIC_DRAW);
gfx.ctx.drawArrays(gfx.ctx.LINES, 0, 2);
}

View File

@ -1,4 +1,4 @@
import { Vec2, Vec4 } from "./common.js"; import { Vec4 } from "./common.js";
export function fullscreenCanvas(gfx, id) { export function fullscreenCanvas(gfx, id) {
const canvas = document.getElementById(id); const canvas = document.getElementById(id);
canvas.width = window.innerWidth; canvas.width = window.innerWidth;
@ -39,24 +39,16 @@ function createProgram(ctx, vertexShaderSource, fragmentShaderSource) {
} }
return program; return program;
} }
export var DrawTag;
(function (DrawTag) {
DrawTag[DrawTag["ISO"] = 0] = "ISO";
})(DrawTag || (DrawTag = {}));
export class Graphics { export class Graphics {
ctx; ctx;
program; program;
attribs = new Map(); attribs = new Map();
uniforms = new Map(); uniforms = new Map();
vao; vao;
vbo;
toRender = [];
texCount = 0;
constructor(ctx, vs, fs) { constructor(ctx, vs, fs) {
this.ctx = ctx; this.ctx = ctx;
this.program = createProgram(ctx, vs, fs); this.program = createProgram(ctx, vs, fs);
this.vao = ctx.createVertexArray(); this.vao = ctx.createVertexArray();
this.vbo = ctx.createBuffer();
ctx.bindVertexArray(this.vao); ctx.bindVertexArray(this.vao);
ctx.viewport(0, 0, ctx.canvas.width, ctx.canvas.height); ctx.viewport(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.useProgram(this.program); ctx.useProgram(this.program);
@ -90,97 +82,60 @@ export class Graphics {
throw new Error("Tried to get uninitialized uniform: " + name); throw new Error("Tried to get uninitialized uniform: " + name);
return loc; return loc;
} }
draw() {
for (let o of this.toRender) {
this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, this.vbo);
this.ctx.bufferData(this.ctx.ARRAY_BUFFER, new Float32Array(o.data), this.ctx.STATIC_DRAW);
let aid = 0;
for (let a of o.attribs) {
let attr = this.getAttribute(a);
if (!attr.formatted)
throw new Error("Tried to use unformatted attribute!");
this.ctx.enableVertexAttribArray(attr.loc);
this.ctx.vertexAttribPointer(attr.loc, attr.size, attr.type, attr.normalized, o.stride, aid * 4);
aid += attr.size;
}
// Generalize the tag uniforms aka. don't hard code them
for (let t of o.tags) {
switch (t) {
case DrawTag.ISO: {
this.ctx.uniform1ui(this.getUniform("u_isIso"), 1);
break;
}
}
}
if (o.fill instanceof Texture) {
this.ctx.uniform1i(this.getUniform("u_isTex"), 1);
o.fill.bind(this);
}
this.ctx.drawArrays(this.ctx.TRIANGLES, 0, o.data.length / o.vertexStride);
if (o.fill instanceof Texture) {
this.ctx.uniform1i(this.getUniform("u_isTex"), 0);
o.fill.unbind(this);
}
for (let t of o.tags) {
switch (t) {
case DrawTag.ISO: {
this.ctx.uniform1ui(this.getUniform("u_isIso"), 0);
break;
}
}
}
}
// TODO: Maybe add persistent rendering?
this.toRender = [];
}
} }
export class Attribute { export class Attribute {
loc; loc;
formatted = false; buffer;
// TODO: maybe use undefined as default value?
size = 0; size = 0;
type = 0; type = 0;
offset = 0;
normalized = false; normalized = false;
stride = 0;
offset = 0;
constructor(ctx, program, name) { constructor(ctx, program, name) {
this.loc = ctx.getAttribLocation(program, name); this.loc = ctx.getAttribLocation(program, name);
this.buffer = ctx.createBuffer();
} }
format(size, type, normalized, offset) { format(size, type, normalized, stride, offset) {
this.size = size; this.size = size;
this.type = type; this.type = type;
this.normalized = normalized; this.normalized = normalized;
this.stride = stride;
this.offset = offset; this.offset = offset;
this.formatted = true; }
data(ctx, data, usage) {
ctx.enableVertexAttribArray(this.loc);
ctx.bindBuffer(ctx.ARRAY_BUFFER, this.buffer);
ctx.bufferData(ctx.ARRAY_BUFFER, new Float32Array(data), usage);
ctx.vertexAttribPointer(this.loc, this.size, this.type, this.normalized, this.stride, this.offset);
} }
} }
export class Texture { export class Texture {
tex; tex;
texId;
width = 0; width = 0;
height = 0; height = 0;
constructor(texId, tex, width, height) { constructor(tex, width, height) {
this.height = height; this.height = height;
this.width = width; this.width = width;
this.tex = tex; this.tex = tex;
this.texId = texId;
} }
// TODO: Load sprite sheet only once static async load(ctx, path) {
// TODO: Allow changing sprite size
static async load(gfx, path) {
let image = await loadTexture(path); let image = await loadTexture(path);
let tex = gfx.ctx.createTexture(); let tex = ctx.createTexture();
gfx.ctx.bindTexture(gfx.ctx.TEXTURE_2D, tex); ctx.bindTexture(ctx.TEXTURE_2D, tex);
gfx.ctx.texImage2D(gfx.ctx.TEXTURE_2D, 0, gfx.ctx.RGBA, gfx.ctx.RGBA, gfx.ctx.UNSIGNED_BYTE, image); ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGBA, ctx.RGBA, ctx.UNSIGNED_BYTE, image);
gfx.ctx.texParameteri(gfx.ctx.TEXTURE_2D, gfx.ctx.TEXTURE_MAG_FILTER, gfx.ctx.NEAREST); ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.NEAREST);
gfx.ctx.texParameteri(gfx.ctx.TEXTURE_2D, gfx.ctx.TEXTURE_MIN_FILTER, gfx.ctx.NEAREST); ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.NEAREST);
gfx.ctx.bindTexture(gfx.ctx.TEXTURE_2D, null); ctx.bindTexture(ctx.TEXTURE_2D, null);
gfx.texCount += 1; return new Texture(tex, image.width, image.height);
return new Texture(gfx.texCount, tex, image.width, image.height);
} }
bind(gfx) { bind(gfx) {
gfx.ctx.uniform1i(gfx.getUniform("u_isTex"), 1);
gfx.ctx.bindTexture(gfx.ctx.TEXTURE_2D, this.tex); gfx.ctx.bindTexture(gfx.ctx.TEXTURE_2D, this.tex);
} }
unbind(gfx) { unbind(gfx) {
gfx.ctx.bindTexture(gfx.ctx.TEXTURE_2D, null); gfx.ctx.bindTexture(gfx.ctx.TEXTURE_2D, null);
gfx.ctx.uniform1i(gfx.getUniform("u_isTex"), 0);
} }
} }
async function loadTexture(path) { async function loadTexture(path) {
@ -197,25 +152,14 @@ export class Camera {
position; position;
movement; movement;
speed = 600; speed = 600;
scale = 1.0;
scaling;
scaleSpeed = 1.5;
constructor(position) { constructor(position) {
this.position = position; this.position = position;
this.movement = new Vec4(0, 0, 0, 0); this.movement = new Vec4(0, 0, 0, 0);
this.scaling = new Vec2(0, 0);
} }
update(dt) { update(dt) {
this.dt = dt; this.dt = dt;
let newPosition = this.movement.multScalarNew(this.dt); let newPosition = this.movement.multScalarNew(this.dt);
this.position.x += (newPosition.x + newPosition.y) * this.speed; this.position.x += (newPosition.x + newPosition.y) * this.speed;
this.position.y += (newPosition.z + newPosition.w) * this.speed; this.position.y += (newPosition.z + newPosition.w) * this.speed;
this.scale += (this.scaling.x + this.scaling.y) * this.dt * this.scaleSpeed;
if (this.scale < 0.5) {
this.scale = 0.5;
}
if (this.scale > 1.5) {
this.scale = 1.5;
}
} }
} }

View File

@ -1,4 +1,3 @@
import * as Assets from "./assets.js";
import {Vec2, Vec3, Vec4} from "./common.js"; import {Vec2, Vec3, Vec4} from "./common.js";
export function fullscreenCanvas(gfx: Graphics, id: string) { export function fullscreenCanvas(gfx: Graphics, id: string) {
@ -52,36 +51,16 @@ function createProgram(ctx: WebGL2RenderingContext, vertexShaderSource: string |
return program; return program;
} }
export enum DrawTag {
ISO,
}
export interface Drawable {
fill: Texture | Assets.Color;
attribs: string[];
tags: Array<DrawTag>;
data: Array<number>;
vertexStride: number;
stride: number;
}
export class Graphics { export class Graphics {
ctx: WebGL2RenderingContext; ctx: WebGL2RenderingContext;
program: WebGLProgram; program: WebGLProgram;
attribs: Map<string, Attribute> = new Map(); attribs: Map<string, Attribute> = new Map();
uniforms: Map<string, WebGLUniformLocation> = new Map(); uniforms: Map<string, WebGLUniformLocation> = new Map();
vao: WebGLVertexArrayObject; vao: WebGLVertexArrayObject;
vbo: WebGLBuffer;
toRender: Array<Drawable> = [];
texCount: number = 0;
constructor(ctx: WebGL2RenderingContext, vs: string, fs: string) { constructor(ctx: WebGL2RenderingContext, vs: string, fs: string) {
this.ctx = ctx; this.ctx = ctx;
this.program = createProgram(ctx, vs, fs); this.program = createProgram(ctx, vs, fs);
this.vao = ctx.createVertexArray(); this.vao = ctx.createVertexArray();
this.vbo = ctx.createBuffer();
ctx.bindVertexArray(this.vao); ctx.bindVertexArray(this.vao);
ctx.viewport(0, 0, ctx.canvas.width, ctx.canvas.height); ctx.viewport(0, 0, ctx.canvas.width, ctx.canvas.height);
@ -128,126 +107,78 @@ export class Graphics {
return loc; return loc;
} }
draw() {
for (let o of this.toRender) {
this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, this.vbo);
this.ctx.bufferData(this.ctx.ARRAY_BUFFER, new Float32Array(o.data), this.ctx.STATIC_DRAW);
let aid = 0;
for (let a of o.attribs) {
let attr = this.getAttribute(a);
if (!attr.formatted)
throw new Error("Tried to use unformatted attribute!");
this.ctx.enableVertexAttribArray(attr.loc);
this.ctx.vertexAttribPointer(attr.loc, attr.size, attr.type, attr.normalized, o.stride, aid * 4);
aid += attr.size;
}
// Generalize the tag uniforms aka. don't hard code them
for (let t of o.tags) {
switch (t) {
case DrawTag.ISO: {
this.ctx.uniform1ui(this.getUniform("u_isIso"), 1);
break;
}
}
}
if (o.fill instanceof Texture)
{
this.ctx.uniform1i(this.getUniform("u_isTex"), 1);
o.fill.bind(this);
}
this.ctx.drawArrays(this.ctx.TRIANGLES, 0, o.data.length / o.vertexStride);
if (o.fill instanceof Texture)
{
this.ctx.uniform1i(this.getUniform("u_isTex"), 0);
o.fill.unbind(this);
}
for (let t of o.tags) {
switch (t) {
case DrawTag.ISO: {
this.ctx.uniform1ui(this.getUniform("u_isIso"), 0);
break;
}
}
}
}
// TODO: Maybe add persistent rendering?
this.toRender = [];
}
} }
export class Attribute { export class Attribute {
loc: GLint; loc: GLint;
formatted: boolean = false; buffer: WebGLBuffer;
// TODO: maybe use undefined as default value?
size: GLint = 0; size: GLint = 0;
type: GLenum = 0; type: GLenum = 0;
offset: GLintptr = 0;
normalized: GLboolean = false; normalized: GLboolean = false;
stride: GLsizei = 0;
offset: GLintptr = 0;
constructor(ctx: WebGL2RenderingContext, program: WebGLProgram, name: string) { constructor(ctx: WebGL2RenderingContext, program: WebGLProgram, name: string) {
this.loc = ctx.getAttribLocation(program, name); this.loc = ctx.getAttribLocation(program, name);
this.buffer = ctx.createBuffer();
} }
format( format(
size: GLint, size: GLint,
type: GLenum, type: GLenum,
normalized: GLboolean, normalized: GLboolean,
stride: GLsizei,
offset: GLintptr) offset: GLintptr)
{ {
this.size = size; this.size = size;
this.type = type; this.type = type;
this.normalized = normalized; this.normalized = normalized;
this.stride = stride;
this.offset = offset; this.offset = offset;
}
this.formatted = true; data(ctx: WebGL2RenderingContext, data: Array<number>, usage: GLenum) {
ctx.enableVertexAttribArray(this.loc);
ctx.bindBuffer(ctx.ARRAY_BUFFER, this.buffer);
ctx.bufferData(ctx.ARRAY_BUFFER, new Float32Array(data), usage);
ctx.vertexAttribPointer(this.loc, this.size, this.type, this.normalized, this.stride, this.offset);
} }
} }
export class Texture { export class Texture {
tex: WebGLTexture | null; tex: WebGLTexture | null;
texId: number;
width: number = 0; width: number = 0;
height: number = 0; height: number = 0;
constructor(texId: number, tex: WebGLTexture, width: number, height: number) { constructor(tex: WebGLTexture, width: number, height: number) {
this.height = height; this.height = height;
this.width = width; this.width = width;
this.tex = tex; this.tex = tex;
this.texId = texId;
} }
// TODO: Load sprite sheet only once static async load(ctx: WebGL2RenderingContext, path: string): Promise<Texture> {
// TODO: Allow changing sprite size
static async load(gfx: Graphics, path: string): Promise<Texture> {
let image = await loadTexture(path); let image = await loadTexture(path);
let tex = gfx.ctx.createTexture(); let tex = ctx.createTexture();
gfx.ctx.bindTexture(gfx.ctx.TEXTURE_2D, tex); ctx.bindTexture(ctx.TEXTURE_2D, tex);
gfx.ctx.texImage2D(gfx.ctx.TEXTURE_2D, 0, gfx.ctx.RGBA, gfx.ctx.RGBA, gfx.ctx.UNSIGNED_BYTE, image); ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGBA, ctx.RGBA, ctx.UNSIGNED_BYTE, image);
gfx.ctx.texParameteri(gfx.ctx.TEXTURE_2D, gfx.ctx.TEXTURE_MAG_FILTER, gfx.ctx.NEAREST); ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.NEAREST);
gfx.ctx.texParameteri(gfx.ctx.TEXTURE_2D, gfx.ctx.TEXTURE_MIN_FILTER, gfx.ctx.NEAREST); ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.NEAREST);
gfx.ctx.bindTexture(gfx.ctx.TEXTURE_2D, null); ctx.bindTexture(ctx.TEXTURE_2D, null);
gfx.texCount += 1; return new Texture(tex, image.width, image.height);
return new Texture(gfx.texCount, tex, image.width, image.height);
} }
bind(gfx: Graphics) { bind(gfx: Graphics) {
gfx.ctx.uniform1i(gfx.getUniform("u_isTex"), 1);
gfx.ctx.bindTexture(gfx.ctx.TEXTURE_2D, this.tex); gfx.ctx.bindTexture(gfx.ctx.TEXTURE_2D, this.tex);
} }
unbind(gfx: Graphics) { unbind(gfx: Graphics) {
gfx.ctx.bindTexture(gfx.ctx.TEXTURE_2D, null); gfx.ctx.bindTexture(gfx.ctx.TEXTURE_2D, null);
gfx.ctx.uniform1i(gfx.getUniform("u_isTex"), 0);
} }
} }
@ -263,19 +194,13 @@ async function loadTexture(path: string): Promise<HTMLImageElement> {
export class Camera { export class Camera {
dt: number = 0; dt: number = 0;
position: Vec3; position: Vec3;
movement: Vec4; movement: Vec4;
speed: number = 600; speed: number = 600;
scale: number = 1.0;
scaling: Vec2;
scaleSpeed: number = 1.5;
constructor(position: Vec3) { constructor(position: Vec3) {
this.position = position; this.position = position;
this.movement = new Vec4(0, 0, 0, 0); this.movement = new Vec4(0, 0, 0, 0);
this.scaling = new Vec2(0, 0);
} }
update(dt: number) { update(dt: number) {
@ -284,16 +209,6 @@ export class Camera {
let newPosition = this.movement.multScalarNew(this.dt); let newPosition = this.movement.multScalarNew(this.dt);
this.position.x += (newPosition.x + newPosition.y) * this.speed; this.position.x += (newPosition.x + newPosition.y) * this.speed;
this.position.y += (newPosition.z + newPosition.w) * this.speed; this.position.y += (newPosition.z + newPosition.w) * this.speed;
this.scale += (this.scaling.x + this.scaling.y) * this.dt * this.scaleSpeed;
if (this.scale < 0.5) {
this.scale = 0.5;
}
if (this.scale > 1.5) {
this.scale = 1.5;
}
} }
} }

View File

@ -7,16 +7,14 @@ import { bush, Grid, Tile, tree } from "./world.js";
import * as Assets from "./assets.js"; import * as Assets from "./assets.js";
const vertexShader = `#version 300 es const vertexShader = `#version 300 es
layout(location = 0) in vec3 a_position; in vec3 a_position;
layout(location = 1) in vec2 a_tex_position; in vec2 a_tex_position;
layout(location = 2) in vec4 a_color;
out vec4 v_color;
out vec2 v_tex_position; out vec2 v_tex_position;
in vec4 a_color;
out vec4 v_color;
uniform mat4 u_matrix; uniform mat4 u_matrix;
uniform bool u_isIso;
uniform bool u_isTex; uniform bool u_isTex;
uniform bool u_isIso;
mat4 Iso = mat4( mat4 Iso = mat4(
1, -1, 0, 0, 1, -1, 0, 0,
@ -49,12 +47,12 @@ const fragmentShader = `#version 300 es
precision highp float; precision highp float;
in vec4 v_color;
in vec2 v_tex_position; in vec2 v_tex_position;
in vec4 v_color;
out vec4 outColor; out vec4 outColor;
uniform bool u_isTex;
uniform sampler2D u_texture; uniform sampler2D u_texture;
uniform bool u_isTex;
void main() { void main() {
if (u_isTex) { if (u_isTex) {
@ -67,26 +65,18 @@ const fragmentShader = `#version 300 es
function draw(gfx, camera, dt, grid) { function draw(gfx, camera, dt, grid) {
gfx.clear(0, 0, 0, 0); gfx.clear(0, 0, 0, 0);
camera.update(dt); camera.update(dt);
let right = gfx.ctx.canvas.width; let zoom = 1;
let right = gfx.ctx.canvas.width * zoom;
let left = 0; let left = 0;
let top = gfx.ctx.canvas.height; let top = gfx.ctx.canvas.height * zoom;
let bottom = 0; let bottom = 0;
let near = -100; let near = -100;
let far = 100; let far = 100;
let m = Mat4.IDENTITY();
let mo = Mat4.orthographic(left, right, bottom, top, near, far); let mo = Mat4.orthographic(left, right, bottom, top, near, far);
let mc = Mat4.translate(new Vec3((gfx.ctx.canvas.width / 2 - camera.position.x), (gfx.ctx.canvas.height / 2 - camera.position.y), 1.0));
let mr = Mat4.translate(new Vec3(-(gfx.ctx.canvas.width / 2 - camera.position.x), -(gfx.ctx.canvas.height / 2 - camera.position.y), 1.0));
let mt = Mat4.translate(camera.position); let mt = Mat4.translate(camera.position);
let ms = Mat4.scale(new Vec3(camera.scale, camera.scale, 1)); let m = mt.multNew(mo);
m = m.multNew(mr);
m = m.multNew(ms);
m = m.multNew(mc);
m = m.multNew(mt);
m = m.multNew(mo);
gfx.ctx.uniformMatrix4fv(gfx.getUniform("u_matrix"), false, m.splat()); gfx.ctx.uniformMatrix4fv(gfx.getUniform("u_matrix"), false, m.splat());
drawing.drawIsometricGrid(gfx, grid); drawing.drawIsometricGrid(gfx, camera, grid);
gfx.draw();
} }
function addDefaultKeybinds(input, camera) { function addDefaultKeybinds(input, camera) {
input.addKeyAction("KeyA", [], camera, (c) => { input.addKeyAction("KeyA", [], camera, (c) => {
@ -109,16 +99,6 @@ function addDefaultKeybinds(input, camera) {
}, (c) => { }, (c) => {
c.movement.w = 1; c.movement.w = 1;
}); });
input.addKeyAction("KeyQ", [], camera, (c) => {
c.scaling.x = 0.0;
}, (c) => {
c.scaling.x = 1.0;
});
input.addKeyAction("KeyE", [], camera, (c) => {
c.scaling.y = 0.0;
}, (c) => {
c.scaling.y = -1.0;
});
} }
(async () => { (async () => {
const canvasId = "game"; const canvasId = "game";
@ -127,19 +107,19 @@ function addDefaultKeybinds(input, camera) {
return; return;
const gfx = new Graphics(ctx, vertexShader, fragmentShader); const gfx = new Graphics(ctx, vertexShader, fragmentShader);
fullscreenCanvas(gfx, canvasId); fullscreenCanvas(gfx, canvasId);
let a = gfx.createAttribute("a_position"); const a_position = gfx.createAttribute("a_position");
a.format(3, ctx.FLOAT, false, 0); a_position.format(3, gfx.ctx.FLOAT, false, 0, 0);
a = gfx.createAttribute("a_color"); const a_color = gfx.createAttribute("a_color");
a.format(4, ctx.FLOAT, false, 0); a_color.format(4, gfx.ctx.FLOAT, false, 0, 0);
a = gfx.createAttribute("a_tex_position"); const a_tex_position = gfx.createAttribute("a_tex_position");
a.format(2, ctx.FLOAT, false, 0); a_tex_position.format(2, gfx.ctx.FLOAT, false, 0, 0);
gfx.createUniform("u_matrix"); gfx.createUniform("u_matrix");
gfx.createUniform("u_isIso");
gfx.createUniform("u_isTex"); gfx.createUniform("u_isTex");
gfx.createUniform("u_isIso");
let camera = new Camera(new Vec3(0, 0, -1)); let camera = new Camera(new Vec3(0, 0, -1));
await Assets.assets.load(gfx); await Assets.assets.load(ctx);
let m = Mat4.isometric(); let m = Mat4.isometric();
let size = 100; let size = 20;
let grid = new Grid(m.transformNew(new Vec4(ctx.canvas.width / 4, ctx.canvas.height / 2, 0, 1)).reduce(), 24, size, size, 10); let grid = new Grid(m.transformNew(new Vec4(ctx.canvas.width / 4, ctx.canvas.height / 2, 0, 1)).reduce(), 24, size, size, 10);
grid.fillLayer(new Tile({ grid.fillLayer(new Tile({
top: Assets.assets.get("grass"), top: Assets.assets.get("grass"),

View File

@ -1,24 +1,22 @@
import { initializeContext, Vec3, Mat4, Vec4, Vec2 } from "./common.js"; import { initializeContext, Vec3, Mat4, Vec4, Vec2 } from "./common.js";
import { Graphics, fullscreenCanvas, Camera, DrawTag } from "./graphics.js"; import { Graphics, fullscreenCanvas, Camera } from "./graphics.js";
import * as drawing from "./draw.js"; import * as drawing from "./draw.js";
import * as wasm from "./wasm.js"; import * as wasm from "./wasm.js";
import { Input } from "./input.js"; import { Input } from "./input.js";
import {bush, Grid, Tile, TileEdge, tree} from "./world.js"; import {bush, Grid, Tile, tree} from "./world.js";
import * as Assets from "./assets.js"; import * as Assets from "./assets.js";
const vertexShader = const vertexShader =
`#version 300 es `#version 300 es
layout(location = 0) in vec3 a_position; in vec3 a_position;
layout(location = 1) in vec2 a_tex_position; in vec2 a_tex_position;
layout(location = 2) in vec4 a_color;
out vec4 v_color;
out vec2 v_tex_position; out vec2 v_tex_position;
in vec4 a_color;
out vec4 v_color;
uniform mat4 u_matrix; uniform mat4 u_matrix;
uniform bool u_isIso;
uniform bool u_isTex; uniform bool u_isTex;
uniform bool u_isIso;
mat4 Iso = mat4( mat4 Iso = mat4(
1, -1, 0, 0, 1, -1, 0, 0,
@ -53,12 +51,12 @@ const fragmentShader =
precision highp float; precision highp float;
in vec4 v_color;
in vec2 v_tex_position; in vec2 v_tex_position;
in vec4 v_color;
out vec4 outColor; out vec4 outColor;
uniform bool u_isTex;
uniform sampler2D u_texture; uniform sampler2D u_texture;
uniform bool u_isTex;
void main() { void main() {
if (u_isTex) { if (u_isTex) {
@ -73,38 +71,17 @@ function draw(gfx: Graphics, camera: Camera, dt: number, grid: Grid) {
gfx.clear(0, 0, 0, 0); gfx.clear(0, 0, 0, 0);
camera.update(dt); camera.update(dt);
let right = gfx.ctx.canvas.width; let zoom = 1;
let right = gfx.ctx.canvas.width * zoom;
let left = 0; let left = 0;
let top = gfx.ctx.canvas.height; let top = gfx.ctx.canvas.height * zoom;
let bottom = 0; let bottom = 0;
let near = -100; let near = -100;
let far = 100; let far = 100;
let m = Mat4.IDENTITY();
let mo = Mat4.orthographic(left, right, bottom, top, near, far); let mo = Mat4.orthographic(left, right, bottom, top, near, far);
let mc = Mat4.translate(
new Vec3(
(gfx.ctx.canvas.width / 2 - camera.position.x),
(gfx.ctx.canvas.height / 2 - camera.position.y),
1.0));
let mr = Mat4.translate(
new Vec3(
-(gfx.ctx.canvas.width / 2 - camera.position.x),
-(gfx.ctx.canvas.height / 2 - camera.position.y),
1.0));
let mt = Mat4.translate(camera.position); let mt = Mat4.translate(camera.position);
let m = mt.multNew(mo);
let ms = Mat4.scale(new Vec3(camera.scale, camera.scale, 1));
m = m.multNew(mr);
m = m.multNew(ms);
m = m.multNew(mc);
m = m.multNew(mt);
m = m.multNew(mo);
gfx.ctx.uniformMatrix4fv( gfx.ctx.uniformMatrix4fv(
gfx.getUniform("u_matrix"), gfx.getUniform("u_matrix"),
@ -112,8 +89,7 @@ function draw(gfx: Graphics, camera: Camera, dt: number, grid: Grid) {
m.splat() m.splat()
); );
drawing.drawIsometricGrid(gfx, grid); drawing.drawIsometricGrid(gfx, camera, grid);
gfx.draw();
} }
function addDefaultKeybinds(input: Input, camera: Camera) { function addDefaultKeybinds(input: Input, camera: Camera) {
@ -148,22 +124,6 @@ function addDefaultKeybinds(input: Input, camera: Camera) {
(c) => { (c) => {
c.movement.w = 1; c.movement.w = 1;
}); });
input.addKeyAction("KeyQ", [], camera,
(c) => {
c.scaling.x = 0.0;
},
(c) => {
c.scaling.x = 1.0;
});
input.addKeyAction("KeyE", [], camera,
(c) => {
c.scaling.y = 0.0;
},
(c) => {
c.scaling.y = -1.0;
});
} }
(async () => { (async () => {
@ -174,24 +134,26 @@ function addDefaultKeybinds(input: Input, camera: Camera) {
const gfx = new Graphics(ctx, vertexShader, fragmentShader); const gfx = new Graphics(ctx, vertexShader, fragmentShader);
fullscreenCanvas(gfx, canvasId); fullscreenCanvas(gfx, canvasId);
let a = gfx.createAttribute("a_position"); const a_position = gfx.createAttribute("a_position");
a.format(3, ctx.FLOAT, false, 0) a_position.format(3, gfx.ctx.FLOAT, false, 0, 0);
a = gfx.createAttribute("a_color");
a.format(4, ctx.FLOAT, false, 0) const a_color = gfx.createAttribute("a_color");
a = gfx.createAttribute("a_tex_position"); a_color.format(4, gfx.ctx.FLOAT, false, 0, 0);
a.format(2, ctx.FLOAT, false, 0)
const a_tex_position = gfx.createAttribute("a_tex_position");
a_tex_position.format(2, gfx.ctx.FLOAT, false, 0, 0);
gfx.createUniform("u_matrix"); gfx.createUniform("u_matrix");
gfx.createUniform("u_isIso");
gfx.createUniform("u_isTex"); gfx.createUniform("u_isTex");
gfx.createUniform("u_isIso");
let camera = new Camera(new Vec3(0, 0, -1)); let camera = new Camera(new Vec3(0, 0, -1));
await Assets.assets.load(gfx); await Assets.assets.load(ctx);
let m = Mat4.isometric(); let m = Mat4.isometric();
let size = 100; let size = 20;
let grid = new Grid(m.transformNew(new Vec4(ctx.canvas.width / 4, ctx.canvas.height / 2, 0, 1)).reduce(), 24, size, size, 10); let grid = new Grid(m.transformNew(new Vec4(ctx.canvas.width / 4, ctx.canvas.height / 2, 0, 1)).reduce(), 24, size, size, 10);
grid.fillLayer(new Tile({ grid.fillLayer(new Tile({
top: Assets.assets.get("grass"), top: Assets.assets.get("grass"),