Added Sprite, Spritesheet and made batching actually do shit

This commit is contained in:
Maciej Samborski 2025-01-05 23:52:15 +01:00
parent 2e9ec2565b
commit 37a91de848
10 changed files with 373 additions and 343 deletions

View File

@ -1,36 +1,26 @@
import { Texture } from "./graphics.js"; import { Vec2 } from "./common.js";
import { Texture, Spritesheet } from "./graphics.js";
export const Colors = { export const Colors = {
Red: [1, 0, 0, 1], Red: [1, 0, 0, 1],
Green: [0, 1, 0, 1], Green: [0, 1, 0, 1],
Blue: [0, 0, 1, 1], Blue: [0, 0, 1, 1],
Brown: [0.341, 0.337, 0.204, 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 { export class Assets {
assets = new Map(); assets = new Map();
loaded = false;
push(name, asset) { push(name, asset) {
if (this.assets.get(name) !== undefined) if (this.assets.get(name) !== undefined)
throw new Error("Asset name occupied!"); throw new Error("Asset name occupied!");
this.assets.set(name, asset); this.assets.set(name, asset);
} }
get(name) { get(name) {
if (!this.loaded) let a = this.assets.get(name);
throw new Error("Tried to assess assets without loading them!"); if (a === undefined)
return this.assets.get(name); throw new Error("Couldn't find asset: " + name);
return a;
} }
async load(gfx) { async load(gfx) {
assets.push("grass", await Texture.load(gfx, "../../assets/grass2.png")); assets.push("sprites", new Spritesheet(await Texture.load(gfx, "../../assets/sprites.png"), new Vec2(16, 16)));
assets.push("leaves", await Texture.load(gfx, "../../assets/greenary.png"));
assets.push("log", await Texture.load(gfx, "../../assets/log.png"));
this.loaded = true;
} }
} }
export const assets = new Assets(); export const assets = new Assets();

View File

@ -1,5 +1,5 @@
import {Graphics, Texture} from "./graphics.js"; import {Vec2} from "./common.js";
import {TileFill} from "./world.js"; import {Graphics, Texture, Spritesheet} from "./graphics.js";
export type Color = [number, number, number, number] export type Color = [number, number, number, number]
@ -10,21 +10,10 @@ export const Colors = {
Brown : [0.341, 0.337, 0.204, 1] as Color, Brown : [0.341, 0.337, 0.204, 1] as Color,
} }
export type Asset = Texture; export type Asset = Texture | Spritesheet;
export function AssetToTileFill(name: string): TileFill {
let asset = assets.get(name);
return {
left: asset,
top: asset,
right: asset,
};
}
export class Assets { export class Assets {
assets: Map<string, Asset> = new Map(); assets: Map<string, Asset> = new Map();
loaded: boolean = false;
push(name: string, asset: Asset) { push(name: string, asset: Asset) {
if (this.assets.get(name) !== undefined) if (this.assets.get(name) !== undefined)
@ -34,18 +23,15 @@ export class Assets {
} }
get(name: string): Asset { get(name: string): Asset {
if (!this.loaded) let a = this.assets.get(name);
throw new Error("Tried to assess assets without loading them!"); if (a === undefined)
throw new Error("Couldn't find asset: " + name);
return this.assets.get(name)!; return a;
} }
async load(gfx: Graphics) { async load(gfx: Graphics) {
assets.push("grass", await Texture.load(gfx, "../../assets/grass2.png")); assets.push("sprites", new Spritesheet(await Texture.load(gfx, "../../assets/sprites.png"), new Vec2(16, 16)));
assets.push("leaves", await Texture.load(gfx, "../../assets/greenary.png"));
assets.push("log", await Texture.load(gfx, "../../assets/log.png"));
this.loaded = true;
} }
} }

View File

@ -1,30 +1,20 @@
import { Vec3 } from "./common.js"; import { Vec3 } from "./common.js";
import { Texture, DrawTag } from "./graphics.js"; import { DrawTag, Sprite } from "./graphics.js";
import { TileEdge } from "./world.js"; import { TileEdge } from "./world.js";
// TODO: Don't assume tile size is same in all directions import * as Assets from "./assets.js";
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;
}
// Attrib format // Attrib format
// position color uv // position color uv
// (3) (4) (2) => 3 + 4 + 2 = 9 <=> data.len % 9 == 0 // (3) (4) (3) => 3 + 4 + 3 = 10 <=> vertexSize == 10
export class Rectangle { export class Rectangle {
fill; attribs = ["a_position", "a_color", "a_tex"];
attribs = ["a_position", "a_color", "a_tex_position"];
tags = []; tags = [];
data = []; data = [];
stride = 0; vertexSize = 10;
vertexStride = 0; sprites = Assets.assets.get("sprites");
constructor(fill, tags, attribs) { constructor(tags, sprites, attribs) {
this.fill = fill; if (sprites !== undefined) {
this.sprites = sprites;
}
if (attribs !== undefined) { if (attribs !== undefined) {
this.attribs = attribs; this.attribs = attribs;
} }
@ -32,61 +22,59 @@ export class Rectangle {
this.tags = tags; this.tags = tags;
} }
} }
overrideDraw(draw) { commit(gfx) {
this.draw = draw;
}
draw(gfx, corners) {
if (this.fill instanceof Texture) {
this.data = [
corners[0].x, corners[0].y, corners[0].z, 0, 0, 0, 0, 0, 0,
corners[1].x, corners[1].y, corners[1].z, 0, 0, 0, 0, -1, 0,
corners[3].x, corners[3].y, corners[3].z, 0, 0, 0, 0, 0, -1,
corners[2].x, corners[2].y, corners[2].z, 0, 0, 0, 0, -1, -1,
corners[1].x, corners[1].y, corners[1].z, 0, 0, 0, 0, -1, 0,
corners[3].x, corners[3].y, corners[3].z, 0, 0, 0, 0, 0, -1,
];
}
else {
this.data = [
corners[0].x, corners[0].y, corners[0].z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
corners[1].x, corners[1].y, corners[1].z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
corners[3].x, corners[3].y, corners[3].z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
corners[2].x, corners[2].y, corners[2].z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
corners[1].x, corners[1].y, corners[1].z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
corners[3].x, corners[3].y, corners[3].z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
];
}
this.vertexStride = 9;
this.stride = this.vertexStride * 4;
gfx.toRender.push({ ...this });
}
drawExts(gfx, position, exts) {
if (this.fill instanceof Texture) {
this.data = [
position.x, position.y, position.z, 0, 0, 0, 0, 0, 0,
position.x + exts.x, position.y, position.z, 0, 0, 0, 0, -1, 0,
position.x, position.y + exts.y, position.z, 0, 0, 0, 0, 0, -1,
position.x + exts.x, position.y + exts.y, position.z, 0, 0, 0, 0, -1, -1,
position.x + exts.x, position.y, position.z, 0, 0, 0, 0, -1, 0,
position.x, position.y + exts.y, position.z, 0, 0, 0, 0, 0, -1,
];
}
else {
this.data = [
position.x, position.y, position.z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
position.x + exts.x, position.y, position.z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
position.x, position.y + exts.y, position.z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
position.x + exts.x, position.y + exts.y, position.z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
position.x + exts.x, position.y, position.z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
position.x, position.y + exts.y, position.z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
];
}
this.vertexStride = 9;
this.stride = this.vertexStride * 4;
gfx.toRender.push(this); gfx.toRender.push(this);
} }
draw(corners, fill) {
if (fill instanceof Sprite) {
let uvs = Assets.assets.get("sprites").getUVs(fill.id);
this.data.push([
corners[0].x, corners[0].y, corners[0].z, 0, 0, 0, 0, uvs[0].x, uvs[0].y, 1,
corners[1].x, corners[1].y, corners[1].z, 0, 0, 0, 0, uvs[1].x, uvs[1].y, 1,
corners[3].x, corners[3].y, corners[3].z, 0, 0, 0, 0, uvs[3].x, uvs[3].y, 1,
corners[2].x, corners[2].y, corners[2].z, 0, 0, 0, 0, uvs[2].x, uvs[2].y, 1,
corners[1].x, corners[1].y, corners[1].z, 0, 0, 0, 0, uvs[1].x, uvs[1].y, 1,
corners[3].x, corners[3].y, corners[3].z, 0, 0, 0, 0, uvs[3].x, uvs[3].y, 1,
]);
} }
export function drawIsometricCube(gfx, position, exts, color, edge) { else {
let color = fill;
this.data.push([
corners[0].x, corners[0].y, corners[0].z, color[0], color[1], color[2], color[3], 0, 0, 0,
corners[1].x, corners[1].y, corners[1].z, color[0], color[1], color[2], color[3], 0, 0, 0,
corners[3].x, corners[3].y, corners[3].z, color[0], color[1], color[2], color[3], 0, 0, 0,
corners[2].x, corners[2].y, corners[2].z, color[0], color[1], color[2], color[3], 0, 0, 0,
corners[1].x, corners[1].y, corners[1].z, color[0], color[1], color[2], color[3], 0, 0, 0,
corners[3].x, corners[3].y, corners[3].z, color[0], color[1], color[2], color[3], 0, 0, 0,
]);
}
}
drawExts(position, exts, fill) {
if (fill instanceof Sprite) {
let uvs = Assets.assets.get("sprites").getUVs(fill.id);
this.data.push([
position.x, position.y, position.z, 0, 0, 0, 0, uvs[0].x, uvs[0].y, 1,
position.x + exts.x, position.y, position.z, 0, 0, 0, 0, uvs[1].x, uvs[1].y, 1,
position.x, position.y + exts.y, position.z, 0, 0, 0, 0, uvs[3].x, uvs[3].y, 1,
position.x + exts.x, position.y + exts.y, position.z, 0, 0, 0, 0, uvs[2].x, uvs[2].y, 1,
position.x + exts.x, position.y, position.z, 0, 0, 0, 0, uvs[1].x, uvs[1].y, 1,
position.x, position.y + exts.y, position.z, 0, 0, 0, 0, uvs[3].x, uvs[3].y, 1,
]);
}
else {
let color = fill;
this.data.push([
position.x, position.y, position.z, color[0], color[1], color[2], color[3], 0, 0,
position.x + exts.x, position.y, position.z, color[0], color[1], color[2], color[3], 0, 0,
position.x, position.y + exts.y, position.z, color[0], color[1], color[2], color[3], 0, 0,
position.x + exts.x, position.y + exts.y, position.z, color[0], color[1], color[2], color[3], 0, 0,
position.x + exts.x, position.y, position.z, color[0], color[1], color[2], color[3], 0, 0,
position.x, position.y + exts.y, position.z, color[0], color[1], color[2], color[3], 0, 0,
]);
}
}
}
export function drawIsometricCube(position, exts, r, fill, edge) {
let points = [ let points = [
// Left Top // Left Top
position, position,
@ -101,41 +89,39 @@ export function drawIsometricCube(gfx, position, exts, color, edge) {
new Vec3(position.x + 1.5 * exts.x, position.y + 0.5 * exts.y, position.z + 0.25 * exts.z), new Vec3(position.x + 1.5 * exts.x, position.y + 0.5 * exts.y, position.z + 0.25 * exts.z),
new Vec3(position.x + 0.5 * exts.x, position.y - 0.5 * exts.y, position.z + 0.25 * exts.z), new Vec3(position.x + 0.5 * exts.x, position.y - 0.5 * exts.y, position.z + 0.25 * exts.z),
]; ];
let r = new Rectangle(color.top, [
DrawTag.ISO,
]);
// Top // Top
r.draw(gfx, [ r.draw([
points[0], points[0],
points[1], points[1],
points[3], points[3],
points[2], points[2],
]); ], fill.top);
// Right Edge // Right Edge
if (edge == TileEdge.Right || edge == TileEdge.Both) { if (edge == TileEdge.Right || edge == TileEdge.Both) {
r.fill = color.right; r.draw([
r.draw(gfx, [
points[3], points[3],
points[2], points[2],
points[4], points[4],
points[5], points[5],
]); ], fill.right);
} }
// Left Edge // Left Edge
if (edge == TileEdge.Left || edge == TileEdge.Both) { if (edge == TileEdge.Left || edge == TileEdge.Both) {
r.fill = color.left; r.draw([
r.draw(gfx, [
points[0], points[0],
points[2], points[2],
points[4], points[4],
points[6], points[6],
]); ], fill.left);
} }
} }
export function drawIsometricGrid(gfx, grid) { export function drawIsometricGrid(gfx, grid) {
let position = { ...grid.position }; let position = { ...grid.position };
let exts = new Vec3(grid.tileSize, grid.tileSize, 0); let exts = new Vec3(grid.tileSize, grid.tileSize, 0);
let tileCoord = new Vec3(0, 0, 0); let tileCoord = new Vec3(0, 0, 0);
let rect = new Rectangle([
DrawTag.ISO,
]);
// TODO: Optimize this // TODO: Optimize this
// 1. Grid based occlusion culling // 1. Grid based occlusion culling
// 2. frustum culling // 2. frustum culling
@ -152,7 +138,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(new Vec3(position.x - grid.tileSize / 2 * k, position.y + grid.tileSize / 2 * k, position.z), exts, rect, tile.fill, tile.edge);
position.x += grid.tileSize; position.x += grid.tileSize;
} }
position.y -= grid.tileSize; position.y -= grid.tileSize;
@ -160,4 +146,5 @@ export function drawIsometricGrid(gfx, grid) {
} }
position.y = grid.position.y; position.y = grid.position.y;
} }
rect.commit(gfx);
} }

