Compare commits
3 Commits
14d5db166e
...
2e9ec2565b
Author | SHA1 | Date |
---|---|---|
|
2e9ec2565b | |
|
87ad6fbd9d | |
|
912487d264 |
Binary file not shown.
After Width: | Height: | Size: 511 B |
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
|
@ -26,12 +26,10 @@ 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(ctx) {
|
async load(gfx) {
|
||||||
assets.push("city", await Texture.load(ctx, "../../assets/genetica/rt/City Night.jpg"));
|
assets.push("grass", await Texture.load(gfx, "../../assets/grass2.png"));
|
||||||
assets.push("wall", await Texture.load(ctx, "../../assets/wall.png"));
|
assets.push("leaves", await Texture.load(gfx, "../../assets/greenary.png"));
|
||||||
assets.push("grass", await Texture.load(ctx, "../../assets/grass.png"));
|
assets.push("log", await Texture.load(gfx, "../../assets/log.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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import {Texture} from "./graphics.js";
|
import {Graphics, 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,12 +40,11 @@ export class Assets {
|
||||||
return this.assets.get(name)!;
|
return this.assets.get(name)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
async load(ctx: WebGL2RenderingContext) {
|
async load(gfx: Graphics) {
|
||||||
assets.push("city", await Texture.load(ctx, "../../assets/genetica/rt/City Night.jpg"));
|
assets.push("grass", await Texture.load(gfx, "../../assets/grass2.png"));
|
||||||
assets.push("wall", await Texture.load(ctx, "../../assets/wall.png"));
|
assets.push("leaves", await Texture.load(gfx, "../../assets/greenary.png"));
|
||||||
assets.push("grass", await Texture.load(ctx, "../../assets/grass.png"));
|
assets.push("log", await Texture.load(gfx, "../../assets/log.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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -267,6 +267,14 @@ 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,
|
||||||
|
@ -330,6 +338,14 @@ 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];
|
||||||
}
|
}
|
||||||
|
|
|
@ -379,6 +379,15 @@ 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,
|
||||||
|
@ -454,6 +463,15 @@ 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];
|
||||||
}
|
}
|
||||||
|
|
238
src/js/draw.js
238
src/js/draw.js
|
@ -1,5 +1,5 @@
|
||||||
import { Vec3, Vec2, Vec4 } from "./common.js";
|
import { Vec3 } from "./common.js";
|
||||||
import { Texture } from "./graphics.js";
|
import { Texture, DrawTag } 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,76 +13,80 @@ function cull(point, screen, tileSize) {
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
export function drawTriangle(gfx, positions, color) {
|
// Attrib format
|
||||||
const a_position = gfx.getAttribute("a_position");
|
// position color uv
|
||||||
const a_color = gfx.getAttribute("a_color");
|
// (3) (4) (2) => 3 + 4 + 2 = 9 <=> data.len % 9 == 0
|
||||||
const points = [
|
export class Rectangle {
|
||||||
positions[0].x, positions[0].y,
|
fill;
|
||||||
positions[1].x, positions[1].y,
|
attribs = ["a_position", "a_color", "a_tex_position"];
|
||||||
positions[2].x, positions[2].y,
|
tags = [];
|
||||||
];
|
data = [];
|
||||||
const colors = [
|
stride = 0;
|
||||||
color,
|
vertexStride = 0;
|
||||||
color,
|
constructor(fill, tags, attribs) {
|
||||||
color,
|
this.fill = fill;
|
||||||
];
|
if (attribs !== undefined) {
|
||||||
a_position.data(gfx.ctx, points, gfx.ctx.STATIC_DRAW);
|
this.attribs = attribs;
|
||||||
a_color.data(gfx.ctx, colors.flat(), gfx.ctx.STATIC_DRAW);
|
}
|
||||||
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 3);
|
if (tags !== undefined) {
|
||||||
}
|
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);
|
|
||||||
}
|
}
|
||||||
else {
|
overrideDraw(draw) {
|
||||||
const a_color = gfx.getAttribute("a_color");
|
this.draw = draw;
|
||||||
const colors = new Array(6);
|
}
|
||||||
colors.fill(color);
|
draw(gfx, corners) {
|
||||||
a_position.data(gfx.ctx, points, gfx.ctx.STATIC_DRAW);
|
if (this.fill instanceof Texture) {
|
||||||
a_color.data(gfx.ctx, colors.flat(), gfx.ctx.STATIC_DRAW);
|
this.data = [
|
||||||
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 6);
|
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, 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, camera, position, exts, color, edge) {
|
export function drawIsometricCube(gfx, position, exts, color, edge) {
|
||||||
let points = [
|
let points = [
|
||||||
// Left Top
|
// Left Top
|
||||||
position,
|
position,
|
||||||
|
@ -97,52 +101,58 @@ export function drawIsometricCube(gfx, camera, 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 screen = new Vec4(-camera.position.x, -camera.position.y, gfx.ctx.canvas.width, gfx.ctx.canvas.height);
|
let r = new Rectangle(color.top, [
|
||||||
gfx.ctx.uniform1i(gfx.getUniform("u_isIso"), 1);
|
DrawTag.ISO,
|
||||||
|
]);
|
||||||
// Top
|
// Top
|
||||||
drawRectangle(gfx, [
|
r.draw(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) {
|
||||||
drawRectangle(gfx, [
|
r.fill = color.right;
|
||||||
|
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) {
|
||||||
drawRectangle(gfx, [
|
r.fill = color.left;
|
||||||
|
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, camera, grid) {
|
export function drawIsometricGrid(gfx, 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, camera, new Vec3(position.x - grid.tileSize / 2 * k, position.y + grid.tileSize / 2 * k, position.z), exts, tile.fill, tile.edge);
|
drawIsometricCube(gfx, 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;
|
||||||
|
@ -151,71 +161,3 @@ export function drawIsometricGrid(gfx, camera, 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);
|
|
||||||
}
|
|
||||||
|
|
285
src/js/draw.ts
285
src/js/draw.ts
|
@ -1,6 +1,6 @@
|
||||||
import { Vec3, Vec2, Vec4, Mat4 } from "./common.js"
|
import { Vec3, Vec2, Vec4 } from "./common.js"
|
||||||
import { Camera, Graphics, Texture } from "./graphics.js";
|
import { Graphics, Texture, Drawable, DrawTag } from "./graphics.js";
|
||||||
import {Grid, TileEdge, TileFill} from "./world.js";
|
import { TileEdge, TileFill, Grid } 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function drawTriangle(gfx: Graphics, positions: [Vec2, Vec2, Vec2], color: Assets.Color) {
|
// Attrib format
|
||||||
const a_position = gfx.getAttribute("a_position");
|
// position color uv
|
||||||
const a_color = gfx.getAttribute("a_color");
|
// (3) (4) (2) => 3 + 4 + 2 = 9 <=> data.len % 9 == 0
|
||||||
|
|
||||||
const points: Array<number> = [
|
export class Rectangle implements Drawable {
|
||||||
positions[0].x, positions[0].y,
|
fill: Texture | Assets.Color;
|
||||||
positions[1].x, positions[1].y,
|
attribs: string[] = ["a_position", "a_color", "a_tex_position"];
|
||||||
positions[2].x, positions[2].y,
|
tags: Array<DrawTag> = [];
|
||||||
]
|
|
||||||
|
|
||||||
const colors: Array<number[]> = [
|
data: number[] = [];
|
||||||
color,
|
stride: number = 0;
|
||||||
color,
|
vertexStride: number = 0;
|
||||||
color,
|
|
||||||
];
|
|
||||||
|
|
||||||
a_position.data(gfx.ctx, points, gfx.ctx.STATIC_DRAW);
|
constructor(fill: Texture | Assets.Color, tags?: Array<DrawTag>, attribs?: string[]) {
|
||||||
a_color.data(gfx.ctx, colors.flat(), gfx.ctx.STATIC_DRAW);
|
this.fill = fill;
|
||||||
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function drawTriangleExts(gfx: Graphics, position: Vec3, exts: Vec2, color: Assets.Color) {
|
if (attribs !== undefined) {
|
||||||
const a_position = gfx.getAttribute("a_position");
|
this.attribs = attribs;
|
||||||
const a_color = gfx.getAttribute("a_color");
|
}
|
||||||
|
|
||||||
const points: Array<number> = [
|
if (tags !== undefined) {
|
||||||
position.x, position.y, position.z,
|
this.tags = tags;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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, camera: Camera, position: Vec3, exts: Vec3, color: TileFill, edge: TileEdge) {
|
export function drawIsometricCube(gfx: Graphics, position: Vec3, exts: Vec3, color: TileFill, edge: TileEdge) {
|
||||||
let points = [
|
let points = [
|
||||||
// Left Top
|
// Left Top
|
||||||
position,
|
position,
|
||||||
|
@ -122,16 +122,12 @@ export function drawIsometricCube(gfx: Graphics, camera: Camera, position: Vec3,
|
||||||
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 screen = new Vec4(
|
let r = new Rectangle(color.top, [
|
||||||
-camera.position.x,
|
DrawTag.ISO,
|
||||||
-camera.position.y,
|
]);
|
||||||
gfx.ctx.canvas.width,
|
|
||||||
gfx.ctx.canvas.height);
|
|
||||||
|
|
||||||
gfx.ctx.uniform1i(gfx.getUniform("u_isIso"), 1);
|
|
||||||
|
|
||||||
// Top
|
// Top
|
||||||
drawRectangle(
|
r.draw(
|
||||||
gfx,
|
gfx,
|
||||||
[
|
[
|
||||||
points[0],
|
points[0],
|
||||||
|
@ -139,44 +135,48 @@ export function drawIsometricCube(gfx: Graphics, camera: Camera, position: Vec3,
|
||||||
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) {
|
||||||
drawRectangle(
|
r.fill = color.right;
|
||||||
|
|
||||||
|
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) {
|
||||||
drawRectangle(
|
r.fill = color.left;
|
||||||
|
|
||||||
|
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, camera: Camera, grid: Grid) {
|
export function drawIsometricGrid(gfx: Graphics, 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,6 +184,8 @@ export function drawIsometricGrid(gfx: Graphics, camera: Camera, 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) {
|
||||||
|
@ -191,7 +193,7 @@ export function drawIsometricGrid(gfx: Graphics, camera: Camera, grid: Grid) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
drawIsometricCube(gfx, camera, new Vec3(position.x - grid.tileSize / 2 * k, position.y + grid.tileSize / 2 * k, position.z), exts, tile.fill, tile.edge);
|
drawIsometricCube(gfx, 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;
|
||||||
}
|
}
|
||||||
|
@ -201,86 +203,3 @@ export function drawIsometricGrid(gfx: Graphics, camera: Camera, 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);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Vec4 } from "./common.js";
|
import { Vec2, 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,16 +39,24 @@ 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);
|
||||||
|
@ -82,60 +90,97 @@ 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;
|
||||||
buffer;
|
formatted = false;
|
||||||
// TODO: maybe use undefined as default value?
|
|
||||||
size = 0;
|
size = 0;
|
||||||
type = 0;
|
type = 0;
|
||||||
normalized = false;
|
|
||||||
stride = 0;
|
|
||||||
offset = 0;
|
offset = 0;
|
||||||
|
normalized = false;
|
||||||
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, stride, offset) {
|
format(size, type, normalized, 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(tex, width, height) {
|
constructor(texId, tex, width, height) {
|
||||||
this.height = height;
|
this.height = height;
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.tex = tex;
|
this.tex = tex;
|
||||||
|
this.texId = texId;
|
||||||
}
|
}
|
||||||
static async load(ctx, path) {
|
// TODO: Load sprite sheet only once
|
||||||
|
// TODO: Allow changing sprite size
|
||||||
|
static async load(gfx, path) {
|
||||||
let image = await loadTexture(path);
|
let image = await loadTexture(path);
|
||||||
let tex = ctx.createTexture();
|
let tex = gfx.ctx.createTexture();
|
||||||
ctx.bindTexture(ctx.TEXTURE_2D, tex);
|
gfx.ctx.bindTexture(gfx.ctx.TEXTURE_2D, tex);
|
||||||
ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGBA, ctx.RGBA, ctx.UNSIGNED_BYTE, image);
|
gfx.ctx.texImage2D(gfx.ctx.TEXTURE_2D, 0, gfx.ctx.RGBA, gfx.ctx.RGBA, gfx.ctx.UNSIGNED_BYTE, image);
|
||||||
ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.NEAREST);
|
gfx.ctx.texParameteri(gfx.ctx.TEXTURE_2D, gfx.ctx.TEXTURE_MAG_FILTER, gfx.ctx.NEAREST);
|
||||||
ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.NEAREST);
|
gfx.ctx.texParameteri(gfx.ctx.TEXTURE_2D, gfx.ctx.TEXTURE_MIN_FILTER, gfx.ctx.NEAREST);
|
||||||
ctx.bindTexture(ctx.TEXTURE_2D, null);
|
gfx.ctx.bindTexture(gfx.ctx.TEXTURE_2D, null);
|
||||||
return new Texture(tex, image.width, image.height);
|
gfx.texCount += 1;
|
||||||
|
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) {
|
||||||
|
@ -152,14 +197,25 @@ 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
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) {
|
||||||
|
@ -51,16 +52,36 @@ 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);
|
||||||
|
@ -107,78 +128,126 @@ 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;
|
||||||
buffer: WebGLBuffer;
|
formatted: boolean = false;
|
||||||
|
|
||||||
// TODO: maybe use undefined as default value?
|
|
||||||
size: GLint = 0;
|
size: GLint = 0;
|
||||||
type: GLenum = 0;
|
type: GLenum = 0;
|
||||||
normalized: GLboolean = false;
|
|
||||||
stride: GLsizei = 0;
|
|
||||||
offset: GLintptr = 0;
|
offset: GLintptr = 0;
|
||||||
|
normalized: GLboolean = false;
|
||||||
|
|
||||||
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;
|
||||||
}
|
|
||||||
|
|
||||||
data(ctx: WebGL2RenderingContext, data: Array<number>, usage: GLenum) {
|
this.formatted = true;
|
||||||
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(tex: WebGLTexture, width: number, height: number) {
|
constructor(texId: number, 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
static async load(ctx: WebGL2RenderingContext, path: string): Promise<Texture> {
|
// TODO: Load sprite sheet only once
|
||||||
|
// 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 = ctx.createTexture();
|
let tex = gfx.ctx.createTexture();
|
||||||
ctx.bindTexture(ctx.TEXTURE_2D, tex);
|
gfx.ctx.bindTexture(gfx.ctx.TEXTURE_2D, tex);
|
||||||
ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGBA, ctx.RGBA, ctx.UNSIGNED_BYTE, image);
|
gfx.ctx.texImage2D(gfx.ctx.TEXTURE_2D, 0, gfx.ctx.RGBA, gfx.ctx.RGBA, gfx.ctx.UNSIGNED_BYTE, image);
|
||||||
ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.NEAREST);
|
gfx.ctx.texParameteri(gfx.ctx.TEXTURE_2D, gfx.ctx.TEXTURE_MAG_FILTER, gfx.ctx.NEAREST);
|
||||||
ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.NEAREST);
|
gfx.ctx.texParameteri(gfx.ctx.TEXTURE_2D, gfx.ctx.TEXTURE_MIN_FILTER, gfx.ctx.NEAREST);
|
||||||
ctx.bindTexture(ctx.TEXTURE_2D, null);
|
gfx.ctx.bindTexture(gfx.ctx.TEXTURE_2D, null);
|
||||||
|
|
||||||
return new Texture(tex, image.width, image.height);
|
gfx.texCount += 1;
|
||||||
|
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,13 +263,19 @@ 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) {
|
||||||
|
@ -209,6 +284,16 @@ 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,14 +7,16 @@ 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
|
||||||
|
|
||||||
in vec3 a_position;
|
layout(location = 0) in vec3 a_position;
|
||||||
in vec2 a_tex_position;
|
layout(location = 1) in vec2 a_tex_position;
|
||||||
out vec2 v_tex_position;
|
layout(location = 2) in vec4 a_color;
|
||||||
in vec4 a_color;
|
|
||||||
out vec4 v_color;
|
out vec4 v_color;
|
||||||
|
out vec2 v_tex_position;
|
||||||
|
|
||||||
uniform mat4 u_matrix;
|
uniform mat4 u_matrix;
|
||||||
uniform bool u_isTex;
|
|
||||||
uniform bool u_isIso;
|
uniform bool u_isIso;
|
||||||
|
uniform bool u_isTex;
|
||||||
|
|
||||||
mat4 Iso = mat4(
|
mat4 Iso = mat4(
|
||||||
1, -1, 0, 0,
|
1, -1, 0, 0,
|
||||||
|
@ -22,7 +24,7 @@ const vertexShader = `#version 300 es
|
||||||
0, 0, 1, 0,
|
0, 0, 1, 0,
|
||||||
0, 0, 0, 1
|
0, 0, 0, 1
|
||||||
);
|
);
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec4 orthographic;
|
vec4 orthographic;
|
||||||
|
|
||||||
|
@ -47,12 +49,12 @@ const fragmentShader = `#version 300 es
|
||||||
|
|
||||||
precision highp float;
|
precision highp float;
|
||||||
|
|
||||||
in vec2 v_tex_position;
|
|
||||||
in vec4 v_color;
|
in vec4 v_color;
|
||||||
|
in vec2 v_tex_position;
|
||||||
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) {
|
||||||
|
@ -65,18 +67,26 @@ 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 zoom = 1;
|
let right = gfx.ctx.canvas.width;
|
||||||
let right = gfx.ctx.canvas.width * zoom;
|
|
||||||
let left = 0;
|
let left = 0;
|
||||||
let top = gfx.ctx.canvas.height * zoom;
|
let top = gfx.ctx.canvas.height;
|
||||||
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.getUniform("u_matrix"), false, m.splat());
|
gfx.ctx.uniformMatrix4fv(gfx.getUniform("u_matrix"), false, m.splat());
|
||||||
drawing.drawIsometricGrid(gfx, camera, grid);
|
drawing.drawIsometricGrid(gfx, grid);
|
||||||
|
gfx.draw();
|
||||||
}
|
}
|
||||||
function addDefaultKeybinds(input, camera) {
|
function addDefaultKeybinds(input, camera) {
|
||||||
input.addKeyAction("KeyA", [], camera, (c) => {
|
input.addKeyAction("KeyA", [], camera, (c) => {
|
||||||
|
@ -99,6 +109,16 @@ 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";
|
||||||
|
@ -107,19 +127,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);
|
||||||
const a_position = gfx.createAttribute("a_position");
|
let a = gfx.createAttribute("a_position");
|
||||||
a_position.format(3, gfx.ctx.FLOAT, false, 0, 0);
|
a.format(3, ctx.FLOAT, false, 0);
|
||||||
const a_color = gfx.createAttribute("a_color");
|
a = gfx.createAttribute("a_color");
|
||||||
a_color.format(4, gfx.ctx.FLOAT, false, 0, 0);
|
a.format(4, ctx.FLOAT, false, 0);
|
||||||
const a_tex_position = gfx.createAttribute("a_tex_position");
|
a = gfx.createAttribute("a_tex_position");
|
||||||
a_tex_position.format(2, gfx.ctx.FLOAT, false, 0, 0);
|
a.format(2, ctx.FLOAT, false, 0);
|
||||||
gfx.createUniform("u_matrix");
|
gfx.createUniform("u_matrix");
|
||||||
gfx.createUniform("u_isTex");
|
|
||||||
gfx.createUniform("u_isIso");
|
gfx.createUniform("u_isIso");
|
||||||
|
gfx.createUniform("u_isTex");
|
||||||
let camera = new Camera(new Vec3(0, 0, -1));
|
let camera = new Camera(new Vec3(0, 0, -1));
|
||||||
await Assets.assets.load(ctx);
|
await Assets.assets.load(gfx);
|
||||||
let m = Mat4.isometric();
|
let m = Mat4.isometric();
|
||||||
let size = 20;
|
let size = 100;
|
||||||
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"),
|
||||||
|
|
|
@ -1,22 +1,24 @@
|
||||||
import { initializeContext, Vec3, Mat4, Vec4, Vec2 } from "./common.js";
|
import { initializeContext, Vec3, Mat4, Vec4, Vec2 } from "./common.js";
|
||||||
import { Graphics, fullscreenCanvas, Camera } from "./graphics.js";
|
import { Graphics, fullscreenCanvas, Camera, DrawTag } 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, tree} from "./world.js";
|
import {bush, Grid, Tile, TileEdge, 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
|
||||||
|
|
||||||
in vec3 a_position;
|
layout(location = 0) in vec3 a_position;
|
||||||
in vec2 a_tex_position;
|
layout(location = 1) in vec2 a_tex_position;
|
||||||
out vec2 v_tex_position;
|
layout(location = 2) in vec4 a_color;
|
||||||
in vec4 a_color;
|
|
||||||
out vec4 v_color;
|
out vec4 v_color;
|
||||||
|
out vec2 v_tex_position;
|
||||||
|
|
||||||
uniform mat4 u_matrix;
|
uniform mat4 u_matrix;
|
||||||
uniform bool u_isTex;
|
|
||||||
uniform bool u_isIso;
|
uniform bool u_isIso;
|
||||||
|
uniform bool u_isTex;
|
||||||
|
|
||||||
mat4 Iso = mat4(
|
mat4 Iso = mat4(
|
||||||
1, -1, 0, 0,
|
1, -1, 0, 0,
|
||||||
|
@ -24,7 +26,7 @@ const vertexShader =
|
||||||
0, 0, 1, 0,
|
0, 0, 1, 0,
|
||||||
0, 0, 0, 1
|
0, 0, 0, 1
|
||||||
);
|
);
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec4 orthographic;
|
vec4 orthographic;
|
||||||
|
|
||||||
|
@ -51,12 +53,12 @@ const fragmentShader =
|
||||||
|
|
||||||
precision highp float;
|
precision highp float;
|
||||||
|
|
||||||
in vec2 v_tex_position;
|
|
||||||
in vec4 v_color;
|
in vec4 v_color;
|
||||||
|
in vec2 v_tex_position;
|
||||||
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) {
|
||||||
|
@ -71,17 +73,38 @@ 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 zoom = 1;
|
let right = gfx.ctx.canvas.width;
|
||||||
let right = gfx.ctx.canvas.width * zoom;
|
|
||||||
let left = 0;
|
let left = 0;
|
||||||
let top = gfx.ctx.canvas.height * zoom;
|
let top = gfx.ctx.canvas.height;
|
||||||
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"),
|
||||||
|
@ -89,7 +112,8 @@ function draw(gfx: Graphics, camera: Camera, dt: number, grid: Grid) {
|
||||||
m.splat()
|
m.splat()
|
||||||
);
|
);
|
||||||
|
|
||||||
drawing.drawIsometricGrid(gfx, camera, grid);
|
drawing.drawIsometricGrid(gfx, grid);
|
||||||
|
gfx.draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
function addDefaultKeybinds(input: Input, camera: Camera) {
|
function addDefaultKeybinds(input: Input, camera: Camera) {
|
||||||
|
@ -124,6 +148,22 @@ 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 () => {
|
||||||
|
@ -134,26 +174,24 @@ 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);
|
||||||
|
|
||||||
const a_position = gfx.createAttribute("a_position");
|
let a = gfx.createAttribute("a_position");
|
||||||
a_position.format(3, gfx.ctx.FLOAT, false, 0, 0);
|
a.format(3, ctx.FLOAT, false, 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");
|
||||||
|
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_isTex");
|
|
||||||
gfx.createUniform("u_isIso");
|
gfx.createUniform("u_isIso");
|
||||||
|
gfx.createUniform("u_isTex");
|
||||||
|
|
||||||
let camera = new Camera(new Vec3(0, 0, -1));
|
let camera = new Camera(new Vec3(0, 0, -1));
|
||||||
|
|
||||||
await Assets.assets.load(ctx);
|
await Assets.assets.load(gfx);
|
||||||
|
|
||||||
let m = Mat4.isometric();
|
let m = Mat4.isometric();
|
||||||
|
|
||||||
let size = 20;
|
let size = 100;
|
||||||
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"),
|
||||||
|
|
Loading…
Reference in New Issue