Compare commits

..

No commits in common. "87ad6fbd9dc60e135b313d15ed3f68cb0b86a341" and "3e9bdcc46900a2150faaa428be99ee25b0409b80" have entirely different histories.

46 changed files with 471 additions and 2229 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -1,3 +0,0 @@
For a description of the contents of this pack, usage rights, and other useful details, go here:
http://blog.spiralgraphics.biz/2011/02/nine-cartoon-backdrops.html

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 368 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 511 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 411 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 337 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -1,36 +0,0 @@
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(gfx) {
assets.push("grass", await Texture.load(gfx, "../../assets/grass2.png"));
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();

View File

@ -1,52 +0,0 @@
import {Graphics, 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(gfx: Graphics) {
assets.push("grass", await Texture.load(gfx, "../../assets/grass2.png"));
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();

View File

@ -10,9 +10,6 @@ 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;
@ -31,43 +28,13 @@ class Vec2 {
this.x -= other.x;
this.y -= other.y;
}
subNew(other) {
let vec = this.copy();
vec.x -= other.x;
vec.y -= other.y;
return vec;
}
multScalar(scalar) {
mult(scalar) {
this.x *= scalar;
this.y *= scalar;
}
multScalarNew(scalar) {
multNew(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];
}
@ -93,320 +60,15 @@ 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 = 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];
}
}
class Vec4 {
x;
y;
z;
w;
constructor(x, y, z, w) {
this.x = x;
this.y = y;
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;
this.z *= scalar;
this.w *= scalar;
}
multScalarNew(scalar) {
let vec = this.copy();
vec.x *= scalar;
vec.y *= scalar;
vec.z *= scalar;
vec.w *= scalar;
return vec;
}
div(other) {
if (other.x == 0 ||
other.y == 0 ||
other.z == 0 ||
other.w == 0) {
throw new Error("Division by zero in Vec4");
}
this.x /= other.x;
this.y /= other.y;
this.z /= other.z;
this.w /= other.w;
}
divNew(other) {
if (other.x == 0 ||
other.y == 0 ||
other.z == 0 ||
other.w == 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;
vec.w /= other.w;
return vec;
}
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;
}
else if (typeof (i) === 'number') {
this.data = new Float32Array(16).fill(i);
return;
}
this.data = new Float32Array(16);
}
static IDENTITY() {
return new Mat4(new Float32Array([
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
]));
}
static orthographic(left, right, bottom, top, near, far) {
let data = new Float32Array([
2 / (right - left), 0, 0, 0,
0, 2 / (top - bottom), 0, 0,
0, 0, -2 / (far - near), 0,
-(right + left) / (right - left),
-(top + bottom) / (top - bottom),
-(far + near) / (far - near),
1,
]);
return new Mat4(data);
}
static isometric() {
return new Mat4(new Float32Array([
1, -1, 0, 0,
1, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
]));
}
static isometric_inverse() {
return new Mat4(new Float32Array([
0.5, 0.5, 0, 0,
-0.5, 0.5, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
]));
}
static rotation_x(angle) {
let data = new Float32Array([
1, 0, 0, 0,
0, Math.cos(angle), -Math.sin(angle), 0,
0, Math.sin(angle), Math.cos(angle), 0,
0, 0, 0, 1,
]);
return new Mat4(data);
}
static rotation_y(angle) {
let data = new Float32Array([
Math.cos(angle), 0, Math.sin(angle), 0,
0, 1, 0, 0,
-Math.sin(angle), 0, Math.cos(angle), 0,
0, 0, 0, 1,
]);
return new Mat4(data);
}
static rotation_z(angle) {
let data = new Float32Array([
Math.cos(angle), -Math.sin(angle), 0, 0,
Math.sin(angle), Math.cos(angle), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
]);
return new Mat4(data);
}
static translate(t) {
return new Mat4(new Float32Array([
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
t.x, t.y, t.z, 1,
]));
}
static scale(scales) {
return new Mat4(new Float32Array([
scales.x, 0, 0, 0,
0, scales.y, 0, 0,
0, 0, scales.z, 0,
0, 0, 0, 1,
]));
}
x(n) {
return this.data[n];
}
y(n) {
return this.data[n + 4];
}
z(n) {
return this.data[n + 8];
}
w(n) {
return this.data[n + 12];
}
splat() {
return Array.from(this.data);
}
row(row, data) {
for (let i = 0; i < data.length; ++i)
this.data[i + 4 * row] = data[i];
}
col(col, data) {
for (let i = 0; i < data.length; ++i)
this.data[i * 4 + col] = data[i];
}
transform(v) {
let x = v.x * this.x(0) + v.y * this.x(1) + v.z * this.x(2) + v.w * this.x(3);
let y = v.x * this.y(0) + v.y * this.y(1) + v.z * this.y(2) + v.w * this.y(3);
let z = v.x * this.z(0) + v.y * this.z(1) + v.z * this.z(2) + v.w * this.z(3);
let w = v.x * this.w(0) + v.y * this.w(1) + v.z * this.w(2) + v.w * this.w(3);
v.x = x;
v.y = y;
v.z = z;
v.w = w;
}
transformNew(v) {
let vec = v.copy();
let x = v.x * this.x(0) + v.y * this.x(1) + v.z * this.x(2) + v.w * this.x(3);
let y = v.x * this.y(0) + v.y * this.y(1) + v.z * this.y(2) + v.w * this.y(3);
let z = v.x * this.z(0) + v.y * this.z(1) + v.z * this.z(2) + v.w * this.z(3);
let w = v.x * this.w(0) + v.y * this.w(1) + v.z * this.w(2) + v.w * this.w(3);
vec.x = x;
vec.y = y;
vec.z = z;
vec.w = w;
return vec;
}
multNew(other) {
let m = new Mat4(0);
for (let i = 0; i < 4; ++i) {
for (let j = 0; j < 4; ++j) {
m.data[(i * 4) + j] += this.data[(i * 4) + 0] * other.data[j + 0];
m.data[(i * 4) + j] += this.data[(i * 4) + 1] * other.data[j + 4];
m.data[(i * 4) + j] += this.data[(i * 4) + 2] * other.data[j + 8];
m.data[(i * 4) + j] += this.data[(i * 4) + 3] * other.data[j + 12];
}
}
return m;
}
multScalar(scalar) {
for (let i = 0; i < this.data.length; ++i) {
this.data[i] *= scalar;
}
}
}
export { initializeContext, Mat4, Vec2, Vec3, Vec4 };
export { initializeContext, Vec2, Vec3 };

View File

