diff --git a/assets/grass.png b/assets/grass.png new file mode 100644 index 0000000..eeb60ba Binary files /dev/null and b/assets/grass.png differ diff --git a/assets/greenary.png b/assets/greenary.png new file mode 100644 index 0000000..d969e5e Binary files /dev/null and b/assets/greenary.png differ diff --git a/assets/log.png b/assets/log.png new file mode 100644 index 0000000..19e5339 Binary files /dev/null and b/assets/log.png differ diff --git a/src/js/assets.js b/src/js/assets.js new file mode 100644 index 0000000..b497e32 --- /dev/null +++ b/src/js/assets.js @@ -0,0 +1,38 @@ +import { Texture } from "./graphics.js"; +export const Colors = { + Red: [1, 0, 0, 1], + Green: [0, 1, 0, 1], + Blue: [0, 0, 1, 1], + Brown: [0.341, 0.337, 0.204, 1], +}; +export function AssetToTileFill(name) { + let asset = assets.get(name); + return { + left: asset, + top: asset, + right: asset, + }; +} +export class Assets { + assets = new Map(); + loaded = false; + push(name, asset) { + if (this.assets.get(name) !== undefined) + throw new Error("Asset name occupied!"); + this.assets.set(name, asset); + } + get(name) { + if (!this.loaded) + throw new Error("Tried to assess assets without loading them!"); + return this.assets.get(name); + } + async load(ctx) { + assets.push("city", await Texture.load(ctx, "../../assets/genetica/rt/City Night.jpg")); + assets.push("wall", await Texture.load(ctx, "../../assets/wall.png")); + assets.push("grass", await Texture.load(ctx, "../../assets/grass.png")); + assets.push("leaves", await Texture.load(ctx, "../../assets/greenary.png")); + assets.push("log", await Texture.load(ctx, "../../assets/log.png")); + this.loaded = true; + } +} +export const assets = new Assets(); diff --git a/src/js/assets.ts b/src/js/assets.ts new file mode 100644 index 0000000..ee62f3b --- /dev/null +++ b/src/js/assets.ts @@ -0,0 +1,53 @@ +import {Texture} from "./graphics.js"; +import {TileFill} from "./world.js"; + +export type Color = [number, number, number, number] + +export const Colors = { + Red : [1, 0, 0, 1] as Color, + Green : [0, 1, 0, 1] as Color, + Blue : [0, 0, 1, 1] as Color, + Brown : [0.341, 0.337, 0.204, 1] as Color, +} + +export type Asset = Texture; + +export function AssetToTileFill(name: string): TileFill { + let asset = assets.get(name); + + return { + left: asset, + top: asset, + right: asset, + }; +} + +export class Assets { + assets: Map = new Map(); + loaded: boolean = false; + + push(name: string, asset: Asset) { + if (this.assets.get(name) !== undefined) + throw new Error("Asset name occupied!"); + + this.assets.set(name, asset); + } + + get(name: string): Asset { + if (!this.loaded) + throw new Error("Tried to assess assets without loading them!"); + + return this.assets.get(name)!; + } + + async load(ctx: WebGL2RenderingContext) { + assets.push("city", await Texture.load(ctx, "../../assets/genetica/rt/City Night.jpg")); + assets.push("wall", await Texture.load(ctx, "../../assets/wall.png")); + assets.push("grass", await Texture.load(ctx, "../../assets/grass.png")); + assets.push("leaves", await Texture.load(ctx, "../../assets/greenary.png")); + assets.push("log", await Texture.load(ctx, "../../assets/log.png")); + this.loaded = true; + } +} + +export const assets = new Assets(); diff --git a/src/js/colors.js b/src/js/colors.js deleted file mode 100644 index 3f184ca..0000000 --- a/src/js/colors.js +++ /dev/null @@ -1,4 +0,0 @@ -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 deleted file mode 100644 index 6fe4f78..0000000 --- a/src/js/colors.ts +++ /dev/null @@ -1,6 +0,0 @@ -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 6b48587..d217270 100644 --- a/src/js/common.js +++ b/src/js/common.js @@ -280,13 +280,20 @@ class Mat4 { return new Mat4(data); } static isometric() { - let m = new Mat4(new Float32Array([ + return new Mat4(new Float32Array([ 1, -1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, ])); - return m; + } + static isometric_inverse() { + return new Mat4(new Float32Array([ + 0.5, 0.5, 0, 0, + -0.5, 0.5, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1, + ])); } static rotation_x(angle) { let data = new Float32Array([ @@ -347,17 +354,17 @@ class Mat4 { this.data[i * 4 + col] = data[i]; } transform(v) { - let x = v.x * this.x(0) + v.x * this.x(1) + v.x * this.x(2) + v.x * this.x(3); - let y = v.y * this.y(0) + v.y * this.y(1) + v.y * this.y(2) + v.y * this.y(3); - let z = v.z * this.z(0) + v.z * this.z(1) + v.z * this.z(2) + v.z * this.z(3); - let w = v.w * this.w(0) + v.w * this.w(1) + v.w * this.w(2) + v.w * this.w(3); + let x = v.x * this.x(0) + v.y * this.x(1) + v.z * this.x(2) + v.w * this.x(3); + let y = v.x * this.y(0) + v.y * this.y(1) + v.z * this.y(2) + v.w * this.y(3); + let z = v.x * this.z(0) + v.y * this.z(1) + v.z * this.z(2) + v.w * this.z(3); + let w = v.x * this.w(0) + v.y * this.w(1) + v.z * this.w(2) + v.w * this.w(3); v.x = x; v.y = y; v.z = z; v.w = w; } transformNew(v) { - let vec = new Vec4(v.x, v.y, v.z, v.w); + let vec = v.copy(); let x = v.x * this.x(0) + v.y * this.x(1) + v.z * this.x(2) + v.w * this.x(3); let y = v.x * this.y(0) + v.y * this.y(1) + v.z * this.y(2) + v.w * this.y(3); let z = v.x * this.z(0) + v.y * this.z(1) + v.z * this.z(2) + v.w * this.z(3); diff --git a/src/js/common.ts b/src/js/common.ts index 9b15e57..2f98ee1 100644 --- a/src/js/common.ts +++ b/src/js/common.ts @@ -395,14 +395,21 @@ class Mat4 { } static isometric(): Mat4 { - let m = new Mat4(new Float32Array([ + return new Mat4(new Float32Array([ 1, -1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, ])); + } - return m; + static isometric_inverse(): Mat4 { + return new Mat4(new Float32Array([ + 0.5, 0.5, 0, 0, + -0.5, 0.5, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1, + ])); } static rotation_x(angle: number): Mat4 { @@ -478,10 +485,10 @@ class Mat4 { } transform(v: Vec4) { - let x = v.x * this.x(0) + v.x * this.x(1) + v.x * this.x(2) + v.x * this.x(3); - let y = v.y * this.y(0) + v.y * this.y(1) + v.y * this.y(2) + v.y * this.y(3); - let z = v.z * this.z(0) + v.z * this.z(1) + v.z * this.z(2) + v.z * this.z(3); - let w = v.w * this.w(0) + v.w * this.w(1) + v.w * this.w(2) + v.w * this.w(3); + let x = v.x * this.x(0) + v.y * this.x(1) + v.z * this.x(2) + v.w * this.x(3); + let y = v.x * this.y(0) + v.y * this.y(1) + v.z * this.y(2) + v.w * this.y(3); + let z = v.x * this.z(0) + v.y * this.z(1) + v.z * this.z(2) + v.w * this.z(3); + let w = v.x * this.w(0) + v.y * this.w(1) + v.z * this.w(2) + v.w * this.w(3); v.x = x; v.y = y; @@ -490,7 +497,7 @@ class Mat4 { } transformNew(v: Vec4): Vec4 { - let vec = new Vec4(v.x, v.y, v.z, v.w); + let vec = v.copy(); let x = v.x * this.x(0) + v.y * this.x(1) + v.z * this.x(2) + v.w * this.x(3); let y = v.x * this.y(0) + v.y * this.y(1) + v.z * this.y(2) + v.w * this.y(3); diff --git a/src/js/draw.js b/src/js/draw.js index 8cdc8b4..1bc9d10 100644 --- a/src/js/draw.js +++ b/src/js/draw.js @@ -1,16 +1,17 @@ -import { Vec3, Vec2 } from "./common.js"; +import { Vec3, Vec2, Vec4 } 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; +// TODO: Don't assume tile size is same in all directions +function cull(point, screen, tileSize) { + if (point.x + tileSize < screen.x) + return true; + if (point.x + tileSize > screen.x + screen.z) + return true; + if (point.y - tileSize < screen.y) + return true; + if (point.y + tileSize > screen.y + screen.w) + return true; + return false; } export function drawTriangle(gfx, positions, color) { const a_position = gfx.getAttribute("a_position"); @@ -81,16 +82,22 @@ export function drawRectangle(gfx, corners, color) { gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 6); } } -export function drawIsometricCube(gfx, position, exts, color, edge) { +export function drawIsometricCube(gfx, camera, position, exts, color, edge) { let points = [ + // Left Top position, + //Top new Vec3(position.x, position.y + exts.y, position.z), + //Mid new Vec3(position.x + exts.x, position.y, position.z), + //Right Top new Vec3(position.x + exts.x, position.y + exts.y, position.z), + //Bottom 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), ]; + let screen = new Vec4(-camera.position.x, -camera.position.y, gfx.ctx.canvas.width, gfx.ctx.canvas.height); gfx.ctx.uniform1i(gfx.getUniform("u_isIso"), 1); // Top drawRectangle(gfx, [ @@ -98,7 +105,7 @@ export function drawIsometricCube(gfx, position, exts, color, edge) { points[1], points[3], points[2], - ], color); + ], color.top); // Right Edge if (edge == TileEdge.Right || edge == TileEdge.Both) { drawRectangle(gfx, [ @@ -106,7 +113,7 @@ export function drawIsometricCube(gfx, position, exts, color, edge) { points[2], points[4], points[5], - ], color); + ], color.right); } // Left Edge if (edge == TileEdge.Left || edge == TileEdge.Both) { @@ -115,17 +122,15 @@ export function drawIsometricCube(gfx, position, exts, color, edge) { points[2], points[4], points[6], - ], color); + ], color.left); } gfx.ctx.uniform1i(gfx.getUniform("u_isIso"), 0); } -export function drawIsometricGrid(gfx, grid) { +export function drawIsometricGrid(gfx, camera, grid) { let position = { ...grid.position }; let 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 + // TODO: Optimize this for (let k = 0; k < grid.height; ++k) { for (let j = 0; j < grid.length; ++j) { for (let i = 0; i < grid.width; ++i) { @@ -137,7 +142,7 @@ export function drawIsometricGrid(gfx, grid) { 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); + drawIsometricCube(gfx, camera, new Vec3(position.x - grid.tileSize / 2 * k, position.y + grid.tileSize / 2 * k, position.z), exts, tile.fill, tile.edge); position.x += grid.tileSize; } position.y -= grid.tileSize; diff --git a/src/js/draw.ts b/src/js/draw.ts index b3d75ce..a27978a 100644 --- a/src/js/draw.ts +++ b/src/js/draw.ts @@ -1,19 +1,26 @@ -import {Color} from "./colors.js"; -import { Vec3, Vec2, Vec4 } from "./common.js" -import { Graphics, Texture } from "./graphics.js"; -import {Grid, TileEdge} from "./world.js"; +import { Vec3, Vec2, Vec4, Mat4 } from "./common.js" +import { Camera, Graphics, Texture } from "./graphics.js"; +import {Grid, TileEdge, TileFill} from "./world.js"; +import * as Assets from "./assets.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; +// TODO: Don't assume tile size is same in all directions +function cull(point: Vec3, screen: Vec4, tileSize: number): boolean { + if (point.x + tileSize < screen.x) + return true; - if (bb.y > screen.y) return false; - if (bb.y + bb.w < screen.y + screen.w) return false; + if (point.x + tileSize > screen.x + screen.z) + return true; - return true; + if (point.y - tileSize < screen.y) + return true; + + if (point.y + tileSize > screen.y + screen.w) + return true; + + return false; } -export function drawTriangle(gfx: Graphics, positions: [Vec2, Vec2, Vec2], color: Color) { +export function drawTriangle(gfx: Graphics, positions: [Vec2, Vec2, Vec2], color: Assets.Color) { const a_position = gfx.getAttribute("a_position"); const a_color = gfx.getAttribute("a_color"); @@ -34,7 +41,7 @@ export function drawTriangle(gfx: Graphics, positions: [Vec2, Vec2, Vec2], color gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 3); } -export function drawTriangleExts(gfx: Graphics, position: Vec3, exts: Vec2, color: Color) { +export function drawTriangleExts(gfx: Graphics, position: Vec3, exts: Vec2, color: Assets.Color) { const a_position = gfx.getAttribute("a_position"); const a_color = gfx.getAttribute("a_color"); @@ -55,7 +62,7 @@ export function drawTriangleExts(gfx: Graphics, position: Vec3, exts: Vec2, colo gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 3); } -export function drawRectangle(gfx: Graphics, corners: [Vec3, Vec3, Vec3, Vec3], color: Color | Texture) { +export function drawRectangle(gfx: Graphics, corners: [Vec3, Vec3, Vec3, Vec3], color: Assets.Color | Texture) { const a_position = gfx.getAttribute("a_position"); const points: Array = [ @@ -99,17 +106,28 @@ export function drawRectangle(gfx: Graphics, corners: [Vec3, Vec3, Vec3, Vec3], } -export function drawIsometricCube(gfx: Graphics, position: Vec3, exts: Vec3, color: Color | Texture, edge: TileEdge) { +export function drawIsometricCube(gfx: Graphics, camera: Camera, position: Vec3, exts: Vec3, color: TileFill, edge: TileEdge) { let points = [ + // Left Top position, + //Top new Vec3(position.x, position.y + exts.y, position.z), + //Mid new Vec3(position.x + exts.x, position.y, position.z), + //Right Top new Vec3(position.x + exts.x, position.y + exts.y, position.z), + //Bottom 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), ]; + let screen = new Vec4( + -camera.position.x, + -camera.position.y, + gfx.ctx.canvas.width, + gfx.ctx.canvas.height); + gfx.ctx.uniform1i(gfx.getUniform("u_isIso"), 1); // Top @@ -121,7 +139,7 @@ export function drawIsometricCube(gfx: Graphics, position: Vec3, exts: Vec3, col points[3], points[2], ], - color); + color.top); // Right Edge @@ -134,7 +152,7 @@ export function drawIsometricCube(gfx: Graphics, position: Vec3, exts: Vec3, col points[4], points[5], ], - color); + color.right); } // Left Edge @@ -147,20 +165,18 @@ export function drawIsometricCube(gfx: Graphics, position: Vec3, exts: Vec3, col points[4], points[6], ], - color); + color.left); } gfx.ctx.uniform1i(gfx.getUniform("u_isIso"), 0); } -export function drawIsometricGrid(gfx: Graphics, grid: Grid) { +export function drawIsometricGrid(gfx: Graphics, camera: Camera, grid: Grid) { let position = {...grid.position} as Vec3; let 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 + // TODO: Optimize this for (let k = 0; k < grid.height; ++k) { for (let j = 0; j < grid.length; ++j) { for (let i = 0; i < grid.width; ++i) { @@ -175,7 +191,7 @@ export function drawIsometricGrid(gfx: Graphics, grid: Grid) { continue; } - drawIsometricCube(gfx, new Vec3(position.x - grid.tileSize / 2 * k, position.y + grid.tileSize / 2 * k, position.z), exts, tile.fill, tile.edge); + drawIsometricCube(gfx, camera, new Vec3(position.x - grid.tileSize / 2 * k, position.y + grid.tileSize / 2 * k, position.z), exts, tile.fill, tile.edge); position.x += grid.tileSize; } @@ -186,7 +202,7 @@ export function drawIsometricGrid(gfx: Graphics, grid: Grid) { } } -export function drawRectangleExts(gfx: Graphics, position: Vec3, exts: Vec2, color: Color | Texture) { +export function drawRectangleExts(gfx: Graphics, position: Vec3, exts: Vec2, color: Assets.Color | Texture) { const a_position = gfx.getAttribute("a_position"); const points: Array = [ @@ -229,7 +245,7 @@ export function drawRectangleExts(gfx: Graphics, position: Vec3, exts: Vec2, col } -export function drawCircle(gfx: Graphics, position: Vec2, radius: number, color: Color) { +export function drawCircle(gfx: Graphics, position: Vec2, radius: number, color: Assets.Color) { const points: Array = new Array(); const precision = 40; @@ -250,7 +266,7 @@ export function drawCircle(gfx: Graphics, position: Vec2, radius: number, color: } } -export function drawLine(gfx: Graphics, A: Vec2, B: Vec2, color: 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"); diff --git a/src/js/graphics.js b/src/js/graphics.js index b3defd2..7ab1873 100644 --- a/src/js/graphics.js +++ b/src/js/graphics.js @@ -52,6 +52,8 @@ export class Graphics { ctx.bindVertexArray(this.vao); ctx.viewport(0, 0, ctx.canvas.width, ctx.canvas.height); ctx.useProgram(this.program); + ctx.blendFunc(ctx.SRC_ALPHA, ctx.ONE_MINUS_SRC_ALPHA); + ctx.enable(ctx.BLEND); } clear(r, g, b, a) { this.ctx.clearColor(r, g, b, a); @@ -122,9 +124,8 @@ export class Texture { let tex = ctx.createTexture(); ctx.bindTexture(ctx.TEXTURE_2D, tex); ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGBA, ctx.RGBA, ctx.UNSIGNED_BYTE, image); - ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.LINEAR); - ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.LINEAR_MIPMAP_NEAREST); - ctx.generateMipmap(ctx.TEXTURE_2D); + ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.NEAREST); + ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.NEAREST); ctx.bindTexture(ctx.TEXTURE_2D, null); return new Texture(tex, image.width, image.height); } @@ -150,6 +151,7 @@ export class Camera { dt = 0; position; movement; + speed = 600; constructor(position) { this.position = position; this.movement = new Vec4(0, 0, 0, 0); @@ -157,7 +159,7 @@ export class Camera { update(dt) { this.dt = dt; let newPosition = this.movement.multScalarNew(this.dt); - this.position.x += (newPosition.x + newPosition.y) / 2; - this.position.y += newPosition.z + newPosition.w; + this.position.x += (newPosition.x + newPosition.y) * this.speed; + this.position.y += (newPosition.z + newPosition.w) * this.speed; } } diff --git a/src/js/graphics.ts b/src/js/graphics.ts index b0e38e9..3d2b43f 100644 --- a/src/js/graphics.ts +++ b/src/js/graphics.ts @@ -65,6 +65,9 @@ export class Graphics { ctx.bindVertexArray(this.vao); ctx.viewport(0, 0, ctx.canvas.width, ctx.canvas.height); ctx.useProgram(this.program); + + ctx.blendFunc(ctx.SRC_ALPHA, ctx.ONE_MINUS_SRC_ALPHA); + ctx.enable(ctx.BLEND); } clear(r: number, g: number, b: number, a: number) { @@ -161,9 +164,8 @@ export class Texture { let tex = ctx.createTexture(); ctx.bindTexture(ctx.TEXTURE_2D, tex); ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGBA, ctx.RGBA, ctx.UNSIGNED_BYTE, image); - ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.LINEAR); - ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.LINEAR_MIPMAP_NEAREST); - ctx.generateMipmap(ctx.TEXTURE_2D); + ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.NEAREST); + ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.NEAREST); ctx.bindTexture(ctx.TEXTURE_2D, null); return new Texture(tex, image.width, image.height); @@ -194,6 +196,7 @@ export class Camera { dt: number = 0; position: Vec3; movement: Vec4; + speed: number = 600; constructor(position: Vec3) { this.position = position; @@ -204,8 +207,8 @@ export class Camera { this.dt = dt; let newPosition = this.movement.multScalarNew(this.dt); - this.position.x += (newPosition.x + newPosition.y) / 2; - this.position.y += newPosition.z + newPosition.w; + this.position.x += (newPosition.x + newPosition.y) * this.speed; + this.position.y += (newPosition.z + newPosition.w) * this.speed; } } diff --git a/src/js/script.js b/src/js/script.js index 269d572..f53fdad 100644 --- a/src/js/script.js +++ b/src/js/script.js @@ -1,15 +1,16 @@ -import { initializeContext, Vec3, Mat4, Vec2 } from "./common.js"; +import { initializeContext, Vec3, Mat4, Vec4, 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"; +import { bush, Grid, Tile, tree } from "./world.js"; +import * as Assets from "./assets.js"; const vertexShader = `#version 300 es in vec3 a_position; in vec2 a_tex_position; - in vec4 a_color; out vec2 v_tex_position; + in vec4 a_color; out vec4 v_color; uniform mat4 u_matrix; uniform bool u_isTex; @@ -28,6 +29,7 @@ const vertexShader = `#version 300 es if (u_isIso) { vec4 isometric = Iso * vec4(a_position.xyz, 1.0); orthographic = u_matrix * isometric; + //orthographic = u_matrix * vec4(a_position.xyz, 1.0); } else { orthographic = u_matrix * vec4(a_position.xyz, 1.0); } @@ -63,27 +65,18 @@ const fragmentShader = `#version 300 es function draw(gfx, camera, dt, grid) { gfx.clear(0, 0, 0, 0); camera.update(dt); - let zoom = 2; + let zoom = 1; let right = gfx.ctx.canvas.width * zoom; - let left = -right * zoom; + let left = 0; let top = gfx.ctx.canvas.height * zoom; - let bottom = -top * zoom; + let bottom = 0; let near = -100; let far = 100; let mo = Mat4.orthographic(left, right, bottom, top, near, far); let mt = Mat4.translate(camera.position); - let m = mo.multNew(mt); + let m = mt.multNew(mo); 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) { - // 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); + drawing.drawIsometricGrid(gfx, camera, grid); } function addDefaultKeybinds(input, camera) { input.addKeyAction("KeyA", [], camera, (c) => { @@ -123,14 +116,22 @@ 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 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 camera = new Camera(new Vec3(0, 0, -1)); + await Assets.assets.load(ctx); + let m = Mat4.isometric(); + let size = 20; + let grid = new Grid(m.transformNew(new Vec4(ctx.canvas.width / 4, ctx.canvas.height / 2, 0, 1)).reduce(), 24, size, size, 10); + grid.fillLayer(new Tile({ + top: Assets.assets.get("grass"), + right: Assets.Colors.Brown, + left: Assets.Colors.Brown, + }), 0); + tree(grid, new Vec2(size / 2, size / 2)); + bush(grid, new Vec2(size / 2 + 4, size / 2 + 4)); + //for (let i = 0; i < 10; i++) { + // tree(grid, new Vec2(Math.floor(Math.random() * size - 1), Math.floor(Math.random() * size - 1))); + //} + //grid.setTile(new Tile(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(0, 29, 1)); let prevTimestamp = 0; const frame = (timestamp) => { const deltaTime = (timestamp - prevTimestamp) / 1000; @@ -143,7 +144,7 @@ function addDefaultKeybinds(input, camera) { prevTimestamp = timestamp; window.requestAnimationFrame(frame); }); - let input = new Input(); + const input = new Input(); addDefaultKeybinds(input, camera); - let wasmgl = new wasm.WASMGL(await wasm.loadWasmModule("./src/wasm/module.wasm")); + const wasmgl = new wasm.WASMGL(await wasm.loadWasmModule("./src/wasm/module.wasm")); })(); diff --git a/src/js/script.ts b/src/js/script.ts index 9b80770..735030d 100644 --- a/src/js/script.ts +++ b/src/js/script.ts @@ -1,17 +1,18 @@ -import { initializeContext, Vec3, Mat4, Vec2 } from "./common.js"; -import { Graphics, fullscreenCanvas, Texture, Camera } from "./graphics.js"; +import { initializeContext, Vec3, Mat4, Vec4, 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"; +import {bush, Grid, Tile, tree} from "./world.js"; +import * as Assets from "./assets.js"; const vertexShader = `#version 300 es in vec3 a_position; in vec2 a_tex_position; - in vec4 a_color; out vec2 v_tex_position; + in vec4 a_color; out vec4 v_color; uniform mat4 u_matrix; uniform bool u_isTex; @@ -30,6 +31,7 @@ const vertexShader = if (u_isIso) { vec4 isometric = Iso * vec4(a_position.xyz, 1.0); orthographic = u_matrix * isometric; + //orthographic = u_matrix * vec4(a_position.xyz, 1.0); } else { orthographic = u_matrix * vec4(a_position.xyz, 1.0); } @@ -69,35 +71,25 @@ function draw(gfx: Graphics, camera: Camera, dt: number, grid: Grid) { gfx.clear(0, 0, 0, 0); camera.update(dt); - let zoom = 2; + let zoom = 1; let right = gfx.ctx.canvas.width * zoom; - let left = -right * zoom; + let left = 0; let top = gfx.ctx.canvas.height * zoom; - let bottom = -top * zoom; + let bottom = 0; let near = -100; let far = 100; let mo = Mat4.orthographic(left, right, bottom, top, near, far); let mt = Mat4.translate(camera.position); - let m = mo.multNew(mt); + let m = mt.multNew(mo); 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) { - // 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); + drawing.drawIsometricGrid(gfx, camera, grid); } function addDefaultKeybinds(input: Input, camera: Camera) { @@ -155,18 +147,27 @@ 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 camera = new Camera(new Vec3(0, 0, -1)); - let camera = new Camera(new Vec3(0, 0, 0)); + await Assets.assets.load(ctx); - let grid = new Grid(new Vec3(-800, 0, 0), 100, 20, 20, 10); - grid.fillLayer(new Tile([0, 0, 1, 1]), 0); + let m = Mat4.isometric(); + let size = 20; + let grid = new Grid(m.transformNew(new Vec4(ctx.canvas.width / 4, ctx.canvas.height / 2, 0, 1)).reduce(), 24, size, size, 10); + grid.fillLayer(new Tile({ + top: Assets.assets.get("grass"), + right: Assets.Colors.Brown, + left: Assets.Colors.Brown, + }), 0); - for (let i = 0; i < 5; i++) { - tree(grid, new Vec2(Math.floor(Math.random() * 19), Math.floor(Math.random() * 19))); - } + tree(grid, new Vec2(size / 2, size / 2)); + bush(grid, new Vec2(size / 2 + 4, size / 2 + 4)); + //for (let i = 0; i < 10; i++) { + // tree(grid, new Vec2(Math.floor(Math.random() * size - 1), Math.floor(Math.random() * size - 1))); + //} + + //grid.setTile(new Tile(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(0, 29, 1)); let prevTimestamp = 0; const frame = (timestamp: number) => { @@ -184,8 +185,8 @@ function addDefaultKeybinds(input: Input, camera: Camera) { window.requestAnimationFrame(frame); }); - let input = new Input(); + const input = new Input(); addDefaultKeybinds(input, camera); - let wasmgl: wasm.WASMGL = new wasm.WASMGL(await wasm.loadWasmModule("./src/wasm/module.wasm")); + const wasmgl: wasm.WASMGL = new wasm.WASMGL(await wasm.loadWasmModule("./src/wasm/module.wasm")); })(); diff --git a/src/js/world.js b/src/js/world.js index 9ddffe0..2aee45b 100644 --- a/src/js/world.js +++ b/src/js/world.js @@ -1,4 +1,4 @@ -import * as Colors from "./colors.js"; +import * as Assets from "./assets.js"; import { Vec3 } from "./common.js"; export var TileEdge; (function (TileEdge) { @@ -8,7 +8,11 @@ export var TileEdge; TileEdge[TileEdge["Both"] = 3] = "Both"; })(TileEdge || (TileEdge = {})); export class Tile { - fill = [1, 0, 1, 1]; + fill = { + top: [1, 0, 1, 1], + left: [0, 0, 0, 1], + right: [0, 0, 0, 1], + }; edge = TileEdge.None; constructor(fill, edge) { if (fill !== undefined) @@ -17,6 +21,13 @@ export class Tile { this.edge = edge; } } +export function ColorToTile(c) { + return { + left: c, + top: c, + right: c, + }; +} export class Grid { position; tiles3d; @@ -62,12 +73,25 @@ export class Grid { } } 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)); + grid.setTile(new Tile(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(position.x, position.y, 1)); + grid.setTile(new Tile(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(position.x, position.y, 2)); + grid.setTile(new Tile(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(position.x, position.y, 3)); + grid.setTile(new Tile(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(position.x, position.y, 4)); + grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.None), new Vec3(position.x, position.y, 4)); + grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y + 1, 4)); + grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y + 1, 5)); + grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y, 5)); + grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y, 4)); + grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y, 5)); + grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y + 1, 4)); + grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y + 1, 5)); +} +export function bush(grid, position) { + grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), position.extend(1)); + grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y, 1)); + grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y + 1, 1)); + grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y + 1, 1)); + grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), position.extend(2)); + grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y, 2)); + grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y + 1, 2)); } diff --git a/src/js/world.ts b/src/js/world.ts index 7612ffe..f0a0ffd 100644 --- a/src/js/world.ts +++ b/src/js/world.ts @@ -1,4 +1,4 @@ -import * as Colors from "./colors.js"; +import * as Assets from "./assets.js"; import {Vec2, Vec3} from "./common.js"; import {Texture} from "./graphics.js"; @@ -9,11 +9,18 @@ export enum TileEdge { Both, } +export type TileFillament = Texture | Assets.Color; +export type TileFill = { left: TileFillament, top: TileFillament, right: TileFillament }; + export class Tile { - fill: Texture | Colors.Color = [1, 0, 1, 1]; + fill: TileFill = { + top : [1, 0, 1, 1], + left : [0, 0, 0, 1], + right : [0, 0, 0, 1], + }; edge: TileEdge = TileEdge.None; - constructor(fill?: Texture | Colors.Color, edge?: TileEdge) { + constructor(fill?: TileFill, edge?: TileEdge) { if (fill !== undefined) this.fill = fill; @@ -22,6 +29,14 @@ export class Tile { } } +export function ColorToTile(c: Assets.Color) { + return { + left: c, + top: c, + right: c, + }; +} + export class Grid { position: Vec3; tiles3d: Tile[][]; @@ -81,12 +96,27 @@ export class Grid { } 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)); + grid.setTile(new Tile(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(position.x, position.y, 1)); + grid.setTile(new Tile(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(position.x, position.y, 2)); + grid.setTile(new Tile(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(position.x, position.y, 3)); + grid.setTile(new Tile(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(position.x, position.y, 4)); + grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.None), new Vec3(position.x, position.y, 4)); + grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y + 1, 4)); + grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y + 1, 5)); + grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y, 5)); + grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y, 4)); + grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y, 5)); + grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y + 1, 4)); + grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y + 1, 5)); +} + +export function bush(grid: Grid, position: Vec2) { + grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), position.extend(1)); + grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y, 1)); + grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y + 1, 1)); + grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y + 1, 1)); + + grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), position.extend(2)); + grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y, 2)); + grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y + 1, 2)); }