Fixed, camera translate, matrix transform and texture transparency

This commit is contained in:
Maciej Samborski 2024-12-31 16:03:15 +01:00
parent e936b626f3
commit 14d5db166e
17 changed files with 333 additions and 156 deletions

BIN
assets/grass.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 B

BIN
assets/greenary.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 411 B

BIN
assets/log.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 B

38
src/js/assets.js Normal file
View File

@ -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();

53
src/js/assets.ts Normal file
View File

@ -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<string, Asset> = 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();

View File

@ -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];

View File

@ -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];

View File

@ -280,13 +280,20 @@ class Mat4 {
return new Mat4(data); return new Mat4(data);
} }
static isometric() { static isometric() {
let m = new Mat4(new Float32Array([ return new Mat4(new Float32Array([
1, -1, 0, 0, 1, -1, 0, 0,
1, 1, 0, 0, 1, 1, 0, 0,
0, 0, 1, 0, 0, 0, 1, 0,
0, 0, 0, 1, 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) { static rotation_x(angle) {
let data = new Float32Array([ let data = new Float32Array([
@ -347,17 +354,17 @@ class Mat4 {
this.data[i * 4 + col] = data[i]; this.data[i * 4 + col] = data[i];
} }
transform(v) { 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 x = v.x * this.x(0) + v.y * this.x(1) + v.z * this.x(2) + v.w * 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 y = v.x * this.y(0) + v.y * this.y(1) + v.z * this.y(2) + v.w * 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 z = v.x * this.z(0) + v.y * this.z(1) + v.z * this.z(2) + v.w * 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 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.x = x;
v.y = y; v.y = y;
v.z = z; v.z = z;
v.w = w; v.w = w;
} }
transformNew(v) { 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 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 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 z = v.x * this.z(0) + v.y * this.z(1) + v.z * this.z(2) + v.w * this.z(3);

View File

@ -395,14 +395,21 @@ class Mat4 {
} }
static isometric(): Mat4 { static isometric(): Mat4 {
let m = new Mat4(new Float32Array([ return new Mat4(new Float32Array([
1, -1, 0, 0, 1, -1, 0, 0,
1, 1, 0, 0, 1, 1, 0, 0,
0, 0, 1, 0, 0, 0, 1, 0,
0, 0, 0, 1, 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 { static rotation_x(angle: number): Mat4 {
@ -478,10 +485,10 @@ class Mat4 {
} }
transform(v: Vec4) { 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 x = v.x * this.x(0) + v.y * this.x(1) + v.z * this.x(2) + v.w * 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 y = v.x * this.y(0) + v.y * this.y(1) + v.z * this.y(2) + v.w * 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 z = v.x * this.z(0) + v.y * this.z(1) + v.z * this.z(2) + v.w * 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 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.x = x;
v.y = y; v.y = y;
@ -490,7 +497,7 @@ class Mat4 {
} }
transformNew(v: Vec4): Vec4 { 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 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 y = v.x * this.y(0) + v.y * this.y(1) + v.z * this.y(2) + v.w * this.y(3);

View File

@ -1,16 +1,17 @@
import { Vec3, Vec2 } from "./common.js"; import { Vec3, Vec2, Vec4 } from "./common.js";
import { Texture } from "./graphics.js"; import { Texture } from "./graphics.js";
import { TileEdge } from "./world.js"; import { TileEdge } from "./world.js";
function cull(bb, screen) { // TODO: Don't assume tile size is same in all directions
if (bb.x > screen.x) function cull(point, screen, tileSize) {
return false; if (point.x + tileSize < screen.x)
if (bb.x + bb.z < screen.x + screen.z) return true;
return false; if (point.x + tileSize > screen.x + screen.z)
if (bb.y > screen.y) return true;
return false; if (point.y - tileSize < screen.y)
if (bb.y + bb.w < screen.y + screen.w) return true;
return false; if (point.y + tileSize > screen.y + screen.w)
return true; return true;
return false;
} }
export function drawTriangle(gfx, positions, color) { export function drawTriangle(gfx, positions, color) {
const a_position = gfx.getAttribute("a_position"); 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); 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 = [ let points = [
// Left Top
position, position,
//Top
new Vec3(position.x, position.y + exts.y, position.z), new Vec3(position.x, position.y + exts.y, position.z),
//Mid
new Vec3(position.x + exts.x, position.y, position.z), new Vec3(position.x + exts.x, position.y, position.z),
//Right Top
new Vec3(position.x + exts.x, position.y + exts.y, position.z), 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 + 1.5 * exts.x, position.y + 0.5 * exts.y, position.z + 0.25 * exts.z), new Vec3(position.x + 1.5 * exts.x, position.y + 0.5 * exts.y, position.z + 0.25 * exts.z),
new Vec3(position.x + 0.5 * exts.x, position.y - 0.5 * exts.y, position.z + 0.25 * exts.z), new Vec3(position.x + 0.5 * exts.x, position.y - 0.5 * exts.y, position.z + 0.25 * exts.z),
]; ];
let screen = new Vec4(-camera.position.x, -camera.position.y, gfx.ctx.canvas.width, gfx.ctx.canvas.height);
gfx.ctx.uniform1i(gfx.getUniform("u_isIso"), 1); gfx.ctx.uniform1i(gfx.getUniform("u_isIso"), 1);
// Top // Top
drawRectangle(gfx, [ drawRectangle(gfx, [
@ -98,7 +105,7 @@ export function drawIsometricCube(gfx, position, exts, color, edge) {
points[1], points[1],
points[3], points[3],
points[2], points[2],
], color); ], color.top);
// Right Edge // Right Edge
if (edge == TileEdge.Right || edge == TileEdge.Both) { if (edge == TileEdge.Right || edge == TileEdge.Both) {
drawRectangle(gfx, [ drawRectangle(gfx, [
@ -106,7 +113,7 @@ export function drawIsometricCube(gfx, position, exts, color, edge) {
points[2], points[2],
points[4], points[4],
points[5], points[5],
], color); ], color.right);
} }
// Left Edge // Left Edge
if (edge == TileEdge.Left || edge == TileEdge.Both) { if (edge == TileEdge.Left || edge == TileEdge.Both) {
@ -115,17 +122,15 @@ export function drawIsometricCube(gfx, position, exts, color, edge) {
points[2], points[2],
points[4], points[4],
points[6], points[6],
], color); ], color.left);
} }
gfx.ctx.uniform1i(gfx.getUniform("u_isIso"), 0); gfx.ctx.uniform1i(gfx.getUniform("u_isIso"), 0);
} }
export function drawIsometricGrid(gfx, grid) { export function drawIsometricGrid(gfx, camera, grid) {
let position = { ...grid.position }; let position = { ...grid.position };
let exts = new Vec3(grid.tileSize, grid.tileSize, 0); let exts = new Vec3(grid.tileSize, grid.tileSize, 0);
let tileCoord = new Vec3(0, 0, 0); let tileCoord = new Vec3(0, 0, 0);
// Optimize this by: // TODO: Optimize this
// 1. Skip all empty tiles by using lowTiles
// 2. tba
for (let k = 0; k < grid.height; ++k) { for (let k = 0; k < grid.height; ++k) {
for (let j = 0; j < grid.length; ++j) { for (let j = 0; j < grid.length; ++j) {
for (let i = 0; i < grid.width; ++i) { for (let i = 0; i < grid.width; ++i) {
@ -137,7 +142,7 @@ export function drawIsometricGrid(gfx, grid) {
position.x += grid.tileSize; position.x += grid.tileSize;
continue; continue;
} }
drawIsometricCube(gfx, new Vec3(position.x - grid.tileSize / 2 * k, position.y + grid.tileSize / 2 * k, position.z), exts, tile.fill, tile.edge); drawIsometricCube(gfx, camera, new Vec3(position.x - grid.tileSize / 2 * k, position.y + grid.tileSize / 2 * k, position.z), exts, tile.fill, tile.edge);
position.x += grid.tileSize; position.x += grid.tileSize;
} }
position.y -= grid.tileSize; position.y -= grid.tileSize;

View File

@ -1,19 +1,26 @@
import {Color} from "./colors.js"; import { Vec3, Vec2, Vec4, Mat4 } from "./common.js"
import { Vec3, Vec2, Vec4 } from "./common.js" import { Camera, Graphics, Texture } from "./graphics.js";
import { Graphics, Texture } from "./graphics.js"; import {Grid, TileEdge, TileFill} from "./world.js";
import {Grid, TileEdge} from "./world.js"; import * as Assets from "./assets.js";
function cull(bb: Vec4, screen: Vec4): boolean { // TODO: Don't assume tile size is same in all directions
if (bb.x > screen.x) return false; function cull(point: Vec3, screen: Vec4, tileSize: number): boolean {
if (bb.x + bb.z < screen.x + screen.z) return false; if (point.x + tileSize < screen.x)
return true;
if (bb.y > screen.y) return false; if (point.x + tileSize > screen.x + screen.z)
if (bb.y + bb.w < screen.y + screen.w) return false; 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_position = gfx.getAttribute("a_position");
const a_color = gfx.getAttribute("a_color"); 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); 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_position = gfx.getAttribute("a_position");
const a_color = gfx.getAttribute("a_color"); 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); 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 a_position = gfx.getAttribute("a_position");
const points: Array<number> = [ const points: Array<number> = [
@ -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 = [ let points = [
// Left Top
position, position,
//Top
new Vec3(position.x, position.y + exts.y, position.z), new Vec3(position.x, position.y + exts.y, position.z),
//Mid
new Vec3(position.x + exts.x, position.y, position.z), new Vec3(position.x + exts.x, position.y, position.z),
//Right Top
new Vec3(position.x + exts.x, position.y + exts.y, position.z), 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 + 1.5 * exts.x, position.y + 0.5 * exts.y, position.z + 0.25 * exts.z), new Vec3(position.x + 1.5 * exts.x, position.y + 0.5 * exts.y, position.z + 0.25 * exts.z),
new Vec3(position.x + 0.5 * exts.x, position.y - 0.5 * exts.y, position.z + 0.25 * exts.z), new Vec3(position.x + 0.5 * exts.x, position.y - 0.5 * exts.y, position.z + 0.25 * exts.z),
]; ];
let screen = new Vec4(
-camera.position.x,
-camera.position.y,
gfx.ctx.canvas.width,
gfx.ctx.canvas.height);
gfx.ctx.uniform1i(gfx.getUniform("u_isIso"), 1); gfx.ctx.uniform1i(gfx.getUniform("u_isIso"), 1);
// Top // Top
@ -121,7 +139,7 @@ export function drawIsometricCube(gfx: Graphics, position: Vec3, exts: Vec3, col
points[3], points[3],
points[2], points[2],
], ],
color); color.top);
// Right Edge // Right Edge
@ -134,7 +152,7 @@ export function drawIsometricCube(gfx: Graphics, position: Vec3, exts: Vec3, col
points[4], points[4],
points[5], points[5],
], ],
color); color.right);
} }
// Left Edge // Left Edge
@ -147,20 +165,18 @@ export function drawIsometricCube(gfx: Graphics, position: Vec3, exts: Vec3, col
points[4], points[4],
points[6], points[6],
], ],
color); color.left);
} }
gfx.ctx.uniform1i(gfx.getUniform("u_isIso"), 0); gfx.ctx.uniform1i(gfx.getUniform("u_isIso"), 0);
} }
export function drawIsometricGrid(gfx: Graphics, grid: Grid) { export function drawIsometricGrid(gfx: Graphics, camera: Camera, grid: Grid) {
let position = {...grid.position} as Vec3; let position = {...grid.position} as Vec3;
let exts = new Vec3(grid.tileSize, grid.tileSize, 0); let exts = new Vec3(grid.tileSize, grid.tileSize, 0);
let tileCoord = new Vec3(0, 0, 0); let tileCoord = new Vec3(0, 0, 0);
// Optimize this by: // TODO: Optimize this
// 1. Skip all empty tiles by using lowTiles
// 2. tba
for (let k = 0; k < grid.height; ++k) { for (let k = 0; k < grid.height; ++k) {
for (let j = 0; j < grid.length; ++j) { for (let j = 0; j < grid.length; ++j) {
for (let i = 0; i < grid.width; ++i) { for (let i = 0; i < grid.width; ++i) {
@ -175,7 +191,7 @@ export function drawIsometricGrid(gfx: Graphics, grid: Grid) {
continue; continue;
} }
drawIsometricCube(gfx, new Vec3(position.x - grid.tileSize / 2 * k, position.y + grid.tileSize / 2 * k, position.z), exts, tile.fill, tile.edge); drawIsometricCube(gfx, camera, new Vec3(position.x - grid.tileSize / 2 * k, position.y + grid.tileSize / 2 * k, position.z), exts, tile.fill, tile.edge);
position.x += grid.tileSize; position.x += grid.tileSize;
} }
@ -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 a_position = gfx.getAttribute("a_position");
const points: Array<number> = [ const points: Array<number> = [
@ -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<Vec2> = new Array<Vec2>(); const points: Array<Vec2> = new Array<Vec2>();
const precision = 40; 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_position = gfx.getAttribute("a_position");
const a_color = gfx.getAttribute("a_color"); const a_color = gfx.getAttribute("a_color");

View File

@ -52,6 +52,8 @@ export class Graphics {
ctx.bindVertexArray(this.vao); ctx.bindVertexArray(this.vao);
ctx.viewport(0, 0, ctx.canvas.width, ctx.canvas.height); ctx.viewport(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.useProgram(this.program); ctx.useProgram(this.program);
ctx.blendFunc(ctx.SRC_ALPHA, ctx.ONE_MINUS_SRC_ALPHA);
ctx.enable(ctx.BLEND);
} }
clear(r, g, b, a) { clear(r, g, b, a) {
this.ctx.clearColor(r, g, b, a); this.ctx.clearColor(r, g, b, a);
@ -122,9 +124,8 @@ export class Texture {
let tex = ctx.createTexture(); let tex = ctx.createTexture();
ctx.bindTexture(ctx.TEXTURE_2D, tex); ctx.bindTexture(ctx.TEXTURE_2D, tex);
ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGBA, ctx.RGBA, ctx.UNSIGNED_BYTE, image); 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_MAG_FILTER, ctx.NEAREST);
ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.LINEAR_MIPMAP_NEAREST); ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.NEAREST);
ctx.generateMipmap(ctx.TEXTURE_2D);
ctx.bindTexture(ctx.TEXTURE_2D, null); ctx.bindTexture(ctx.TEXTURE_2D, null);
return new Texture(tex, image.width, image.height); return new Texture(tex, image.width, image.height);
} }
@ -150,6 +151,7 @@ export class Camera {
dt = 0; dt = 0;
position; position;
movement; movement;
speed = 600;
constructor(position) { constructor(position) {
this.position = position; this.position = position;
this.movement = new Vec4(0, 0, 0, 0); this.movement = new Vec4(0, 0, 0, 0);
@ -157,7 +159,7 @@ export class Camera {
update(dt) { update(dt) {
this.dt = dt; this.dt = dt;
let newPosition = this.movement.multScalarNew(this.dt); let newPosition = this.movement.multScalarNew(this.dt);
this.position.x += (newPosition.x + newPosition.y) / 2; this.position.x += (newPosition.x + newPosition.y) * this.speed;
this.position.y += newPosition.z + newPosition.w; this.position.y += (newPosition.z + newPosition.w) * this.speed;
} }
} }

View File

@ -65,6 +65,9 @@ export class Graphics {
ctx.bindVertexArray(this.vao); ctx.bindVertexArray(this.vao);
ctx.viewport(0, 0, ctx.canvas.width, ctx.canvas.height); ctx.viewport(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.useProgram(this.program); ctx.useProgram(this.program);
ctx.blendFunc(ctx.SRC_ALPHA, ctx.ONE_MINUS_SRC_ALPHA);
ctx.enable(ctx.BLEND);
} }
clear(r: number, g: number, b: number, a: number) { clear(r: number, g: number, b: number, a: number) {
@ -161,9 +164,8 @@ export class Texture {
let tex = ctx.createTexture(); let tex = ctx.createTexture();
ctx.bindTexture(ctx.TEXTURE_2D, tex); ctx.bindTexture(ctx.TEXTURE_2D, tex);
ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGBA, ctx.RGBA, ctx.UNSIGNED_BYTE, image); 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_MAG_FILTER, ctx.NEAREST);
ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.LINEAR_MIPMAP_NEAREST); ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.NEAREST);
ctx.generateMipmap(ctx.TEXTURE_2D);
ctx.bindTexture(ctx.TEXTURE_2D, null); ctx.bindTexture(ctx.TEXTURE_2D, null);
return new Texture(tex, image.width, image.height); return new Texture(tex, image.width, image.height);
@ -194,6 +196,7 @@ export class Camera {
dt: number = 0; dt: number = 0;
position: Vec3; position: Vec3;
movement: Vec4; movement: Vec4;
speed: number = 600;
constructor(position: Vec3) { constructor(position: Vec3) {
this.position = position; this.position = position;
@ -204,8 +207,8 @@ export class Camera {
this.dt = dt; this.dt = dt;
let newPosition = this.movement.multScalarNew(this.dt); let newPosition = this.movement.multScalarNew(this.dt);
this.position.x += (newPosition.x + newPosition.y) / 2; this.position.x += (newPosition.x + newPosition.y) * this.speed;
this.position.y += newPosition.z + newPosition.w; this.position.y += (newPosition.z + newPosition.w) * this.speed;
} }
} }

View File

@ -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 { Graphics, fullscreenCanvas, Camera } from "./graphics.js";
import * as drawing from "./draw.js"; import * as drawing from "./draw.js";
import * as wasm from "./wasm.js"; import * as wasm from "./wasm.js";
import { Input } from "./input.js"; import { Input } from "./input.js";
import { 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 const vertexShader = `#version 300 es
in vec3 a_position; in vec3 a_position;
in vec2 a_tex_position; in vec2 a_tex_position;
in vec4 a_color;
out vec2 v_tex_position; out vec2 v_tex_position;
in vec4 a_color;
out vec4 v_color; out vec4 v_color;
uniform mat4 u_matrix; uniform mat4 u_matrix;
uniform bool u_isTex; uniform bool u_isTex;
@ -28,6 +29,7 @@ const vertexShader = `#version 300 es
if (u_isIso) { if (u_isIso) {
vec4 isometric = Iso * vec4(a_position.xyz, 1.0); vec4 isometric = Iso * vec4(a_position.xyz, 1.0);
orthographic = u_matrix * isometric; orthographic = u_matrix * isometric;
//orthographic = u_matrix * vec4(a_position.xyz, 1.0);
} else { } else {
orthographic = u_matrix * vec4(a_position.xyz, 1.0); orthographic = u_matrix * vec4(a_position.xyz, 1.0);
} }
@ -63,27 +65,18 @@ const fragmentShader = `#version 300 es
function draw(gfx, camera, dt, grid) { function draw(gfx, camera, dt, grid) {
gfx.clear(0, 0, 0, 0); gfx.clear(0, 0, 0, 0);
camera.update(dt); camera.update(dt);
let zoom = 2; let zoom = 1;
let right = gfx.ctx.canvas.width * zoom; let right = gfx.ctx.canvas.width * zoom;
let left = -right * zoom; let left = 0;
let top = gfx.ctx.canvas.height * zoom; let top = gfx.ctx.canvas.height * zoom;
let bottom = -top * zoom; let bottom = 0;
let near = -100; let near = -100;
let far = 100; let far = 100;
let mo = Mat4.orthographic(left, right, bottom, top, near, far); let mo = Mat4.orthographic(left, right, bottom, top, near, far);
let mt = Mat4.translate(camera.position); 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()); gfx.ctx.uniformMatrix4fv(gfx.getUniform("u_matrix"), false, m.splat());
//let exts = new Vec3(50, 50, 20); drawing.drawIsometricGrid(gfx, camera, grid);
//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) { function addDefaultKeybinds(input, camera) {
input.addKeyAction("KeyA", [], camera, (c) => { input.addKeyAction("KeyA", [], camera, (c) => {
@ -123,14 +116,22 @@ function addDefaultKeybinds(input, camera) {
gfx.createUniform("u_matrix"); gfx.createUniform("u_matrix");
gfx.createUniform("u_isTex"); gfx.createUniform("u_isTex");
gfx.createUniform("u_isIso"); gfx.createUniform("u_isIso");
//let city = await Texture.load(ctx, "../../assets/genetica/rt/City Night.jpg"); let camera = new Camera(new Vec3(0, 0, -1));
//let wall = await Texture.load(ctx, "../../assets/wall.png"); await Assets.assets.load(ctx);
let camera = new Camera(new Vec3(0, 0, 0)); let m = Mat4.isometric();
let grid = new Grid(new Vec3(-800, 0, 0), 100, 20, 20, 10); let size = 20;
grid.fillLayer(new Tile([0, 0, 1, 1]), 0); let grid = new Grid(m.transformNew(new Vec4(ctx.canvas.width / 4, ctx.canvas.height / 2, 0, 1)).reduce(), 24, size, size, 10);
for (let i = 0; i < 5; i++) { grid.fillLayer(new Tile({
tree(grid, new Vec2(Math.floor(Math.random() * 19), Math.floor(Math.random() * 19))); 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; let prevTimestamp = 0;
const frame = (timestamp) => { const frame = (timestamp) => {
const deltaTime = (timestamp - prevTimestamp) / 1000; const deltaTime = (timestamp - prevTimestamp) / 1000;
@ -143,7 +144,7 @@ function addDefaultKeybinds(input, camera) {
prevTimestamp = timestamp; prevTimestamp = timestamp;
window.requestAnimationFrame(frame); window.requestAnimationFrame(frame);
}); });
let input = new Input(); const input = new Input();
addDefaultKeybinds(input, camera); 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"));
})(); })();

View File

@ -1,17 +1,18 @@
import { initializeContext, Vec3, Mat4, Vec2 } from "./common.js"; import { initializeContext, Vec3, Mat4, Vec4, Vec2 } from "./common.js";
import { Graphics, fullscreenCanvas, Texture, Camera } from "./graphics.js"; import { Graphics, fullscreenCanvas, Camera } from "./graphics.js";
import * as drawing from "./draw.js"; import * as drawing from "./draw.js";
import * as wasm from "./wasm.js"; import * as wasm from "./wasm.js";
import { Input } from "./input.js"; import { Input } from "./input.js";
import {Grid, Tile, tree} from "./world.js"; import {bush, Grid, Tile, tree} from "./world.js";
import * as Assets from "./assets.js";
const vertexShader = const vertexShader =
`#version 300 es `#version 300 es
in vec3 a_position; in vec3 a_position;
in vec2 a_tex_position; in vec2 a_tex_position;
in vec4 a_color;
out vec2 v_tex_position; out vec2 v_tex_position;
in vec4 a_color;
out vec4 v_color; out vec4 v_color;
uniform mat4 u_matrix; uniform mat4 u_matrix;
uniform bool u_isTex; uniform bool u_isTex;
@ -30,6 +31,7 @@ const vertexShader =
if (u_isIso) { if (u_isIso) {
vec4 isometric = Iso * vec4(a_position.xyz, 1.0); vec4 isometric = Iso * vec4(a_position.xyz, 1.0);
orthographic = u_matrix * isometric; orthographic = u_matrix * isometric;
//orthographic = u_matrix * vec4(a_position.xyz, 1.0);
} else { } else {
orthographic = u_matrix * vec4(a_position.xyz, 1.0); 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); gfx.clear(0, 0, 0, 0);
camera.update(dt); camera.update(dt);
let zoom = 2; let zoom = 1;
let right = gfx.ctx.canvas.width * zoom; let right = gfx.ctx.canvas.width * zoom;
let left = -right * zoom; let left = 0;
let top = gfx.ctx.canvas.height * zoom; let top = gfx.ctx.canvas.height * zoom;
let bottom = -top * zoom; let bottom = 0;
let near = -100; let near = -100;
let far = 100; let far = 100;
let mo = Mat4.orthographic(left, right, bottom, top, near, far); let mo = Mat4.orthographic(left, right, bottom, top, near, far);
let mt = Mat4.translate(camera.position); let mt = Mat4.translate(camera.position);
let m = mo.multNew(mt); let m = mt.multNew(mo);
gfx.ctx.uniformMatrix4fv( gfx.ctx.uniformMatrix4fv(
gfx.getUniform("u_matrix"), gfx.getUniform("u_matrix"),
false, false,
m.splat() 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) { function addDefaultKeybinds(input: Input, camera: Camera) {
@ -155,18 +147,27 @@ function addDefaultKeybinds(input: Input, camera: Camera) {
gfx.createUniform("u_isTex"); gfx.createUniform("u_isTex");
gfx.createUniform("u_isIso"); gfx.createUniform("u_isIso");
//let city = await Texture.load(ctx, "../../assets/genetica/rt/City Night.jpg"); let camera = new Camera(new Vec3(0, 0, -1));
//let wall = await Texture.load(ctx, "../../assets/wall.png");
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); let m = Mat4.isometric();
grid.fillLayer(new Tile([0, 0, 1, 1]), 0);
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(size / 2, size / 2));
tree(grid, new Vec2(Math.floor(Math.random() * 19), Math.floor(Math.random() * 19))); 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; let prevTimestamp = 0;
const frame = (timestamp: number) => { const frame = (timestamp: number) => {
@ -184,8 +185,8 @@ function addDefaultKeybinds(input: Input, camera: Camera) {
window.requestAnimationFrame(frame); window.requestAnimationFrame(frame);
}); });
let input = new Input(); const input = new Input();
addDefaultKeybinds(input, camera); 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"));
})(); })();

View File

@ -1,4 +1,4 @@
import * as Colors from "./colors.js"; import * as Assets from "./assets.js";
import { Vec3 } from "./common.js"; import { Vec3 } from "./common.js";
export var TileEdge; export var TileEdge;
(function (TileEdge) { (function (TileEdge) {
@ -8,7 +8,11 @@ export var TileEdge;
TileEdge[TileEdge["Both"] = 3] = "Both"; TileEdge[TileEdge["Both"] = 3] = "Both";
})(TileEdge || (TileEdge = {})); })(TileEdge || (TileEdge = {}));
export class Tile { 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; edge = TileEdge.None;
constructor(fill, edge) { constructor(fill, edge) {
if (fill !== undefined) if (fill !== undefined)
@ -17,6 +21,13 @@ export class Tile {
this.edge = edge; this.edge = edge;
} }
} }
export function ColorToTile(c) {
return {
left: c,
top: c,
right: c,
};
}
export class Grid { export class Grid {
position; position;
tiles3d; tiles3d;
@ -62,12 +73,25 @@ export class Grid {
} }
} }
export function tree(grid, position) { export function tree(grid, position) {
grid.setTile(new Tile(Colors.Brown, TileEdge.Both), new Vec3(position.x, position.y, 1)); grid.setTile(new Tile(Assets.AssetToTileFill("log"), 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(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(position.x, position.y, 2));
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x, position.y + 1, 3)); grid.setTile(new Tile(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(position.x, position.y, 3));
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x, position.y + 1, 4)); grid.setTile(new Tile(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(position.x, position.y, 4));
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x, position.y, 5)); grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.None), new Vec3(position.x, position.y, 4));
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x + 1, position.y, 3)); grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y + 1, 4));
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x + 1, position.y, 4)); grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y + 1, 5));
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x, position.y, 6)); 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));
} }

