webgl_game/src/js/common.ts

378 lines
8.5 KiB
TypeScript

function initializeContext(canvasId: string): WebGL2RenderingContext | null {
const canvas = document.getElementById(canvasId) as HTMLCanvasElement;
const ctx = canvas.getContext("webgl2", {antialias: false});
return ctx;
}
type Color = [number, number, number, number]
// TODO: Make all vectors follow one interface
interface Vector {
}
class Vec2 {
x: number;
y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
add(other: Vec2) {
this.x += other.x;
this.y += other.y;
}
addScalar(scalar: number) {
this.x += scalar;
this.y += scalar;
}
addNew(other: Vec2): Vec2 {
return new Vec2(this.x + other.x, this.y + other.y);
}
addScalarNew(scalar: number): Vec2 {
return new Vec2(this.x + scalar, this.y + scalar);
}
sub(other: Vec2) {
this.x -= other.x;
this.y -= other.y;
}
mult(scalar: number) {
this.x *= scalar;
this.y *= scalar;
}
multNew(scalar: number): Vec2 {
return new Vec2(this.x * scalar, this.y * scalar);
}
splatToArray(): Array<number> {
return [this.x, this.y];
}
static angle(angle: number): Vec2 {
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);
}
}
class Vec3 {
x: number;
y: number;
z: number;
constructor(x: number, y: number, z: number) {
this.x = x;
this.y = y;
this.z = z;
}
add(other: Vec3) {
this.x += other.x;
this.y += other.y;
this.z += other.z;
}
sub(other: Vec3) {
this.x -= other.x;
this.y -= other.y;
this.z -= other.z;
}
multScalar(scalar: number) {
this.x *= scalar;
this.y *= scalar;
this.z *= scalar;
}
multScalarNew(scalar: number): Vec3 {
let vec = new Vec3(this.x, this.y, this.z);
vec.x *= scalar;
vec.y *= scalar;
vec.z *= scalar;
return vec;
}
splatToArray(): Array<number> {
return [this.x, this.y, this.z];
}
}
class Vec4 {
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;
}
add(other: Vec4) {
this.x += other.x;
this.y += other.y;
this.z += other.z;
this.w += other.w;
}
sub(other: Vec4) {
this.x -= other.x;
this.y -= other.y;
this.z -= other.z;
this.w -= other.w;
}
multScalar(scalar: number) {
this.x *= scalar;
this.y *= scalar;
this.z *= scalar;
this.w *= scalar;
}
multScalarNew(scalar: number): Vec4 {
let vec = new Vec4(this.x, this.y, this.z, this.w);
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 = new Vec4(this.x, this.y, this.z, this.w);
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);
}
}
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) {
this.data = i;
return;
} else if (typeof(i) === 'number') {
this.data = new Float32Array(16).fill(i);
return;
}
this.data = new Float32Array(16);
}
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 {
let m = new Mat4(new Float32Array([
1, -1, 0, 0,
1, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
]));
return m;
}
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,
]));
}
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.x * this.x(1) + v.x * this.x(2) + v.x * this.x(3);
let y = v.y * this.y(0) + v.y * this.y(1) + v.y * this.y(2) + v.y * this.y(3);
let z = v.z * this.z(0) + v.z * this.z(1) + v.z * this.z(2) + v.z * this.z(3);
let w = v.w * this.w(0) + v.w * this.w(1) + v.w * this.w(2) + v.w * this.w(3);
v.x = x;
v.y = y;
v.z = z;
v.w = w;
}
transformNew(v: Vec4): Vec4 {
let vec = new Vec4(v.x, v.y, v.z, v.w);
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, Color };