View File

@ -1,40 +1,25 @@
import { Vec3, Vec2, Vec4 } from "./common.js" import { Vec3, Vec2 } from "./common.js"
import { Graphics, Texture, Drawable, DrawTag } from "./graphics.js"; import { Graphics, Drawable, DrawTag, Sprite, Spritesheet } from "./graphics.js";
import { TileEdge, TileFill, Grid } from "./world.js"; import { TileEdge, TileFill, TileFillament, Grid } from "./world.js";
import * as Assets from "./assets.js"; import * as Assets from "./assets.js";
// TODO: Don't assume tile size is same in all directions
function cull(point: Vec3, screen: Vec4, tileSize: number): boolean {
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;
}
// Attrib format // Attrib format
// position color uv // position color uv
// (3) (4) (2) => 3 + 4 + 2 = 9 <=> data.len % 9 == 0 // (3) (4) (3) => 3 + 4 + 3 = 10 <=> vertexSize == 10
export class Rectangle implements Drawable { export class Rectangle implements Drawable {
fill: Texture | Assets.Color; attribs: string[] = ["a_position", "a_color", "a_tex"];
attribs: string[] = ["a_position", "a_color", "a_tex_position"];
tags: Array<DrawTag> = []; tags: Array<DrawTag> = [];
data: number[] = []; data: number[][] = [];
stride: number = 0; vertexSize: number = 10;
vertexStride: number = 0;
constructor(fill: Texture | Assets.Color, tags?: Array<DrawTag>, attribs?: string[]) { sprites: Spritesheet = Assets.assets.get("sprites") as Spritesheet;
this.fill = fill;
constructor(tags?: Array<DrawTag>, sprites?: Spritesheet, attribs?: string[]) {
if (sprites !== undefined) {
this.sprites = sprites;
}
if (attribs !== undefined) { if (attribs !== undefined) {
this.attribs = attribs; this.attribs = attribs;
@ -45,68 +30,68 @@ export class Rectangle implements Drawable {
} }
} }
overrideDraw(draw: (...args: any[]) => void) { commit(gfx: Graphics) {
this.draw = draw;
}
draw(gfx: Graphics, corners: [Vec3, Vec3, Vec3, Vec3]) {
if (this.fill instanceof Texture) {
this.data = [
corners[0].x, corners[0].y, corners[0].z, 0, 0, 0, 0, 0, 0,
corners[1].x, corners[1].y, corners[1].z, 0, 0, 0, 0, -1, 0,
corners[3].x, corners[3].y, corners[3].z, 0, 0, 0, 0, 0, -1,
corners[2].x, corners[2].y, corners[2].z, 0, 0, 0, 0, -1, -1,
corners[1].x, corners[1].y, corners[1].z, 0, 0, 0, 0, -1, 0,
corners[3].x, corners[3].y, corners[3].z, 0, 0, 0, 0, 0, -1,
]
} else {
this.data = [
corners[0].x, corners[0].y, corners[0].z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
corners[1].x, corners[1].y, corners[1].z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
corners[3].x, corners[3].y, corners[3].z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
corners[2].x, corners[2].y, corners[2].z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
corners[1].x, corners[1].y, corners[1].z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
corners[3].x, corners[3].y, corners[3].z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
]
}
this.vertexStride = 9;
this.stride = this.vertexStride * 4
gfx.toRender.push({...this});
}
drawExts(gfx: Graphics, position: Vec3, exts: Vec2) {
if (this.fill instanceof Texture) {
this.data = [
position.x, position.y, position.z, 0, 0, 0, 0, 0, 0,
position.x + exts.x, position.y, position.z, 0, 0, 0, 0, -1, 0,
position.x, position.y + exts.y, position.z, 0, 0, 0, 0, 0, -1,
position.x + exts.x, position.y + exts.y, position.z, 0, 0, 0, 0, -1, -1,
position.x + exts.x, position.y, position.z, 0, 0, 0, 0, -1, 0,
position.x, position.y + exts.y, position.z, 0, 0, 0, 0, 0, -1,
]
} else {
this.data = [
position.x, position.y, position.z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
position.x + exts.x, position.y, position.z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
position.x, position.y + exts.y, position.z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
position.x + exts.x, position.y + exts.y, position.z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
position.x + exts.x, position.y, position.z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
position.x, position.y + exts.y, position.z, this.fill[0], this.fill[1], this.fill[2], this.fill[3], 0, 0,
]
}
this.vertexStride = 9;
this.stride = this.vertexStride * 4
gfx.toRender.push(this); gfx.toRender.push(this);
} }
draw(corners: [Vec3, Vec3, Vec3, Vec3], fill: TileFillament) {
if (fill instanceof Sprite) {
let uvs = (Assets.assets.get("sprites") as Spritesheet).getUVs(fill.id);
this.data.push([
corners[0].x, corners[0].y, corners[0].z, 0, 0, 0, 0, uvs[0].x, uvs[0].y, 1,
corners[1].x, corners[1].y, corners[1].z, 0, 0, 0, 0, uvs[1].x, uvs[1].y, 1,
corners[3].x, corners[3].y, corners[3].z, 0, 0, 0, 0, uvs[3].x, uvs[3].y, 1,
corners[2].x, corners[2].y, corners[2].z, 0, 0, 0, 0, uvs[2].x, uvs[2].y, 1,
corners[1].x, corners[1].y, corners[1].z, 0, 0, 0, 0, uvs[1].x, uvs[1].y, 1,
corners[3].x, corners[3].y, corners[3].z, 0, 0, 0, 0, uvs[3].x, uvs[3].y, 1,
]);
} else {
let color = fill;
this.data.push([
corners[0].x, corners[0].y, corners[0].z, color[0], color[1], color[2], color[3], 0, 0, 0,
corners[1].x, corners[1].y, corners[1].z, color[0], color[1], color[2], color[3], 0, 0, 0,
corners[3].x, corners[3].y, corners[3].z, color[0], color[1], color[2], color[3], 0, 0, 0,
corners[2].x, corners[2].y, corners[2].z, color[0], color[1], color[2], color[3], 0, 0, 0,
corners[1].x, corners[1].y, corners[1].z, color[0], color[1], color[2], color[3], 0, 0, 0,
corners[3].x, corners[3].y, corners[3].z, color[0], color[1], color[2], color[3], 0, 0, 0,
]);
}
} }
export function drawIsometricCube(gfx: Graphics, position: Vec3, exts: Vec3, color: TileFill, edge: TileEdge) { drawExts(position: Vec3, exts: Vec2, fill: TileFillament) {
if (fill instanceof Sprite) {
let uvs = (Assets.assets.get("sprites") as Spritesheet).getUVs(fill.id);
this.data.push([
position.x, position.y, position.z, 0, 0, 0, 0, uvs[0].x, uvs[0].y, 1,
position.x + exts.x, position.y, position.z, 0, 0, 0, 0, uvs[1].x, uvs[1].y, 1,
position.x, position.y + exts.y, position.z, 0, 0, 0, 0, uvs[3].x, uvs[3].y, 1,
position.x + exts.x, position.y + exts.y, position.z, 0, 0, 0, 0, uvs[2].x, uvs[2].y, 1,
position.x + exts.x, position.y, position.z, 0, 0, 0, 0, uvs[1].x, uvs[1].y, 1,
position.x, position.y + exts.y, position.z, 0, 0, 0, 0, uvs[3].x, uvs[3].y, 1,
]);
} else {
let color = fill;
this.data.push([
position.x, position.y, position.z, color[0], color[1], color[2], color[3], 0, 0,
position.x + exts.x, position.y, position.z, color[0], color[1], color[2], color[3], 0, 0,
position.x, position.y + exts.y, position.z, color[0], color[1], color[2], color[3], 0, 0,
position.x + exts.x, position.y + exts.y, position.z, color[0], color[1], color[2], color[3], 0, 0,
position.x + exts.x, position.y, position.z, color[0], color[1], color[2], color[3], 0, 0,
position.x, position.y + exts.y, position.z, color[0], color[1], color[2], color[3], 0, 0,
]);
}
}
}
export function drawIsometricCube(position: Vec3, exts: Vec3, r: Rectangle, fill: TileFill, edge: TileEdge) {
let points = [ let points = [
// Left Top // Left Top
position, position,
@ -122,49 +107,40 @@ export function drawIsometricCube(gfx: Graphics, position: Vec3, exts: Vec3, col
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 r = new Rectangle(color.top, [
DrawTag.ISO,
]);
// Top // Top
r.draw( r.draw(
gfx,
[ [
points[0], points[0],
points[1], points[1],
points[3], points[3],
points[2], points[2],
], ],
fill.top
); );
// Right Edge // Right Edge
if (edge == TileEdge.Right || edge == TileEdge.Both) { if (edge == TileEdge.Right || edge == TileEdge.Both) {
r.fill = color.right;
r.draw( r.draw(
gfx,
[ [
points[3], points[3],
points[2], points[2],
points[4], points[4],
points[5], points[5],
] ],
fill.right
); );
} }
// Left Edge // Left Edge
if (edge == TileEdge.Left || edge == TileEdge.Both) { if (edge == TileEdge.Left || edge == TileEdge.Both) {
r.fill = color.left;
r.draw( r.draw(
gfx,
[ [
points[0], points[0],
points[2], points[2],
points[4], points[4],
points[6], points[6],
] ],
fill.left
); );
} }
} }
@ -173,6 +149,9 @@ export function drawIsometricGrid(gfx: Graphics, grid: Grid) {
let position = {...grid.position} as Vec3; let position = {...grid.position} as Vec3;
let exts = new Vec3(grid.tileSize, grid.tileSize, 0); let exts = new Vec3(grid.tileSize, grid.tileSize, 0);
let tileCoord = new Vec3(0, 0, 0); let tileCoord = new Vec3(0, 0, 0);
let rect = new Rectangle([
DrawTag.ISO,
]);
// TODO: Optimize this // TODO: Optimize this
// 1. Grid based occlusion culling // 1. Grid based occlusion culling
@ -193,7 +172,13 @@ 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(
new Vec3(position.x - grid.tileSize / 2 * k, position.y + grid.tileSize / 2 * k, position.z),
exts,
rect,
tile.fill,
tile.edge
);
position.x += grid.tileSize; position.x += grid.tileSize;
} }
@ -202,4 +187,6 @@ export function drawIsometricGrid(gfx: Graphics, grid: Grid) {
} }
position.y = grid.position.y; position.y = grid.position.y;
} }
rect.commit(gfx);
} }