View File

@ -1,4 +1,4 @@
import * as Colors from "./colors.js"; import * as Assets from "./assets.js";
import {Vec2, Vec3} from "./common.js"; import {Vec2, Vec3} from "./common.js";
import {Texture} from "./graphics.js"; import {Texture} from "./graphics.js";
@ -9,11 +9,18 @@ export enum TileEdge {
Both, Both,
} }
export type TileFillament = Texture | Assets.Color;
export type TileFill = { left: TileFillament, top: TileFillament, right: TileFillament };
export class Tile { 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; edge: TileEdge = TileEdge.None;
constructor(fill?: Texture | Colors.Color, edge?: TileEdge) { constructor(fill?: TileFill, edge?: TileEdge) {
if (fill !== undefined) if (fill !== undefined)
this.fill = fill; 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 { export class Grid {
position: Vec3; position: Vec3;
tiles3d: Tile[][]; tiles3d: Tile[][];
@ -81,12 +96,27 @@ export class Grid {
} }
export function tree(grid: Grid, position: Vec2) { 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(Assets.AssetToTileFill("log"), 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(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(position.x, position.y, 2));
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x, position.y + 1, 3)); grid.setTile(new Tile(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(position.x, position.y, 3));
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x, position.y + 1, 4)); grid.setTile(new Tile(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(position.x, position.y, 4));
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x, position.y, 5)); grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.None), new Vec3(position.x, position.y, 4));
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x + 1, position.y, 3)); grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y + 1, 4));
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x + 1, position.y, 4)); grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y + 1, 5));
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x, position.y, 6)); 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));
} }