@ -5,27 +5,9 @@ function initializeContext(canvasId: string): WebGL2RenderingContext | null {
return ctx;
}
// TODO: Make all vectors follow one interface
interface Vector<P, T, N> {
copy(): T;
type Color = [number, number, number, number]
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 implements Vector<void, Vec2, Vec3> {
class Vec2 {
x: number;
y: number;
@ -34,10 +16,6 @@ class Vec2 implements Vector<void, Vec2, Vec3> {
this.y = y;
}
copy(): Vec2 {
return new Vec2(this.x, this.y);
}
add(other: Vec2) {
this.x += other.x;
this.y += other.y;
@ -61,58 +39,15 @@ class Vec2 implements Vector<void, Vec2, Vec3> {
this.y -= other.y;
}
subNew(other: Vec2): Vec2 {
let vec = this.copy();
vec.x -= other.x;
vec.y -= other.y;
return vec;
}
multScalar(scalar: number) {
mult(scalar: number) {
this.x *= scalar;
this.y *= scalar;
}
multScalarNew(scalar: number): Vec2 {
multNew(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];
}
@ -134,7 +69,7 @@ class Vec2 implements Vector<void, Vec2, Vec3> {
}
}
class Vec3 implements Vector<Vec2, Vec3, Vec4> {
class Vec3 {
x: number;
y: number;
z: number;
@ -145,411 +80,17 @@ class Vec3 implements Vector<Vec2, Vec3, Vec4> {
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;
this.z *= scalar;
}
multScalarNew(scalar: number): Vec3 {
let vec = this.copy();
vec.x *= scalar;
vec.y *= scalar;
vec.z *= scalar;
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 implements Vector<Vec3, Vec4, void> {
x: number;
y: number;
z: number;
w: number;
constructor(x: number, y: number, z: number, w: number) {
this.x = x;
this.y = y;
this.z = z;
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;
this.z += other.z;
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;
this.z -= other.z;
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;
this.z *= scalar;
this.w *= scalar;
}
multScalarNew(scalar: number): Vec4 {
let vec = this.copy();
vec.x *= scalar;
vec.y *= scalar;
vec.z *= scalar;
vec.w *= scalar;
return vec;
}
div(other: Vec4) {
if ( other.x == 0 ||
other.y == 0 ||
other.z == 0 ||
other.w == 0)
{
throw new Error("Division by zero in Vec4");
}
this.x /= other.x;
this.y /= other.y;
this.z /= other.z;
this.w /= other.w;
}
divNew(other: Vec4): Vec4 {
if ( other.x == 0 ||
other.y == 0 ||
other.z == 0 ||
other.w == 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;
vec.w /= other.w;
return vec;
}
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;
type Mat4Row = 0 | 1 | 2 | 3
type Mat4Col = Mat4Row
type Mat4X = Mat4Row
type Mat4Y = Mat4Row
type Mat4Z = Mat4Row
type Mat4W = Mat4Row
class Mat4 {
data: Float32Array;
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') {
this.data = new Float32Array(16).fill(i);
return;
}
this.data = new Float32Array(16);
}
static IDENTITY(): Mat4 {
return new Mat4(new Float32Array([
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
]));
}
static orthographic(left: number, right: number, bottom: number, top: number, near: number, far: number): Mat4 {
let data = new Float32Array([
2 / (right - left), 0, 0, 0,
0, 2 / (top - bottom), 0, 0,
0, 0, -2 / (far - near), 0,
-(right + left)/(right - left),
-(top + bottom)/(top - bottom),
-(far + near)/(far - near),
1,
]);
return new Mat4(data);
}
static isometric(): Mat4 {
return new Mat4(new Float32Array([
1, -1, 0, 0,
1, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
]));
}
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 {
let data = new Float32Array([
1, 0, 0, 0,
0, Math.cos(angle), -Math.sin(angle), 0,
0, Math.sin(angle), Math.cos(angle), 0,
0, 0, 0, 1,
]);
return new Mat4(data);
}
static rotation_y(angle: number): Mat4 {
let data = new Float32Array([
Math.cos(angle), 0, Math.sin(angle), 0,
0, 1, 0, 0,
-Math.sin(angle), 0, Math.cos(angle), 0,
0, 0, 0, 1,
]);
return new Mat4(data);
}
static rotation_z(angle: number): Mat4 {
let data = new Float32Array([
Math.cos(angle), -Math.sin(angle), 0, 0,
Math.sin(angle), Math.cos(angle), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
]);
return new Mat4(data);
}
static translate(t: Vec3): Mat4 {
return new Mat4(new Float32Array([
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
t.x, t.y, t.z, 1,
]));
}
static scale(scales: Vec3) {
return new Mat4(new Float32Array([
scales.x, 0, 0, 0,
0, scales.y, 0, 0,
0, 0, scales.z, 0,
0, 0, 0, 1,
]));
}
x(n: Mat4X) {
return this.data[n];
}
y(n: Mat4Y) {
return this.data[n + 4];
}
z(n: Mat4Z) {
return this.data[n + 8];
}
w(n: Mat4W) {
return this.data[n + 12];
}
splat() {
return Array.from(this.data);
}
row(row: Mat4Row, data: [number, number, number, number]) {
for (let i = 0; i < data.length; ++i)
this.data[i + 4 * row] = data[i];
}
col(col: Mat4Col, data: [number, number, number, number]) {
for (let i = 0; i < data.length; ++i)
this.data[i*4 + col] = data[i];
}
transform(v: Vec4) {
let x = v.x * this.x(0) + v.y * this.x(1) + v.z * this.x(2) + v.w * this.x(3);
let y = v.x * this.y(0) + v.y * this.y(1) + v.z * this.y(2) + v.w * this.y(3);
let z = v.x * this.z(0) + v.y * this.z(1) + v.z * this.z(2) + v.w * this.z(3);
let w = v.x * this.w(0) + v.y * this.w(1) + v.z * this.w(2) + v.w * this.w(3);
v.x = x;
v.y = y;
v.z = z;
v.w = w;
}
transformNew(v: Vec4): Vec4 {
let vec = v.copy();
let x = v.x * this.x(0) + v.y * this.x(1) + v.z * this.x(2) + v.w * this.x(3);
let y = v.x * this.y(0) + v.y * this.y(1) + v.z * this.y(2) + v.w * this.y(3);
let z = v.x * this.z(0) + v.y * this.z(1) + v.z * this.z(2) + v.w * this.z(3);
let w = v.x * this.w(0) + v.y * this.w(1) + v.z * this.w(2) + v.w * this.w(3);
vec.x = x;
vec.y = y;
vec.z = z;
vec.w = w;
return vec;
}
multNew(other: Mat4): Mat4 {
let m = new Mat4(0);
for (let i = 0; i < 4; ++i) {
for (let j = 0; j < 4; ++j) {
m.data[(i * 4) + j] += this.data[(i * 4) + 0] * other.data[j + 0]
m.data[(i * 4) + j] += this.data[(i * 4) + 1] * other.data[j + 4]
m.data[(i * 4) + j] += this.data[(i * 4) + 2] * other.data[j + 8]
m.data[(i * 4) + j] += this.data[(i * 4) + 3] * other.data[j + 12]
}
}
return m;
}
multScalar(scalar: number) {
for (let i = 0; i < this.data.length; ++i) {
this.data[i] *= scalar;
}
}
}
export { initializeContext, Mat4, Vec2, Vec3, Vec4 };
export { initializeContext, Vec2, Vec3, Color };

View File

@ -1,159 +1,92 @@
import { Vec3 } from "./common.js";
import { Texture, DrawTag } from "./graphics.js";
import { TileEdge } from "./world.js";
// TODO: Don't assume tile size is same in all directions
function cull(point, screen, tileSize) {
if (point.x + tileSize < screen.x)
return true;
if (point.x + tileSize > screen.x + screen.z)
return true;
if (point.y - tileSize < screen.y)
return true;
if (point.y + tileSize > screen.y + screen.w)
return true;
return false;
}
// Attrib format
// position color uv
// (3) (4) (2) => 3 + 4 + 2 = 9 <=> data.len % 9 == 0
export class Rectangle {
fill;
attribs = ["a_position", "a_color", "a_tex_position"];
tags = [];
data = [];
stride = 0;
vertexStride = 0;
constructor(fill, tags, attribs) {
this.fill = fill;
if (attribs !== undefined) {
this.attribs = attribs;
}
if (tags !== undefined) {
this.tags = tags;
}
}
overrideDraw(draw) {
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);
}
}
export function drawIsometricCube(gfx, position, exts, color, edge) {
let points = [
// Left Top
position,
//Top
new Vec3(position.x, position.y + exts.y, position.z),
//Mid
new Vec3(position.x + exts.x, position.y, position.z),
//Right Top
new Vec3(position.x + exts.x, position.y + exts.y, position.z),
//Bottom
new Vec3(position.x + 1.5 * exts.x, position.y - 0.5 * exts.y, position.z + 0.25 * exts.z),
new Vec3(position.x + 1.5 * exts.x, position.y + 0.5 * exts.y, position.z + 0.25 * exts.z),
new Vec3(position.x + 0.5 * exts.x, position.y - 0.5 * exts.y, position.z + 0.25 * exts.z),
import { Vec2 } from "./common.js";
function drawTriangle(gfx, positions, color) {
const a_position = gfx.getAttribute("a_position");
const a_color = gfx.getAttribute("a_color");
const points = [
positions[0].x, positions[0].y,
positions[1].x, positions[1].y,
positions[2].x, positions[2].y,
];
let r = new Rectangle(color.top, [
DrawTag.ISO,
]);
// Top
r.draw(gfx, [
points[0],
points[1],
points[3],
points[2],
]);
// Right Edge
if (edge == TileEdge.Right || edge == TileEdge.Both) {
r.fill = color.right;
r.draw(gfx, [
points[3],
points[2],
points[4],
points[5],
]);
const colors = [
color,
color,
color,
];
a_position.data(gfx.ctx, points, gfx.ctx.STATIC_DRAW);
a_color.data(gfx.ctx, colors.flat(), gfx.ctx.STATIC_DRAW);
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 3);
}
function drawTriangleExts(gfx, position, exts, color) {
const a_position = gfx.getAttribute("a_position");
const a_color = gfx.getAttribute("a_color");
const points = [
position.x, position.y,
position.x + exts.x, position.y,
position.x, position.y + exts.y,
];
const colors = [
color,
color,
color,
];
a_position.data(gfx.ctx, points, gfx.ctx.STATIC_DRAW);
a_color.data(gfx.ctx, colors.flat(), gfx.ctx.STATIC_DRAW);
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 3);
}
function drawRectangle(gfx, position, exts, color) {
const a_position = gfx.getAttribute("a_position");
const a_color = gfx.getAttribute("a_color");
const points = [
position.x, position.y,
position.x + exts.x, position.y,
position.x, position.y + exts.y,
position.x + exts.x, position.y + exts.y,
position.x + exts.x, position.y,
position.x, position.y + exts.y,
];
const colors = [
color,
color,
color,
color,
color,
color,
];
a_position.data(gfx.ctx, points, gfx.ctx.STATIC_DRAW);
a_color.data(gfx.ctx, colors.flat(), gfx.ctx.STATIC_DRAW);
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 6);
}
function drawCircle(gfx, position, radius, color) {
const points = new Array();
const precision = 40;
const angle = 2.0 * Math.PI / precision;
let a = 0;
for (let i = 0; i < precision; ++i) {
var vec = Vec2.angle(a);
vec.mult(radius);
a += angle;
points.push(vec);
}
// Left Edge
if (edge == TileEdge.Left || edge == TileEdge.Both) {
r.fill = color.left;
r.draw(gfx, [
points[0],
points[2],
points[4],
points[6],
]);
for (let i = 0; i < points.length; i++) {
const current = points[i];
const next = points[(i + 1) % points.length];
let center = position;
drawTriangle(gfx, [center, center.addNew(current), center.addNew(next)], color);
}
}
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);
// TODO: Optimize this
for (let k = 0; k < grid.height; ++k) {
for (let j = 0; j < grid.length; ++j) {
for (let i = 0; i < grid.width; ++i) {
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;
}
function drawLine(gfx, A, B, color) {
const a_position = gfx.getAttribute("a_position");
const a_color = gfx.getAttribute("a_color");
let points = [
A.x, A.y,
B.x, B.y,
];
const colors = [
color,
color,
];
a_position.data(gfx.ctx, points, gfx.ctx.STATIC_DRAW);
a_color.data(gfx.ctx, colors.flat(), gfx.ctx.STATIC_DRAW);
gfx.ctx.drawArrays(gfx.ctx.LINES, 0, 2);
}
export { drawTriangle, drawTriangleExts, drawRectangle, drawCircle, drawLine };

View File

@ -1,201 +1,116 @@
import { Vec3, Vec2, Vec4 } from "./common.js"
import { Graphics, Texture, Drawable, DrawTag } from "./graphics.js";
import { TileEdge, TileFill, Grid } from "./world.js";
import * as Assets from "./assets.js";
import { Vec2 } from "./common.js"
import { Graphics } from "./graphics.js";
import { Color } from "./common.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;
function drawTriangle(gfx: Graphics, positions: [Vec2, Vec2, Vec2], color: Color) {
const a_position = gfx.getAttribute("a_position");
const a_color = gfx.getAttribute("a_color");
if (point.x + tileSize > screen.x + screen.z)
return true;
const points: Array<number> = [
positions[0].x, positions[0].y,
positions[1].x, positions[1].y,
positions[2].x, positions[2].y,
]
if (point.y - tileSize < screen.y)
return true;
if (point.y + tileSize > screen.y + screen.w)
return true;
return false;
}
// Attrib format
// position color uv
// (3) (4) (2) => 3 + 4 + 2 = 9 <=> data.len % 9 == 0
export class Rectangle implements Drawable {
fill: Texture | Assets.Color;
attribs: string[] = ["a_position", "a_color", "a_tex_position"];
tags: Array<DrawTag> = [];
data: number[] = [];
stride: number = 0;
vertexStride: number = 0;
constructor(fill: Texture | Assets.Color, tags?: Array<DrawTag>, attribs?: string[]) {
this.fill = fill;
if (attribs !== undefined) {
this.attribs = attribs;
}
if (tags !== undefined) {
this.tags = tags;
}
}
overrideDraw(draw: (...args: any[]) => void) {
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);
}
}
export function drawIsometricCube(gfx: Graphics, position: Vec3, exts: Vec3, color: TileFill, edge: TileEdge) {
let points = [
// Left Top
position,
//Top
new Vec3(position.x, position.y + exts.y, position.z),
//Mid
new Vec3(position.x + exts.x, position.y, position.z),
//Right Top
new Vec3(position.x + exts.x, position.y + exts.y, position.z),
//Bottom
new Vec3(position.x + 1.5 * exts.x, position.y - 0.5 * exts.y, position.z + 0.25 * exts.z),
new Vec3(position.x + 1.5 * exts.x, position.y + 0.5 * exts.y, position.z + 0.25 * exts.z),
new Vec3(position.x + 0.5 * exts.x, position.y - 0.5 * exts.y, position.z + 0.25 * exts.z),
const colors: Array<number[]> = [
color,
color,
color,
];
let r = new Rectangle(color.top, [
DrawTag.ISO,
]);
a_position.data(gfx.ctx, points, gfx.ctx.STATIC_DRAW);
a_color.data(gfx.ctx, colors.flat(), gfx.ctx.STATIC_DRAW);
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 3);
}
// Top
r.draw(
gfx,
[
points[0],
points[1],
points[3],
points[2],
],
);
// Right Edge
function drawTriangleExts(gfx: Graphics, position: Vec2, exts: Vec2, color: Color) {
const a_position = gfx.getAttribute("a_position");
const a_color = gfx.getAttribute("a_color");
if (edge == TileEdge.Right || edge == TileEdge.Both) {
r.fill = color.right;
const points: Array<number> = [
position.x, position.y,
position.x + exts.x, position.y,
position.x, position.y + exts.y,
]
r.draw(
gfx,
[
points[3],
points[2],
points[4],
points[5],
]
);
const colors: Array<number[]> = [
color,
color,
color,
];
a_position.data(gfx.ctx, points, gfx.ctx.STATIC_DRAW);
a_color.data(gfx.ctx, colors.flat(), gfx.ctx.STATIC_DRAW);
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 3);
}
function drawRectangle(gfx: Graphics, position: Vec2, exts: Vec2, color: Color) {
const a_position = gfx.getAttribute("a_position");
const a_color = gfx.getAttribute("a_color");
const points: Array<number> = [
position.x, position.y,
position.x + exts.x, position.y,
position.x, position.y + exts.y,
position.x + exts.x, position.y + exts.y,
position.x + exts.x, position.y,
position.x, position.y + exts.y,
]
const colors: Array<number[]> = [
color,
color,
color,
color,
color,
color,
];
a_position.data(gfx.ctx, points, gfx.ctx.STATIC_DRAW);
a_color.data(gfx.ctx, colors.flat(), gfx.ctx.STATIC_DRAW);
gfx.ctx.drawArrays(gfx.ctx.TRIANGLES, 0, 6);
}
function drawCircle(gfx: Graphics, position: Vec2, radius: number, color: Color) {
const points: Array<Vec2> = new Array<Vec2>();
const precision = 40;
const angle = 2.0*Math.PI/precision;
let a = 0;
for (let i = 0; i < precision; ++i) {
var vec = Vec2.angle(a);
vec.mult(radius);
a += angle;
points.push(vec);
}
// Left Edge
if (edge == TileEdge.Left || edge == TileEdge.Both) {
r.fill = color.left;
r.draw(
gfx,
[
points[0],
points[2],
points[4],
points[6],
]
);
for (let i = 0; i < points.length; i++) {
const current = points[i];
const next = points[(i + 1) % points.length];
let center = position;
drawTriangle(gfx, [center, center.addNew(current), center.addNew(next)], color);
}
}
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);
function drawLine(gfx: Graphics, A: Vec2, B: Vec2, color: Color) {
const a_position = gfx.getAttribute("a_position");
const a_color = gfx.getAttribute("a_color");
// TODO: Optimize this
for (let k = 0; k < grid.height; ++k) {
for (let j = 0; j < grid.length; ++j) {
for (let i = 0; i < grid.width; ++i) {
tileCoord.x = i;
tileCoord.y = j;
tileCoord.z = k;
let points: Array<number> = [
A.x, A.y,
B.x, B.y,
];
let tile = grid.getTile(tileCoord);
const colors: Array<number[]> = [
color,
color,
];
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;
}
a_position.data(gfx.ctx, points, gfx.ctx.STATIC_DRAW);
a_color.data(gfx.ctx, colors.flat(), gfx.ctx.STATIC_DRAW);
gfx.ctx.drawArrays(gfx.ctx.LINES, 0, 2);
}
export { drawTriangle, drawTriangleExts, drawRectangle, drawCircle, drawLine }

View File

@ -1,5 +1,4 @@
import { Vec4 } from "./common.js";
export function fullscreenCanvas(gfx, id) {
function fullscreenCanvas(gfx, id) {
const canvas = document.getElementById(id);
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
@ -39,29 +38,19 @@ function createProgram(ctx, vertexShaderSource, fragmentShaderSource) {
}
return program;
}
export var DrawTag;
(function (DrawTag) {
DrawTag[DrawTag["ISO"] = 0] = "ISO";
})(DrawTag || (DrawTag = {}));
export class Graphics {
class Graphics {
ctx;
program;
attribs = new Map();
uniforms = new Map();
vao;
vbo;
toRender = [];
texCount = 0;
constructor(ctx, vs, fs) {
this.ctx = ctx;
this.program = createProgram(ctx, vs, fs);
this.vao = ctx.createVertexArray();
this.vbo = ctx.createBuffer();
ctx.bindVertexArray(this.vao);
ctx.viewport(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.useProgram(this.program);
ctx.blendFunc(ctx.SRC_ALPHA, ctx.ONE_MINUS_SRC_ALPHA);
ctx.enable(ctx.BLEND);
}
clear(r, g, b, a) {
this.ctx.clearColor(r, g, b, a);
@ -90,131 +79,32 @@ export class Graphics {
throw new Error("Tried to get uninitialized uniform: " + name);
return loc;
}
draw() {
for (let o of this.toRender) {
this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, this.vbo);
this.ctx.bufferData(this.ctx.ARRAY_BUFFER, new Float32Array(o.data), this.ctx.STATIC_DRAW);
let aid = 0;
for (let a of o.attribs) {
let attr = this.getAttribute(a);
if (!attr.formatted)
throw new Error("Tried to use unformatted attribute!");
this.ctx.enableVertexAttribArray(attr.loc);
this.ctx.vertexAttribPointer(attr.loc, attr.size, attr.type, attr.normalized, o.stride, aid * 4);
aid += attr.size;
}
// Generalize the tag uniforms aka. don't hard code them
for (let t of o.tags) {
switch (t) {
case DrawTag.ISO: {
this.ctx.uniform1ui(this.getUniform("u_isIso"), 1);
break;
}
}
}
if (o.fill instanceof Texture) {
this.ctx.uniform1i(this.getUniform("u_isTex"), 1);
o.fill.bind(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) {
switch (t) {
case DrawTag.ISO: {
this.ctx.uniform1ui(this.getUniform("u_isIso"), 0);
break;
}
}
}
}
// TODO: Maybe add persistent rendering?
this.toRender = [];
}
}
export class Attribute {
class Attribute {
loc;
formatted = false;
buffer;
// TODO: maybe use undefined as default value?
size = 0;
type = 0;
offset = 0;
normalized = false;
stride = 0;
offset = 0;
constructor(ctx, program, name) {
this.loc = ctx.getAttribLocation(program, name);
this.buffer = ctx.createBuffer();
ctx.enableVertexAttribArray(this.loc);
}
format(size, type, normalized, offset) {
format(size, type, normalized, stride, offset) {
this.size = size;
this.type = type;
this.normalized = normalized;
this.stride = stride;
this.offset = offset;
this.formatted = true;
}
}
export class Texture {
tex;
texId;
width = 0;
height = 0;
constructor(texId, tex, width, height) {
this.height = height;
this.width = width;
this.tex = tex;
this.texId = texId;
}
// TODO: Load sprite sheet only once
// TODO: Allow changing sprite size
static async load(gfx, path) {
let image = await loadTexture(path);
let tex = gfx.ctx.createTexture();
gfx.ctx.bindTexture(gfx.ctx.TEXTURE_2D, tex);
gfx.ctx.texImage2D(gfx.ctx.TEXTURE_2D, 0, gfx.ctx.RGBA, gfx.ctx.RGBA, gfx.ctx.UNSIGNED_BYTE, image);
gfx.ctx.texParameteri(gfx.ctx.TEXTURE_2D, gfx.ctx.TEXTURE_MAG_FILTER, gfx.ctx.NEAREST);
gfx.ctx.texParameteri(gfx.ctx.TEXTURE_2D, gfx.ctx.TEXTURE_MIN_FILTER, gfx.ctx.NEAREST);
gfx.ctx.bindTexture(gfx.ctx.TEXTURE_2D, null);
gfx.texCount += 1;
return new Texture(gfx.texCount, tex, image.width, image.height);
}
bind(gfx) {
gfx.ctx.bindTexture(gfx.ctx.TEXTURE_2D, this.tex);
}
unbind(gfx) {
gfx.ctx.bindTexture(gfx.ctx.TEXTURE_2D, null);
}
}
async function loadTexture(path) {
return new Promise(resolve => {
const img = new Image();
img.addEventListener("load", () => {
resolve(img);
});
img.src = path;
});
}
export class Camera {
dt = 0;
position;
movement;
speed = 600;
scale = 1.0;
scaling = 0.0;
scaleSpeed = 1.5;
constructor(position) {
this.position = position;
this.movement = new Vec4(0, 0, 0, 0);
}
update(dt) {
this.dt = dt;
let newPosition = this.movement.multScalarNew(this.dt);
this.position.x += (newPosition.x + newPosition.y) * this.speed;
this.position.y += (newPosition.z + newPosition.w) * this.speed;
this.scale += this.scaling * this.dt * this.scaleSpeed;
if (this.scale < 0.5) {
this.scale = 0.5;
}
if (this.scale > 1.5) {
this.scale = 1.5;
}
}
data(ctx, data, usage) {
ctx.bindBuffer(ctx.ARRAY_BUFFER, this.buffer);
ctx.bufferData(ctx.ARRAY_BUFFER, new Float32Array(data), usage);
ctx.vertexAttribPointer(this.loc, this.size, this.type, this.normalized, this.stride, this.offset);
}
}
export { fullscreenCanvas, Graphics, Attribute };

View File

@ -1,7 +1,6 @@
import * as Assets from "./assets.js";
import {Vec2, Vec3, Vec4} from "./common.js";
import { Vec2 } from "./common.js"
export function fullscreenCanvas(gfx: Graphics, id: string) {
function fullscreenCanvas(gfx: Graphics, id: string) {
const canvas = document.getElementById(id) as HTMLCanvasElement;
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
@ -52,43 +51,20 @@ function createProgram(ctx: WebGL2RenderingContext, vertexShaderSource: string |
return program;
}
export enum DrawTag {
ISO,
}
export interface Drawable {
fill: Texture | Assets.Color;
attribs: string[];
tags: Array<DrawTag>;
data: Array<number>;
vertexStride: number;
stride: number;
}
export class Graphics {
class Graphics {
ctx: WebGL2RenderingContext;
program: WebGLProgram;
attribs: Map<string, Attribute> = new Map();
uniforms: Map<string, WebGLUniformLocation> = new Map();
vao: WebGLVertexArrayObject;
vbo: WebGLBuffer;
toRender: Array<Drawable> = [];
texCount: number = 0;
constructor(ctx: WebGL2RenderingContext, vs: string, fs: string) {
this.ctx = ctx;
this.program = createProgram(ctx, vs, fs);
this.vao = ctx.createVertexArray();
this.vbo = ctx.createBuffer();
ctx.bindVertexArray(this.vao);
ctx.viewport(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.useProgram(this.program);
ctx.blendFunc(ctx.SRC_ALPHA, ctx.ONE_MINUS_SRC_ALPHA);
ctx.enable(ctx.BLEND);
}
clear(r: number, g: number, b: number, a: number) {
@ -128,171 +104,45 @@ export class Graphics {
return loc;
}
draw() {
for (let o of this.toRender) {
this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, this.vbo);
this.ctx.bufferData(this.ctx.ARRAY_BUFFER, new Float32Array(o.data), this.ctx.STATIC_DRAW);
let aid = 0;
for (let a of o.attribs) {
let attr = this.getAttribute(a);
if (!attr.formatted)
throw new Error("Tried to use unformatted attribute!");
this.ctx.enableVertexAttribArray(attr.loc);
this.ctx.vertexAttribPointer(attr.loc, attr.size, attr.type, attr.normalized, o.stride, aid * 4);
aid += attr.size;
}
// Generalize the tag uniforms aka. don't hard code them
for (let t of o.tags) {
switch (t) {
case DrawTag.ISO: {
this.ctx.uniform1ui(this.getUniform("u_isIso"), 1);
break;
}
}
}
if (o.fill instanceof Texture)
{
this.ctx.uniform1i(this.getUniform("u_isTex"), 1);
o.fill.bind(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) {
switch (t) {
case DrawTag.ISO: {
this.ctx.uniform1ui(this.getUniform("u_isIso"), 0);
break;
}
}
}
}
// TODO: Maybe add persistent rendering?
this.toRender = [];
}
}
export class Attribute {
class Attribute {
loc: GLint;
formatted: boolean = false;
buffer: WebGLBuffer;
// TODO: maybe use undefined as default value?
size: GLint = 0;
type: GLenum = 0;
offset: GLintptr = 0;
normalized: GLboolean = false;
stride: GLsizei = 0;
offset: GLintptr = 0;
constructor(ctx: WebGL2RenderingContext, program: WebGLProgram, name: string) {
this.loc = ctx.getAttribLocation(program, name);
this.buffer = ctx.createBuffer();
ctx.enableVertexAttribArray(this.loc);
}
format(
size: GLint,
type: GLenum,
normalized: GLboolean,
stride: GLsizei,
offset: GLintptr)
{
this.size = size;
this.type = type;
this.normalized = normalized;
this.stride = stride;
this.offset = offset;
}
this.formatted = true;
}
}
export class Texture {
tex: WebGLTexture | null;
texId: number;
width: number = 0;
height: number = 0;
constructor(texId: number, tex: WebGLTexture, width: number, height: number) {
this.height = height;
this.width = width;
this.tex = tex;
this.texId = texId;
}
// TODO: Load sprite sheet only once
// TODO: Allow changing sprite size
static async load(gfx: Graphics, path: string): Promise<Texture> {
let image = await loadTexture(path);
let tex = gfx.ctx.createTexture();
gfx.ctx.bindTexture(gfx.ctx.TEXTURE_2D, tex);
gfx.ctx.texImage2D(gfx.ctx.TEXTURE_2D, 0, gfx.ctx.RGBA, gfx.ctx.RGBA, gfx.ctx.UNSIGNED_BYTE, image);
gfx.ctx.texParameteri(gfx.ctx.TEXTURE_2D, gfx.ctx.TEXTURE_MAG_FILTER, gfx.ctx.NEAREST);
gfx.ctx.texParameteri(gfx.ctx.TEXTURE_2D, gfx.ctx.TEXTURE_MIN_FILTER, gfx.ctx.NEAREST);
gfx.ctx.bindTexture(gfx.ctx.TEXTURE_2D, null);
gfx.texCount += 1;
return new Texture(gfx.texCount, tex, image.width, image.height);
}
bind(gfx: Graphics) {
gfx.ctx.bindTexture(gfx.ctx.TEXTURE_2D, this.tex);
}
unbind(gfx: Graphics) {
gfx.ctx.bindTexture(gfx.ctx.TEXTURE_2D, null);
}
}
async function loadTexture(path: string): Promise<HTMLImageElement> {
return new Promise(resolve => {
const img = new Image();
img.addEventListener("load", () => {
resolve(img);
})
img.src = path;
});
}
export class Camera {
dt: number = 0;
position: Vec3;
movement: Vec4;
speed: number = 600;
scale: number = 1.0;
scaling: number = 0.0;
scaleSpeed: number = 1.5;
constructor(position: Vec3) {
this.position = position;
this.movement = new Vec4(0, 0, 0, 0);
}
update(dt: number) {
this.dt = dt;
let newPosition = this.movement.multScalarNew(this.dt);
this.position.x += (newPosition.x + newPosition.y) * this.speed;
this.position.y += (newPosition.z + newPosition.w) * this.speed;
this.scale += this.scaling * this.dt * this.scaleSpeed;
if (this.scale < 0.5) {
this.scale = 0.5;
}
if (this.scale > 1.5) {
this.scale = 1.5;
}
data(ctx: WebGL2RenderingContext, data: Array<number>, usage: GLenum) {
ctx.bindBuffer(ctx.ARRAY_BUFFER, this.buffer);
ctx.bufferData(ctx.ARRAY_BUFFER, new Float32Array(data), usage);
ctx.vertexAttribPointer(this.loc, this.size, this.type, this.normalized, this.stride, this.offset);
}
}
export { fullscreenCanvas, Graphics, Attribute }

View File

@ -1,35 +0,0 @@
class KeyAction {
key;
keyup;
keydown;
data;
constructor(key, ku, kd, data) {
this.key = key;
this.keyup = ku;
this.keydown = kd;
this.data = data;
}
}
export class Input {
handlers = new Map();
constructor() {
window.addEventListener("keyup", e => {
this.handlers.forEach(ka => {
if (ka.keyup !== null && ka.key == e.code) {
ka.keyup(ka.data);
}
});
});
window.addEventListener("keydown", e => {
this.handlers.forEach(ka => {
if (ka.keydown !== null && ka.key == e.code) {
ka.keydown(ka.data);
}
});
});
}
//TODO: add modifier key support
addKeyAction(key, modifiers, data, keydown, keyup) {
this.handlers.set(key, new KeyAction(key, keydown, keyup, data));
}
}

View File

@ -1,39 +0,0 @@
type Action = ((data: any) => void);
class KeyAction {
key: string;
keyup: Action | null;
keydown: Action | null;
data: any;
constructor(key: string, ku: Action | null, kd: Action | null, data: any) {
this.key = key;
this.keyup = ku;
this.keydown = kd;
this.data = data;
}
}
export class Input {
handlers: Map<string, KeyAction> = new Map();
constructor() {
window.addEventListener("keyup", e => {
this.handlers.forEach(ka => {
if (ka.keyup !== null && ka.key == e.code) {
ka.keyup(ka.data);
}
});
});
window.addEventListener("keydown", e => {
this.handlers.forEach(ka => {
if (ka.keydown !== null && ka.key == e.code) {
ka.keydown(ka.data);
}
});
});
}
//TODO: add modifier key support
addKeyAction(key: string, modifiers: [string] | [], data: any, keydown: Action | null, keyup: Action | null) {
this.handlers.set(key, new KeyAction(key, keydown, keyup, data));
}
}

View File

@ -1,124 +1,53 @@
import { initializeContext, Vec3, Mat4, Vec4, Vec2 } from "./common.js";
import { Graphics, fullscreenCanvas, Camera } from "./graphics.js";
import { initializeContext, Vec2 } from "./common.js";
import { Graphics, fullscreenCanvas } from "./graphics.js";
import * as drawing from "./draw.js";
import * as wasm from "./wasm.js";
import { Input } from "./input.js";
import { bush, Grid, Tile, tree } from "./world.js";
import * as Assets from "./assets.js";
const vertexShader = `#version 300 es
layout(location = 0) in vec3 a_position;
layout(location = 1) in vec2 a_tex_position;
layout(location = 2) in vec4 a_color;
out vec4 v_color;
out vec2 v_tex_position;
uniform mat4 u_matrix;
uniform bool u_isIso;
uniform bool u_isTex;
mat4 Iso = mat4(
1, -1, 0, 0,
1, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
);
in vec2 a_position;
in vec4 a_color;
out vec4 color;
uniform vec2 u_resolution;
void main() {
vec4 orthographic;
vec2 clipSpace = (a_position / u_resolution) * 2.0 - 1.0;
if (u_isIso) {
vec4 isometric = Iso * vec4(a_position.xyz, 1.0);
orthographic = u_matrix * isometric;
//orthographic = u_matrix * vec4(a_position.xyz, 1.0);
} else {
orthographic = u_matrix * vec4(a_position.xyz, 1.0);
}
color = a_color;
gl_Position = orthographic;
if (u_isTex) {
v_tex_position = a_tex_position;
} else {
v_color = a_color;
}
gl_Position = vec4(clipSpace.xy, 0.0, 1.0);
}
`;
const fragmentShader = `#version 300 es
precision highp float;
in vec4 v_color;
in vec2 v_tex_position;
in vec4 color;
out vec4 outColor;
uniform sampler2D u_texture;
uniform bool u_isTex;
void main() {
if (u_isTex) {
outColor = texture(u_texture, v_tex_position);
} else {
outColor = v_color;
}
outColor = color;
}
`;
function draw(gfx, camera, dt, grid) {
function draw(gfx, dt, pos, velocity) {
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 near = -100;
let far = 100;
let m = Mat4.IDENTITY();
let mo = Mat4.orthographic(left, right, bottom, top, near, far);
let mc = Mat4.translate(new Vec3((gfx.ctx.canvas.width / 2 - camera.position.x), (gfx.ctx.canvas.height / 2 - camera.position.y), 1.0));
let mr = Mat4.translate(new Vec3(-(gfx.ctx.canvas.width / 2 - camera.position.x), -(gfx.ctx.canvas.height / 2 - camera.position.y), 1.0));
let mt = Mat4.translate(camera.position);
let ms = Mat4.scale(new Vec3(camera.scale, camera.scale, 1));
m = m.multNew(mr);
m = m.multNew(ms);
m = m.multNew(mc);
m = m.multNew(mt);
m = m.multNew(mo);
gfx.ctx.uniformMatrix4fv(gfx.getUniform("u_matrix"), false, m.splat());
drawing.drawIsometricGrid(gfx, grid);
gfx.draw();
}
function addDefaultKeybinds(input, camera) {
input.addKeyAction("KeyA", [], camera, (c) => {
c.movement.x = 0;
}, (c) => {
c.movement.x = 1;
});
input.addKeyAction("KeyD", [], camera, (c) => {
c.movement.y = 0;
}, (c) => {
c.movement.y = -1;
});
input.addKeyAction("KeyW", [], camera, (c) => {
c.movement.z = 0;
}, (c) => {
c.movement.z = -1;
});
input.addKeyAction("KeyS", [], camera, (c) => {
c.movement.w = 0;
}, (c) => {
c.movement.w = 1;
});
input.addKeyAction("KeyQ", [], camera, (c) => {
c.scaling = 0.0;
}, (c) => {
c.scaling = 1.0;
});
input.addKeyAction("KeyE", [], camera, (c) => {
c.scaling = 0.0;
}, (c) => {
c.scaling = -1.0;
});
gfx.ctx.uniform2f(gfx.getUniform("u_resolution"), gfx.ctx.canvas.width, gfx.ctx.canvas.height);
drawing.drawCircle(gfx, pos, 200, [1, 0, 0, 1]);
if (pos.x + 200 >= gfx.ctx.canvas.width) {
pos.x = gfx.ctx.canvas.width - 200;
velocity.x *= -1;
}
else if (pos.x - 200 <= 0) {
pos.x = 200;
velocity.x *= -1;
}
if (pos.y + 200 >= gfx.ctx.canvas.height) {
pos.y = gfx.ctx.canvas.height - 200;
velocity.y *= -1;
}
else if (pos.y - 200 <= 0) {
pos.y = 200;
velocity.y *= -1;
}
pos.add(velocity.multNew(dt));
}
(async () => {
const canvasId = "game";
@ -127,44 +56,24 @@ function addDefaultKeybinds(input, camera) {
return;
const gfx = new Graphics(ctx, vertexShader, fragmentShader);
fullscreenCanvas(gfx, canvasId);
let a = gfx.createAttribute("a_position");
a.format(3, ctx.FLOAT, false, 0);
a = gfx.createAttribute("a_color");
a.format(4, ctx.FLOAT, false, 0);
a = gfx.createAttribute("a_tex_position");
a.format(2, ctx.FLOAT, false, 0);
gfx.createUniform("u_matrix");
gfx.createUniform("u_isIso");
gfx.createUniform("u_isTex");
let camera = new Camera(new Vec3(0, 0, -1));
await Assets.assets.load(gfx);
let m = Mat4.isometric();
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);
grid.fillLayer(new Tile({
top: Assets.assets.get("grass"),
right: Assets.Colors.Brown,
left: Assets.Colors.Brown,
}), 0);
tree(grid, new Vec2(size / 2, size / 2));
bush(grid, new Vec2(size / 2 + 4, size / 2 + 4));
//for (let i = 0; i < 10; i++) {
// tree(grid, new Vec2(Math.floor(Math.random() * size - 1), Math.floor(Math.random() * size - 1)));
//}
//grid.setTile(new Tile(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(0, 29, 1));
const a_position = gfx.createAttribute("a_position");
a_position.format(2, gfx.ctx.FLOAT, false, 0, 0);
const a_color = gfx.createAttribute("a_color");
a_color.format(4, gfx.ctx.FLOAT, false, 0, 0);
gfx.createUniform("u_resolution");
let pos = new Vec2(300, 300);
let velocity = new Vec2(200, 200);
let prevTimestamp = 0;
const frame = (timestamp) => {
const deltaTime = (timestamp - prevTimestamp) / 1000;
prevTimestamp = timestamp;
fullscreenCanvas(gfx, "game");
draw(gfx, camera, deltaTime, grid);
draw(gfx, deltaTime, pos, velocity);
window.requestAnimationFrame(frame);
};
window.requestAnimationFrame((timestamp) => {
prevTimestamp = timestamp;
window.requestAnimationFrame(frame);
});
const input = new Input();
addDefaultKeybinds(input, camera);
const wasmgl = new wasm.WASMGL(await wasm.loadWasmModule("./src/wasm/module.wasm"));
let env = await wasm.loadWasmModule("./src/wasm/module.wasm");
})();

View File

@ -1,50 +1,22 @@
import { initializeContext, Vec3, Mat4, Vec4, Vec2 } from "./common.js";
import { Graphics, fullscreenCanvas, Camera, DrawTag } from "./graphics.js";
import { initializeContext, Vec2 } from "./common.js";
import { Graphics, fullscreenCanvas } from "./graphics.js";
import * as drawing from "./draw.js";
import * as wasm from "./wasm.js";
import { Input } from "./input.js";
import {bush, Grid, Tile, TileEdge, tree} from "./world.js";
import * as Assets from "./assets.js";
const vertexShader =
`#version 300 es
layout(location = 0) in vec3 a_position;
layout(location = 1) in vec2 a_tex_position;
layout(location = 2) in vec4 a_color;
out vec4 v_color;
out vec2 v_tex_position;
uniform mat4 u_matrix;
uniform bool u_isIso;
uniform bool u_isTex;
mat4 Iso = mat4(
1, -1, 0, 0,
1, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
);
in vec2 a_position;
in vec4 a_color;
out vec4 color;
uniform vec2 u_resolution;
void main() {
vec4 orthographic;
vec2 clipSpace = (a_position / u_resolution) * 2.0 - 1.0;
if (u_isIso) {
vec4 isometric = Iso * vec4(a_position.xyz, 1.0);
orthographic = u_matrix * isometric;
//orthographic = u_matrix * vec4(a_position.xyz, 1.0);
} else {
orthographic = u_matrix * vec4(a_position.xyz, 1.0);
}
color = a_color;
gl_Position = orthographic;
if (u_isTex) {
v_tex_position = a_tex_position;
} else {
v_color = a_color;
}
gl_Position = vec4(clipSpace.xy, 0.0, 1.0);
}
`;
@ -52,118 +24,42 @@ const fragmentShader =
`#version 300 es
precision highp float;
in vec4 v_color;
in vec2 v_tex_position;
in vec4 color;
out vec4 outColor;
uniform sampler2D u_texture;
uniform bool u_isTex;
void main() {
if (u_isTex) {
outColor = texture(u_texture, v_tex_position);
} else {
outColor = v_color;
}
outColor = color;
}
`;
function draw(gfx: Graphics, camera: Camera, dt: number, grid: Grid) {
function draw(gfx: Graphics, dt: number, pos: Vec2, velocity: Vec2) {
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 near = -100;
let far = 100;
gfx.ctx.uniform2f(gfx.getUniform("u_resolution"), gfx.ctx.canvas.width, gfx.ctx.canvas.height);
drawing.drawCircle(gfx, pos, 200, [1, 0, 0, 1]);
let m = Mat4.IDENTITY();
if (pos.x + 200 >= gfx.ctx.canvas.width)
{
pos.x = gfx.ctx.canvas.width - 200;
velocity.x *= -1;
} else if (pos.x - 200 <= 0)
{
pos.x = 200;
velocity.x *= -1;
}
let mo = Mat4.orthographic(left, right, bottom, top, near, far);
if (pos.y + 200 >= gfx.ctx.canvas.height)
{
pos.y = gfx.ctx.canvas.height - 200;
velocity.y *= -1;
} else if (pos.y - 200 <= 0)
{
pos.y = 200;
velocity.y *= -1;
}
let mc = Mat4.translate(
new Vec3(
(gfx.ctx.canvas.width / 2 - camera.position.x),
(gfx.ctx.canvas.height / 2 - camera.position.y),
1.0));
let mr = Mat4.translate(
new Vec3(
-(gfx.ctx.canvas.width / 2 - camera.position.x),
-(gfx.ctx.canvas.height / 2 - camera.position.y),
1.0));
let mt = Mat4.translate(camera.position);
let ms = Mat4.scale(new Vec3(camera.scale, camera.scale, 1));
m = m.multNew(mr);
m = m.multNew(ms);
m = m.multNew(mc);
m = m.multNew(mt);
m = m.multNew(mo);
gfx.ctx.uniformMatrix4fv(
gfx.getUniform("u_matrix"),
false,
m.splat()
);
drawing.drawIsometricGrid(gfx, grid);
gfx.draw();
}
function addDefaultKeybinds(input: Input, camera: Camera) {
input.addKeyAction("KeyA", [], camera,
(c) => {
c.movement.x = 0;
},
(c) => {
c.movement.x = 1;
});
input.addKeyAction("KeyD", [], camera,
(c) => {
c.movement.y = 0;
},
(c) => {
c.movement.y = -1;
});
input.addKeyAction("KeyW", [], camera,
(c) => {
c.movement.z = 0;
},
(c) => {
c.movement.z = -1;
});
input.addKeyAction("KeyS", [], camera,
(c) => {
c.movement.w = 0;
},
(c) => {
c.movement.w = 1;
});
input.addKeyAction("KeyQ", [], camera,
(c) => {
c.scaling = 0.0;
},
(c) => {
c.scaling = 1.0;
});
input.addKeyAction("KeyE", [], camera,
(c) => {
c.scaling = 0.0;
},
(c) => {
c.scaling = -1.0;
});
pos.add(velocity.multNew(dt));
}
(async () => {
@ -174,46 +70,24 @@ function addDefaultKeybinds(input: Input, camera: Camera) {
const gfx = new Graphics(ctx, vertexShader, fragmentShader);
fullscreenCanvas(gfx, canvasId);
let a = gfx.createAttribute("a_position");
a.format(3, ctx.FLOAT, false, 0)
a = gfx.createAttribute("a_color");
a.format(4, ctx.FLOAT, false, 0)
a = gfx.createAttribute("a_tex_position");
a.format(2, ctx.FLOAT, false, 0)
const a_position = gfx.createAttribute("a_position");
a_position.format(2, gfx.ctx.FLOAT, false, 0, 0);
gfx.createUniform("u_matrix");
gfx.createUniform("u_isIso");
gfx.createUniform("u_isTex");
const a_color = gfx.createAttribute("a_color");
a_color.format(4, gfx.ctx.FLOAT, false, 0, 0);
let camera = new Camera(new Vec3(0, 0, -1));
await Assets.assets.load(gfx);
let m = Mat4.isometric();
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);
grid.fillLayer(new Tile({
top: Assets.assets.get("grass"),
right: Assets.Colors.Brown,
left: Assets.Colors.Brown,
}), 0);
tree(grid, new Vec2(size / 2, size / 2));
bush(grid, new Vec2(size / 2 + 4, size / 2 + 4));
//for (let i = 0; i < 10; i++) {
// tree(grid, new Vec2(Math.floor(Math.random() * size - 1), Math.floor(Math.random() * size - 1)));
//}
//grid.setTile(new Tile(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(0, 29, 1));
gfx.createUniform("u_resolution");
let pos = new Vec2(300, 300);
let velocity = new Vec2(200, 200);
let prevTimestamp = 0;
const frame = (timestamp: number) => {
const deltaTime = (timestamp - prevTimestamp)/1000;
prevTimestamp = timestamp;
fullscreenCanvas(gfx, "game");
draw(gfx, camera, deltaTime, grid);
draw(gfx, deltaTime, pos, velocity);
window.requestAnimationFrame(frame);
}
@ -223,8 +97,5 @@ function addDefaultKeybinds(input: Input, camera: Camera) {
window.requestAnimationFrame(frame);
});
const input = new Input();
addDefaultKeybinds(input, camera);
const wasmgl: wasm.WASMGL = new wasm.WASMGL(await wasm.loadWasmModule("./src/wasm/module.wasm"));
let env: any = await wasm.loadWasmModule("./src/wasm/module.wasm");
})();

View File

@ -1,4 +1,4 @@
export class WASMGLvalue {
class WASMGLvalue {
ptr;
size;
constructor(ptr, size) {
@ -6,32 +6,58 @@ export class WASMGLvalue {
this.size = size;
}
}
export async function loadWasmModule(path) {
return WebAssembly.instantiateStreaming(fetch(path));
async function loadWasmModule(path) {
let wasm = await WebAssembly.instantiateStreaming(fetch(path));
const memSize = new Int32Array(wasm.instance.exports.memory.buffer, wasm.instance.exports.WASMGLmemory.value + 4, 1)[0];
let memInt = new Int32Array(wasm.instance.exports.memory.buffer, wasm.instance.exports.WASMGLmemory.value, memSize);
let memFloat = new Float32Array(wasm.instance.exports.memory.buffer, wasm.instance.exports.WASMGLmemory.value, memSize);
wasm.instance.exports.WASMGLmain();
const data = [
1.5,
2.5,
3.5,
4.5,
5.5,
6.5,
7.5,
8.5,
];
let ptr = sendDataFloat(memFloat, data);
wasm.instance.exports.calc(ptr, data.length);
for (let i = 0; i < data.length; ++i) {
console.log(memFloat[ptr + i]);
}
return wasm.instance.exports;
}
export class WASMGL {
exports;
mem;
constructor(wasm) {
this.exports = wasm.instance.exports;
const memSize = new Float32Array(this.exports.memory.buffer, this.exports.WASMGLmemory.value + 4, 1).at(0);
this.mem = new Float32Array(this.exports.memory.buffer, this.exports.WASMGLmemory.value, memSize);
}
alloc(size) {
const head = this.mem[2];
this.mem[2] += size;
return head;
}
setstr(ptr, str) {
for (let i = 0; i < str.length; i++) {
this.mem[ptr] = str.charCodeAt(i);
++ptr;
}
}
set(ptr, data) {
data.forEach((v, i) => {
this.mem[ptr + i] = v;
});
return ptr;
function alloc(mem, size) {
const head = mem[2];
mem[2] += size;
return head;
}
function allocFloat(mem, size) {
const head = mem[2];
mem[2] += size;
return head;
}
function setstr(mem, ptr, size, str) {
for (let i = 0; i < size; i++) {
mem[ptr] = str.charCodeAt(i);
++ptr;
}
}
function sendData(mem, data) {
let ptr = alloc(mem, data.length);
data.forEach((v, i) => {
mem[ptr + i] = v;
});
return ptr;
}
function sendDataFloat(mem, data) {
let ptr = allocFloat(mem, data.length);
data.forEach((v, i) => {
mem[ptr + i] = v;
console.log(mem[ptr + i]);
});
return ptr;
}
export { loadWasmModule, alloc, setstr };

View File

@ -1,4 +1,4 @@
export class WASMGLvalue {
class WASMGLvalue {
ptr: number;
size: number;
@ -8,54 +8,90 @@ export class WASMGLvalue {
}
}
export interface WASMGLEnvironment {
exports: any,
mem: Float32Array,
}
async function loadWasmModule(path: string): Promise<WebAssembly.Exports> {
let wasm: any = await WebAssembly.instantiateStreaming(fetch(path));
export async function loadWasmModule(path: string): Promise<WebAssembly.WebAssemblyInstantiatedSource> {
return WebAssembly.instantiateStreaming(fetch(path));
}
export class WASMGL {
exports: any;
mem: Float32Array;
constructor(wasm: WebAssembly.WebAssemblyInstantiatedSource) {
this.exports = wasm.instance.exports;
const memSize = new Float32Array(
this.exports.memory.buffer,
this.exports.WASMGLmemory.value + 4,
const memSize = new Int32Array(
wasm.instance.exports.memory.buffer,
wasm.instance.exports.WASMGLmemory.value + 4,
1
).at(0);
)[0];
this.mem = new Float32Array(
this.exports.memory.buffer,
this.exports.WASMGLmemory.value,
memSize
);
let memInt = new Int32Array(
wasm.instance.exports.memory.buffer,
wasm.instance.exports.WASMGLmemory.value,
memSize
);
let memFloat = new Float32Array(
wasm.instance.exports.memory.buffer,
wasm.instance.exports.WASMGLmemory.value,
memSize
);
wasm.instance.exports.WASMGLmain();
const data = [
1.5,
2.5,
3.5,
4.5,
5.5,
6.5,
7.5,
8.5,
];
let ptr = sendDataFloat(memFloat, data);
wasm.instance.exports.calc(ptr, data.length);
for (let i = 0; i < data.length; ++i) {
console.log(memFloat[ptr + i]);
}
alloc(size: number): number {
const head = this.mem[2];
this.mem[2] += size;
return wasm.instance.exports;
}
return head;
}
function alloc(mem: Int32Array, size: number): number {
const head = mem[2];
mem[2] += size;
setstr(ptr: number, str: string) {
for (let i = 0; i < str.length; i++) {
this.mem[ptr] = str.charCodeAt(i);
++ptr;
}
}
return head;
}
set(ptr: number, data: number[]): number {
data.forEach((v, i) => {
this.mem[ptr + i] = v;
});
function allocFloat(mem: Float32Array, size: number): number {
const head = mem[2];
mem[2] += size;
return ptr;
return head;
}
function setstr(mem: Int32Array, ptr: number, size: number, str: string) {
for (let i = 0; i < size; i++) {
mem[ptr] = str.charCodeAt(i);
++ptr;
}
}
function sendData(mem: Int32Array, data: number[]): number {
let ptr = alloc(mem, data.length);
data.forEach((v, i) => {
mem[ptr + i] = v;
});
return ptr;
}
function sendDataFloat(mem: Float32Array, data: number[]): number {
let ptr = allocFloat(mem, data.length);
data.forEach((v, i) => {
mem[ptr + i] = v;
console.log(mem[ptr + i]);
});
return ptr;
}
export { loadWasmModule, alloc, setstr }

View File

@ -1,97 +0,0 @@
import * as Assets from "./assets.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 = {
top: [1, 0, 1, 1],
left: [0, 0, 0, 1],
right: [0, 0, 0, 1],
};
edge = TileEdge.None;
constructor(fill, edge) {
if (fill !== undefined)
this.fill = fill;
if (edge !== undefined)
this.edge = edge;
}
}
export function ColorToTile(c) {
return {
left: c,
top: c,
right: c,
};
}
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(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(position.x, position.y, 1));
grid.setTile(new Tile(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(position.x, position.y, 2));
grid.setTile(new Tile(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(position.x, position.y, 3));
grid.setTile(new Tile(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(position.x, position.y, 4));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.None), new Vec3(position.x, position.y, 4));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y + 1, 4));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y + 1, 5));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y, 5));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y, 4));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y, 5));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y + 1, 4));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y + 1, 5));
}
export function bush(grid, position) {
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), position.extend(1));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y, 1));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y + 1, 1));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y + 1, 1));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), position.extend(2));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y, 2));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y + 1, 2));
}

View File

@ -1,122 +0,0 @@
import * as Assets from "./assets.js";
import {Vec2, Vec3} from "./common.js";
import {Texture} from "./graphics.js";
export enum TileEdge {
None,
Left,
Right,
Both,
}
export type TileFillament = Texture | Assets.Color;
export type TileFill = { left: TileFillament, top: TileFillament, right: TileFillament };
export class Tile {
fill: TileFill = {
top : [1, 0, 1, 1],
left : [0, 0, 0, 1],
right : [0, 0, 0, 1],
};
edge: TileEdge = TileEdge.None;
constructor(fill?: TileFill, edge?: TileEdge) {
if (fill !== undefined)
this.fill = fill;
if (edge !== undefined)
this.edge = edge;
}
}
export function ColorToTile(c: Assets.Color) {
return {
left: c,
top: c,
right: c,
};
}
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(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(position.x, position.y, 1));
grid.setTile(new Tile(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(position.x, position.y, 2));
grid.setTile(new Tile(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(position.x, position.y, 3));
grid.setTile(new Tile(Assets.AssetToTileFill("log"), TileEdge.Both), new Vec3(position.x, position.y, 4));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.None), new Vec3(position.x, position.y, 4));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y + 1, 4));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y + 1, 5));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y, 5));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y, 4));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y, 5));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y + 1, 4));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y + 1, 5));
}
export function bush(grid: Grid, position: Vec2) {
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), position.extend(1));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y, 1));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y + 1, 1));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y + 1, 1));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), position.extend(2));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x + 1, position.y, 2));
grid.setTile(new Tile(Assets.AssetToTileFill("leaves"), TileEdge.Both), new Vec3(position.x, position.y + 1, 2));
}

