diff --git a/src/js/colors.js b/src/js/colors.js new file mode 100644 index 0000000..3f184ca --- /dev/null +++ b/src/js/colors.js @@ -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]; diff --git a/src/js/colors.ts b/src/js/colors.ts new file mode 100644 index 0000000..6fe4f78 --- /dev/null +++ b/src/js/colors.ts @@ -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]; diff --git a/src/js/common.js b/src/js/common.js index f0c813a..6b48587 100644 --- a/src/js/common.js +++ b/src/js/common.js @@ -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; } diff --git a/src/js/common.ts b/src/js/common.ts index aad594f..9b15e57 100644 --- a/src/js/common.ts +++ b/src/js/common.ts @@ -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 { + 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 { 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 { return [this.x, this.y]; } @@ -74,7 +134,7 @@ class Vec2 { } } -class Vec3 { +class Vec3 implements Vector { 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 { return [this.x, this.y, this.z]; } } -class Vec4 { +class Vec4 implements Vector { 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 }; diff --git a/src/js/draw.js b/src/js/draw.js index a351379..8cdc8b4 100644 --- a/src/js/draw.js +++ b/src/js/draw.js @@ -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); } diff --git a/src/js/draw.ts b/src/js/draw.ts index f7ed7b2..b3d75ce 100644 --- a/src/js/draw.ts +++ b/src/js/draw.ts @@ -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); } diff --git a/src/js/graphics.js b/src/js/graphics.js index c7027a2..b3defd2 100644 --- a/src/js/graphics.js +++ b/src/js/graphics.js @@ -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); diff --git a/src/js/graphics.ts b/src/js/graphics.ts index 8b90fc9..b0e38e9 100644 --- a/src/js/graphics.ts +++ b/src/js/graphics.ts @@ -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) { diff --git a/src/js/script.js b/src/js/script.js index f5efe7d..269d572 100644 --- a/src/js/script.js +++ b/src/js/script.js @@ -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) => { diff --git a/src/js/script.ts b/src/js/script.ts index 342901e..9b80770 100644 --- a/src/js/script.ts +++ b/src/js/script.ts @@ -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); } diff --git a/src/js/world.js b/src/js/world.js new file mode 100644 index 0000000..9ddffe0 --- /dev/null +++ b/src/js/world.js @@ -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)); +} diff --git a/src/js/world.ts b/src/js/world.ts new file mode 100644 index 0000000..7612ffe --- /dev/null +++ b/src/js/world.ts @@ -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(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)); +}