View File

@ -92,15 +92,16 @@ export class Graphics {
} }
draw() { draw() {
for (let o of this.toRender) { for (let o of this.toRender) {
const data = o.data.flat();
this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, this.vbo); this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, this.vbo);
this.ctx.bufferData(this.ctx.ARRAY_BUFFER, new Float32Array(o.data), this.ctx.STATIC_DRAW); this.ctx.bufferData(this.ctx.ARRAY_BUFFER, new Float32Array(data), this.ctx.STATIC_DRAW);
let aid = 0; let aid = 0;
for (let a of o.attribs) { for (let a of o.attribs) {
let attr = this.getAttribute(a); let attr = this.getAttribute(a);
if (!attr.formatted) if (!attr.formatted)
throw new Error("Tried to use unformatted attribute!"); throw new Error("Tried to use unformatted attribute!");
this.ctx.enableVertexAttribArray(attr.loc); this.ctx.enableVertexAttribArray(attr.loc);
this.ctx.vertexAttribPointer(attr.loc, attr.size, attr.type, attr.normalized, o.stride, aid * 4); this.ctx.vertexAttribPointer(attr.loc, attr.size, attr.type, attr.normalized, o.vertexSize * 4, aid * 4);
aid += attr.size; aid += attr.size;
} }
// Generalize the tag uniforms aka. don't hard code them // Generalize the tag uniforms aka. don't hard code them
@ -112,15 +113,9 @@ export class Graphics {
} }
} }
} }
if (o.fill instanceof Texture) { o.sprites?.bind(this);
this.ctx.uniform1i(this.getUniform("u_isTex"), 1); this.ctx.drawArrays(this.ctx.TRIANGLES, 0, data.length / o.vertexSize);
o.fill.bind(this); o.sprites?.unbind(this);
}
this.ctx.drawArrays(this.ctx.TRIANGLES, 0, o.data.length / o.vertexStride);
if (o.fill instanceof Texture) {
this.ctx.uniform1i(this.getUniform("u_isTex"), 0);
o.fill.unbind(this);
}
for (let t of o.tags) { for (let t of o.tags) {
switch (t) { switch (t) {
case DrawTag.ISO: { case DrawTag.ISO: {
@ -183,6 +178,48 @@ export class Texture {
gfx.ctx.bindTexture(gfx.ctx.TEXTURE_2D, null); gfx.ctx.bindTexture(gfx.ctx.TEXTURE_2D, null);
} }
} }
export class Sprite {
id = 0;
constructor(id) {
this.id = id;
}
static id(id) {
return new Sprite(id);
}
static tile(id) {
let s = new Sprite(id);
return {
left: s,
top: s,
right: s,
};
}
}
;
export class Spritesheet {
texture; // Texture is a horizontal spritesheet
spriteSize; // width and height of one sprite
spriteCount; // number of sprites
constructor(texture, spriteSize) {
this.texture = texture;
this.spriteSize = spriteSize;
this.spriteCount = texture.width / spriteSize.x;
}
getUVs(id) {
return [
new Vec2((this.spriteSize.x * id) / this.texture.width, 0),
new Vec2((this.spriteSize.x * (id + 1)) / this.texture.width, 0),
new Vec2((this.spriteSize.x * (id + 1)) / this.texture.width, -1),
new Vec2((this.spriteSize.x * id) / this.texture.width, -1),
];
}
bind(gfx) {
this.texture.bind(gfx);
}
unbind(gfx) {
this.texture.unbind(gfx);
}
}
async function loadTexture(path) { async function loadTexture(path) {
return new Promise(resolve => { return new Promise(resolve => {
const img = new Image(); const img = new Image();

View File

@ -1,5 +1,5 @@
import * as Assets from "./assets.js";
import {Vec2, Vec3, Vec4} from "./common.js"; import {Vec2, Vec3, Vec4} from "./common.js";
import { TileFillament, TileFill } from "./world.js";
export function fullscreenCanvas(gfx: Graphics, id: string) { export function fullscreenCanvas(gfx: Graphics, id: string) {
const canvas = document.getElementById(id) as HTMLCanvasElement; const canvas = document.getElementById(id) as HTMLCanvasElement;
@ -57,13 +57,13 @@ export enum DrawTag {
} }
export interface Drawable { export interface Drawable {
fill: Texture | Assets.Color;
attribs: string[]; attribs: string[];
tags: Array<DrawTag>; tags: Array<DrawTag>;
data: Array<number>; data: number[][];
vertexStride: number; vertexSize: number;
stride: number;
sprites: Spritesheet | undefined;
} }
export class Graphics { export class Graphics {
@ -131,8 +131,10 @@ export class Graphics {
draw() { draw() {
for (let o of this.toRender) { for (let o of this.toRender) {
const data = o.data.flat();
this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, this.vbo); this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, this.vbo);
this.ctx.bufferData(this.ctx.ARRAY_BUFFER, new Float32Array(o.data), this.ctx.STATIC_DRAW); this.ctx.bufferData(this.ctx.ARRAY_BUFFER, new Float32Array(data), this.ctx.STATIC_DRAW);
let aid = 0; let aid = 0;
for (let a of o.attribs) { for (let a of o.attribs) {
@ -141,7 +143,7 @@ export class Graphics {
throw new Error("Tried to use unformatted attribute!"); throw new Error("Tried to use unformatted attribute!");
this.ctx.enableVertexAttribArray(attr.loc); this.ctx.enableVertexAttribArray(attr.loc);
this.ctx.vertexAttribPointer(attr.loc, attr.size, attr.type, attr.normalized, o.stride, aid * 4); this.ctx.vertexAttribPointer(attr.loc, attr.size, attr.type, attr.normalized, o.vertexSize * 4, aid * 4);
aid += attr.size; aid += attr.size;
} }
@ -155,19 +157,11 @@ export class Graphics {
} }
} }
if (o.fill instanceof Texture) o.sprites?.bind(this);
{
this.ctx.uniform1i(this.getUniform("u_isTex"), 1);
o.fill.bind(this);
}
this.ctx.drawArrays(this.ctx.TRIANGLES, 0, o.data.length / o.vertexStride); this.ctx.drawArrays(this.ctx.TRIANGLES, 0, data.length / o.vertexSize);
if (o.fill instanceof Texture) o.sprites?.unbind(this);
{
this.ctx.uniform1i(this.getUniform("u_isTex"), 0);
o.fill.unbind(this);
}
for (let t of o.tags) { for (let t of o.tags) {
switch (t) { switch (t) {
@ -177,7 +171,6 @@ export class Graphics {
} }
} }
} }
} }
// TODO: Maybe add persistent rendering? // TODO: Maybe add persistent rendering?
@ -251,6 +244,59 @@ export class Texture {
} }
} }
export type SpriteId = number;
export class Sprite {
id: SpriteId = 0;
private constructor(id: SpriteId) {
this.id = id;
}
static id(id: SpriteId): Sprite {
return new Sprite(id);
}
static tile(id: SpriteId): TileFill {
let s = new Sprite(id);
return {
left: s,
top: s,
right: s,
}
}
};
export class Spritesheet {
texture: Texture; // Texture is a horizontal spritesheet
spriteSize: Vec2; // width and height of one sprite
spriteCount: number; // number of sprites
constructor(texture: Texture, spriteSize: Vec2) {
this.texture = texture;
this.spriteSize = spriteSize;
this.spriteCount = texture.width / spriteSize.x;
}
getUVs(id: number): [Vec2, Vec2, Vec2, Vec2] {
return [
new Vec2((this.spriteSize.x * id) / this.texture.width, 0),
new Vec2((this.spriteSize.x * (id + 1)) / this.texture.width, 0),
new Vec2((this.spriteSize.x * (id + 1)) / this.texture.width, -1),
new Vec2((this.spriteSize.x * id) / this.texture.width, -1),
];
}
bind(gfx: Graphics) {
this.texture.bind(gfx);
}
unbind(gfx: Graphics) {
this.texture.unbind(gfx);
}
}
async function loadTexture(path: string): Promise<HTMLImageElement> { async function loadTexture(path: string): Promise<HTMLImageElement> {
return new Promise(resolve => { return new Promise(resolve => {
const img = new Image(); const img = new Image();

View File

@ -1,22 +1,21 @@
import { initializeContext, Vec3, Mat4, Vec4, Vec2 } from "./common.js"; import { initializeContext, Vec3, Mat4, Vec4, Vec2 } from "./common.js";
import { Graphics, fullscreenCanvas, Camera } from "./graphics.js"; import { Graphics, fullscreenCanvas, Camera, Sprite } from "./graphics.js";
import * as drawing from "./draw.js"; import * as drawing from "./draw.js";
import * as wasm from "./wasm.js"; import * as wasm from "./wasm.js";
import { Input } from "./input.js"; import { Input } from "./input.js";
import { bush, Grid, Tile, tree } from "./world.js"; import { Grid, Tile, tree } from "./world.js";
import * as Assets from "./assets.js"; import * as Assets from "./assets.js";
const vertexShader = `#version 300 es const vertexShader = `#version 300 es
layout(location = 0) in vec3 a_position; layout(location = 0) in vec3 a_position;
layout(location = 1) in vec2 a_tex_position; layout(location = 1) in vec3 a_tex;
layout(location = 2) in vec4 a_color; layout(location = 2) in vec4 a_color;
out vec4 v_color; out vec4 v_color;
out vec2 v_tex_position; out vec3 v_tex;
uniform mat4 u_matrix; uniform mat4 u_matrix;
uniform bool u_isIso; uniform bool u_isIso;
uniform bool u_isTex;
mat4 Iso = mat4( mat4 Iso = mat4(
1, -1, 0, 0, 1, -1, 0, 0,
@ -38,27 +37,23 @@ const vertexShader = `#version 300 es
gl_Position = orthographic; gl_Position = orthographic;
if (u_isTex) { v_tex = a_tex;
v_tex_position = a_tex_position;
} else {
v_color = a_color; v_color = a_color;
} }
}
`; `;
const fragmentShader = `#version 300 es const fragmentShader = `#version 300 es
precision highp float; precision highp float;
in vec4 v_color; in vec4 v_color;
in vec2 v_tex_position; in vec3 v_tex;
out vec4 outColor; out vec4 outColor;
uniform sampler2D u_texture; uniform sampler2D u_texture;
uniform bool u_isTex;
void main() { void main() {
if (u_isTex) { if (v_tex.z == 1.0) {
outColor = texture(u_texture, v_tex_position); outColor = texture(u_texture, v_tex.xy);
} else { } else {
outColor = v_color; outColor = v_color;
} }
@ -131,23 +126,21 @@ function addDefaultKeybinds(input, camera) {
a.format(3, ctx.FLOAT, false, 0); a.format(3, ctx.FLOAT, false, 0);
a = gfx.createAttribute("a_color"); a = gfx.createAttribute("a_color");
a.format(4, ctx.FLOAT, false, 0); a.format(4, ctx.FLOAT, false, 0);
a = gfx.createAttribute("a_tex_position"); a = gfx.createAttribute("a_tex");
a.format(2, ctx.FLOAT, false, 0); a.format(3, ctx.FLOAT, false, 0);
gfx.createUniform("u_matrix"); gfx.createUniform("u_matrix");
gfx.createUniform("u_isIso"); gfx.createUniform("u_isIso");
gfx.createUniform("u_isTex");
let camera = new Camera(new Vec3(0, 0, -1)); let camera = new Camera(new Vec3(0, 0, -1));
await Assets.assets.load(gfx); await Assets.assets.load(gfx);
let m = Mat4.isometric(); let m = Mat4.isometric();
let size = 100; let size = 100;
let grid = new Grid(m.transformNew(new Vec4(ctx.canvas.width / 4, ctx.canvas.height / 2, 0, 1)).reduce(), 24, size, size, 10); let grid = new Grid(m.transformNew(new Vec4(ctx.canvas.width / 4, ctx.canvas.height / 2, 0, 1)).reduce(), 24, size, size, 10);
grid.fillLayer(new Tile({ grid.fillLayer(new Tile({
top: Assets.assets.get("grass"), top: Sprite.id(0),
right: Assets.Colors.Brown, right: Assets.Colors.Brown,
left: Assets.Colors.Brown, left: Assets.Colors.Brown,
}), 0); }), 0);
tree(grid, new Vec2(size / 2, size / 2)); tree(grid, new Vec2(5, 5));
bush(grid, new Vec2(size / 2 + 4, size / 2 + 4));
//for (let i = 0; i < 10; i++) { //for (let i = 0; i < 10; i++) {
// tree(grid, new Vec2(Math.floor(Math.random() * size - 1), Math.floor(Math.random() * size - 1))); // tree(grid, new Vec2(Math.floor(Math.random() * size - 1), Math.floor(Math.random() * size - 1)));
//} //}

View File

@ -1,24 +1,23 @@
import { initializeContext, Vec3, Mat4, Vec4, Vec2 } from "./common.js"; import { initializeContext, Vec3, Mat4, Vec4, Vec2 } from "./common.js";
import { Graphics, fullscreenCanvas, Camera, DrawTag } from "./graphics.js"; import { Graphics, fullscreenCanvas, Camera, Sprite } from "./graphics.js";
import * as drawing from "./draw.js"; import * as drawing from "./draw.js";
import * as wasm from "./wasm.js"; import * as wasm from "./wasm.js";
import { Input } from "./input.js"; import { Input } from "./input.js";
import {bush, Grid, Tile, TileEdge, tree} from "./world.js"; import {Grid, Tile, TileEdge, tree} from "./world.js";
import * as Assets from "./assets.js"; import * as Assets from "./assets.js";
const vertexShader = const vertexShader =
`#version 300 es `#version 300 es
layout(location = 0) in vec3 a_position; layout(location = 0) in vec3 a_position;
layout(location = 1) in vec2 a_tex_position; layout(location = 1) in vec3 a_tex;
layout(location = 2) in vec4 a_color; layout(location = 2) in vec4 a_color;
out vec4 v_color; out vec4 v_color;
out vec2 v_tex_position; out vec3 v_tex;
uniform mat4 u_matrix; uniform mat4 u_matrix;
uniform bool u_isIso; uniform bool u_isIso;
uniform bool u_isTex;
mat4 Iso = mat4( mat4 Iso = mat4(
1, -1, 0, 0, 1, -1, 0, 0,
@ -40,12 +39,9 @@ const vertexShader =
gl_Position = orthographic; gl_Position = orthographic;
if (u_isTex) { v_tex = a_tex;
v_tex_position = a_tex_position;
} else {
v_color = a_color; v_color = a_color;
} }
}
`; `;
const fragmentShader = const fragmentShader =
@ -54,15 +50,14 @@ const fragmentShader =
precision highp float; precision highp float;
in vec4 v_color; in vec4 v_color;
in vec2 v_tex_position; in vec3 v_tex;
out vec4 outColor; out vec4 outColor;
uniform sampler2D u_texture; uniform sampler2D u_texture;
uniform bool u_isTex;
void main() { void main() {
if (u_isTex) { if (v_tex.z == 1.0) {
outColor = texture(u_texture, v_tex_position); outColor = texture(u_texture, v_tex.xy);
} else { } else {
outColor = v_color; outColor = v_color;
} }
@ -178,12 +173,11 @@ function addDefaultKeybinds(input: Input, camera: Camera) {
a.format(3, ctx.FLOAT, false, 0) a.format(3, ctx.FLOAT, false, 0)
a = gfx.createAttribute("a_color"); a = gfx.createAttribute("a_color");
a.format(4, ctx.FLOAT, false, 0) a.format(4, ctx.FLOAT, false, 0)
a = gfx.createAttribute("a_tex_position"); a = gfx.createAttribute("a_tex");
a.format(2, ctx.FLOAT, false, 0) a.format(3, ctx.FLOAT, false, 0)
gfx.createUniform("u_matrix"); gfx.createUniform("u_matrix");
gfx.createUniform("u_isIso"); gfx.createUniform("u_isIso");
gfx.createUniform("u_isTex");
let camera = new Camera(new Vec3(0, 0, -1)); let camera = new Camera(new Vec3(0, 0, -1));
@ -194,13 +188,11 @@ function addDefaultKeybinds(input: Input, camera: Camera) {
let size = 100; let size = 100;
let grid = new Grid(m.transformNew(new Vec4(ctx.canvas.width / 4, ctx.canvas.height / 2, 0, 1)).reduce(), 24, size, size, 10); let grid = new Grid(m.transformNew(new Vec4(ctx.canvas.width / 4, ctx.canvas.height / 2, 0, 1)).reduce(), 24, size, size, 10);
grid.fillLayer(new Tile({ grid.fillLayer(new Tile({
top: Assets.assets.get("grass"), top: Sprite.id(0),
right: Assets.Colors.Brown, right: Assets.Colors.Brown,
left: Assets.Colors.Brown, left: Assets.Colors.Brown,
}), 0); }), 0);
tree(grid, new Vec2(5, 5));
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++) { //for (let i = 0; i < 10; i++) {
// tree(grid, new Vec2(Math.floor(Math.random() * size - 1), Math.floor(Math.random() * size - 1))); // tree(grid, new Vec2(Math.floor(Math.random() * size - 1), Math.floor(Math.random() * size - 1)));
//} //}

View File

@ -1,5 +1,5 @@
import * as Assets from "./assets.js";
import { Vec3 } from "./common.js"; import { Vec3 } from "./common.js";
import { Sprite } from "./graphics.js";
export var TileEdge; export var TileEdge;
(function (TileEdge) { (function (TileEdge) {
TileEdge[TileEdge["None"] = 0] = "None"; TileEdge[TileEdge["None"] = 0] = "None";
@ -73,25 +73,28 @@ export class Grid {
} }
} }
export function tree(grid, position) { export function tree(grid, position) {
grid.setTile(new Tile(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(position.x, position.y, 1)); let log = Sprite.tile(2);
grid.setTile(new Tile(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(position.x, position.y, 2)); let leaves = Sprite.tile(1);
grid.setTile(new Tile(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(position.x, position.y, 3)); grid.setTile(new Tile(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, 4)); grid.setTile(new Tile(log, TileEdge.Both), new Vec3(position.x, position.y, 2));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.None), new Vec3(position.x, position.y, 4)); grid.setTile(new Tile(log, TileEdge.Both), new Vec3(position.x, position.y, 3));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y + 1, 4)); grid.setTile(new Tile(log, TileEdge.Both), new Vec3(position.x, position.y, 4));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y + 1, 5)); grid.setTile(new Tile(log, TileEdge.None), new Vec3(position.x, position.y, 4));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y, 5)); grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x, position.y + 1, 4));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y, 4)); grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x, position.y + 1, 5));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y, 5)); grid.setTile(new Tile(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 + 1, 4)); grid.setTile(new Tile(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 + 1, 5)); grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x + 1, position.y, 5));
grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x + 1, position.y + 1, 4));
grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x + 1, position.y + 1, 5));
} }
export function bush(grid, position) { export function bush(grid, position) {
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), position.extend(1)); let leaves = Sprite.tile(1);
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y, 1)); grid.setTile(new Tile(leaves, TileEdge.Both), position.extend(1));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y + 1, 1)); grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x + 1, position.y, 1));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y + 1, 1)); grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x, position.y + 1, 1));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), position.extend(2)); grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x + 1, position.y + 1, 1));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y, 2)); grid.setTile(new Tile(leaves, TileEdge.Both), position.extend(2));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y + 1, 2)); grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x + 1, position.y, 2));
grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x, position.y + 1, 2));
} }

