Define basic data structure

This commit is contained in:
Szymon Nowakowski 2023-07-26 23:13:16 +02:00 committed by Szymon Nowakowski
parent 8b25bceaa9
commit 2c3020ff95
16 changed files with 1249 additions and 2 deletions

View File

@ -2,7 +2,11 @@
"name": "oktaeder",
"version": "0.1.0",
"description": "3D rendering library for WebGPU",
"keywords": ["3d", "gltf", "wegbpu"],
"keywords": [
"3d",
"gltf",
"wegbpu"
],
"homepage": "https://github.com/iszn11/oktaeder",
"bugs": {
"url": "https://github.com/iszn11/oktaeder/issues"
@ -20,6 +24,7 @@
"tslib": "^2.6.1"
},
"devDependencies": {
"@webgpu/types": "^0.1.34",
"typescript": "5.1.6"
},
"exports": {

View File

@ -10,12 +10,19 @@ dependencies:
version: 2.6.1
devDependencies:
'@webgpu/types':
specifier: ^0.1.34
version: 0.1.34
typescript:
specifier: 5.1.6
version: 5.1.6
packages:
/@webgpu/types@0.1.34:
resolution: {integrity: sha512-9mXtH+CC8q+Ku7Z+1XazNIte81FvfdXwR2lLRO7Ykzjd/hh1J1krJa0gtnkF1kvP11psUmKEPKo7iMTeEcUpNA==}
dev: true
/tslib@2.6.1:
resolution: {integrity: sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==}
dev: false

115
src/Camera.ts Normal file
View File

@ -0,0 +1,115 @@
/*!
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at http://mozilla.org/MPL/2.0/.
*/
import { Node } from "./Node";
export type Camera = CameraOrthographic | CameraPerspective;
export interface CameraOrthographicProps {
readonly name?: string;
readonly verticalSize: number;
readonly nearPlane: number;
readonly farPlane: number;
}
export interface CameraPerspectiveProps {
readonly name?: string;
readonly verticalFovRad: number;
readonly nearPlane: number;
readonly farPlane: number;
}
export class CameraOrthographic {
readonly type!: "CameraOrthographic";
_name: string;
_verticalSize: number;
_nearPlane: number;
_farPlane: number;
/** backreference */
_node: Node | undefined;
constructor({
name = "",
verticalSize,
nearPlane,
farPlane,
}: CameraOrthographicProps) {
Object.defineProperty(this, "type", { value: "CameraOrthographic" });
this._name = name;
this._verticalSize = verticalSize;
this._nearPlane = nearPlane;
this._farPlane = farPlane;
this._node = undefined;
}
detach(): Camera {
if (this._node === undefined) {
return this;
}
this._node._camera = undefined;
this._node = undefined;
return this;
}
}
export class CameraPerspective {
readonly type!: "CameraPerspective";
_name: string;
_verticalFovRad: number;
_nearPlane: number;
_farPlane: number;
/** backreference */
_node: Node | undefined;
constructor({
name = "",
verticalFovRad,
nearPlane,
farPlane,
}: CameraPerspectiveProps) {
Object.defineProperty(this, "type", { value: "CameraPerspective" });
this._name = name;
this._verticalFovRad = verticalFovRad;
this._nearPlane = nearPlane;
this._farPlane = farPlane;
this._node = undefined;
}
detach(): Camera {
if (this._node === undefined) {
return this;
}
this._node._camera = undefined;
this._node = undefined;
return this;
}
}
export function isCameraOrthographic(value: unknown): value is CameraOrthographic {
return Boolean(value) && (value as CameraOrthographic).type === "CameraOrthographic";
}
export function isCameraPerspective(value: unknown): value is CameraPerspective {
return Boolean(value) && (value as CameraPerspective).type === "CameraPerspective";
}

266
src/Color.ts Normal file
View File

@ -0,0 +1,266 @@
/*!
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at http://mozilla.org/MPL/2.0/.
*/
import { Vector3Object } from "./Vector3";
/* Named colors
* black #000000 (0, 0, 0, 1)
* silver #C0C0C0 (192 / 255, 192 / 255, 192 / 255, 1)
* gray #808080 (128 / 255, 128 / 255, 128 / 255, 1)
* white #FFFFFF (1, 1, 1, 1)
* maroon #800000 (128 / 255, 0, 0, 1)
* red #FF0000 (1, 0, 0, 1)
* purple #800080 (128 / 255, 0, 128 / 255, 1)
* fuchsia #FF00FF (1, 0, 1, 1)
* green #008000 (0, 128 / 255, 0, 1)
* lime #00FF00 (0, 255, 0, 1)
* olive #808000 (128 / 255, 128 / 255, 0, 1)
* yellow #FFFF00 (1, 1, 0, 1)
* navy #000080 (0, 0, 128 / 255, 1)
* blue #0000FF (0, 0, 1, 1)
* teal #008080 (0, 128 / 255, 128 / 255, 1)
* aqua #00FFFF (0, 1, 1, 1)
* orange #FFA500 (1, 165 / 255, 0, 1)
*/
export type ColorName =
| "black"
| "silver"
| "gray"
| "white"
| "maroon"
| "red"
| "purple"
| "fuchsia"
| "green"
| "lime"
| "olive"
| "yellow"
| "navy"
| "blue"
| "teal"
| "aqua"
| "orange"
;
export interface ColorObject {
readonly r: number;
readonly g: number;
readonly b: number;
}
export type ColorTuple = readonly [r: number, g: number, b: number];
export class Color {
readonly type!: "Color";
r: number;
g: number;
b: number;
constructor(r: number, g: number, b: number) {
Object.defineProperty(this, "type", { value: "Color" });
this.r = r;
this.g = g;
this.b = b;
}
static fromObject(object: ColorObject): Color {
return new Color(object.r, object.g, object.b);
}
static fromTuple(tuple: ColorTuple): Color {
return new Color(...tuple);
}
static fromName(name: ColorName): Color {
switch (name) {
case "black": return new Color(0, 0, 0);
case "silver": return new Color(192 / 255, 192 / 255, 192 / 255);
case "gray": return new Color(128 / 255, 128 / 255, 128 / 255);
case "white": return new Color(1, 1, 1);
case "maroon": return new Color(128 / 255, 0, 0);
case "red": return new Color(1, 0, 0);
case "purple": return new Color(128 / 255, 0, 128 / 255);
case "fuchsia": return new Color(1, 0, 1);
case "green": return new Color(0, 128 / 255, 0);
case "lime": return new Color(0, 255, 0);
case "olive": return new Color(128 / 255, 128 / 255, 0);
case "yellow": return new Color(1, 1, 0);
case "navy": return new Color(0, 0, 128 / 255);
case "blue": return new Color(0, 0, 1);
case "teal": return new Color(0, 128 / 255, 128 / 255);
case "aqua": return new Color(0, 1, 1);
case "orange": return new Color(1, 165 / 255, 0);
}
}
static fromVector3(vector: Vector3Object): Color {
return new Color(vector.x, vector.y, vector.z);
}
static white(): Color {
return new Color(1, 1, 1);
}
static black(): Color {
return new Color(0, 0, 0);
}
set(r: number, g: number, b: number): Color {
this.r = r;
this.g = g;
this.b = b;
return this;
}
setObject(object: ColorObject): Color {
this.r = object.r;
this.g = object.g;
this.b = object.b;
return this;
}
setTuple(tuple: ColorTuple): Color {
this.r = tuple[0];
this.g = tuple[1];
this.b = tuple[2];
return this;
}
setName(name: ColorName): Color {
switch (name) {
case "black":
this.r = 0;
this.g = 0;
this.b = 0;
break;
case "silver":
this.r = 192 / 255;
this.g = 192 / 255;
this.b = 192 / 255;
break;
case "gray":
this.r = 128 / 255;
this.g = 128 / 255;
this.b = 128 / 255;
break;
case "white":
this.r = 1;
this.g = 1;
this.b = 1;
break;
case "maroon":
this.r = 128 / 255;
this.g = 0;
this.b = 0;
break;
case "red":
this.r = 1;
this.g = 0;
this.b = 0;
break;
case "purple":
this.r = 128 / 255;
this.g = 0;
this.b = 128 / 255;
break;
case "fuchsia":
this.r = 1;
this.g = 0;
this.b = 1;
break;
case "green":
this.r = 0;
this.g = 128 / 255;
this.b = 0;
break;
case "lime":
this.r = 0;
this.g = 255;
this.b = 0;
break;
case "olive":
this.r = 128 / 255;
this.g = 128 / 255;
this.b = 0;
break;
case "yellow":
this.r = 1;
this.g = 1;
this.b = 0;
break;
case "navy":
this.r = 0;
this.g = 0;
this.b = 128 / 255;
break;
case "blue":
this.r = 0;
this.g = 0;
this.b = 1;
break;
case "teal":
this.r = 0;
this.g = 128 / 255;
this.b = 128 / 255;
break;
case "aqua":
this.r = 0;
this.g = 1;
this.b = 1;
break;
case "orange":
this.r = 1;
this.g = 165 / 255;
this.b = 0;
break;
}
return this;
}
setVector3(vector: Vector3Object): Color {
this.r = vector.x;
this.g = vector.y;
this.b = vector.z;
return this;
}
setWhite(): Color {
this.r = 1;
this.g = 1;
this.b = 1;
return this;
}
setBlack(): Color {
this.r = 0;
this.g = 0;
this.b = 0;
return this;
}
setR(r: number): Color {
this.r = r;
return this;
}
setG(g: number): Color {
this.g = g;
return this;
}
setB(b: number): Color {
this.b = b;
return this;
}
}
export function isColor(value: unknown): value is Color {
return Boolean(value) && (value as Color).type === "Color";
}

49
src/IndexBuffer.ts Normal file
View File

@ -0,0 +1,49 @@
/*!
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at http://mozilla.org/MPL/2.0/.
*/
export const INDEX_SIZE = 2;
export class IndexBuffer {
readonly type!: "IndexBuffer";
_device: GPUDevice;
_buffer: GPUBuffer;
constructor(device: GPUDevice, indexCount: number) {
Object.defineProperty(this, "type", { value: "IndexBuffer" });
this._device = device;
this._buffer = device.createBuffer({
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.INDEX,
size: indexCount * INDEX_SIZE,
});
}
dispose(): IndexBuffer {
this._buffer.destroy();
return this;
}
get vertexCount(): number {
return this._buffer.size / INDEX_SIZE | 0;
}
writeArray(offset: number, indices: readonly number[]): IndexBuffer {
const array = new Uint16Array(indices);
this._device.queue.writeBuffer(this._buffer, offset * INDEX_SIZE | 0, array);
return this;
}
writeTypedArray(offset: number, indices: Uint16Array): IndexBuffer {
this._device.queue.writeBuffer(this._buffer, offset * INDEX_SIZE | 0, indices);
return this;
}
}
export function isIndexBuffer(value: unknown): value is IndexBuffer {
return Boolean(value) && (value as IndexBuffer).type === "IndexBuffer";
}

76
src/Material.ts Normal file
View File

@ -0,0 +1,76 @@
/*!
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at http://mozilla.org/MPL/2.0/.
*/
import { Color, ColorObject } from "./Color";
export interface MaterialProps {
name?: string;
baseColor?: ColorObject;
metallic?: number;
roughness?: number;
emissive?: ColorObject;
partialCoverage?: number;
transmission?: ColorObject;
collimation?: number;
ior?: number;
doubleSided?: boolean;
}
export class Material {
readonly type!: "Material";
_name: string;
_baseColor: Color;
_metallic: number;
_roughness: number;
_emissive: Color;
_partialCoverage: number;
_transmission: Color;
_collimation: number;
_ior: number;
_doubleSided: boolean;
constructor({
name = "",
baseColor,
metallic = 1,
roughness = 1,
emissive,
partialCoverage = 1,
transmission,
collimation = 1,
ior = 1.45,
doubleSided = false,
}: MaterialProps) {
Object.defineProperty(this, "type", { value: "Material" });
this._name = name;
this._baseColor = baseColor !== undefined ? Color.fromObject(baseColor) : Color.white();
this._metallic = metallic;
this._roughness = roughness;
this._emissive = emissive !== undefined ? Color.fromObject(emissive) : Color.black();
this._partialCoverage = partialCoverage;
this._transmission = transmission !== undefined ? Color.fromObject(transmission) : Color.black();
this._collimation = collimation;
this._ior = ior;
this._doubleSided = doubleSided;
}
get isTransparent(): boolean {
return this._partialCoverage < 1 || this._transmission.r > 0 || this._transmission.g > 0 || this._transmission.b > 0;
}
}
export function isMaterial(value: unknown): value is Material {
return Boolean(value) && (value as Material).type === "Material";
}

246
src/Matrix4x4.ts Normal file
View File

@ -0,0 +1,246 @@
/*!
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at http://mozilla.org/MPL/2.0/.
*/
import { QuaternionObject } from "./Quaternion";
import { Vector3Object } from "./Vector3";
export interface Matrix4x4Object {
readonly ix: number;
readonly iy: number;
readonly iz: number;
readonly iw: number;
readonly jx: number;
readonly jy: number;
readonly jz: number;
readonly jw: number;
readonly kx: number;
readonly ky: number;
readonly kz: number;
readonly kw: number;
readonly tx: number;
readonly ty: number;
readonly tz: number;
readonly tw: number;
}
export type Matrix4x4Tuple = readonly [
ix: number, iy: number, iz: number, iw: number,
jx: number, jy: number, jz: number, jw: number,
kx: number, ky: number, kz: number, kw: number,
tx: number, ty: number, tz: number, tw: number,
];
export class Matrix4x4 {
readonly type!: "Matrix4x4";
ix: number;
iy: number;
iz: number;
iw: number;
jx: number;
jy: number;
jz: number;
jw: number;
kx: number;
ky: number;
kz: number;
kw: number;
tx: number;
ty: number;
tz: number;
tw: number;
constructor(
ix: number, iy: number, iz: number, iw: number,
jx: number, jy: number, jz: number, jw: number,
kx: number, ky: number, kz: number, kw: number,
tx: number, ty: number, tz: number, tw: number
) {
Object.defineProperty(this, "type", { value: "Matrix4x4" });
this.ix = ix;
this.iy = iy;
this.iz = iz;
this.iw = iw;
this.jx = jx;
this.jy = jy;
this.jz = jz;
this.jw = jw;
this.kx = kx;
this.ky = ky;
this.kz = kz;
this.kw = kw;
this.tx = tx;
this.ty = ty;
this.tz = tz;
this.tw = tw;
}
static fromObject(object: Matrix4x4Object): Matrix4x4 {
return new Matrix4x4(
object.ix, object.iy, object.iz, object.iw,
object.jx, object.jy, object.jz, object.jw,
object.kx, object.ky, object.kz, object.kw,
object.tx, object.ty, object.tz, object.tw,
);
}
static fromTuple(tuple: Matrix4x4Tuple): Matrix4x4 {
return new Matrix4x4(...tuple);
}
static fromTranslation(translation: Vector3Object): Matrix4x4 {
return new Matrix4x4(
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
translation.x, translation.y, translation.z, 1,
);
}
static fromQuaternion(quaternion: QuaternionObject): Matrix4x4 {
const xx = quaternion.x * quaternion.x;
const xy = quaternion.x * quaternion.y;
const xz = quaternion.x * quaternion.z;
const xw = quaternion.x * quaternion.w;
const yy = quaternion.y * quaternion.y;
const yz = quaternion.y * quaternion.z;
const yw = quaternion.y * quaternion.w;
const zz = quaternion.z * quaternion.z;
const zw = quaternion.z * quaternion.w;
return new Matrix4x4(
1 - 2 * (yy + zz), 2 * (xy + zw), 2 * (xz - yw), 0,
2 * (xy - zw), 1 - 2 * (xx + zz), 2 * (yz + xw), 0,
2 * (xz + yw), 2 * (yz - xw), 1 - 2 * (xx + yy), 0,
0, 0, 0, 1,
);
}
static fromScale(scale: Vector3Object): Matrix4x4 {
return new Matrix4x4(
scale.x, 0, 0, 0,
0, scale.y, 0, 0,
0, 0, scale.z, 0,
0, 0, 0, 1
);
}
setObject(object: Matrix4x4Object): Matrix4x4 {
this.ix = object.ix;
this.iy = object.iy;
this.iz = object.iz;
this.iw = object.iw;
this.jx = object.jx;
this.jy = object.jy;
this.jz = object.jz;
this.jw = object.jw;
this.kx = object.kx;
this.ky = object.ky;
this.kz = object.kz;
this.kw = object.kw;
this.tx = object.tx;
this.ty = object.ty;
this.tz = object.tz;
this.tw = object.tw;
return this;
}
setTuple(tuple: Matrix4x4Tuple): Matrix4x4 {
this.ix = tuple[0];
this.iy = tuple[1];
this.iz = tuple[2];
this.iw = tuple[3];
this.jx = tuple[4];
this.jy = tuple[5];
this.jz = tuple[6];
this.jw = tuple[7];
this.kx = tuple[8];
this.ky = tuple[9];
this.kz = tuple[10];
this.kw = tuple[11];
this.tx = tuple[12];
this.ty = tuple[13];
this.tz = tuple[14];
this.tw = tuple[15];
return this;
}
setTranslation(translation: Vector3Object): Matrix4x4 {
this.ix = 1;
this.iy = 0;
this.iz = 0;
this.iw = 0;
this.jx = 0;
this.jy = 1;
this.jz = 0;
this.jw = 0;
this.kx = 0;
this.ky = 0;
this.kz = 1;
this.kw = 0;
this.tx = translation.x;
this.ty = translation.y;
this.tz = translation.z;
this.tw = 1;
return this;
}
setQuaternion(quaternion: QuaternionObject): Matrix4x4 {
const xx = quaternion.x * quaternion.x;
const xy = quaternion.x * quaternion.y;
const xz = quaternion.x * quaternion.z;
const xw = quaternion.x * quaternion.w;
const yy = quaternion.y * quaternion.y;
const yz = quaternion.y * quaternion.z;
const yw = quaternion.y * quaternion.w;
const zz = quaternion.z * quaternion.z;
const zw = quaternion.z * quaternion.w;
this.ix = 1 - 2 * (yy + zz);
this.iy = 2 * (xy + zw);
this.iz = 2 * (xz - yw);
this.iw = 0;
this.jx = 2 * (xy - zw);
this.jy = 1 - 2 * (xx + zz);
this.jz = 2 * (yz + xw);
this.jw = 0;
this.kx = 2 * (xz + yw);
this.ky = 2 * (yz - xw);
this.kz = 1 - 2 * (xx + yy);
this.kw = 0;
this.tx = 0;
this.ty = 0;
this.tz = 0;
this.tw = 1;
return this;
}
setScale(scale: Vector3Object): Matrix4x4 {
this.ix = scale.x;
this.iy = 0;
this.iz = 0;
this.iw = 0;
this.jx = 0;
this.jy = scale.y;
this.jz = 0;
this.jw = 0;
this.kx = 0;
this.ky = 0;
this.kz = scale.z;
this.kw = 0;
this.tx = 0;
this.ty = 0;
this.tz = 0;
this.tw = 1;
return this;
}
}
export function isMatrix4x4(value: unknown): value is Matrix4x4 {
return Boolean(value) && (value as Matrix4x4).type === "Matrix4x4";
}

42
src/Mesh.ts Normal file
View File

@ -0,0 +1,42 @@
/*!
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at http://mozilla.org/MPL/2.0/.
*/
import { IndexBuffer } from "./IndexBuffer";
import { VertexBuffer } from "./VertexBuffer";
export interface MeshProps {
readonly name?: string;
readonly vertexBuffer: VertexBuffer;
readonly indexBuffer: IndexBuffer;
}
export class Mesh {
readonly type!: "Mesh"
_name: string;
_vertexBuffer: VertexBuffer;
_indexBuffer: IndexBuffer;
constructor({
name = "",
vertexBuffer,
indexBuffer,
}: MeshProps) {
Object.defineProperty(this, "type", { value: "Mesh" });
this._name = name;
this._vertexBuffer = vertexBuffer;
this._indexBuffer = indexBuffer
}
}
export function isMesh(value: unknown): value is Mesh {
return Boolean(value) && (value as Mesh).type === "Mesh";
}

84
src/Node.ts Normal file
View File

@ -0,0 +1,84 @@
/*!
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at http://mozilla.org/MPL/2.0/.
*/
import { Camera } from "./Camera";
import { Mesh } from "./Mesh";
import { Quaternion, QuaternionObject } from "./Quaternion";
import { Vector3, Vector3Object } from "./Vector3";
export interface NodeProps {
readonly name?: string;
readonly translation?: Vector3Object;
readonly rotation?: QuaternionObject;
readonly scale?: Vector3Object;
readonly camera?: Camera;
readonly mesh?: Mesh;
readonly children?: Node[];
}
export class Node {
readonly type!: "Node";
_name: string;
_translation: Vector3;
_rotation: Quaternion;
_scale: Vector3;
/** unique */
_camera: Camera | undefined;
/** shared */
_mesh: Mesh | undefined;
/** unique */
_children: Node[];
/** backreference */
_parent: Node | undefined;
constructor({
name = "",
translation,
rotation,
scale,
camera,
mesh,
children = [],
}: NodeProps) {
Object.defineProperty(this, "type", { value: "Node" });
this._name = name;
this._translation = translation !== undefined ? Vector3.fromObject(translation) : Vector3.zero();
this._rotation = rotation !== undefined ? Quaternion.fromObject(rotation) : Quaternion.identity();
this._scale = scale !== undefined ? Vector3.fromObject(scale) : Vector3.one();
this._camera = camera;
this._mesh = mesh;
this._children = children;
this._parent = undefined;
if (this._camera !== undefined) {
this._camera._node = this;
}
if (this._children !== undefined) {
for (const child of this._children) {
child._parent = this;
}
}
}
}
export function isNode(value: unknown): value is Node {
return Boolean(value) && (value as Node).type === "Node";
}

73
src/Quaternion.ts Normal file
View File

@ -0,0 +1,73 @@
/*!
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at http://mozilla.org/MPL/2.0/.
*/
export interface QuaternionObject {
readonly x: number;
readonly y: number;
readonly z: number;
readonly w: number;
}
export type QuaternionTuple = readonly [x: number, y: number, z: number, w: number];
export class Quaternion {
readonly type!: "Quaternion";
x: number;
y: number;
z: number;
w: number;
constructor(x: number, y: number, z: number, w: number) {
Object.defineProperty(this, "type", { value: "Quaternion" });
this.x = x;
this.y = y;
this.z = z;
this.w = w;
}
static fromObject(object: QuaternionObject): Quaternion {
return new Quaternion(object.x, object.y, object.z, object.w);
}
static fromTuple(tuple: QuaternionTuple): Quaternion {
return new Quaternion(...tuple);
}
static identity(): Quaternion {
return new Quaternion(0, 0, 0, 1);
}
setObject(object: QuaternionObject): Quaternion {
this.x = object.x;
this.y = object.y;
this.z = object.z;
this.w = object.w;
return this;
}
setTuple(tuple: QuaternionTuple): Quaternion {
this.x = tuple[0];
this.y = tuple[1];
this.z = tuple[2];
this.w = tuple[3];
return this;
}
setIdentity(): Quaternion {
this.x = 0;
this.y = 0;
this.z = 0;
this.w = 1;
return this;
}
}
export function isQuaternion(value: unknown): value is Quaternion {
return Boolean(value) && (value as Quaternion).type === "Quaternion";
}

37
src/Scene.ts Normal file
View File

@ -0,0 +1,37 @@
/*!
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at http://mozilla.org/MPL/2.0/.
*/
import { Node } from "./Node";
export interface SceneProps {
readonly name?: string;
readonly nodes?: Node[];
}
export class Scene {
readonly type!: "Scene";
_name: string | undefined;
_nodes: Node[];
constructor({
name = "",
nodes = [],
}: SceneProps) {
Object.defineProperty(this, "type", { value: "Scene" });
this._name = name;
this._nodes = nodes;
}
}
export function isScene(value: unknown): value is Scene {
return Boolean(value) && (value as Scene).type === "Scene";
}

72
src/Texture2D.ts Normal file
View File

@ -0,0 +1,72 @@
/*!
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at http://mozilla.org/MPL/2.0/.
*/
export interface Texture2DProps {
name?: string;
device: GPUDevice;
width: number;
height: number;
}
export class Texture2D {
readonly type!: "Texture2D";
_name: string;
_device: GPUDevice;
_texture: GPUTexture;
_textureView: GPUTextureView;
constructor({
name = "",
device,
width,
height,
}: Texture2DProps) {
Object.defineProperty(this, "type", { value: "Texture2D" });
this._name = name;
this._device = device;
this._texture = device.createTexture({
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST,
size: { width, height },
format: "rgba8unorm",
});
this._textureView = this._texture.createView({
format: "rgba8unorm",
dimension: "2d",
});
}
dispose(): Texture2D {
this._texture.destroy();
return this;
}
get width(): number {
return this._texture.width;
}
get height(): number {
return this._texture.height;
}
writeTypedArray(data: Uint8Array): Texture2D {
this._device.queue.writeTexture(
{ texture: this._texture },
data,
{ bytesPerRow: 4 * this._texture.width },
{ width: this._texture.width, height: this._texture.height },
);
return this;
}
}
export function isTexture2D(value: unknown): value is Texture2D {
return Boolean(value) && (value as Texture2D).type === "Texture2D";
}

100
src/Vector3.ts Normal file
View File

@ -0,0 +1,100 @@
/*!
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at http://mozilla.org/MPL/2.0/.
*/
export interface Vector3Object {
readonly x: number;
readonly y: number;
readonly z: number;
}
export type Vector3Tuple = readonly [x: number, y: number, z: number];
export class Vector3 {
readonly type!: "Vector3";
x: number;
y: number;
z: number;
constructor(x: number, y: number, z: number) {
Object.defineProperty(this, "type", { value: "Vector3" });
this.x = x;
this.y = y;
this.z = z;
}
static fromObject(object: Vector3Object): Vector3 {
return new Vector3(object.x, object.y, object.z);
}
static fromTuple(tuple: Vector3Tuple): Vector3 {
return new Vector3(...tuple);
}
static zero(): Vector3 {
return new Vector3(0, 0, 0);
}
static one(): Vector3 {
return new Vector3(1, 1, 1);
}
set(x: number, y: number, z: number): Vector3 {
this.x = x;
this.y = y;
this.z = z;
return this;
}
setObject(object: Vector3Object): Vector3 {
this.x = object.x;
this.y = object.y;
this.z = object.z;
return this;
}
setTuple(tuple: Vector3Tuple): Vector3 {
this.x = tuple[0];
this.y = tuple[1];
this.z = tuple[2];
return this;
}
setZero(): Vector3 {
this.x = 0;
this.y = 0;
this.z = 0;
return this;
}
setOne(): Vector3 {
this.x = 1;
this.y = 1;
this.z = 1;
return this;
}
setX(x: number): Vector3 {
this.x = x;
return this;
}
setY(y: number): Vector3 {
this.y = y;
return this;
}
setZ(z: number): Vector3 {
this.z = z;
return this;
}
}
export function isVector3(value: unknown): value is Vector3 {
return Boolean(value) && (value as Vector3).type === "Vector3";
}

57
src/VertexBuffer.ts Normal file
View File

@ -0,0 +1,57 @@
/*!
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at http://mozilla.org/MPL/2.0/.
*/
import { Vector3Object } from "./Vector3";
export const VERTEX_SIZE = 12;
export class VertexBuffer {
readonly type!: "VertexBuffer";
_device: GPUDevice;
_buffer: GPUBuffer;
constructor(device: GPUDevice, vertexCount: number) {
Object.defineProperty(this, "type", { value: "VertexBuffer" });
this._device = device;
this._buffer = device.createBuffer({
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.VERTEX,
size: vertexCount * VERTEX_SIZE,
});
}
dispose(): VertexBuffer {
this._buffer.destroy();
return this;
}
get vertexCount(): number {
return this._buffer.size / VERTEX_SIZE | 0;
}
writeArray(offset: number, vertices: readonly Vector3Object[]): VertexBuffer {
const array = new Float32Array(vertices.length * 3);
for (let vi = 0, ptr = 0; vi < vertices.length; ++vi) {
const vertex = vertices[vi]!;
array[ptr++] = vertex.x;
array[ptr++] = vertex.y;
array[ptr++] = vertex.z;
}
this._device.queue.writeBuffer(this._buffer, offset * VERTEX_SIZE | 0, array);
return this;
}
writeTypedArray(offset: number, vertices: Float32Array): VertexBuffer {
this._device.queue.writeBuffer(this._buffer, offset * VERTEX_SIZE | 0, vertices);
return this;
}
}
export function isVertexBuffer(value: unknown): value is VertexBuffer {
return Boolean(value) && (value as VertexBuffer).type === "VertexBuffer";
}

View File

@ -1 +1,18 @@
export {};
/*!
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at http://mozilla.org/MPL/2.0/.
*/
export * from "./Camera";
export * from "./Color";
export * from "./IndexBuffer";
export * from "./Material";
export * from "./Matrix4x4";
export * from "./Mesh";
export * from "./Node";
export * from "./Quaternion";
export * from "./Scene";
export * from "./Texture2D";
export * from "./Vector3";
export * from "./VertexBuffer";

View File

@ -12,6 +12,7 @@
"target": "ES2022",
"lib": ["ES2022", "DOM"],
"typeRoots": ["./node_modules/@webgpu/types"],
"sourceMap": true,
"declaration": true,