456 lines
11 KiB
JavaScript
456 lines
11 KiB
JavaScript
export function initializeContext(canvasId) {
|
|
const canvas = document.getElementById(canvasId);
|
|
const ctx = canvas.getContext("webgl2", { antialias: false });
|
|
return ctx;
|
|
}
|
|
export class Vec2 {
|
|
x;
|
|
y;
|
|
constructor(x, y) {
|
|
this.x = x;
|
|
this.y = y;
|
|
}
|
|
static ZERO() {
|
|
return new Vec2(0, 0);
|
|
}
|
|
static ID() {
|
|
return new Vec2(1, 1);
|
|
}
|
|
copy() {
|
|
return new Vec2(this.x, this.y);
|
|
}
|
|
add(other) {
|
|
this.x += other.x;
|
|
this.y += other.y;
|
|
}
|
|
addScalar(scalar) {
|
|
this.x += scalar;
|
|
this.y += scalar;
|
|
}
|
|
addNew(other) {
|
|
return new Vec2(this.x + other.x, this.y + other.y);
|
|
}
|
|
addScalarNew(scalar) {
|
|
return new Vec2(this.x + scalar, this.y + scalar);
|
|
}
|
|
sub(other) {
|
|
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) {
|
|
this.x *= scalar;
|
|
this.y *= 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];
|
|
}
|
|
static angle(angle) {
|
|
const eps = 1e-6;
|
|
let x = Math.cos(angle);
|
|
let y = Math.sin(angle);
|
|
if ((x > 0 && x < eps)
|
|
|| (x < 0 && x > -eps))
|
|
x = 0;
|
|
if ((y > 0 && y < eps)
|
|
|| (y < 0 && y > -eps))
|
|
y = 0;
|
|
return new Vec2(x, y);
|
|
}
|
|
}
|
|
export class Vec3 {
|
|
x;
|
|
y;
|
|
z;
|
|
constructor(x, y, z) {
|
|
this.x = x;
|
|
this.y = y;
|
|
this.z = z;
|
|
}
|
|
addScalar(scalar) {
|
|
this.x += scalar;
|
|
this.y += scalar;
|
|
this.z += scalar;
|
|
}
|
|
addScalarNew(scalar) {
|
|
let vec = this.copy();
|
|
vec.x += scalar;
|
|
vec.y += scalar;
|
|
vec.z += scalar;
|
|
return vec;
|
|
}
|
|
static ZERO() {
|
|
return new Vec3(0, 0, 0);
|
|
}
|
|
static ID() {
|
|
return new Vec3(1, 1, 1);
|
|
}
|
|
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];
|
|
}
|
|
}
|
|
export class Vec4 {
|
|
x;
|
|
y;
|
|
z;
|
|
w;
|
|
constructor(x, y, z, w) {
|
|
this.x = x;
|
|
this.y = y;
|
|
this.z = z;
|
|
this.w = w;
|
|
}
|
|
static ZERO() {
|
|
return new Vec4(0, 0, 0, 0);
|
|
}
|
|
static ID() {
|
|
return new Vec4(1, 1, 1, 1);
|
|
}
|
|
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;
|
|
}
|
|
addScalar(scalar) {
|
|
this.x += scalar;
|
|
this.y += scalar;
|
|
this.z += scalar;
|
|
this.w += scalar;
|
|
}
|
|
addScalarNew(scalar) {
|
|
let vec = this.copy();
|
|
vec.x += scalar;
|
|
vec.y += scalar;
|
|
vec.z += scalar;
|
|
vec.w += scalar;
|
|
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");
|
|
}
|
|
}
|
|
export 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.y(0) + v.z * this.z(0) + v.w * this.w(0);
|
|
let y = v.x * this.x(1) + v.y * this.y(1) + v.z * this.z(1) + v.w * this.w(1);
|
|
let z = v.x * this.x(2) + v.y * this.y(2) + v.z * this.z(2) + v.w * this.w(2);
|
|
let w = v.x * this.x(3) + v.y * this.y(3) + v.z * this.z(3) + 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.y(0) + v.z * this.z(0) + v.w * this.w(0);
|
|
let y = v.x * this.x(1) + v.y * this.y(1) + v.z * this.z(1) + v.w * this.w(1);
|
|
let z = v.x * this.x(2) + v.y * this.y(2) + v.z * this.z(2) + v.w * this.w(2);
|
|
let w = v.x * this.x(3) + v.y * this.y(3) + v.z * this.z(3) + 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;
|
|
}
|
|
}
|
|
}
|