View File

@ -1,6 +1,6 @@
import * as Assets from "./assets.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 {Sprite} from "./graphics.js";
export enum TileEdge { export enum TileEdge {
None, None,
@ -9,8 +9,12 @@ export enum TileEdge {
Both, Both,
} }
export type TileFillament = Texture | Assets.Color; export type TileFillament = Sprite | Assets.Color;
export type TileFill = { left: TileFillament, top: TileFillament, right: TileFillament }; export type TileFill = {
right: TileFillament
left: TileFillament,
top: TileFillament,
};
export class Tile { export class Tile {
fill: TileFill = { fill: TileFill = {
@ -96,27 +100,32 @@ export class Grid {
} }
export function tree(grid: Grid, position: Vec2) { export function tree(grid: Grid, position: Vec2) {
grid.setTile(new Tile(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(position.x, position.y, 1)); let log = Sprite.tile(2);
grid.setTile(new Tile(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(position.x, position.y, 2)); let leaves = Sprite.tile(1);
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(log, TileEdge.Both), new Vec3(position.x, position.y, 1));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.None), new Vec3(position.x, position.y, 4)); grid.setTile(new Tile(log, TileEdge.Both), new Vec3(position.x, position.y, 2));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y + 1, 4)); grid.setTile(new Tile(log, TileEdge.Both), new Vec3(position.x, position.y, 3));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y + 1, 5)); grid.setTile(new Tile(log, TileEdge.Both), new Vec3(position.x, position.y, 4));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y, 5)); grid.setTile(new Tile(log, TileEdge.None), new Vec3(position.x, position.y, 4));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y, 4)); grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x, position.y + 1, 4));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y, 5)); grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x, position.y + 1, 5));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y + 1, 4)); grid.setTile(new Tile(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 + 1, 5)); grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x + 1, position.y, 4));
grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x + 1, position.y, 5));
grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x + 1, position.y + 1, 4));
grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x + 1, position.y + 1, 5));
} }
export function bush(grid: Grid, position: Vec2) { export function bush(grid: Grid, position: Vec2) {
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), position.extend(1)); let leaves = Sprite.tile(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(leaves, TileEdge.Both), position.extend(1));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y, 2)); grid.setTile(new Tile(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, 2)); grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x, position.y + 1, 1));
grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x + 1, position.y + 1, 1));
grid.setTile(new Tile(leaves, TileEdge.Both), position.extend(2));
grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x + 1, position.y, 2));
grid.setTile(new Tile(leaves, TileEdge.Both), new Vec3(position.x, position.y + 1, 2));
} }