Added the WebGpu Framework
This commit is contained in:
4
demo.js
4
demo.js
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
import Shader from "../framework/WebGpu.js"
|
import Shader from "./framework/WebGpu.js"
|
||||||
|
|
||||||
import Measure from "../framework/Measure.js"
|
import Measure from "./framework/Measure.js"
|
||||||
|
|
||||||
|
|
||||||
const adapter = await navigator.gpu.requestAdapter();
|
const adapter = await navigator.gpu.requestAdapter();
|
||||||
|
|||||||
83
framework/Camera.js
Normal file
83
framework/Camera.js
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
import Vector3 from "./Vector3.js";
|
||||||
|
import Matrix4 from "./Matrix4.js";
|
||||||
|
|
||||||
|
export default class Camera {
|
||||||
|
|
||||||
|
eye = new Vector3();
|
||||||
|
target = new Vector3();
|
||||||
|
up = new Vector3( 0, 1, 0 );
|
||||||
|
|
||||||
|
yaw = 0;
|
||||||
|
pitch = 0;
|
||||||
|
fovRadians = Math.PI / 4;
|
||||||
|
near = 0.1;
|
||||||
|
far = 3000.0;
|
||||||
|
distance = 10;
|
||||||
|
viewMatrix = new Float32Array( 16 );
|
||||||
|
|
||||||
|
constructor( eye = [0, 0, 5], target = [0, 0, 0], up = [0, 1, 0] ) {
|
||||||
|
|
||||||
|
this.eye = new Vector3( ...eye );
|
||||||
|
this.target = new Vector3( ...target );
|
||||||
|
this.up = new Vector3( ...up );
|
||||||
|
|
||||||
|
this.distance = Vector3.subtract( this.eye, this.target ).length();
|
||||||
|
|
||||||
|
this.viewMatrix = Matrix4.lookAt( this.eye, this.target, this.up );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
|
||||||
|
const x = this.distance * Math.cos( this.pitch ) * Math.sin( this.yaw );
|
||||||
|
const y = this.distance * Math.sin( this.pitch );
|
||||||
|
const z = this.distance * Math.cos( this.pitch ) * Math.cos( this.yaw );
|
||||||
|
|
||||||
|
this.eye = new Vector3(
|
||||||
|
x + this.target.x,
|
||||||
|
y + this.target.y,
|
||||||
|
z + this.target.z
|
||||||
|
);
|
||||||
|
|
||||||
|
this.viewMatrix = Matrix4.lookAt( this.eye, this.target, this.up );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
getViewMatrix() {
|
||||||
|
|
||||||
|
return this.viewMatrix;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
rotate( deltaYaw, deltaPitch ) {
|
||||||
|
|
||||||
|
this.yaw += deltaYaw;
|
||||||
|
this.pitch -= deltaPitch;
|
||||||
|
|
||||||
|
const maxPitch = Math.PI / 2 - 0.01;
|
||||||
|
|
||||||
|
if ( this.pitch > maxPitch ) this.pitch = maxPitch;
|
||||||
|
if ( this.pitch < -maxPitch ) this.pitch = -maxPitch;
|
||||||
|
|
||||||
|
this.update();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
zoom( delta ) {
|
||||||
|
|
||||||
|
this.distance += delta * 1;
|
||||||
|
|
||||||
|
if ( this.distance < 0.1 ) this.distance = 0.1;
|
||||||
|
|
||||||
|
this.update();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
setTarget( target ) {
|
||||||
|
|
||||||
|
this.target = new Vector3( ...target );
|
||||||
|
|
||||||
|
this.update();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
125
framework/Matrix4.js
Normal file
125
framework/Matrix4.js
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
import Vector3 from "./Vector3.js";
|
||||||
|
|
||||||
|
export default class Matrix4 {
|
||||||
|
|
||||||
|
static lookAt( eye, target, up ) {
|
||||||
|
|
||||||
|
const zAxis = Vector3.normalize( Vector3.subtract( eye, target ) );
|
||||||
|
|
||||||
|
const xAxis = Vector3.normalize( Vector3.cross( up, zAxis ) );
|
||||||
|
|
||||||
|
const yAxis = Vector3.cross( zAxis, xAxis );
|
||||||
|
|
||||||
|
return new Float32Array([
|
||||||
|
xAxis.x, yAxis.x, zAxis.x, 0,
|
||||||
|
xAxis.y, yAxis.y, zAxis.y, 0,
|
||||||
|
xAxis.z, yAxis.z, zAxis.z, 0,
|
||||||
|
-Vector3.dot( xAxis, eye ), -Vector3.dot( yAxis, eye ), -Vector3.dot( zAxis, eye ), 1,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static getColumn( matrix, index ) {
|
||||||
|
const i = index * 4;
|
||||||
|
|
||||||
|
return new Vector3(
|
||||||
|
matrix[ i + 0 ],
|
||||||
|
matrix[ i + 1 ],
|
||||||
|
matrix[ i + 2 ]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static createProjectionMatrix( camera, canvas ) {
|
||||||
|
return Matrix4.perspective(
|
||||||
|
camera.fovRadians,
|
||||||
|
canvas.width / canvas.height,
|
||||||
|
camera.near,
|
||||||
|
camera.far
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static invert( m ) {
|
||||||
|
const out = new Float32Array(16);
|
||||||
|
|
||||||
|
const m00 = m[0], m01 = m[1], m02 = m[2], m03 = m[3];
|
||||||
|
const m10 = m[4], m11 = m[5], m12 = m[6], m13 = m[7];
|
||||||
|
const m20 = m[8], m21 = m[9], m22 = m[10], m23 = m[11];
|
||||||
|
const m30 = m[12], m31 = m[13], m32 = m[14], m33 = m[15];
|
||||||
|
|
||||||
|
const a0 = m00 * m11 - m01 * m10;
|
||||||
|
const a1 = m00 * m12 - m02 * m10;
|
||||||
|
const a2 = m00 * m13 - m03 * m10;
|
||||||
|
const a3 = m01 * m12 - m02 * m11;
|
||||||
|
const a4 = m01 * m13 - m03 * m11;
|
||||||
|
const a5 = m02 * m13 - m03 * m12;
|
||||||
|
|
||||||
|
const b0 = m20 * m31 - m21 * m30;
|
||||||
|
const b1 = m20 * m32 - m22 * m30;
|
||||||
|
const b2 = m20 * m33 - m23 * m30;
|
||||||
|
const b3 = m21 * m32 - m22 * m31;
|
||||||
|
const b4 = m21 * m33 - m23 * m31;
|
||||||
|
const b5 = m22 * m33 - m23 * m32;
|
||||||
|
|
||||||
|
const det = a0 * b5 - a1 * b4 + a2 * b3 + a3 * b2 - a4 * b1 + a5 * b0;
|
||||||
|
|
||||||
|
if (det === 0) return null;
|
||||||
|
|
||||||
|
const invDet = 1 / det;
|
||||||
|
|
||||||
|
out[0] = ( m11 * b5 - m12 * b4 + m13 * b3) * invDet;
|
||||||
|
out[1] = (-m01 * b5 + m02 * b4 - m03 * b3) * invDet;
|
||||||
|
out[2] = ( m31 * a5 - m32 * a4 + m33 * a3) * invDet;
|
||||||
|
out[3] = (-m21 * a5 + m22 * a4 - m23 * a3) * invDet;
|
||||||
|
|
||||||
|
out[4] = (-m10 * b5 + m12 * b2 - m13 * b1) * invDet;
|
||||||
|
out[5] = ( m00 * b5 - m02 * b2 + m03 * b1) * invDet;
|
||||||
|
out[6] = (-m30 * a5 + m32 * a2 - m33 * a1) * invDet;
|
||||||
|
out[7] = ( m20 * a5 - m22 * a2 + m23 * a1) * invDet;
|
||||||
|
|
||||||
|
out[8] = ( m10 * b4 - m11 * b2 + m13 * b0) * invDet;
|
||||||
|
out[9] = (-m00 * b4 + m01 * b2 - m03 * b0) * invDet;
|
||||||
|
out[10] = ( m30 * a4 - m31 * a2 + m33 * a0) * invDet;
|
||||||
|
out[11] = (-m20 * a4 + m21 * a2 - m23 * a0) * invDet;
|
||||||
|
|
||||||
|
out[12] = (-m10 * b3 + m11 * b1 - m12 * b0) * invDet;
|
||||||
|
out[13] = ( m00 * b3 - m01 * b1 + m02 * b0) * invDet;
|
||||||
|
out[14] = (-m30 * a3 + m31 * a1 - m32 * a0) * invDet;
|
||||||
|
out[15] = ( m20 * a3 - m21 * a1 + m22 * a0) * invDet;
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static perspective( fovRadians, aspect, near, far ) {
|
||||||
|
|
||||||
|
const f = 1.0 / Math.tan( fovRadians / 2 );
|
||||||
|
|
||||||
|
const nf = 1 / ( near - far );
|
||||||
|
|
||||||
|
return new Float32Array([
|
||||||
|
f / aspect, 0, 0, 0,
|
||||||
|
0, f, 0, 0,
|
||||||
|
0, 0, (far + near) * nf, -1,
|
||||||
|
0, 0, (2 * far * near) * nf, 0,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static multiply( a, b ) {
|
||||||
|
const out = new Float32Array(16);
|
||||||
|
|
||||||
|
for ( let col = 0; col < 4; col++ ) {
|
||||||
|
for ( let row = 0; row < 4; row++ ) {
|
||||||
|
let sum = 0;
|
||||||
|
|
||||||
|
for ( let k = 0; k < 4; k++ ) {
|
||||||
|
// a is column-major: element at col k, row row => a[k*4 + row]
|
||||||
|
// b is column-major: element at col col, row k => b[col*4 + k]
|
||||||
|
sum += a[k * 4 + row] * b[col * 4 + k];
|
||||||
|
}
|
||||||
|
|
||||||
|
out[col * 4 + row] = sum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
49
framework/Measure.js
Normal file
49
framework/Measure.js
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
export default class Measure {
|
||||||
|
|
||||||
|
startTimes = {};
|
||||||
|
|
||||||
|
endTimes = {};
|
||||||
|
|
||||||
|
writeToPage = false;
|
||||||
|
|
||||||
|
element = false;
|
||||||
|
|
||||||
|
start ( label ) {
|
||||||
|
|
||||||
|
this.startTimes[ label ] = performance.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
end ( label ) {
|
||||||
|
|
||||||
|
this.endTimes[ label ] = performance.now();
|
||||||
|
|
||||||
|
this.log( label );
|
||||||
|
}
|
||||||
|
|
||||||
|
getElapsed ( label ) {
|
||||||
|
|
||||||
|
if ( this.startTimes[ label ] === undefined || this.endTimes[ label ] === undefined ) {
|
||||||
|
|
||||||
|
throw new Error( "Start or end time missing for label: " + label );
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.endTimes[ label ] - this.startTimes[ label ];
|
||||||
|
}
|
||||||
|
|
||||||
|
log ( label ) {
|
||||||
|
|
||||||
|
const elapsed = this.getElapsed( label );
|
||||||
|
|
||||||
|
if( this.writeToPage ) {
|
||||||
|
|
||||||
|
var p = document.createElement("p")
|
||||||
|
|
||||||
|
p.innerText = label + " took " + elapsed.toFixed(3) + " ms";
|
||||||
|
|
||||||
|
this.element.appendChild( p );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log( label + " took " + elapsed.toFixed(3) + " ms" );
|
||||||
|
}
|
||||||
|
}
|
||||||
11
framework/Request.js
Normal file
11
framework/Request.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
export class Request {
|
||||||
|
|
||||||
|
constructor( method, payload = {} ) {
|
||||||
|
|
||||||
|
this.method = method; // method name to call on Controller, e.g. "Ping"
|
||||||
|
|
||||||
|
this.payload = payload; // any data for the method
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
67
framework/ShaderInpector.js
Normal file
67
framework/ShaderInpector.js
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
|
||||||
|
class shaderDebugger{
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
|
||||||
|
var shaders = document.shaders;
|
||||||
|
|
||||||
|
var select = document.querySelector(".selectDebugShader");
|
||||||
|
|
||||||
|
for (var i = 0; i < shaders.length; i++) {
|
||||||
|
|
||||||
|
var currentShader = shaders[i];
|
||||||
|
|
||||||
|
var option = document.createElement("option");
|
||||||
|
|
||||||
|
option.innerText = currentShader.path;
|
||||||
|
|
||||||
|
option.id = i;
|
||||||
|
|
||||||
|
select.appendChild( option );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
document.querySelector( "#showBuffers" ).addEventListener( "click", async function() {
|
||||||
|
|
||||||
|
var select = document.querySelector(".selectDebugShader");
|
||||||
|
|
||||||
|
var selectedIndex = select.selectedIndex;
|
||||||
|
|
||||||
|
var selectedShader = document.shaders[ selectedIndex ]
|
||||||
|
|
||||||
|
const keysArray = Array.from( selectedShader.buffers );
|
||||||
|
|
||||||
|
console.log("\n\n\n\n -------------------- Debugging Shader --------------- \n\n\n\n");
|
||||||
|
|
||||||
|
console.log( "Shader Path: ", selectedShader.path );
|
||||||
|
|
||||||
|
console.log( selectedShader );
|
||||||
|
|
||||||
|
for (var i = 0; i < keysArray.length; i++) {
|
||||||
|
|
||||||
|
const bindingInfo = selectedShader.bindings.find( b => b.varName === keysArray[i][0] );
|
||||||
|
|
||||||
|
|
||||||
|
if( bindingInfo ) {
|
||||||
|
|
||||||
|
if( bindingInfo.type == "storage" ) {
|
||||||
|
|
||||||
|
await selectedShader.debugBuffer( keysArray[i][0] );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
console.log("this is a Uniform", keysArray, selectedShader.bindings);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default shaderDebugger;
|
||||||
60
framework/Vector3.js
Normal file
60
framework/Vector3.js
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
export default class Vector3 {
|
||||||
|
|
||||||
|
x = 0;
|
||||||
|
y = 0;
|
||||||
|
z = 0;
|
||||||
|
|
||||||
|
constructor( x = 0, y = 0, z = 0 ) {
|
||||||
|
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static subtract( a, b ) {
|
||||||
|
|
||||||
|
return new Vector3( a.x - b.x, a.y - b.y, a.z - b.z );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
length() {
|
||||||
|
|
||||||
|
return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static cross( a, b ) {
|
||||||
|
|
||||||
|
return new Vector3(
|
||||||
|
|
||||||
|
a.y * b.z - a.z * b.y,
|
||||||
|
a.z * b.x - a.x * b.z,
|
||||||
|
a.x * b.y - a.y * b.x
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static dot( a, b ) {
|
||||||
|
|
||||||
|
return a.x * b.x + a.y * b.y + a.z * b.z;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static normalize( v ) {
|
||||||
|
|
||||||
|
const length = Math.sqrt( v.x * v.x + v.y * v.y + v.z * v.z );
|
||||||
|
|
||||||
|
if ( length > 0.00001 ) {
|
||||||
|
|
||||||
|
return new Vector3( v.x / length, v.y / length, v.z / length );
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
return new Vector3( 0, 0, 0 );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
1893
framework/WebGpu.js
Normal file
1893
framework/WebGpu.js
Normal file
File diff suppressed because it is too large
Load Diff
1960
framework/WebGpu_node.js
Normal file
1960
framework/WebGpu_node.js
Normal file
File diff suppressed because it is too large
Load Diff
113
framework/eventManager.js
Normal file
113
framework/eventManager.js
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
// eventManager.js
|
||||||
|
|
||||||
|
export default class EventManager {
|
||||||
|
|
||||||
|
isDragging = false;
|
||||||
|
|
||||||
|
lastX = 0;
|
||||||
|
|
||||||
|
lastY = 0;
|
||||||
|
|
||||||
|
camera;
|
||||||
|
|
||||||
|
canvas;
|
||||||
|
|
||||||
|
setCanvas( canvas ) {
|
||||||
|
|
||||||
|
this.canvas = canvas;
|
||||||
|
|
||||||
|
|
||||||
|
//this.registerEventListeners();
|
||||||
|
|
||||||
|
//this.handleResize();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
setup( canvas, camera ) {
|
||||||
|
|
||||||
|
this.canvas = canvas;
|
||||||
|
|
||||||
|
this.camera = camera;
|
||||||
|
|
||||||
|
//this.registerEventListeners();
|
||||||
|
|
||||||
|
//this.handleResize();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
registerEventListeners() {
|
||||||
|
|
||||||
|
this.canvas.addEventListener( "mousedown", this.onMouseDown.bind(this) );
|
||||||
|
|
||||||
|
this.canvas.addEventListener( "mouseup", this.onMouseUp.bind(this) );
|
||||||
|
|
||||||
|
this.canvas.addEventListener( "mouseleave", this.onMouseLeave.bind(this) );
|
||||||
|
|
||||||
|
this.canvas.addEventListener( "mousemove", this.onMouseMove.bind(this) );
|
||||||
|
|
||||||
|
this.canvas.addEventListener( "wheel", this.onWheel.bind(this), { passive: false } );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
resize( event ) {
|
||||||
|
|
||||||
|
this.canvas.width = event.width;
|
||||||
|
|
||||||
|
this.canvas.height = event.height;
|
||||||
|
|
||||||
|
//this.canvas.width = window.innerWidth;
|
||||||
|
|
||||||
|
//this.canvas.height = window.innerHeight;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
mousedown( event ) {
|
||||||
|
|
||||||
|
console.log("mouseDownHandler");
|
||||||
|
|
||||||
|
this.isDragging = true;
|
||||||
|
|
||||||
|
this.lastX = event.clientX;
|
||||||
|
|
||||||
|
this.lastY = event.clientY;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
mouseup( event ) {
|
||||||
|
|
||||||
|
this.isDragging = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
mouseleave( event ) {
|
||||||
|
|
||||||
|
this.isDragging = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
mousemove( event ) {
|
||||||
|
|
||||||
|
if ( !this.isDragging ) return;
|
||||||
|
|
||||||
|
const deltaX = ( event.clientX - this.lastX ) * 0.005;
|
||||||
|
|
||||||
|
const deltaY = ( event.clientY - this.lastY ) * 0.005;
|
||||||
|
|
||||||
|
this.camera.rotate( deltaX, -deltaY );
|
||||||
|
|
||||||
|
this.lastX = event.clientX;
|
||||||
|
|
||||||
|
this.lastY = event.clientY;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
wheel( event ) {
|
||||||
|
|
||||||
|
|
||||||
|
const delta = event.deltaY * 0.01;
|
||||||
|
|
||||||
|
this.camera.zoom( delta );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
214
framework/eventManager_node.js
Normal file
214
framework/eventManager_node.js
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
// eventManager.js
|
||||||
|
|
||||||
|
import sdl from '@kmamal/sdl'
|
||||||
|
|
||||||
|
var isNode = true;
|
||||||
|
|
||||||
|
if ( typeof window === 'undefined' ) {
|
||||||
|
|
||||||
|
//isNode = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("isNode", isNode);
|
||||||
|
|
||||||
|
export default class EventManager {
|
||||||
|
|
||||||
|
isDragging = false;
|
||||||
|
|
||||||
|
lastX = 0;
|
||||||
|
|
||||||
|
lastY = 0;
|
||||||
|
|
||||||
|
camera;
|
||||||
|
|
||||||
|
canvas;
|
||||||
|
|
||||||
|
setCanvas( canvas ) {
|
||||||
|
|
||||||
|
this.canvas = canvas;
|
||||||
|
|
||||||
|
|
||||||
|
//this.registerEventListeners();
|
||||||
|
|
||||||
|
//this.handleResize();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
setup( canvas, camera ) {
|
||||||
|
|
||||||
|
this.canvas = canvas;
|
||||||
|
|
||||||
|
this.camera = camera;
|
||||||
|
|
||||||
|
//this.registerEventListeners();
|
||||||
|
|
||||||
|
//this.handleResize();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
registerEventListeners() {
|
||||||
|
|
||||||
|
this.canvas.addEventListener( "mousedown", this.onMouseDown.bind(this) );
|
||||||
|
|
||||||
|
this.canvas.addEventListener( "mouseup", this.onMouseUp.bind(this) );
|
||||||
|
|
||||||
|
this.canvas.addEventListener( "mouseleave", this.onMouseLeave.bind(this) );
|
||||||
|
|
||||||
|
this.canvas.addEventListener( "mousemove", this.onMouseMove.bind(this) );
|
||||||
|
|
||||||
|
this.canvas.addEventListener( "wheel", this.onWheel.bind(this), { passive: false } );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
registerEventListenersNode() {
|
||||||
|
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
this.canvas.on('mouseMove', function( event ) {
|
||||||
|
|
||||||
|
that.mousemove( event )
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
this.canvas.on('mouseButtonDown', function( event ) {
|
||||||
|
|
||||||
|
that.mousedown( event )
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
this.canvas.on('mouseButtonUp', function( event ) {
|
||||||
|
|
||||||
|
that.mouseup( event )
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
this.canvas.on( "mouseButtonDown", this.onMouseDown.bind(this) );
|
||||||
|
|
||||||
|
this.canvas.on( "mouseButtonUp", this.onMouseUp.bind(this) );
|
||||||
|
|
||||||
|
//this.canvas.on( "mouseleave", this.onMouseLeave.bind(this) );
|
||||||
|
|
||||||
|
this.canvas.on( "mouseMove", this.onMouseMove.bind(this) );
|
||||||
|
|
||||||
|
this.canvas.on( "mouseWheel", this.onWheel.bind(this), { passive: false } );
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
resize( event ) {
|
||||||
|
|
||||||
|
this.canvas.width = event.width;
|
||||||
|
|
||||||
|
this.canvas.height = event.height;
|
||||||
|
|
||||||
|
//this.canvas.width = window.innerWidth;
|
||||||
|
|
||||||
|
//this.canvas.height = window.innerHeight;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
mousedown( event ) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
this.isDragging = true;
|
||||||
|
|
||||||
|
if( isNode ) {
|
||||||
|
|
||||||
|
var mouseX = event.x;
|
||||||
|
|
||||||
|
var mouseY = event.y;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
var mouseX = event.clientX;
|
||||||
|
|
||||||
|
var mouseY = event.clientY;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//console.log("mouseDownHandler", mouseX, mouseY);
|
||||||
|
|
||||||
|
if( isNode ) {
|
||||||
|
|
||||||
|
this.lastX = mouseX;
|
||||||
|
|
||||||
|
this.lastY = mouseY;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
this.lastX = mouseX;
|
||||||
|
|
||||||
|
this.lastY = mouseY;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
mouseup( event ) {
|
||||||
|
|
||||||
|
this.isDragging = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
mouseleave( event ) {
|
||||||
|
|
||||||
|
this.isDragging = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
mousemove( event ) {
|
||||||
|
|
||||||
|
if( isNode ) {
|
||||||
|
|
||||||
|
var mouseX = event.x;
|
||||||
|
|
||||||
|
var mouseY = event.y;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
var mouseX = event.clientX;
|
||||||
|
|
||||||
|
var mouseY = event.clientY;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if ( !this.isDragging ) return;
|
||||||
|
|
||||||
|
const deltaX = ( mouseX - this.lastX ) * 0.005;
|
||||||
|
|
||||||
|
const deltaY = ( mouseY - this.lastY ) * 0.005;
|
||||||
|
|
||||||
|
//console.log("mousemove", mouseX, mouseY);
|
||||||
|
|
||||||
|
this.camera.rotate( deltaX, -deltaY );
|
||||||
|
|
||||||
|
this.lastX = mouseX;
|
||||||
|
|
||||||
|
this.lastY = mouseY;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
wheel( event ) {
|
||||||
|
|
||||||
|
|
||||||
|
const delta = event.deltaY * 0.01;
|
||||||
|
|
||||||
|
this.camera.zoom( delta );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
6
framework/package.json
Normal file
6
framework/package.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"type": "module",
|
||||||
|
"dependencies": {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
168
server.js
Normal file
168
server.js
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
import http from "http";
|
||||||
|
|
||||||
|
import { readdir } from "fs/promises";
|
||||||
|
import { stat } from "fs/promises";
|
||||||
|
import { readFile } from "fs/promises";
|
||||||
|
import { join } from "path";
|
||||||
|
import { dirname } from "path";
|
||||||
|
import { fileURLToPath } from "url";
|
||||||
|
|
||||||
|
|
||||||
|
class App
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
constructor( )
|
||||||
|
{
|
||||||
|
|
||||||
|
const selfPath = fileURLToPath( import.meta.url );
|
||||||
|
|
||||||
|
this.rootPath = dirname( selfPath );
|
||||||
|
this.httpServer = null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async start( )
|
||||||
|
{
|
||||||
|
|
||||||
|
this.httpServer = http.createServer( this.handleRequest.bind( this ) );
|
||||||
|
|
||||||
|
this.httpServer.listen( 2030 );
|
||||||
|
|
||||||
|
console.log("Server started on port http://localhost:2030/");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async handleRequest( req, res )
|
||||||
|
{
|
||||||
|
|
||||||
|
const requestedPath = decodeURI( req.url );
|
||||||
|
const fullPath = join( this.rootPath, requestedPath );
|
||||||
|
|
||||||
|
const exists = await this.checkFileExists( fullPath );
|
||||||
|
|
||||||
|
if ( !exists )
|
||||||
|
{
|
||||||
|
|
||||||
|
res.statusCode = 404;
|
||||||
|
res.end( "Not Found" );
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const stats = await stat( fullPath );
|
||||||
|
|
||||||
|
if ( stats.isDirectory( ) )
|
||||||
|
{
|
||||||
|
|
||||||
|
const indexPath = join( fullPath, "index.html" );
|
||||||
|
const indexExists = await this.checkFileExists( indexPath );
|
||||||
|
|
||||||
|
if ( indexExists )
|
||||||
|
{
|
||||||
|
|
||||||
|
await this.sendFile( indexPath, res );
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.sendDirectoryListing( fullPath, requestedPath, res );
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.sendFile( fullPath, res );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async sendFile( path, res )
|
||||||
|
{
|
||||||
|
|
||||||
|
const contentType = this.getContentType( path );
|
||||||
|
const fileData = await readFile( path );
|
||||||
|
|
||||||
|
res.setHeader( "Content-Type", contentType );
|
||||||
|
res.statusCode = 200;
|
||||||
|
|
||||||
|
res.end( fileData );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async sendDirectoryListing( dirPath, urlPath, res )
|
||||||
|
{
|
||||||
|
|
||||||
|
const entries = await readdir( dirPath, { withFileTypes : true } );
|
||||||
|
|
||||||
|
let html = "<html><body><h1>Index of " + urlPath + "</h1><ul>";
|
||||||
|
|
||||||
|
let i = 0;
|
||||||
|
|
||||||
|
while ( i < entries.length )
|
||||||
|
{
|
||||||
|
|
||||||
|
const e = entries[ i ].name;
|
||||||
|
const link = urlPath.endsWith( "/" )
|
||||||
|
? urlPath + e
|
||||||
|
: urlPath + "/" + e;
|
||||||
|
|
||||||
|
html = html + "<li><a href=\"" + link + "\">" + e + "</a></li>";
|
||||||
|
|
||||||
|
i = i + 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
html = html + "</ul></body></html>";
|
||||||
|
|
||||||
|
res.setHeader( "Content-Type", "text/html" );
|
||||||
|
res.statusCode = 200;
|
||||||
|
|
||||||
|
res.end( html );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async checkFileExists( path )
|
||||||
|
{
|
||||||
|
|
||||||
|
const exists = await stat( path )
|
||||||
|
.then( function( ) { return true; } )
|
||||||
|
.catch( function( ) { return false; } );
|
||||||
|
|
||||||
|
return exists;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
getContentType( path )
|
||||||
|
{
|
||||||
|
|
||||||
|
const lower = path.toLowerCase( );
|
||||||
|
|
||||||
|
if ( lower.endsWith( ".html" ) ) return "text/html";
|
||||||
|
if ( lower.endsWith( ".css" ) ) return "text/css";
|
||||||
|
if ( lower.endsWith( ".js" ) ) return "text/javascript";
|
||||||
|
if ( lower.endsWith( ".json" ) ) return "application/json";
|
||||||
|
if ( lower.endsWith( ".wasm" ) ) return "application/wasm";
|
||||||
|
if ( lower.endsWith( ".png" ) ) return "image/png";
|
||||||
|
if ( lower.endsWith( ".jpg" ) ) return "image/jpeg";
|
||||||
|
if ( lower.endsWith( ".jpeg" ) ) return "image/jpeg";
|
||||||
|
if ( lower.endsWith( ".gif" ) ) return "image/gif";
|
||||||
|
if ( lower.endsWith( ".svg" ) ) return "image/svg+xml";
|
||||||
|
if ( lower.endsWith( ".wgsl" ) ) return "text/plain";
|
||||||
|
if ( lower.endsWith( ".txt" ) ) return "text/plain";
|
||||||
|
|
||||||
|
return "application/octet-stream";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const app = new App( );
|
||||||
|
|
||||||
|
await app.start( );
|
||||||
Reference in New Issue
Block a user