Added Grid and grid based rendering

This commit is contained in:
Maciej Samborski 2024-12-27 22:50:07 +01:00
parent 95257a4ef3
commit e936b626f3
12 changed files with 648 additions and 101 deletions

4
src/js/colors.js Normal file
View File

@ -0,0 +1,4 @@
export let Red = [1, 0, 0, 1];
export let Green = [0, 1, 0, 1];
export let Blue = [0, 0, 1, 1];
export let Brown = [0.341, 0.337, 0.204, 1];

6
src/js/colors.ts Normal file
View File

@ -0,0 +1,6 @@
export type Color = [number, number, number, number]
export let Red : Color = [1, 0, 0, 1];
export let Green : Color = [0, 1, 0, 1];
export let Blue : Color = [0, 0, 1, 1];
export let Brown : Color = [0.341, 0.337, 0.204, 1];

View File

@ -10,6 +10,9 @@ class Vec2 {
this.x = x;
this.y = y;
}
copy() {
return new Vec2(this.x, this.y);
}
add(other) {
this.x += other.x;
this.y += other.y;
@ -28,13 +31,43 @@ class Vec2 {
this.x -= other.x;
this.y -= other.y;
}
mult(scalar) {
subNew(other) {
let vec = this.copy();
vec.x -= other.x;
vec.y -= other.y;
return vec;
}
multScalar(scalar) {
this.x *= scalar;
this.y *= scalar;
}
multNew(scalar) {
multScalarNew(scalar) {
return new Vec2(this.x * scalar, this.y * scalar);
}
div(other) {
if (other.x == 0 ||
other.y == 0) {
throw new Error("Division by zero in Vec4");
}
this.x /= other.x;
this.y /= other.y;
}
divNew(other) {
if (other.x == 0 ||
other.y == 0) {
throw new Error("Division by zero in Vec4");
}
let vec = this.copy();
vec.x /= other.x;
vec.y /= other.y;
return vec;
}
reduce() {
throw new Error("Can't reduce Vec2!");
}
extend(value) {
return new Vec3(this.x, this.y, value);
}
splatToArray() {
return [this.x, this.y];
}
@ -60,28 +93,73 @@ class Vec3 {
this.y = y;
this.z = z;
}
copy() {
return new Vec3(this.x, this.y, this.z);
}
add(other) {
this.x += other.x;
this.y += other.y;
this.z += other.z;
}
addNew(other) {
let vec = this.copy();
vec.x += other.x;
vec.y += other.y;
vec.z += other.z;
return vec;
}
sub(other) {
this.x -= other.x;
this.y -= other.y;
this.z -= other.z;
}
subNew(other) {
let vec = this.copy();
vec.x -= other.x;
vec.y -= other.y;
vec.z -= other.z;
return vec;
}
multScalar(scalar) {
this.x *= scalar;
this.y *= scalar;
this.z *= scalar;
}
multScalarNew(scalar) {
let vec = new Vec3(this.x, this.y, this.z);
let vec = this.copy();
vec.x *= scalar;
vec.y *= scalar;
vec.z *= scalar;
return vec;
}
div(other) {
if (other.x == 0 ||
other.y == 0 ||
other.z == 0) {
throw new Error("Division by zero in Vec4");
}
this.x /= other.x;
this.y /= other.y;
this.z /= other.z;
}
divNew(other) {
if (other.x == 0 ||
other.y == 0 ||
other.z == 0) {
throw new Error("Division by zero in Vec4");
}
let vec = this.copy();
vec.x /= other.x;
vec.y /= other.y;
vec.z /= other.z;
return vec;
}
reduce() {
return new Vec2(this.x, this.y);
}
extend(value) {
return new Vec4(this.x, this.y, this.z, value);
}
splatToArray() {
return [this.x, this.y, this.z];
}
@ -97,18 +175,37 @@ class Vec4 {
this.z = z;
this.w = w;
}
copy() {
return new Vec4(this.x, this.y, this.z, this.w);
}
add(other) {
this.x += other.x;
this.y += other.y;
this.z += other.z;
this.w += other.w;
}
addNew(other) {
let vec = this.copy();
vec.x += other.x;
vec.y += other.y;
vec.z += other.z;
vec.w += other.w;
return vec;
}
sub(other) {
this.x -= other.x;
this.y -= other.y;
this.z -= other.z;
this.w -= other.w;
}
subNew(other) {
let vec = this.copy();
vec.x -= other.x;
vec.y -= other.y;
vec.z -= other.z;
vec.w -= other.w;
return vec;
}
multScalar(scalar) {
this.x *= scalar;
this.y *= scalar;
@ -116,7 +213,7 @@ class Vec4 {
this.w *= scalar;
}
multScalarNew(scalar) {
let vec = new Vec4(this.x, this.y, this.z, this.w);
let vec = this.copy();
vec.x *= scalar;
vec.y *= scalar;
vec.z *= scalar;
@ -142,7 +239,7 @@ class Vec4 {
other.w == 0) {
throw new Error("Division by zero in Vec4");
}
let vec = new Vec4(this.x, this.y, this.z, this.w);
let vec = this.copy();
vec.x /= other.x;
vec.y /= other.y;
vec.z /= other.z;
@ -152,11 +249,15 @@ class Vec4 {
reduce() {
return new Vec3(this.x, this.y, this.z);
}
extend(_value) {
throw new Error("Can't extend Vec4");
}
}
class Mat4 {
data;
constructor(i) {
if (i instanceof Float32Array) {
console.assert(i.length == 16, "Mat4 has to have 16 elements");
this.data = i;
return;
}

View File

@ -5,14 +5,27 @@ function initializeContext(canvasId: string): WebGL2RenderingContext | null {
return ctx;
}
type Color = [number, number, number, number]
// TODO: Make all vectors follow one interface
interface Vector {
interface Vector<P, T, N> {
copy(): T;
add(other: T): void;
addNew(other: T): T;
sub(other: T): void;
subNew(other: T): T;
multScalar(scalar: number): void;
multScalarNew(scalar: number): T;
div(other: T): void;
divNew(other: T): T;
reduce(): P;
extend(value: number): N;
}
class Vec2 {
class Vec2 implements Vector<void, Vec2, Vec3> {
x: number;
y: number;
@ -21,6 +34,10 @@ class Vec2 {
this.y = y;
}
copy(): Vec2 {
return new Vec2(this.x, this.y);
}
add(other: Vec2) {
this.x += other.x;
this.y += other.y;
@ -44,15 +61,58 @@ class Vec2 {
this.y -= other.y;
}
mult(scalar: number) {
subNew(other: Vec2): Vec2 {
let vec = this.copy();
vec.x -= other.x;
vec.y -= other.y;
return vec;
}
multScalar(scalar: number) {
this.x *= scalar;
this.y *= scalar;
}
multNew(scalar: number): Vec2 {
multScalarNew(scalar: number): Vec2 {
return new Vec2(this.x * scalar, this.y * scalar);
}
div(other: Vec2) {
if ( other.x == 0 ||
other.y == 0)
{
throw new Error("Division by zero in Vec4");
}
this.x /= other.x;
this.y /= other.y;
}
divNew(other: Vec2): Vec2 {
if ( other.x == 0 ||
other.y == 0)
{
throw new Error("Division by zero in Vec4");
}
let vec = this.copy();
vec.x /= other.x;
vec.y /= other.y;
return vec;
}
reduce(): null {
throw new Error("Can't reduce Vec2!");
}
extend(value: number): Vec3 {
return new Vec3(this.x, this.y, value);
}
splatToArray(): Array<number> {
return [this.x, this.y];
}
@ -74,7 +134,7 @@ class Vec2 {
}
}
class Vec3 {
class Vec3 implements Vector<Vec2, Vec3, Vec4> {
x: number;
y: number;
z: number;
@ -85,18 +145,42 @@ class Vec3 {
this.z = z;
}
copy(): Vec3 {
return new Vec3(this.x, this.y, this.z);
}
add(other: Vec3) {
this.x += other.x;
this.y += other.y;
this.z += other.z;
}
addNew(other: Vec3): Vec3 {
let vec = this.copy();
vec.x += other.x;
vec.y += other.y;
vec.z += other.z;
return vec;
}
sub(other: Vec3) {
this.x -= other.x;
this.y -= other.y;
this.z -= other.z;
}
subNew(other: Vec3): Vec3 {
let vec = this.copy();
vec.x -= other.x;
vec.y -= other.y;
vec.z -= other.z;
return vec;
}
multScalar(scalar: number) {
this.x *= scalar;
this.y *= scalar;
@ -104,7 +188,7 @@ class Vec3 {
}
multScalarNew(scalar: number): Vec3 {
let vec = new Vec3(this.x, this.y, this.z);
let vec = this.copy();
vec.x *= scalar;
vec.y *= scalar;
@ -113,12 +197,50 @@ class Vec3 {
return vec;
}
div(other: Vec3) {
if ( other.x == 0 ||
other.y == 0 ||
other.z == 0)
{
throw new Error("Division by zero in Vec4");
}
this.x /= other.x;
this.y /= other.y;
this.z /= other.z;
}
divNew(other: Vec3): Vec3 {
if ( other.x == 0 ||
other.y == 0 ||
other.z == 0)
{
throw new Error("Division by zero in Vec4");
}
let vec = this.copy();
vec.x /= other.x;
vec.y /= other.y;
vec.z /= other.z;
return vec;
}
reduce(): Vec2 {
return new Vec2(this.x, this.y);
}
extend(value: number): Vec4 {
return new Vec4(this.x, this.y, this.z, value);
}
splatToArray(): Array<number> {
return [this.x, this.y, this.z];
}
}
class Vec4 {
class Vec4 implements Vector<Vec3, Vec4, void> {
x: number;
y: number;
z: number;
@ -131,6 +253,10 @@ class Vec4 {
this.w = w;
}
copy(): Vec4 {
return new Vec4(this.x, this.y, this.z, this.w);
}
add(other: Vec4) {
this.x += other.x;
this.y += other.y;
@ -138,6 +264,17 @@ class Vec4 {
this.w += other.w;
}
addNew(other: Vec4): Vec4 {
let vec = this.copy();
vec.x += other.x;
vec.y += other.y;
vec.z += other.z;
vec.w += other.w;
return vec;
}
sub(other: Vec4) {
this.x -= other.x;
this.y -= other.y;
@ -145,6 +282,17 @@ class Vec4 {
this.w -= other.w;
}
subNew(other: Vec4): Vec4 {
let vec = this.copy();
vec.x -= other.x;
vec.y -= other.y;
vec.z -= other.z;
vec.w -= other.w;
return vec;
}
multScalar(scalar: number) {
this.x *= scalar;
this.y *= scalar;
@ -153,7 +301,7 @@ class Vec4 {
}
multScalarNew(scalar: number): Vec4 {
let vec = new Vec4(this.x, this.y, this.z, this.w);
let vec = this.copy();
vec.x *= scalar;
vec.y *= scalar;
@ -187,7 +335,7 @@ class Vec4 {
throw new Error("Division by zero in Vec4");
}
let vec = new Vec4(this.x, this.y, this.z, this.w);
let vec = this.copy();
vec.x /= other.x;
vec.y /= other.y;
@ -200,6 +348,10 @@ class Vec4 {
reduce(): Vec3 {
return new Vec3(this.x, this.y, this.z);
}
extend(_value: number): void {
throw new Error("Can't extend Vec4");
}
}
type Mat4Init = number | Float32Array;
@ -216,6 +368,7 @@ class Mat4 {
constructor(i: Mat4Init) {
if (i instanceof Float32Array) {
console.assert(i.length == 16, "Mat4 has to have 16 elements");
this.data = i;
return;
} else if (typeof(i) === 'number') {
@ -374,4 +527,4 @@ class Mat4 {
}
}
export { initializeContext, Mat4, Vec2, Vec3, Vec4, Color };
export { initializeContext, Mat4, Vec2, Vec3, Vec4 };

View File

@ -1,5 +1,17 @@
import { Vec3, Vec2 } from "./common.js";
import { Texture } from "./graphics.js";
import { TileEdge } from "./world.js";
function cull(bb, screen) {
if (bb.x > screen.x)
return false;
if (bb.x + bb.z < screen.x + screen.z)
return false;
if (bb.y > screen.y)
return false;
if (bb.y + bb.w < screen.y + screen.w)
return false;
return true;
}
export function drawTriangle(gfx, positions, color) {
const a_position = gfx.getAttribute("a_position");
const a_color = gfx.getAttribute("a_color");
@ -69,7 +81,7 @@ export function drawRectangle(gfx, corners, color) {
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 6);
}
}
export function drawIsometricCube(gfx, position, exts, color) {
export function drawIsometricCube(gfx, position, exts, color, edge) {
let points = [
position,
new Vec3(position.x, position.y + exts.y, position.z),
@ -80,26 +92,60 @@ export function drawIsometricCube(gfx, position, exts, color) {
new Vec3(position.x + 0.5 * exts.x, position.y - 0.5 * exts.y, position.z + 0.25 * exts.z),
];
gfx.ctx.uniform1i(gfx.getUniform("u_isIso"), 1);
// Top
drawRectangle(gfx, [
points[0],
points[1],
points[3],
points[2],
], color);
drawRectangle(gfx, [
points[3],
points[2],
points[4],
points[5],
], color);
drawRectangle(gfx, [
points[0],
points[2],
points[4],
points[6],
], color);
// Right Edge
if (edge == TileEdge.Right || edge == TileEdge.Both) {
drawRectangle(gfx, [
points[3],
points[2],
points[4],
points[5],
], color);
}
// Left Edge
if (edge == TileEdge.Left || edge == TileEdge.Both) {
drawRectangle(gfx, [
points[0],
points[2],
points[4],
points[6],
], color);
}
gfx.ctx.uniform1i(gfx.getUniform("u_isIso"), 0);
}
export function drawIsometricGrid(gfx, grid) {
let position = { ...grid.position };
let exts = new Vec3(grid.tileSize, grid.tileSize, 0);
let tileCoord = new Vec3(0, 0, 0);
// Optimize this by:
// 1. Skip all empty tiles by using lowTiles
// 2. tba
for (let k = 0; k < grid.height; ++k) {
for (let j = 0; j < grid.length; ++j) {
for (let i = 0; i < grid.width; ++i) {
tileCoord.x = i;
tileCoord.y = j;
tileCoord.z = k;
let tile = grid.getTile(tileCoord);
if (tile === null) {
position.x += grid.tileSize;
continue;
}
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.y -= grid.tileSize;
position.x = grid.position.x;
}
position.y = grid.position.y;
}
}
export function drawRectangleExts(gfx, position, exts, color) {
const a_position = gfx.getAttribute("a_position");
const points = [
@ -142,7 +188,7 @@ export function drawCircle(gfx, position, radius, color) {
let a = 0;
for (let i = 0; i < precision; ++i) {
var vec = Vec2.angle(a);
vec.mult(radius);
vec.multScalar(radius);
a += angle;
points.push(vec);
}

View File

@ -1,5 +1,17 @@
import { Vec3, Vec2, Color } from "./common.js"
import {Color} from "./colors.js";
import { Vec3, Vec2, Vec4 } from "./common.js"
import { Graphics, Texture } from "./graphics.js";
import {Grid, TileEdge} from "./world.js";
function cull(bb: Vec4, screen: Vec4): boolean {
if (bb.x > screen.x) return false;
if (bb.x + bb.z < screen.x + screen.z) return false;
if (bb.y > screen.y) return false;
if (bb.y + bb.w < screen.y + screen.w) return false;
return true;
}
export function drawTriangle(gfx: Graphics, positions: [Vec2, Vec2, Vec2], color: Color) {
const a_position = gfx.getAttribute("a_position");
@ -87,7 +99,7 @@ export function drawRectangle(gfx: Graphics, corners: [Vec3, Vec3, Vec3, Vec3],
}
export function drawIsometricCube(gfx: Graphics, position: Vec3, exts: Vec3, color: Color | Texture) {
export function drawIsometricCube(gfx: Graphics, position: Vec3, exts: Vec3, color: Color | Texture, edge: TileEdge) {
let points = [
position,
new Vec3(position.x, position.y + exts.y, position.z),
@ -100,6 +112,7 @@ export function drawIsometricCube(gfx: Graphics, position: Vec3, exts: Vec3, col
gfx.ctx.uniform1i(gfx.getUniform("u_isIso"), 1);
// Top
drawRectangle(
gfx,
[
@ -109,30 +122,70 @@ export function drawIsometricCube(gfx: Graphics, position: Vec3, exts: Vec3, col
points[2],
],
color);
// Right Edge
drawRectangle(
gfx,
[
points[3],
points[2],
points[4],
points[5],
],
color);
if (edge == TileEdge.Right || edge == TileEdge.Both) {
drawRectangle(
gfx,
[
points[3],
points[2],
points[4],
points[5],
],
color);
}
drawRectangle(
gfx,
[
points[0],
points[2],
points[4],
points[6],
],
color);
// Left Edge
if (edge == TileEdge.Left || edge == TileEdge.Both) {
drawRectangle(
gfx,
[
points[0],
points[2],
points[4],
points[6],
],
color);
}
gfx.ctx.uniform1i(gfx.getUniform("u_isIso"), 0);
}
export function drawIsometricGrid(gfx: Graphics, grid: Grid) {
let position = {...grid.position} as Vec3;
let exts = new Vec3(grid.tileSize, grid.tileSize, 0);
let tileCoord = new Vec3(0, 0, 0);
// Optimize this by:
// 1. Skip all empty tiles by using lowTiles
// 2. tba
for (let k = 0; k < grid.height; ++k) {
for (let j = 0; j < grid.length; ++j) {
for (let i = 0; i < grid.width; ++i) {
tileCoord.x = i;
tileCoord.y = j;
tileCoord.z = k;
let tile = grid.getTile(tileCoord);
if (tile === null) {
position.x += grid.tileSize;
continue;
}
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.y -= grid.tileSize;
position.x = grid.position.x;
}
position.y = grid.position.y;
}
}
export function drawRectangleExts(gfx: Graphics, position: Vec3, exts: Vec2, color: Color | Texture) {
const a_position = gfx.getAttribute("a_position");
@ -184,7 +237,7 @@ export function drawCircle(gfx: Graphics, position: Vec2, radius: number, color:
let a = 0;
for (let i = 0; i < precision; ++i) {
var vec = Vec2.angle(a);
vec.mult(radius);
vec.multScalar(radius);
a += angle;
points.push(vec);
}

View File

@ -110,7 +110,11 @@ export class Attribute {
}
export class Texture {
tex;
constructor(tex) {
width = 0;
height = 0;
constructor(tex, width, height) {
this.height = height;
this.width = width;
this.tex = tex;
}
static async load(ctx, path) {
@ -122,7 +126,7 @@ export class Texture {
ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.LINEAR_MIPMAP_NEAREST);
ctx.generateMipmap(ctx.TEXTURE_2D);
ctx.bindTexture(ctx.TEXTURE_2D, null);
return new Texture(tex);
return new Texture(tex, image.width, image.height);
}
bind(gfx) {
gfx.ctx.uniform1i(gfx.getUniform("u_isTex"), 1);

View File

@ -146,8 +146,12 @@ export class Attribute {
export class Texture {
tex: WebGLTexture | null;
width: number = 0;
height: number = 0;
constructor(tex: WebGLTexture) {
constructor(tex: WebGLTexture, width: number, height: number) {
this.height = height;
this.width = width;
this.tex = tex;
}
@ -162,7 +166,7 @@ export class Texture {
ctx.generateMipmap(ctx.TEXTURE_2D);
ctx.bindTexture(ctx.TEXTURE_2D, null);
return new Texture(tex);
return new Texture(tex, image.width, image.height);
}
bind(gfx: Graphics) {

View File

@ -1,8 +1,9 @@
import { initializeContext, Vec3, Mat4 } from "./common.js";
import { Graphics, fullscreenCanvas, Texture, Camera } from "./graphics.js";
import { initializeContext, Vec3, Mat4, Vec2 } from "./common.js";
import { Graphics, fullscreenCanvas, Camera } from "./graphics.js";
import * as drawing from "./draw.js";
import * as wasm from "./wasm.js";
import { Input } from "./input.js";
import { Grid, Tile, tree } from "./world.js";
const vertexShader = `#version 300 es
in vec3 a_position;
@ -59,30 +60,30 @@ const fragmentShader = `#version 300 es
}
}
`;
function draw(gfx, camera, dt, tex) {
function draw(gfx, camera, dt, grid) {
gfx.clear(0, 0, 0, 0);
camera.update(dt);
let right = gfx.ctx.canvas.width;
let left = 0;
let top = gfx.ctx.canvas.height;
let bottom = 0;
let zoom = 2;
let right = gfx.ctx.canvas.width * zoom;
let left = -right * zoom;
let top = gfx.ctx.canvas.height * zoom;
let bottom = -top * zoom;
let near = -100;
let far = 100;
let mo = Mat4.orthographic(left, right, bottom, top, near, far);
let mt = Mat4.translate(camera.position);
let mi = Mat4.isometric();
let m = mo.multNew(mt);
gfx.ctx.uniformMatrix4fv(gfx.getUniform("u_matrix"), false, m.splat());
let exts = new Vec3(50, 50, 20);
for (let i = 0; i < 10; ++i) {
for (let j = 0; j < 10; ++j) {
//drawing.drawIsometricCube(gfx, new Vec3(exts.x * i, 1000 - exts.y * j, 0), exts, [Math.sin(angle * i + j), Math.cos(angle * i + j), -Math.sin(angle * i + j), 1]);
if ((i + j) % 2)
drawing.drawIsometricCube(gfx, new Vec3(exts.x * i, 1000 - exts.y * j, 0), exts, [1, 1, 1, 1]);
else
drawing.drawIsometricCube(gfx, new Vec3(exts.x * i, 1000 - exts.y * j, 0), exts, tex);
}
}
//let exts = new Vec3(50, 50, 20);
//for (let i = 0; i < 10; ++i) {
// for (let j = 0; j < 10; ++j) {
// if ((i + j) % 2)
// drawing.drawIsometricCube(gfx, new Vec3(exts.x * i, 1000 - exts.y * j, 0), exts, [1, 0, 1, 1], TileEdge.None);
// else
// drawing.drawIsometricCube(gfx, new Vec3(exts.x * i, 1000 - exts.y * j, 0), exts, [1, 1, 0, 1], TileEdge.None);
// }
//}
drawing.drawIsometricGrid(gfx, grid);
}
function addDefaultKeybinds(input, camera) {
input.addKeyAction("KeyA", [], camera, (c) => {
@ -122,15 +123,20 @@ function addDefaultKeybinds(input, camera) {
gfx.createUniform("u_matrix");
gfx.createUniform("u_isTex");
gfx.createUniform("u_isIso");
let city = await Texture.load(ctx, "../../assets/genetica/rt/City Night.jpg");
let wall = await Texture.load(ctx, "../../assets/wall.png");
//let city = await Texture.load(ctx, "../../assets/genetica/rt/City Night.jpg");
//let wall = await Texture.load(ctx, "../../assets/wall.png");
let camera = new Camera(new Vec3(0, 0, 0));
let grid = new Grid(new Vec3(-800, 0, 0), 100, 20, 20, 10);
grid.fillLayer(new Tile([0, 0, 1, 1]), 0);
for (let i = 0; i < 5; i++) {
tree(grid, new Vec2(Math.floor(Math.random() * 19), Math.floor(Math.random() * 19)));
}
let prevTimestamp = 0;
const frame = (timestamp) => {
const deltaTime = (timestamp - prevTimestamp) / 1000;
prevTimestamp = timestamp;
fullscreenCanvas(gfx, "game");
draw(gfx, camera, deltaTime, wall);
draw(gfx, camera, deltaTime, grid);
window.requestAnimationFrame(frame);
};
window.requestAnimationFrame((timestamp) => {

View File

@ -3,6 +3,7 @@ import { Graphics, fullscreenCanvas, Texture, Camera } from "./graphics.js";
import * as drawing from "./draw.js";
import * as wasm from "./wasm.js";
import { Input } from "./input.js";
import {Grid, Tile, tree} from "./world.js";
const vertexShader =
`#version 300 es
@ -64,24 +65,20 @@ const fragmentShader =
}
`;
function draw(gfx: Graphics, camera: Camera, dt: number, tex: Texture) {
function draw(gfx: Graphics, camera: Camera, dt: number, grid: Grid) {
gfx.clear(0, 0, 0, 0);
camera.update(dt);
let right = gfx.ctx.canvas.width;
let left = 0;
let top = gfx.ctx.canvas.height;
let bottom = 0;
let zoom = 2;
let right = gfx.ctx.canvas.width * zoom;
let left = -right * zoom;
let top = gfx.ctx.canvas.height * zoom;
let bottom = -top * zoom;
let near = -100;
let far = 100;
let mo = Mat4.orthographic(left, right, bottom, top, near, far);
let mt = Mat4.translate(camera.position);
let mi = Mat4.isometric();
let m = mo.multNew(mt);
gfx.ctx.uniformMatrix4fv(
@ -90,17 +87,17 @@ function draw(gfx: Graphics, camera: Camera, dt: number, tex: Texture) {
m.splat()
);
let exts = new Vec3(50, 50, 20);
for (let i = 0; i < 10; ++i) {
for (let j = 0; j < 10; ++j) {
//drawing.drawIsometricCube(gfx, new Vec3(exts.x * i, 1000 - exts.y * j, 0), exts, [Math.sin(angle * i + j), Math.cos(angle * i + j), -Math.sin(angle * i + j), 1]);
if ((i + j) % 2)
drawing.drawIsometricCube(gfx, new Vec3(exts.x * i, 1000 - exts.y * j, 0), exts, [1, 1, 1, 1]);
else
drawing.drawIsometricCube(gfx, new Vec3(exts.x * i, 1000 - exts.y * j, 0), exts, tex);
}
}
//let exts = new Vec3(50, 50, 20);
//for (let i = 0; i < 10; ++i) {
// for (let j = 0; j < 10; ++j) {
// if ((i + j) % 2)
// drawing.drawIsometricCube(gfx, new Vec3(exts.x * i, 1000 - exts.y * j, 0), exts, [1, 0, 1, 1], TileEdge.None);
// else
// drawing.drawIsometricCube(gfx, new Vec3(exts.x * i, 1000 - exts.y * j, 0), exts, [1, 1, 0, 1], TileEdge.None);
// }
//}
drawing.drawIsometricGrid(gfx, grid);
}
function addDefaultKeybinds(input: Input, camera: Camera) {
@ -158,18 +155,26 @@ function addDefaultKeybinds(input: Input, camera: Camera) {
gfx.createUniform("u_isTex");
gfx.createUniform("u_isIso");
let city = await Texture.load(ctx, "../../assets/genetica/rt/City Night.jpg");
let wall = await Texture.load(ctx, "../../assets/wall.png");
//let city = await Texture.load(ctx, "../../assets/genetica/rt/City Night.jpg");
//let wall = await Texture.load(ctx, "../../assets/wall.png");
let camera = new Camera(new Vec3(0, 0, 0));
let grid = new Grid(new Vec3(-800, 0, 0), 100, 20, 20, 10);
grid.fillLayer(new Tile([0, 0, 1, 1]), 0);
for (let i = 0; i < 5; i++) {
tree(grid, new Vec2(Math.floor(Math.random() * 19), Math.floor(Math.random() * 19)));
}
let prevTimestamp = 0;
const frame = (timestamp: number) => {
const deltaTime = (timestamp - prevTimestamp)/1000;
prevTimestamp = timestamp;
fullscreenCanvas(gfx, "game");
draw(gfx, camera, deltaTime, wall);
draw(gfx, camera, deltaTime, grid);
window.requestAnimationFrame(frame);
}

73
src/js/world.js Normal file
View File

@ -0,0 +1,73 @@
import * as Colors from "./colors.js";
import { Vec3 } from "./common.js";
export var TileEdge;
(function (TileEdge) {
TileEdge[TileEdge["None"] = 0] = "None";
TileEdge[TileEdge["Left"] = 1] = "Left";
TileEdge[TileEdge["Right"] = 2] = "Right";
TileEdge[TileEdge["Both"] = 3] = "Both";
})(TileEdge || (TileEdge = {}));
export class Tile {
fill = [1, 0, 1, 1];
edge = TileEdge.None;
constructor(fill, edge) {
if (fill !== undefined)
this.fill = fill;
if (edge !== undefined)
this.edge = edge;
}
}
export class Grid {
position;
tiles3d;
tileSize;
width;
length;
height;
constructor(position, tileSize, width, length, height) {
this.tiles3d = new Array(height);
this.position = position;
this.tileSize = tileSize;
this.width = width;
this.length = length;
this.height = height;
let layer = new Array(width * length);
for (let i = 0; i < this.height; ++i)
this.tiles3d[i] = { ...layer };
}
fillLayer(tile, z) {
for (let i = 0; i < this.width; ++i) {
for (let j = 0; j < this.length; ++j) {
this.tiles3d[z][i + j * this.width] = { ...tile };
}
}
for (let i = 0; i < this.width; ++i) {
this.tiles3d[z][this.length * i - 1] = { ...tile, edge: TileEdge.Right };
}
for (let i = 0; i < this.length - 1; ++i) {
this.tiles3d[z][this.width * (this.length - 1) + i] = { ...tile, edge: TileEdge.Left };
}
this.tiles3d[z][this.width * this.length - 1] = { ...tile, edge: TileEdge.Both };
}
setTile(tile, coord) {
let index = coord.x + coord.y * this.width;
this.tiles3d[coord.z][index] = { ...tile };
}
getTile(coord) {
let index = coord.x + coord.y * this.width;
let tile = this.tiles3d[coord.z][index];
if (tile === undefined)
return null;
return tile;
}
}
export function tree(grid, position) {
grid.setTile(new Tile(Colors.Brown, TileEdge.Both), new Vec3(position.x, position.y, 1));
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x, position.y, 4));
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x, position.y + 1, 3));
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x, position.y + 1, 4));
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x, position.y, 5));
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x + 1, position.y, 3));
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x + 1, position.y, 4));
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x, position.y, 6));
}

92
src/js/world.ts Normal file
View File

@ -0,0 +1,92 @@
import * as Colors from "./colors.js";
import {Vec2, Vec3} from "./common.js";
import {Texture} from "./graphics.js";
export enum TileEdge {
None,
Left,
Right,
Both,
}
export class Tile {
fill: Texture | Colors.Color = [1, 0, 1, 1];
edge: TileEdge = TileEdge.None;
constructor(fill?: Texture | Colors.Color, edge?: TileEdge) {
if (fill !== undefined)
this.fill = fill;
if (edge !== undefined)
this.edge = edge;
}
}
export class Grid {
position: Vec3;
tiles3d: Tile[][];
tileSize: number;
width: number;
length: number;
height: number;
constructor(position: Vec3, tileSize: number, width: number, length: number, height: number) {
this.tiles3d = new Array<Tile[]>(height);
this.position = position;
this.tileSize = tileSize;
this.width = width;
this.length = length;
this.height = height;
let layer = new Array(width * length);
for (let i = 0; i < this.height; ++i)
this.tiles3d[i] = {...layer};
}
fillLayer(tile: Tile, z: number) {
for (let i = 0; i < this.width; ++i) {
for (let j = 0; j < this.length; ++j) {
this.tiles3d[z][i + j * this.width] = {...tile};
}
}
for (let i = 0; i < this.width; ++i) {
this.tiles3d[z][this.length * i - 1] = {...tile, edge: TileEdge.Right};
}
for (let i = 0; i < this.length - 1; ++i) {
this.tiles3d[z][this.width * (this.length - 1) + i] = {...tile, edge: TileEdge.Left};
}
this.tiles3d[z][this.width * this.length - 1] = {...tile, edge: TileEdge.Both};
}
setTile(tile: Tile, coord: Vec3) {
let index = coord.x + coord.y * this.width;
this.tiles3d[coord.z][index] = {...tile};
}
getTile(coord: Vec3): Tile | null {
let index = coord.x + coord.y * this.width;
let tile = this.tiles3d[coord.z][index];
if (tile === undefined) return null;
return tile;
}
}
export function tree(grid: Grid, position: Vec2) {
grid.setTile(new Tile(Colors.Brown, TileEdge.Both), new Vec3(position.x, position.y, 1));
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x, position.y, 4));
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x, position.y + 1, 3));
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x, position.y + 1, 4));
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x, position.y, 5));
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x + 1, position.y, 3));
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x + 1, position.y, 4));
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x, position.y, 6));
}