View File

@ -1,20 +1,19 @@
#include "wasmgl.h"
void doubel(WASMGLvalue(0))
int WASMGLmemory[WASMGLmemory_size] = {
[MEM_SIZE] = WASMGLmemory_size,
[MEM_HEAD] = MEM_ELEM_COUNT,
0,
};
void calc(WASMGLvalue(0))
{
for (int i = 0; i < size_0; ++i)
WASMGLset(ptr_0 + i, WASMGLmemory[ptr_0 + i] * 2.0);
WASMGLmemory[ptr_0 + i] = ((float) WASMGLmemory[ptr_0 + i]) * 2.0;
}
void uppercase(WASMGLvalue(0)) {
int val = 0;
int main(void)
{
for (int i = 0; i < size_0; ++i)
{
val = WASMGLmemory[ptr_0 + i] - 32;
if (val < 65 || val > 122) val = WASMGLmemory[ptr_0 + i];
WASMGLset(ptr_0 + i, val);
}
return 0;
}

Binary file not shown.

View File

@ -1,26 +1,22 @@
#include "wasmgl.h"
float WASMGLmemory[WASMGLmemory_size] = {
[MEM_SIZE] = WASMGLmemory_size,
[MEM_HEAD] = MEM_ELEM_COUNT,
0,
};
WASMGLptr WASMGLmalloc(WASMGLsize size)
WASMGLptr WASMGLmalloc(int * mem, WASMGLsize size)
{
WASMGLptr ptr = WASMGLmemory[MEM_HEAD];
WASMGLmemory[MEM_HEAD] += size;
WASMGLptr ptr = mem[MEM_HEAD];
mem[MEM_HEAD] += size;
return ptr;
}
void WASMGLset(WASMGLptr ptr, int value)
void WASMGLset(int * mem, WASMGLptr ptr, int value)
{
WASMGLmemory[ptr] = value;
mem[ptr] = value;
}
void WASMGLsetstr(WASMGLptr ptr, const char * cstr, WASMGLsize size)
void WASMGLsetstr(int * mem, WASMGLptr ptr, const char * cstr, WASMGLsize size)
{
for (int i = 0; i < size; ++i)
WASMGLset(ptr + i, cstr[i]);
{
WASMGLset(mem, ptr + i, cstr[i]);
}
}

View File

@ -12,14 +12,12 @@ typedef enum {
MEM_ELEM_COUNT,
} WASMGLmemory_layout;
extern float WASMGLmemory[WASMGLmemory_size];
typedef unsigned int WASMGLptr;
typedef unsigned int WASMGLsize;
#define WASMGLvalue(n) WASMGLptr ptr_##n, WASMGLsize size_##n
WASMGLptr WASMGLmalloc(WASMGLsize size);
void WASMGLset(WASMGLptr ptr, int value);
void WASMGLsetstr(WASMGLptr ptr, const char * cstr, WASMGLsize size);
WASMGLptr WASMGLmalloc(int * mem, WASMGLsize size);
void WASMGLset(int * mem, WASMGLptr ptr, int value);
void WASMGLsetstr(int * mem, WASMGLptr ptr, const char * cstr, WASMGLsize size);
#endif // WASMGL_H_