Added Grid and grid based rendering
This commit is contained in:
parent
95257a4ef3
commit
e936b626f3
|
@ -0,0 +1,4 @@
|
|||
export let Red = [1, 0, 0, 1];
|
||||
export let Green = [0, 1, 0, 1];
|
||||
export let Blue = [0, 0, 1, 1];
|
||||
export let Brown = [0.341, 0.337, 0.204, 1];
|
|
@ -0,0 +1,6 @@
|
|||
export type Color = [number, number, number, number]
|
||||
|
||||
export let Red : Color = [1, 0, 0, 1];
|
||||
export let Green : Color = [0, 1, 0, 1];
|
||||
export let Blue : Color = [0, 0, 1, 1];
|
||||
export let Brown : Color = [0.341, 0.337, 0.204, 1];
|
111
src/js/common.js
111
src/js/common.js
|
@ -10,6 +10,9 @@ class Vec2 {
|
|||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
copy() {
|
||||
return new Vec2(this.x, this.y);
|
||||
}
|
||||
add(other) {
|
||||
this.x += other.x;
|
||||
this.y += other.y;
|
||||
|
@ -28,13 +31,43 @@ class Vec2 {
|
|||
this.x -= other.x;
|
||||
this.y -= other.y;
|
||||
}
|
||||
mult(scalar) {
|
||||
subNew(other) {
|
||||
let vec = this.copy();
|
||||
vec.x -= other.x;
|
||||
vec.y -= other.y;
|
||||
return vec;
|
||||
}
|
||||
multScalar(scalar) {
|
||||
this.x *= scalar;
|
||||
this.y *= scalar;
|
||||
}
|
||||
multNew(scalar) {
|
||||
multScalarNew(scalar) {
|
||||
return new Vec2(this.x * scalar, this.y * scalar);
|
||||
}
|
||||
div(other) {
|
||||
if (other.x == 0 ||
|
||||
other.y == 0) {
|
||||
throw new Error("Division by zero in Vec4");
|
||||
}
|
||||
this.x /= other.x;
|
||||
this.y /= other.y;
|
||||
}
|
||||
divNew(other) {
|
||||
if (other.x == 0 ||
|
||||
other.y == 0) {
|
||||
throw new Error("Division by zero in Vec4");
|
||||
}
|
||||
let vec = this.copy();
|
||||
vec.x /= other.x;
|
||||
vec.y /= other.y;
|
||||
return vec;
|
||||
}
|
||||
reduce() {
|
||||
throw new Error("Can't reduce Vec2!");
|
||||
}
|
||||
extend(value) {
|
||||
return new Vec3(this.x, this.y, value);
|
||||
}
|
||||
splatToArray() {
|
||||
return [this.x, this.y];
|
||||
}
|
||||
|
@ -60,28 +93,73 @@ class Vec3 {
|
|||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
copy() {
|
||||
return new Vec3(this.x, this.y, this.z);
|
||||
}
|
||||
add(other) {
|
||||
this.x += other.x;
|
||||
this.y += other.y;
|
||||
this.z += other.z;
|
||||
}
|
||||
addNew(other) {
|
||||
let vec = this.copy();
|
||||
vec.x += other.x;
|
||||
vec.y += other.y;
|
||||
vec.z += other.z;
|
||||
return vec;
|
||||
}
|
||||
sub(other) {
|
||||
this.x -= other.x;
|
||||
this.y -= other.y;
|
||||
this.z -= other.z;
|
||||
}
|
||||
subNew(other) {
|
||||
let vec = this.copy();
|
||||
vec.x -= other.x;
|
||||
vec.y -= other.y;
|
||||
vec.z -= other.z;
|
||||
return vec;
|
||||
}
|
||||
multScalar(scalar) {
|
||||
this.x *= scalar;
|
||||
this.y *= scalar;
|
||||
this.z *= scalar;
|
||||
}
|
||||
multScalarNew(scalar) {
|
||||
let vec = new Vec3(this.x, this.y, this.z);
|
||||
let vec = this.copy();
|
||||
vec.x *= scalar;
|
||||
vec.y *= scalar;
|
||||
vec.z *= scalar;
|
||||
return vec;
|
||||
}
|
||||
div(other) {
|
||||
if (other.x == 0 ||
|
||||
other.y == 0 ||
|
||||
other.z == 0) {
|
||||
throw new Error("Division by zero in Vec4");
|
||||
}
|
||||
this.x /= other.x;
|
||||
this.y /= other.y;
|
||||
this.z /= other.z;
|
||||
}
|
||||
divNew(other) {
|
||||
if (other.x == 0 ||
|
||||
other.y == 0 ||
|
||||
other.z == 0) {
|
||||
throw new Error("Division by zero in Vec4");
|
||||
}
|
||||
let vec = this.copy();
|
||||
vec.x /= other.x;
|
||||
vec.y /= other.y;
|
||||
vec.z /= other.z;
|
||||
return vec;
|
||||
}
|
||||
reduce() {
|
||||
return new Vec2(this.x, this.y);
|
||||
}
|
||||
extend(value) {
|
||||
return new Vec4(this.x, this.y, this.z, value);
|
||||
}
|
||||
splatToArray() {
|
||||
return [this.x, this.y, this.z];
|
||||
}
|
||||
|
@ -97,18 +175,37 @@ class Vec4 {
|
|||
this.z = z;
|
||||
this.w = w;
|
||||
}
|
||||
copy() {
|
||||
return new Vec4(this.x, this.y, this.z, this.w);
|
||||
}
|
||||
add(other) {
|
||||
this.x += other.x;
|
||||
this.y += other.y;
|
||||
this.z += other.z;
|
||||
this.w += other.w;
|
||||
}
|
||||
addNew(other) {
|
||||
let vec = this.copy();
|
||||
vec.x += other.x;
|
||||
vec.y += other.y;
|
||||
vec.z += other.z;
|
||||
vec.w += other.w;
|
||||
return vec;
|
||||
}
|
||||
sub(other) {
|
||||
this.x -= other.x;
|
||||
this.y -= other.y;
|
||||
this.z -= other.z;
|
||||
this.w -= other.w;
|
||||
}
|
||||
subNew(other) {
|
||||
let vec = this.copy();
|
||||
vec.x -= other.x;
|
||||
vec.y -= other.y;
|
||||
vec.z -= other.z;
|
||||
vec.w -= other.w;
|
||||
return vec;
|
||||
}
|
||||
multScalar(scalar) {
|
||||
this.x *= scalar;
|
||||
this.y *= scalar;
|
||||
|
@ -116,7 +213,7 @@ class Vec4 {
|
|||
this.w *= scalar;
|
||||
}
|
||||
multScalarNew(scalar) {
|
||||
let vec = new Vec4(this.x, this.y, this.z, this.w);
|
||||
let vec = this.copy();
|
||||
vec.x *= scalar;
|
||||
vec.y *= scalar;
|
||||
vec.z *= scalar;
|
||||
|
@ -142,7 +239,7 @@ class Vec4 {
|
|||
other.w == 0) {
|
||||
throw new Error("Division by zero in Vec4");
|
||||
}
|
||||
let vec = new Vec4(this.x, this.y, this.z, this.w);
|
||||
let vec = this.copy();
|
||||
vec.x /= other.x;
|
||||
vec.y /= other.y;
|
||||
vec.z /= other.z;
|
||||
|
@ -152,11 +249,15 @@ class Vec4 {
|
|||
reduce() {
|
||||
return new Vec3(this.x, this.y, this.z);
|
||||
}
|
||||
extend(_value) {
|
||||
throw new Error("Can't extend Vec4");
|
||||
}
|
||||
}
|
||||
class Mat4 {
|
||||
data;
|
||||
constructor(i) {
|
||||
if (i instanceof Float32Array) {
|
||||
console.assert(i.length == 16, "Mat4 has to have 16 elements");
|
||||
this.data = i;
|
||||
return;
|
||||
}
|
||||
|
|
177
src/js/common.ts
177
src/js/common.ts
|
@ -5,14 +5,27 @@ function initializeContext(canvasId: string): WebGL2RenderingContext | null {
|
|||
return ctx;
|
||||
}
|
||||
|
||||
type Color = [number, number, number, number]
|
||||
|
||||
// TODO: Make all vectors follow one interface
|
||||
interface Vector {
|
||||
interface Vector<P, T, N> {
|
||||
copy(): T;
|
||||
|
||||
add(other: T): void;
|
||||
addNew(other: T): T;
|
||||
|
||||
sub(other: T): void;
|
||||
subNew(other: T): T;
|
||||
|
||||
multScalar(scalar: number): void;
|
||||
multScalarNew(scalar: number): T;
|
||||
|
||||
div(other: T): void;
|
||||
divNew(other: T): T;
|
||||
|
||||
reduce(): P;
|
||||
extend(value: number): N;
|
||||
}
|
||||
|
||||
class Vec2 {
|
||||
class Vec2 implements Vector<void, Vec2, Vec3> {
|
||||
x: number;
|
||||
y: number;
|
||||
|
||||
|
@ -21,6 +34,10 @@ class Vec2 {
|
|||
this.y = y;
|
||||
}
|
||||
|
||||
copy(): Vec2 {
|
||||
return new Vec2(this.x, this.y);
|
||||
}
|
||||
|
||||
add(other: Vec2) {
|
||||
this.x += other.x;
|
||||
this.y += other.y;
|
||||
|
@ -44,15 +61,58 @@ class Vec2 {
|
|||
this.y -= other.y;
|
||||
}
|
||||
|
||||
mult(scalar: number) {
|
||||
subNew(other: Vec2): Vec2 {
|
||||
let vec = this.copy();
|
||||
|
||||
vec.x -= other.x;
|
||||
vec.y -= other.y;
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
multScalar(scalar: number) {
|
||||
this.x *= scalar;
|
||||
this.y *= scalar;
|
||||
}
|
||||
|
||||
multNew(scalar: number): Vec2 {
|
||||
multScalarNew(scalar: number): Vec2 {
|
||||
return new Vec2(this.x * scalar, this.y * scalar);
|
||||
}
|
||||
|
||||
div(other: Vec2) {
|
||||
if ( other.x == 0 ||
|
||||
other.y == 0)
|
||||
{
|
||||
throw new Error("Division by zero in Vec4");
|
||||
}
|
||||
|
||||
this.x /= other.x;
|
||||
this.y /= other.y;
|
||||
}
|
||||
|
||||
divNew(other: Vec2): Vec2 {
|
||||
if ( other.x == 0 ||
|
||||
other.y == 0)
|
||||
{
|
||||
throw new Error("Division by zero in Vec4");
|
||||
}
|
||||
|
||||
let vec = this.copy();
|
||||
|
||||
vec.x /= other.x;
|
||||
vec.y /= other.y;
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
reduce(): null {
|
||||
throw new Error("Can't reduce Vec2!");
|
||||
}
|
||||
|
||||
extend(value: number): Vec3 {
|
||||
return new Vec3(this.x, this.y, value);
|
||||
}
|
||||
|
||||
splatToArray(): Array<number> {
|
||||
return [this.x, this.y];
|
||||
}
|
||||
|
@ -74,7 +134,7 @@ class Vec2 {
|
|||
}
|
||||
}
|
||||
|
||||
class Vec3 {
|
||||
class Vec3 implements Vector<Vec2, Vec3, Vec4> {
|
||||
x: number;
|
||||
y: number;
|
||||
z: number;
|
||||
|
@ -85,18 +145,42 @@ class Vec3 {
|
|||
this.z = z;
|
||||
}
|
||||
|
||||
copy(): Vec3 {
|
||||
return new Vec3(this.x, this.y, this.z);
|
||||
}
|
||||
|
||||
add(other: Vec3) {
|
||||
this.x += other.x;
|
||||
this.y += other.y;
|
||||
this.z += other.z;
|
||||
}
|
||||
|
||||
addNew(other: Vec3): Vec3 {
|
||||
let vec = this.copy();
|
||||
|
||||
vec.x += other.x;
|
||||
vec.y += other.y;
|
||||
vec.z += other.z;
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
sub(other: Vec3) {
|
||||
this.x -= other.x;
|
||||
this.y -= other.y;
|
||||
this.z -= other.z;
|
||||
}
|
||||
|
||||
subNew(other: Vec3): Vec3 {
|
||||
let vec = this.copy();
|
||||
|
||||
vec.x -= other.x;
|
||||
vec.y -= other.y;
|
||||
vec.z -= other.z;
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
multScalar(scalar: number) {
|
||||
this.x *= scalar;
|
||||
this.y *= scalar;
|
||||
|
@ -104,7 +188,7 @@ class Vec3 {
|
|||
}
|
||||
|
||||
multScalarNew(scalar: number): Vec3 {
|
||||
let vec = new Vec3(this.x, this.y, this.z);
|
||||
let vec = this.copy();
|
||||
|
||||
vec.x *= scalar;
|
||||
vec.y *= scalar;
|
||||
|
@ -113,12 +197,50 @@ class Vec3 {
|
|||
return vec;
|
||||
}
|
||||
|
||||
div(other: Vec3) {
|
||||
if ( other.x == 0 ||
|
||||
other.y == 0 ||
|
||||
other.z == 0)
|
||||
{
|
||||
throw new Error("Division by zero in Vec4");
|
||||
}
|
||||
|
||||
this.x /= other.x;
|
||||
this.y /= other.y;
|
||||
this.z /= other.z;
|
||||
}
|
||||
|
||||
divNew(other: Vec3): Vec3 {
|
||||
if ( other.x == 0 ||
|
||||
other.y == 0 ||
|
||||
other.z == 0)
|
||||
{
|
||||
throw new Error("Division by zero in Vec4");
|
||||
}
|
||||
|
||||
let vec = this.copy();
|
||||
|
||||
vec.x /= other.x;
|
||||
vec.y /= other.y;
|
||||
vec.z /= other.z;
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
reduce(): Vec2 {
|
||||
return new Vec2(this.x, this.y);
|
||||
}
|
||||
|
||||
extend(value: number): Vec4 {
|
||||
return new Vec4(this.x, this.y, this.z, value);
|
||||
}
|
||||
|
||||
splatToArray(): Array<number> {
|
||||
return [this.x, this.y, this.z];
|
||||
}
|
||||
}
|
||||
|
||||
class Vec4 {
|
||||
class Vec4 implements Vector<Vec3, Vec4, void> {
|
||||
x: number;
|
||||
y: number;
|
||||
z: number;
|
||||
|
@ -131,6 +253,10 @@ class Vec4 {
|
|||
this.w = w;
|
||||
}
|
||||
|
||||
copy(): Vec4 {
|
||||
return new Vec4(this.x, this.y, this.z, this.w);
|
||||
}
|
||||
|
||||
add(other: Vec4) {
|
||||
this.x += other.x;
|
||||
this.y += other.y;
|
||||
|
@ -138,6 +264,17 @@ class Vec4 {
|
|||
this.w += other.w;
|
||||
}
|
||||
|
||||
addNew(other: Vec4): Vec4 {
|
||||
let vec = this.copy();
|
||||
|
||||
vec.x += other.x;
|
||||
vec.y += other.y;
|
||||
vec.z += other.z;
|
||||
vec.w += other.w;
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
sub(other: Vec4) {
|
||||
this.x -= other.x;
|
||||
this.y -= other.y;
|
||||
|
@ -145,6 +282,17 @@ class Vec4 {
|
|||
this.w -= other.w;
|
||||
}
|
||||
|
||||
subNew(other: Vec4): Vec4 {
|
||||
let vec = this.copy();
|
||||
|
||||
vec.x -= other.x;
|
||||
vec.y -= other.y;
|
||||
vec.z -= other.z;
|
||||
vec.w -= other.w;
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
multScalar(scalar: number) {
|
||||
this.x *= scalar;
|
||||
this.y *= scalar;
|
||||
|
@ -153,7 +301,7 @@ class Vec4 {
|
|||
}
|
||||
|
||||
multScalarNew(scalar: number): Vec4 {
|
||||
let vec = new Vec4(this.x, this.y, this.z, this.w);
|
||||
let vec = this.copy();
|
||||
|
||||
vec.x *= scalar;
|
||||
vec.y *= scalar;
|
||||
|
@ -187,7 +335,7 @@ class Vec4 {
|
|||
throw new Error("Division by zero in Vec4");
|
||||
}
|
||||
|
||||
let vec = new Vec4(this.x, this.y, this.z, this.w);
|
||||
let vec = this.copy();
|
||||
|
||||
vec.x /= other.x;
|
||||
vec.y /= other.y;
|
||||
|
@ -200,6 +348,10 @@ class Vec4 {
|
|||
reduce(): Vec3 {
|
||||
return new Vec3(this.x, this.y, this.z);
|
||||
}
|
||||
|
||||
extend(_value: number): void {
|
||||
throw new Error("Can't extend Vec4");
|
||||
}
|
||||
}
|
||||
|
||||
type Mat4Init = number | Float32Array;
|
||||
|
@ -216,6 +368,7 @@ class Mat4 {
|
|||
|
||||
constructor(i: Mat4Init) {
|
||||
if (i instanceof Float32Array) {
|
||||
console.assert(i.length == 16, "Mat4 has to have 16 elements");
|
||||
this.data = i;
|
||||
return;
|
||||
} else if (typeof(i) === 'number') {
|
||||
|
@ -374,4 +527,4 @@ class Mat4 {
|
|||
}
|
||||
}
|
||||
|
||||
export { initializeContext, Mat4, Vec2, Vec3, Vec4, Color };
|
||||
export { initializeContext, Mat4, Vec2, Vec3, Vec4 };
|
||||
|
|
|
@ -1,5 +1,17 @@
|
|||
import { Vec3, Vec2 } from "./common.js";
|
||||
import { Texture } from "./graphics.js";
|
||||
import { TileEdge } from "./world.js";
|
||||
function cull(bb, screen) {
|
||||
if (bb.x > screen.x)
|
||||
return false;
|
||||
if (bb.x + bb.z < screen.x + screen.z)
|
||||
return false;
|
||||
if (bb.y > screen.y)
|
||||
return false;
|
||||
if (bb.y + bb.w < screen.y + screen.w)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
export function drawTriangle(gfx, positions, color) {
|
||||
const a_position = gfx.getAttribute("a_position");
|
||||
const a_color = gfx.getAttribute("a_color");
|
||||
|
@ -69,7 +81,7 @@ export function drawRectangle(gfx, corners, color) {
|
|||
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 6);
|
||||
}
|
||||
}
|
||||
export function drawIsometricCube(gfx, position, exts, color) {
|
||||
export function drawIsometricCube(gfx, position, exts, color, edge) {
|
||||
let points = [
|
||||
position,
|
||||
new Vec3(position.x, position.y + exts.y, position.z),
|
||||
|
@ -80,26 +92,60 @@ export function drawIsometricCube(gfx, position, exts, color) {
|
|||
new Vec3(position.x + 0.5 * exts.x, position.y - 0.5 * exts.y, position.z + 0.25 * exts.z),
|
||||
];
|
||||
gfx.ctx.uniform1i(gfx.getUniform("u_isIso"), 1);
|
||||
// Top
|
||||
drawRectangle(gfx, [
|
||||
points[0],
|
||||
points[1],
|
||||
points[3],
|
||||
points[2],
|
||||
], color);
|
||||
drawRectangle(gfx, [
|
||||
points[3],
|
||||
points[2],
|
||||
points[4],
|
||||
points[5],
|
||||
], color);
|
||||
drawRectangle(gfx, [
|
||||
points[0],
|
||||
points[2],
|
||||
points[4],
|
||||
points[6],
|
||||
], color);
|
||||
// Right Edge
|
||||
if (edge == TileEdge.Right || edge == TileEdge.Both) {
|
||||
drawRectangle(gfx, [
|
||||
points[3],
|
||||
points[2],
|
||||
points[4],
|
||||
points[5],
|
||||
], color);
|
||||
}
|
||||
// Left Edge
|
||||
if (edge == TileEdge.Left || edge == TileEdge.Both) {
|
||||
drawRectangle(gfx, [
|
||||
points[0],
|
||||
points[2],
|
||||
points[4],
|
||||
points[6],
|
||||
], color);
|
||||
}
|
||||
gfx.ctx.uniform1i(gfx.getUniform("u_isIso"), 0);
|
||||
}
|
||||
export function drawIsometricGrid(gfx, grid) {
|
||||
let position = { ...grid.position };
|
||||
let exts = new Vec3(grid.tileSize, grid.tileSize, 0);
|
||||
let tileCoord = new Vec3(0, 0, 0);
|
||||
// Optimize this by:
|
||||
// 1. Skip all empty tiles by using lowTiles
|
||||
// 2. tba
|
||||
for (let k = 0; k < grid.height; ++k) {
|
||||
for (let j = 0; j < grid.length; ++j) {
|
||||
for (let i = 0; i < grid.width; ++i) {
|
||||
tileCoord.x = i;
|
||||
tileCoord.y = j;
|
||||
tileCoord.z = k;
|
||||
let tile = grid.getTile(tileCoord);
|
||||
if (tile === null) {
|
||||
position.x += grid.tileSize;
|
||||
continue;
|
||||
}
|
||||
drawIsometricCube(gfx, new Vec3(position.x - grid.tileSize / 2 * k, position.y + grid.tileSize / 2 * k, position.z), exts, tile.fill, tile.edge);
|
||||
position.x += grid.tileSize;
|
||||
}
|
||||
position.y -= grid.tileSize;
|
||||
position.x = grid.position.x;
|
||||
}
|
||||
position.y = grid.position.y;
|
||||
}
|
||||
}
|
||||
export function drawRectangleExts(gfx, position, exts, color) {
|
||||
const a_position = gfx.getAttribute("a_position");
|
||||
const points = [
|
||||
|
@ -142,7 +188,7 @@ export function drawCircle(gfx, position, radius, color) {
|
|||
let a = 0;
|
||||
for (let i = 0; i < precision; ++i) {
|
||||
var vec = Vec2.angle(a);
|
||||
vec.mult(radius);
|
||||
vec.multScalar(radius);
|
||||
a += angle;
|
||||
points.push(vec);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,17 @@
|
|||
import { Vec3, Vec2, Color } from "./common.js"
|
||||
import {Color} from "./colors.js";
|
||||
import { Vec3, Vec2, Vec4 } from "./common.js"
|
||||
import { Graphics, Texture } from "./graphics.js";
|
||||
import {Grid, TileEdge} from "./world.js";
|
||||
|
||||
function cull(bb: Vec4, screen: Vec4): boolean {
|
||||
if (bb.x > screen.x) return false;
|
||||
if (bb.x + bb.z < screen.x + screen.z) return false;
|
||||
|
||||
if (bb.y > screen.y) return false;
|
||||
if (bb.y + bb.w < screen.y + screen.w) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function drawTriangle(gfx: Graphics, positions: [Vec2, Vec2, Vec2], color: Color) {
|
||||
const a_position = gfx.getAttribute("a_position");
|
||||
|
@ -87,7 +99,7 @@ export function drawRectangle(gfx: Graphics, corners: [Vec3, Vec3, Vec3, Vec3],
|
|||
|
||||
}
|
||||
|
||||
export function drawIsometricCube(gfx: Graphics, position: Vec3, exts: Vec3, color: Color | Texture) {
|
||||
export function drawIsometricCube(gfx: Graphics, position: Vec3, exts: Vec3, color: Color | Texture, edge: TileEdge) {
|
||||
let points = [
|
||||
position,
|
||||
new Vec3(position.x, position.y + exts.y, position.z),
|
||||
|
@ -100,6 +112,7 @@ export function drawIsometricCube(gfx: Graphics, position: Vec3, exts: Vec3, col
|
|||
|
||||
gfx.ctx.uniform1i(gfx.getUniform("u_isIso"), 1);
|
||||
|
||||
// Top
|
||||
drawRectangle(
|
||||
gfx,
|
||||
[
|
||||
|
@ -109,30 +122,70 @@ export function drawIsometricCube(gfx: Graphics, position: Vec3, exts: Vec3, col
|
|||
points[2],
|
||||
],
|
||||
color);
|
||||
|
||||
// Right Edge
|
||||
|
||||
drawRectangle(
|
||||
gfx,
|
||||
[
|
||||
points[3],
|
||||
points[2],
|
||||
points[4],
|
||||
points[5],
|
||||
],
|
||||
color);
|
||||
if (edge == TileEdge.Right || edge == TileEdge.Both) {
|
||||
drawRectangle(
|
||||
gfx,
|
||||
[
|
||||
points[3],
|
||||
points[2],
|
||||
points[4],
|
||||
points[5],
|
||||
],
|
||||
color);
|
||||
}
|
||||
|
||||
drawRectangle(
|
||||
gfx,
|
||||
[
|
||||
points[0],
|
||||
points[2],
|
||||
points[4],
|
||||
points[6],
|
||||
],
|
||||
color);
|
||||
// Left Edge
|
||||
if (edge == TileEdge.Left || edge == TileEdge.Both) {
|
||||
drawRectangle(
|
||||
gfx,
|
||||
[
|
||||
points[0],
|
||||
points[2],
|
||||
points[4],
|
||||
points[6],
|
||||
],
|
||||
color);
|
||||
}
|
||||
|
||||
gfx.ctx.uniform1i(gfx.getUniform("u_isIso"), 0);
|
||||
}
|
||||
|
||||
export function drawIsometricGrid(gfx: Graphics, grid: Grid) {
|
||||
let position = {...grid.position} as Vec3;
|
||||
let exts = new Vec3(grid.tileSize, grid.tileSize, 0);
|
||||
let tileCoord = new Vec3(0, 0, 0);
|
||||
|
||||
// Optimize this by:
|
||||
// 1. Skip all empty tiles by using lowTiles
|
||||
// 2. tba
|
||||
for (let k = 0; k < grid.height; ++k) {
|
||||
for (let j = 0; j < grid.length; ++j) {
|
||||
for (let i = 0; i < grid.width; ++i) {
|
||||
tileCoord.x = i;
|
||||
tileCoord.y = j;
|
||||
tileCoord.z = k;
|
||||
|
||||
let tile = grid.getTile(tileCoord);
|
||||
|
||||
if (tile === null) {
|
||||
position.x += grid.tileSize;
|
||||
continue;
|
||||
}
|
||||
|
||||
drawIsometricCube(gfx, new Vec3(position.x - grid.tileSize / 2 * k, position.y + grid.tileSize / 2 * k, position.z), exts, tile.fill, tile.edge);
|
||||
|
||||
position.x += grid.tileSize;
|
||||
}
|
||||
position.y -= grid.tileSize;
|
||||
position.x = grid.position.x;
|
||||
}
|
||||
position.y = grid.position.y;
|
||||
}
|
||||
}
|
||||
|
||||
export function drawRectangleExts(gfx: Graphics, position: Vec3, exts: Vec2, color: Color | Texture) {
|
||||
const a_position = gfx.getAttribute("a_position");
|
||||
|
||||
|
@ -184,7 +237,7 @@ export function drawCircle(gfx: Graphics, position: Vec2, radius: number, color:
|
|||
let a = 0;
|
||||
for (let i = 0; i < precision; ++i) {
|
||||
var vec = Vec2.angle(a);
|
||||
vec.mult(radius);
|
||||
vec.multScalar(radius);
|
||||
a += angle;
|
||||
points.push(vec);
|
||||
}
|
||||
|
|
|
@ -110,7 +110,11 @@ export class Attribute {
|
|||
}
|
||||
export class Texture {
|
||||
tex;
|
||||
constructor(tex) {
|
||||
width = 0;
|
||||
height = 0;
|
||||
constructor(tex, width, height) {
|
||||
this.height = height;
|
||||
this.width = width;
|
||||
this.tex = tex;
|
||||
}
|
||||
static async load(ctx, path) {
|
||||
|
@ -122,7 +126,7 @@ export class Texture {
|
|||
ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.LINEAR_MIPMAP_NEAREST);
|
||||
ctx.generateMipmap(ctx.TEXTURE_2D);
|
||||
ctx.bindTexture(ctx.TEXTURE_2D, null);
|
||||
return new Texture(tex);
|
||||
return new Texture(tex, image.width, image.height);
|
||||
}
|
||||
bind(gfx) {
|
||||
gfx.ctx.uniform1i(gfx.getUniform("u_isTex"), 1);
|
||||
|
|
|
@ -146,8 +146,12 @@ export class Attribute {
|
|||
|
||||
export class Texture {
|
||||
tex: WebGLTexture | null;
|
||||
width: number = 0;
|
||||
height: number = 0;
|
||||
|
||||
constructor(tex: WebGLTexture) {
|
||||
constructor(tex: WebGLTexture, width: number, height: number) {
|
||||
this.height = height;
|
||||
this.width = width;
|
||||
this.tex = tex;
|
||||
}
|
||||
|
||||
|
@ -162,7 +166,7 @@ export class Texture {
|
|||
ctx.generateMipmap(ctx.TEXTURE_2D);
|
||||
ctx.bindTexture(ctx.TEXTURE_2D, null);
|
||||
|
||||
return new Texture(tex);
|
||||
return new Texture(tex, image.width, image.height);
|
||||
}
|
||||
|
||||
bind(gfx: Graphics) {
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import { initializeContext, Vec3, Mat4 } from "./common.js";
|
||||
import { Graphics, fullscreenCanvas, Texture, Camera } from "./graphics.js";
|
||||
import { initializeContext, Vec3, Mat4, Vec2 } from "./common.js";
|
||||
import { Graphics, fullscreenCanvas, Camera } from "./graphics.js";
|
||||
import * as drawing from "./draw.js";
|
||||
import * as wasm from "./wasm.js";
|
||||
import { Input } from "./input.js";
|
||||
import { Grid, Tile, tree } from "./world.js";
|
||||
const vertexShader = `#version 300 es
|
||||
|
||||
in vec3 a_position;
|
||||
|
@ -59,30 +60,30 @@ const fragmentShader = `#version 300 es
|
|||
}
|
||||
}
|
||||
`;
|
||||
function draw(gfx, camera, dt, tex) {
|
||||
function draw(gfx, camera, dt, grid) {
|
||||
gfx.clear(0, 0, 0, 0);
|
||||
camera.update(dt);
|
||||
let right = gfx.ctx.canvas.width;
|
||||
let left = 0;
|
||||
let top = gfx.ctx.canvas.height;
|
||||
let bottom = 0;
|
||||
let zoom = 2;
|
||||
let right = gfx.ctx.canvas.width * zoom;
|
||||
let left = -right * zoom;
|
||||
let top = gfx.ctx.canvas.height * zoom;
|
||||
let bottom = -top * zoom;
|
||||
let near = -100;
|
||||
let far = 100;
|
||||
let mo = Mat4.orthographic(left, right, bottom, top, near, far);
|
||||
let mt = Mat4.translate(camera.position);
|
||||
let mi = Mat4.isometric();
|
||||
let m = mo.multNew(mt);
|
||||
gfx.ctx.uniformMatrix4fv(gfx.getUniform("u_matrix"), false, m.splat());
|
||||
let exts = new Vec3(50, 50, 20);
|
||||
for (let i = 0; i < 10; ++i) {
|
||||
for (let j = 0; j < 10; ++j) {
|
||||
//drawing.drawIsometricCube(gfx, new Vec3(exts.x * i, 1000 - exts.y * j, 0), exts, [Math.sin(angle * i + j), Math.cos(angle * i + j), -Math.sin(angle * i + j), 1]);
|
||||
if ((i + j) % 2)
|
||||
drawing.drawIsometricCube(gfx, new Vec3(exts.x * i, 1000 - exts.y * j, 0), exts, [1, 1, 1, 1]);
|
||||
else
|
||||
drawing.drawIsometricCube(gfx, new Vec3(exts.x * i, 1000 - exts.y * j, 0), exts, tex);
|
||||
}
|
||||
}
|
||||
//let exts = new Vec3(50, 50, 20);
|
||||
//for (let i = 0; i < 10; ++i) {
|
||||
// for (let j = 0; j < 10; ++j) {
|
||||
// if ((i + j) % 2)
|
||||
// drawing.drawIsometricCube(gfx, new Vec3(exts.x * i, 1000 - exts.y * j, 0), exts, [1, 0, 1, 1], TileEdge.None);
|
||||
// else
|
||||
// drawing.drawIsometricCube(gfx, new Vec3(exts.x * i, 1000 - exts.y * j, 0), exts, [1, 1, 0, 1], TileEdge.None);
|
||||
// }
|
||||
//}
|
||||
drawing.drawIsometricGrid(gfx, grid);
|
||||
}
|
||||
function addDefaultKeybinds(input, camera) {
|
||||
input.addKeyAction("KeyA", [], camera, (c) => {
|
||||
|
@ -122,15 +123,20 @@ function addDefaultKeybinds(input, camera) {
|
|||
gfx.createUniform("u_matrix");
|
||||
gfx.createUniform("u_isTex");
|
||||
gfx.createUniform("u_isIso");
|
||||
let city = await Texture.load(ctx, "../../assets/genetica/rt/City Night.jpg");
|
||||
let wall = await Texture.load(ctx, "../../assets/wall.png");
|
||||
//let city = await Texture.load(ctx, "../../assets/genetica/rt/City Night.jpg");
|
||||
//let wall = await Texture.load(ctx, "../../assets/wall.png");
|
||||
let camera = new Camera(new Vec3(0, 0, 0));
|
||||
let grid = new Grid(new Vec3(-800, 0, 0), 100, 20, 20, 10);
|
||||
grid.fillLayer(new Tile([0, 0, 1, 1]), 0);
|
||||
for (let i = 0; i < 5; i++) {
|
||||
tree(grid, new Vec2(Math.floor(Math.random() * 19), Math.floor(Math.random() * 19)));
|
||||
}
|
||||
let prevTimestamp = 0;
|
||||
const frame = (timestamp) => {
|
||||
const deltaTime = (timestamp - prevTimestamp) / 1000;
|
||||
prevTimestamp = timestamp;
|
||||
fullscreenCanvas(gfx, "game");
|
||||
draw(gfx, camera, deltaTime, wall);
|
||||
draw(gfx, camera, deltaTime, grid);
|
||||
window.requestAnimationFrame(frame);
|
||||
};
|
||||
window.requestAnimationFrame((timestamp) => {
|
||||
|
|
|
@ -3,6 +3,7 @@ import { Graphics, fullscreenCanvas, Texture, Camera } from "./graphics.js";
|
|||
import * as drawing from "./draw.js";
|
||||
import * as wasm from "./wasm.js";
|
||||
import { Input } from "./input.js";
|
||||
import {Grid, Tile, tree} from "./world.js";
|
||||
|
||||
const vertexShader =
|
||||
`#version 300 es
|
||||
|
@ -64,24 +65,20 @@ const fragmentShader =
|
|||
}
|
||||
`;
|
||||
|
||||
|
||||
|
||||
function draw(gfx: Graphics, camera: Camera, dt: number, tex: Texture) {
|
||||
function draw(gfx: Graphics, camera: Camera, dt: number, grid: Grid) {
|
||||
gfx.clear(0, 0, 0, 0);
|
||||
camera.update(dt);
|
||||
|
||||
|
||||
let right = gfx.ctx.canvas.width;
|
||||
let left = 0;
|
||||
let top = gfx.ctx.canvas.height;
|
||||
let bottom = 0;
|
||||
let zoom = 2;
|
||||
let right = gfx.ctx.canvas.width * zoom;
|
||||
let left = -right * zoom;
|
||||
let top = gfx.ctx.canvas.height * zoom;
|
||||
let bottom = -top * zoom;
|
||||
let near = -100;
|
||||
let far = 100;
|
||||
|
||||
let mo = Mat4.orthographic(left, right, bottom, top, near, far);
|
||||
let mt = Mat4.translate(camera.position);
|
||||
let mi = Mat4.isometric();
|
||||
|
||||
let m = mo.multNew(mt);
|
||||
|
||||
gfx.ctx.uniformMatrix4fv(
|
||||
|
@ -90,17 +87,17 @@ function draw(gfx: Graphics, camera: Camera, dt: number, tex: Texture) {
|
|||
m.splat()
|
||||
);
|
||||
|
||||
let exts = new Vec3(50, 50, 20);
|
||||
for (let i = 0; i < 10; ++i) {
|
||||
for (let j = 0; j < 10; ++j) {
|
||||
//drawing.drawIsometricCube(gfx, new Vec3(exts.x * i, 1000 - exts.y * j, 0), exts, [Math.sin(angle * i + j), Math.cos(angle * i + j), -Math.sin(angle * i + j), 1]);
|
||||
|
||||
if ((i + j) % 2)
|
||||
drawing.drawIsometricCube(gfx, new Vec3(exts.x * i, 1000 - exts.y * j, 0), exts, [1, 1, 1, 1]);
|
||||
else
|
||||
drawing.drawIsometricCube(gfx, new Vec3(exts.x * i, 1000 - exts.y * j, 0), exts, tex);
|
||||
}
|
||||
}
|
||||
//let exts = new Vec3(50, 50, 20);
|
||||
//for (let i = 0; i < 10; ++i) {
|
||||
// for (let j = 0; j < 10; ++j) {
|
||||
// if ((i + j) % 2)
|
||||
// drawing.drawIsometricCube(gfx, new Vec3(exts.x * i, 1000 - exts.y * j, 0), exts, [1, 0, 1, 1], TileEdge.None);
|
||||
// else
|
||||
// drawing.drawIsometricCube(gfx, new Vec3(exts.x * i, 1000 - exts.y * j, 0), exts, [1, 1, 0, 1], TileEdge.None);
|
||||
// }
|
||||
//}
|
||||
|
||||
drawing.drawIsometricGrid(gfx, grid);
|
||||
}
|
||||
|
||||
function addDefaultKeybinds(input: Input, camera: Camera) {
|
||||
|
@ -158,18 +155,26 @@ function addDefaultKeybinds(input: Input, camera: Camera) {
|
|||
gfx.createUniform("u_isTex");
|
||||
gfx.createUniform("u_isIso");
|
||||
|
||||
let city = await Texture.load(ctx, "../../assets/genetica/rt/City Night.jpg");
|
||||
let wall = await Texture.load(ctx, "../../assets/wall.png");
|
||||
//let city = await Texture.load(ctx, "../../assets/genetica/rt/City Night.jpg");
|
||||
//let wall = await Texture.load(ctx, "../../assets/wall.png");
|
||||
|
||||
let camera = new Camera(new Vec3(0, 0, 0));
|
||||
|
||||
let grid = new Grid(new Vec3(-800, 0, 0), 100, 20, 20, 10);
|
||||
grid.fillLayer(new Tile([0, 0, 1, 1]), 0);
|
||||
|
||||
|
||||
for (let i = 0; i < 5; i++) {
|
||||
tree(grid, new Vec2(Math.floor(Math.random() * 19), Math.floor(Math.random() * 19)));
|
||||
}
|
||||
|
||||
let prevTimestamp = 0;
|
||||
const frame = (timestamp: number) => {
|
||||
const deltaTime = (timestamp - prevTimestamp)/1000;
|
||||
prevTimestamp = timestamp;
|
||||
|
||||
fullscreenCanvas(gfx, "game");
|
||||
draw(gfx, camera, deltaTime, wall);
|
||||
draw(gfx, camera, deltaTime, grid);
|
||||
|
||||
window.requestAnimationFrame(frame);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
import * as Colors from "./colors.js";
|
||||
import { Vec3 } from "./common.js";
|
||||
export var TileEdge;
|
||||
(function (TileEdge) {
|
||||
TileEdge[TileEdge["None"] = 0] = "None";
|
||||
TileEdge[TileEdge["Left"] = 1] = "Left";
|
||||
TileEdge[TileEdge["Right"] = 2] = "Right";
|
||||
TileEdge[TileEdge["Both"] = 3] = "Both";
|
||||
})(TileEdge || (TileEdge = {}));
|
||||
export class Tile {
|
||||
fill = [1, 0, 1, 1];
|
||||
edge = TileEdge.None;
|
||||
constructor(fill, edge) {
|
||||
if (fill !== undefined)
|
||||
this.fill = fill;
|
||||
if (edge !== undefined)
|
||||
this.edge = edge;
|
||||
}
|
||||
}
|
||||
export class Grid {
|
||||
position;
|
||||
tiles3d;
|
||||
tileSize;
|
||||
width;
|
||||
length;
|
||||
height;
|
||||
constructor(position, tileSize, width, length, height) {
|
||||
this.tiles3d = new Array(height);
|
||||
this.position = position;
|
||||
this.tileSize = tileSize;
|
||||
this.width = width;
|
||||
this.length = length;
|
||||
this.height = height;
|
||||
let layer = new Array(width * length);
|
||||
for (let i = 0; i < this.height; ++i)
|
||||
this.tiles3d[i] = { ...layer };
|
||||
}
|
||||
fillLayer(tile, z) {
|
||||
for (let i = 0; i < this.width; ++i) {
|
||||
for (let j = 0; j < this.length; ++j) {
|
||||
this.tiles3d[z][i + j * this.width] = { ...tile };
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < this.width; ++i) {
|
||||
this.tiles3d[z][this.length * i - 1] = { ...tile, edge: TileEdge.Right };
|
||||
}
|
||||
for (let i = 0; i < this.length - 1; ++i) {
|
||||
this.tiles3d[z][this.width * (this.length - 1) + i] = { ...tile, edge: TileEdge.Left };
|
||||
}
|
||||
this.tiles3d[z][this.width * this.length - 1] = { ...tile, edge: TileEdge.Both };
|
||||
}
|
||||
setTile(tile, coord) {
|
||||
let index = coord.x + coord.y * this.width;
|
||||
this.tiles3d[coord.z][index] = { ...tile };
|
||||
}
|
||||
getTile(coord) {
|
||||
let index = coord.x + coord.y * this.width;
|
||||
let tile = this.tiles3d[coord.z][index];
|
||||
if (tile === undefined)
|
||||
return null;
|
||||
return tile;
|
||||
}
|
||||
}
|
||||
export function tree(grid, position) {
|
||||
grid.setTile(new Tile(Colors.Brown, TileEdge.Both), new Vec3(position.x, position.y, 1));
|
||||
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x, position.y, 4));
|
||||
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x, position.y + 1, 3));
|
||||
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x, position.y + 1, 4));
|
||||
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x, position.y, 5));
|
||||
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x + 1, position.y, 3));
|
||||
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x + 1, position.y, 4));
|
||||
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x, position.y, 6));
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
import * as Colors from "./colors.js";
|
||||
import {Vec2, Vec3} from "./common.js";
|
||||
import {Texture} from "./graphics.js";
|
||||
|
||||
export enum TileEdge {
|
||||
None,
|
||||
Left,
|
||||
Right,
|
||||
Both,
|
||||
}
|
||||
|
||||
export class Tile {
|
||||
fill: Texture | Colors.Color = [1, 0, 1, 1];
|
||||
edge: TileEdge = TileEdge.None;
|
||||
|
||||
constructor(fill?: Texture | Colors.Color, edge?: TileEdge) {
|
||||
if (fill !== undefined)
|
||||
this.fill = fill;
|
||||
|
||||
if (edge !== undefined)
|
||||
this.edge = edge;
|
||||
}
|
||||
}
|
||||
|
||||
export class Grid {
|
||||
position: Vec3;
|
||||
tiles3d: Tile[][];
|
||||
tileSize: number;
|
||||
|
||||
width: number;
|
||||
length: number;
|
||||
height: number;
|
||||
|
||||
constructor(position: Vec3, tileSize: number, width: number, length: number, height: number) {
|
||||
this.tiles3d = new Array<Tile[]>(height);
|
||||
this.position = position;
|
||||
|
||||
this.tileSize = tileSize;
|
||||
|
||||
this.width = width;
|
||||
this.length = length;
|
||||
this.height = height;
|
||||
|
||||
let layer = new Array(width * length);
|
||||
|
||||
for (let i = 0; i < this.height; ++i)
|
||||
this.tiles3d[i] = {...layer};
|
||||
}
|
||||
|
||||
fillLayer(tile: Tile, z: number) {
|
||||
for (let i = 0; i < this.width; ++i) {
|
||||
for (let j = 0; j < this.length; ++j) {
|
||||
this.tiles3d[z][i + j * this.width] = {...tile};
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.width; ++i) {
|
||||
this.tiles3d[z][this.length * i - 1] = {...tile, edge: TileEdge.Right};
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.length - 1; ++i) {
|
||||
this.tiles3d[z][this.width * (this.length - 1) + i] = {...tile, edge: TileEdge.Left};
|
||||
}
|
||||
|
||||
this.tiles3d[z][this.width * this.length - 1] = {...tile, edge: TileEdge.Both};
|
||||
}
|
||||
|
||||
setTile(tile: Tile, coord: Vec3) {
|
||||
let index = coord.x + coord.y * this.width;
|
||||
this.tiles3d[coord.z][index] = {...tile};
|
||||
}
|
||||
|
||||
getTile(coord: Vec3): Tile | null {
|
||||
let index = coord.x + coord.y * this.width;
|
||||
let tile = this.tiles3d[coord.z][index];
|
||||
|
||||
if (tile === undefined) return null;
|
||||
|
||||
return tile;
|
||||
}
|
||||
}
|
||||
|
||||
export function tree(grid: Grid, position: Vec2) {
|
||||
grid.setTile(new Tile(Colors.Brown, TileEdge.Both), new Vec3(position.x, position.y, 1));
|
||||
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x, position.y, 4));
|
||||
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x, position.y + 1, 3));
|
||||
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x, position.y + 1, 4));
|
||||
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x, position.y, 5));
|
||||
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x + 1, position.y, 3));
|
||||
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x + 1, position.y, 4));
|
||||
grid.setTile(new Tile(Colors.Green, TileEdge.Both), new Vec3(position.x, position.y, 6));
|
||||
}
|
Loading…
Reference in New Issue