Define basic data structure
This commit is contained in:
parent
31732e11a8
commit
e2cef2d172
@ -2,7 +2,11 @@
|
|||||||
"name": "oktaeder",
|
"name": "oktaeder",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"description": "3D rendering library for WebGPU",
|
"description": "3D rendering library for WebGPU",
|
||||||
"keywords": ["3d", "gltf", "wegbpu"],
|
"keywords": [
|
||||||
|
"3d",
|
||||||
|
"gltf",
|
||||||
|
"wegbpu"
|
||||||
|
],
|
||||||
"homepage": "https://github.com/iszn11/oktaeder",
|
"homepage": "https://github.com/iszn11/oktaeder",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/iszn11/oktaeder/issues"
|
"url": "https://github.com/iszn11/oktaeder/issues"
|
||||||
@ -20,6 +24,7 @@
|
|||||||
"tslib": "^2.6.1"
|
"tslib": "^2.6.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@webgpu/types": "^0.1.34",
|
||||||
"typescript": "5.1.6"
|
"typescript": "5.1.6"
|
||||||
},
|
},
|
||||||
"exports": {
|
"exports": {
|
||||||
|
7
pnpm-lock.yaml
generated
7
pnpm-lock.yaml
generated
@ -10,12 +10,19 @@ dependencies:
|
|||||||
version: 2.6.1
|
version: 2.6.1
|
||||||
|
|
||||||
devDependencies:
|
devDependencies:
|
||||||
|
'@webgpu/types':
|
||||||
|
specifier: ^0.1.34
|
||||||
|
version: 0.1.34
|
||||||
typescript:
|
typescript:
|
||||||
specifier: 5.1.6
|
specifier: 5.1.6
|
||||||
version: 5.1.6
|
version: 5.1.6
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
|
/@webgpu/types@0.1.34:
|
||||||
|
resolution: {integrity: sha512-9mXtH+CC8q+Ku7Z+1XazNIte81FvfdXwR2lLRO7Ykzjd/hh1J1krJa0gtnkF1kvP11psUmKEPKo7iMTeEcUpNA==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/tslib@2.6.1:
|
/tslib@2.6.1:
|
||||||
resolution: {integrity: sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==}
|
resolution: {integrity: sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==}
|
||||||
dev: false
|
dev: false
|
||||||
|
115
src/Camera.ts
Normal file
115
src/Camera.ts
Normal 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
266
src/Color.ts
Normal 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
49
src/IndexBuffer.ts
Normal 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
76
src/Material.ts
Normal 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
246
src/Matrix4x4.ts
Normal 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
42
src/Mesh.ts
Normal 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
84
src/Node.ts
Normal 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
73
src/Quaternion.ts
Normal 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
37
src/Scene.ts
Normal 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
72
src/Texture2D.ts
Normal 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
100
src/Vector3.ts
Normal 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
57
src/VertexBuffer.ts
Normal 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";
|
||||||
|
}
|
@ -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";
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
"target": "ES2022",
|
"target": "ES2022",
|
||||||
"lib": ["ES2022", "DOM"],
|
"lib": ["ES2022", "DOM"],
|
||||||
|
"typeRoots": ["./node_modules/@webgpu/types"],
|
||||||
|
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
|
Loading…
Reference in New Issue
Block a user