main repo

This commit is contained in:
Basilosaurusrex
2025-11-24 18:09:40 +01:00
parent b636ee5e70
commit f027651f9b
34146 changed files with 4436636 additions and 0 deletions

263
node_modules/ogl/README.md generated vendored Normal file
View File

@@ -0,0 +1,263 @@
<p align="center">
<img src="https://github.com/oframe/ogl/raw/master/examples/assets/ogl.png" alt="OGL" width="510" />
</p>
<h1 align="center">OGL</h1>
<p align="center">
<a href="https://npmjs.org/package/ogl">
<img src="https://img.shields.io/npm/v/ogl.svg" alt="version" />
</a>
<a href="https://github.com/oframe/ogl/blob/master/LICENSE">
<img src="https://img.shields.io/npm/l/ogl.svg" alt="license" />
</a>
<a href="https://bundlephobia.com/result?p=ogl">
<img src="https://badgen.net/bundlephobia/minzip/ogl" alt="size" />
</a>
</p>
<p align="center"><b>Minimal WebGL library.</b></p>
<br />
[See the Examples!](https://oframe.github.io/ogl/examples)
OGL is a small, effective WebGL library aimed at developers who like minimal layers of abstraction, and are interested in creating their own shaders.
Written in es6 modules with zero dependencies, the API shares many similarities with ThreeJS, however it is tightly coupled with WebGL and comes with much fewer features.
In its design, the library does the minimum abstraction necessary, so devs should still feel comfortable using it in conjunction with native WebGL commands.
Keeping the level of abstraction low helps to make the library easier to understand, extend, and also makes it more practical as a WebGL learning resource.
## Install
[Download](https://github.com/oframe/ogl/archive/master.zip)
**or**
```
npm i ogl
```
**or**
```
yarn add ogl
```
## Examples
[Show me what you got!](https://oframe.github.io/ogl/examples) - Explore a comprehensive list of examples, with comments in the source code.
Inspired by the effectiveness of ThreeJS' examples, they will hopefully serve as reference for how to use the library, and to achieve a wide range of techniques.
## Weight
Even though the source is modular, as a guide, below are the complete component download sizes.
| Component | Size (minzipped) |
| --------- | ---------------: |
| Core | 8kb |
| Math | 6kb |
| Extras | 15kb |
| Total | 29kb |
With tree-shaking applied in a build step, one can expect the final size to be much lighter than the values above.
## Usage
If installed amongst your project files, importing can be done from one single entry point.
```js
import { ... } from './path/to/src/index.js';
```
Else if using a bundler or import maps with node modules, then import directly from the installed node module.
```js
import { ... } from 'ogl';
```
By default, the ES source modules are loaded (`src/index.js`).
As another alternative, you could load from a CDN, using either the jsdelivr, unpkg or skypack services.
```js
import { ... } from 'https://cdn.jsdelivr.net/npm/ogl';
import { ... } from 'https://unpkg.com/ogl';
import { ... } from 'https://cdn.skypack.dev/ogl';
```
If you take this route, I would highly recommend defining a specific version (append `@x.x.x`) to avoid code breaking, rather than fetching the latest version, as per the above links.
As a basic API example, below renders a spinning white cube.
```js
import { Renderer, Camera, Transform, Box, Program, Mesh } from 'ogl';
{
const renderer = new Renderer();
const gl = renderer.gl;
document.body.appendChild(gl.canvas);
const camera = new Camera(gl);
camera.position.z = 5;
function resize() {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.perspective({
aspect: gl.canvas.width / gl.canvas.height,
});
}
window.addEventListener('resize', resize, false);
resize();
const scene = new Transform();
const geometry = new Box(gl);
const program = new Program(gl, {
vertex: /* glsl */ `
attribute vec3 position;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
void main() {
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragment: /* glsl */ `
void main() {
gl_FragColor = vec4(1.0);
}
`,
});
const mesh = new Mesh(gl, { geometry, program });
mesh.setParent(scene);
requestAnimationFrame(update);
function update(t) {
requestAnimationFrame(update);
mesh.rotation.y -= 0.04;
mesh.rotation.x += 0.03;
renderer.render({ scene, camera });
}
}
```
Here you can play with the above template live in a codesandbox
https://codesandbox.io/s/ogl-5i69p
For a simpler use, such as a full-screen shader, more of the core can be omitted as a scene graph (Transform) and projection matrices (Camera) are not necessary. We'll also show how to easily create custom geometry.
```js
import { Renderer, Geometry, Program, Mesh } from 'ogl';
{
const renderer = new Renderer({
width: window.innerWidth,
height: window.innerHeight,
});
const gl = renderer.gl;
document.body.appendChild(gl.canvas);
// Triangle that covers viewport, with UVs that still span 0 > 1 across viewport
const geometry = new Geometry(gl, {
position: { size: 2, data: new Float32Array([-1, -1, 3, -1, -1, 3]) },
uv: { size: 2, data: new Float32Array([0, 0, 2, 0, 0, 2]) },
});
// Alternatively, you could use the Triangle class.
const program = new Program(gl, {
vertex: /* glsl */ `
attribute vec2 uv;
attribute vec2 position;
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = vec4(position, 0, 1);
}
`,
fragment: /* glsl */ `
precision highp float;
uniform float uTime;
varying vec2 vUv;
void main() {
gl_FragColor.rgb = vec3(0.8, 0.7, 1.0) + 0.3 * cos(vUv.xyx + uTime);
gl_FragColor.a = 1.0;
}
`,
uniforms: {
uTime: { value: 0 },
},
});
const mesh = new Mesh(gl, { geometry, program });
requestAnimationFrame(update);
function update(t) {
requestAnimationFrame(update);
program.uniforms.uTime.value = t * 0.001;
// Don't need a camera if camera uniforms aren't required
renderer.render({ scene: mesh });
}
}
```
## Structure
In an attempt to keep things light and modular, the library is split up into three components: **Math**, **Core**, and **Extras**.
The **Math** component is an extension of [gl-matrix](http://glmatrix.net/), providing instancable classes that extend Array for each of the module types. 8kb when gzipped, it has no dependencies and can be used separately.
The **Core** is made up of the following:
- Geometry.js
- Program.js
- Renderer.js
- Camera.js
- Transform.js
- Mesh.js
- Texture.js
- RenderTarget.js
Any additional layers of abstraction will be included as **Extras**, and not part of the core as to reduce bloat. These provide a wide breadth of functionality, ranging from simple to advanced.
## Unlicense
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <https://unlicense.org>

46
node_modules/ogl/package.json generated vendored Normal file
View File

@@ -0,0 +1,46 @@
{
"name": "ogl",
"version": "1.0.11",
"description": "WebGL Library",
"type": "module",
"main": "./src/index.js",
"exports": {
".": {
"types": "./types/index.d.ts",
"default": "./src/index.js"
},
"./src/*": "./src/*"
},
"sideEffects": false,
"types": "./types/index.d.ts",
"directories": {
"example": "examples"
},
"repository": {
"type": "git",
"url": "git+https://gordonnl@github.com/oframe/ogl.git"
},
"author": {
"name": "Nathan Gordon",
"email": "gordonnl@gmail.com",
"url": "https://twitter.com/gordonnl"
},
"license": "Unlicense",
"bugs": {
"url": "https://github.com/oframe/ogl/issues"
},
"homepage": "https://github.com/oframe/ogl#readme",
"prettier": {
"arrowParens": "always",
"bracketSpacing": true,
"endOfLine": "lf",
"htmlWhitespaceSensitivity": "css",
"printWidth": 200,
"quoteProps": "as-needed",
"semi": true,
"singleQuote": true,
"tabWidth": 4,
"trailingComma": "es5",
"useTabs": false
}
}

137
node_modules/ogl/src/core/Camera.js generated vendored Normal file
View File

@@ -0,0 +1,137 @@
import { Transform } from './Transform.js';
import { Mat4 } from '../math/Mat4.js';
import { Vec3 } from '../math/Vec3.js';
const tempMat4 = /* @__PURE__ */ new Mat4();
const tempVec3a = /* @__PURE__ */ new Vec3();
const tempVec3b = /* @__PURE__ */ new Vec3();
export class Camera extends Transform {
constructor(gl, { near = 0.1, far = 100, fov = 45, aspect = 1, left, right, bottom, top, zoom = 1 } = {}) {
super();
Object.assign(this, { near, far, fov, aspect, left, right, bottom, top, zoom });
this.projectionMatrix = new Mat4();
this.viewMatrix = new Mat4();
this.projectionViewMatrix = new Mat4();
this.worldPosition = new Vec3();
// Use orthographic if left/right set, else default to perspective camera
this.type = left || right ? 'orthographic' : 'perspective';
if (this.type === 'orthographic') this.orthographic();
else this.perspective();
}
perspective({ near = this.near, far = this.far, fov = this.fov, aspect = this.aspect } = {}) {
Object.assign(this, { near, far, fov, aspect });
this.projectionMatrix.fromPerspective({ fov: fov * (Math.PI / 180), aspect, near, far });
this.type = 'perspective';
return this;
}
orthographic({
near = this.near,
far = this.far,
left = this.left || -1,
right = this.right || 1,
bottom = this.bottom || -1,
top = this.top || 1,
zoom = this.zoom,
} = {}) {
Object.assign(this, { near, far, left, right, bottom, top, zoom });
left /= zoom;
right /= zoom;
bottom /= zoom;
top /= zoom;
this.projectionMatrix.fromOrthogonal({ left, right, bottom, top, near, far });
this.type = 'orthographic';
return this;
}
updateMatrixWorld() {
super.updateMatrixWorld();
this.viewMatrix.inverse(this.worldMatrix);
this.worldMatrix.getTranslation(this.worldPosition);
// used for sorting
this.projectionViewMatrix.multiply(this.projectionMatrix, this.viewMatrix);
return this;
}
updateProjectionMatrix() {
if (this.type === 'perspective') {
return this.perspective();
} else {
return this.orthographic();
}
}
lookAt(target) {
super.lookAt(target, true);
return this;
}
// Project 3D coordinate to 2D point
project(v) {
v.applyMatrix4(this.viewMatrix);
v.applyMatrix4(this.projectionMatrix);
return this;
}
// Unproject 2D point to 3D coordinate
unproject(v) {
v.applyMatrix4(tempMat4.inverse(this.projectionMatrix));
v.applyMatrix4(this.worldMatrix);
return this;
}
updateFrustum() {
if (!this.frustum) {
this.frustum = [new Vec3(), new Vec3(), new Vec3(), new Vec3(), new Vec3(), new Vec3()];
}
const m = this.projectionViewMatrix;
this.frustum[0].set(m[3] - m[0], m[7] - m[4], m[11] - m[8]).constant = m[15] - m[12]; // -x
this.frustum[1].set(m[3] + m[0], m[7] + m[4], m[11] + m[8]).constant = m[15] + m[12]; // +x
this.frustum[2].set(m[3] + m[1], m[7] + m[5], m[11] + m[9]).constant = m[15] + m[13]; // +y
this.frustum[3].set(m[3] - m[1], m[7] - m[5], m[11] - m[9]).constant = m[15] - m[13]; // -y
this.frustum[4].set(m[3] - m[2], m[7] - m[6], m[11] - m[10]).constant = m[15] - m[14]; // +z (far)
this.frustum[5].set(m[3] + m[2], m[7] + m[6], m[11] + m[10]).constant = m[15] + m[14]; // -z (near)
for (let i = 0; i < 6; i++) {
const invLen = 1.0 / this.frustum[i].distance();
this.frustum[i].multiply(invLen);
this.frustum[i].constant *= invLen;
}
}
frustumIntersectsMesh(node, worldMatrix = node.worldMatrix) {
// If no position attribute, treat as frustumCulled false
if (!node.geometry.attributes.position) return true;
if (!node.geometry.bounds || node.geometry.bounds.radius === Infinity) node.geometry.computeBoundingSphere();
if (!node.geometry.bounds) return true;
const center = tempVec3a;
center.copy(node.geometry.bounds.center);
center.applyMatrix4(worldMatrix);
const radius = node.geometry.bounds.radius * worldMatrix.getMaxScaleOnAxis();
return this.frustumIntersectsSphere(center, radius);
}
frustumIntersectsSphere(center, radius) {
const normal = tempVec3b;
for (let i = 0; i < 6; i++) {
const plane = this.frustum[i];
const distance = normal.copy(plane).dot(center) + plane.constant;
if (distance < -radius) return false;
}
return true;
}
}

294
node_modules/ogl/src/core/Geometry.js generated vendored Normal file
View File

@@ -0,0 +1,294 @@
// attribute params
// {
// data - typed array eg UInt16Array for indices, Float32Array
// size - int default 1
// instanced - default null. Pass divisor amount
// type - gl enum default gl.UNSIGNED_SHORT for 'index', gl.FLOAT for others
// normalized - boolean default false
// buffer - gl buffer, if buffer exists, don't need to provide data - although needs position data for bounds calculation
// stride - default 0 - for when passing in buffer
// offset - default 0 - for when passing in buffer
// count - default null - for when passing in buffer
// min - array - for when passing in buffer
// max - array - for when passing in buffer
// }
// TODO: fit in transform feedback
import { Vec3 } from '../math/Vec3.js';
const tempVec3 = /* @__PURE__ */ new Vec3();
let ID = 1;
let ATTR_ID = 1;
// To stop inifinite warnings
let isBoundsWarned = false;
export class Geometry {
constructor(gl, attributes = {}) {
if (!gl.canvas) console.error('gl not passed as first argument to Geometry');
this.gl = gl;
this.attributes = attributes;
this.id = ID++;
// Store one VAO per program attribute locations order
this.VAOs = {};
this.drawRange = { start: 0, count: 0 };
this.instancedCount = 0;
// Unbind current VAO so that new buffers don't get added to active mesh
this.gl.renderer.bindVertexArray(null);
this.gl.renderer.currentGeometry = null;
// Alias for state store to avoid redundant calls for global state
this.glState = this.gl.renderer.state;
// create the buffers
for (let key in attributes) {
this.addAttribute(key, attributes[key]);
}
}
addAttribute(key, attr) {
this.attributes[key] = attr;
// Set options
attr.id = ATTR_ID++; // TODO: currently unused, remove?
attr.size = attr.size || 1;
attr.type =
attr.type ||
(attr.data.constructor === Float32Array
? this.gl.FLOAT
: attr.data.constructor === Uint16Array
? this.gl.UNSIGNED_SHORT
: this.gl.UNSIGNED_INT); // Uint32Array
attr.target = key === 'index' ? this.gl.ELEMENT_ARRAY_BUFFER : this.gl.ARRAY_BUFFER;
attr.normalized = attr.normalized || false;
attr.stride = attr.stride || 0;
attr.offset = attr.offset || 0;
attr.count = attr.count || (attr.stride ? attr.data.byteLength / attr.stride : attr.data.length / attr.size);
attr.divisor = attr.instanced || 0;
attr.needsUpdate = false;
attr.usage = attr.usage || this.gl.STATIC_DRAW;
if (!attr.buffer) {
// Push data to buffer
this.updateAttribute(attr);
}
// Update geometry counts. If indexed, ignore regular attributes
if (attr.divisor) {
this.isInstanced = true;
if (this.instancedCount && this.instancedCount !== attr.count * attr.divisor) {
console.warn('geometry has multiple instanced buffers of different length');
return (this.instancedCount = Math.min(this.instancedCount, attr.count * attr.divisor));
}
this.instancedCount = attr.count * attr.divisor;
} else if (key === 'index') {
this.drawRange.count = attr.count;
} else if (!this.attributes.index) {
this.drawRange.count = Math.max(this.drawRange.count, attr.count);
}
}
updateAttribute(attr) {
const isNewBuffer = !attr.buffer;
if (isNewBuffer) attr.buffer = this.gl.createBuffer();
if (this.glState.boundBuffer !== attr.buffer) {
this.gl.bindBuffer(attr.target, attr.buffer);
this.glState.boundBuffer = attr.buffer;
}
if (isNewBuffer) {
this.gl.bufferData(attr.target, attr.data, attr.usage);
} else {
this.gl.bufferSubData(attr.target, 0, attr.data);
}
attr.needsUpdate = false;
}
setIndex(value) {
this.addAttribute('index', value);
}
setDrawRange(start, count) {
this.drawRange.start = start;
this.drawRange.count = count;
}
setInstancedCount(value) {
this.instancedCount = value;
}
createVAO(program) {
this.VAOs[program.attributeOrder] = this.gl.renderer.createVertexArray();
this.gl.renderer.bindVertexArray(this.VAOs[program.attributeOrder]);
this.bindAttributes(program);
}
bindAttributes(program) {
// Link all attributes to program using gl.vertexAttribPointer
program.attributeLocations.forEach((location, { name, type }) => {
// If geometry missing a required shader attribute
if (!this.attributes[name]) {
console.warn(`active attribute ${name} not being supplied`);
return;
}
const attr = this.attributes[name];
this.gl.bindBuffer(attr.target, attr.buffer);
this.glState.boundBuffer = attr.buffer;
// For matrix attributes, buffer needs to be defined per column
let numLoc = 1;
if (type === 35674) numLoc = 2; // mat2
if (type === 35675) numLoc = 3; // mat3
if (type === 35676) numLoc = 4; // mat4
const size = attr.size / numLoc;
const stride = numLoc === 1 ? 0 : numLoc * numLoc * 4;
const offset = numLoc === 1 ? 0 : numLoc * 4;
for (let i = 0; i < numLoc; i++) {
this.gl.vertexAttribPointer(location + i, size, attr.type, attr.normalized, attr.stride + stride, attr.offset + i * offset);
this.gl.enableVertexAttribArray(location + i);
// For instanced attributes, divisor needs to be set.
// For firefox, need to set back to 0 if non-instanced drawn after instanced. Else won't render
this.gl.renderer.vertexAttribDivisor(location + i, attr.divisor);
}
});
// Bind indices if geometry indexed
if (this.attributes.index) this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, this.attributes.index.buffer);
}
draw({ program, mode = this.gl.TRIANGLES }) {
if (this.gl.renderer.currentGeometry !== `${this.id}_${program.attributeOrder}`) {
if (!this.VAOs[program.attributeOrder]) this.createVAO(program);
this.gl.renderer.bindVertexArray(this.VAOs[program.attributeOrder]);
this.gl.renderer.currentGeometry = `${this.id}_${program.attributeOrder}`;
}
// Check if any attributes need updating
program.attributeLocations.forEach((location, { name }) => {
const attr = this.attributes[name];
if (attr.needsUpdate) this.updateAttribute(attr);
});
// For drawElements, offset needs to be multiple of type size
let indexBytesPerElement = 2;
if (this.attributes.index?.type === this.gl.UNSIGNED_INT) indexBytesPerElement = 4;
if (this.isInstanced) {
if (this.attributes.index) {
this.gl.renderer.drawElementsInstanced(
mode,
this.drawRange.count,
this.attributes.index.type,
this.attributes.index.offset + this.drawRange.start * indexBytesPerElement,
this.instancedCount
);
} else {
this.gl.renderer.drawArraysInstanced(mode, this.drawRange.start, this.drawRange.count, this.instancedCount);
}
} else {
if (this.attributes.index) {
this.gl.drawElements(
mode,
this.drawRange.count,
this.attributes.index.type,
this.attributes.index.offset + this.drawRange.start * indexBytesPerElement
);
} else {
this.gl.drawArrays(mode, this.drawRange.start, this.drawRange.count);
}
}
}
getPosition() {
// Use position buffer, or min/max if available
const attr = this.attributes.position;
// if (attr.min) return [...attr.min, ...attr.max];
if (attr.data) return attr;
if (isBoundsWarned) return;
console.warn('No position buffer data found to compute bounds');
return (isBoundsWarned = true);
}
computeBoundingBox(attr) {
if (!attr) attr = this.getPosition();
const array = attr.data;
// Data loaded shouldn't haave stride, only buffers
// const stride = attr.stride ? attr.stride / array.BYTES_PER_ELEMENT : attr.size;
const stride = attr.size;
if (!this.bounds) {
this.bounds = {
min: new Vec3(),
max: new Vec3(),
center: new Vec3(),
scale: new Vec3(),
radius: Infinity,
};
}
const min = this.bounds.min;
const max = this.bounds.max;
const center = this.bounds.center;
const scale = this.bounds.scale;
min.set(+Infinity);
max.set(-Infinity);
// TODO: check size of position (eg triangle with Vec2)
for (let i = 0, l = array.length; i < l; i += stride) {
const x = array[i];
const y = array[i + 1];
const z = array[i + 2];
min.x = Math.min(x, min.x);
min.y = Math.min(y, min.y);
min.z = Math.min(z, min.z);
max.x = Math.max(x, max.x);
max.y = Math.max(y, max.y);
max.z = Math.max(z, max.z);
}
scale.sub(max, min);
center.add(min, max).divide(2);
}
computeBoundingSphere(attr) {
if (!attr) attr = this.getPosition();
const array = attr.data;
// Data loaded shouldn't haave stride, only buffers
// const stride = attr.stride ? attr.stride / array.BYTES_PER_ELEMENT : attr.size;
const stride = attr.size;
if (!this.bounds) this.computeBoundingBox(attr);
let maxRadiusSq = 0;
for (let i = 0, l = array.length; i < l; i += stride) {
tempVec3.fromArray(array, i);
maxRadiusSq = Math.max(maxRadiusSq, this.bounds.center.squaredDistance(tempVec3));
}
this.bounds.radius = Math.sqrt(maxRadiusSq);
}
remove() {
for (let key in this.VAOs) {
this.gl.renderer.deleteVertexArray(this.VAOs[key]);
delete this.VAOs[key];
}
for (let key in this.attributes) {
this.gl.deleteBuffer(this.attributes[key].buffer);
delete this.attributes[key];
}
}
}

70
node_modules/ogl/src/core/Mesh.js generated vendored Normal file
View File

@@ -0,0 +1,70 @@
import { Transform } from './Transform.js';
import { Mat3 } from '../math/Mat3.js';
import { Mat4 } from '../math/Mat4.js';
let ID = 0;
export class Mesh extends Transform {
constructor(gl, { geometry, program, mode = gl.TRIANGLES, frustumCulled = true, renderOrder = 0 } = {}) {
super();
if (!gl.canvas) console.error('gl not passed as first argument to Mesh');
this.gl = gl;
this.id = ID++;
this.geometry = geometry;
this.program = program;
this.mode = mode;
// Used to skip frustum culling
this.frustumCulled = frustumCulled;
// Override sorting to force an order
this.renderOrder = renderOrder;
this.modelViewMatrix = new Mat4();
this.normalMatrix = new Mat3();
this.beforeRenderCallbacks = [];
this.afterRenderCallbacks = [];
}
onBeforeRender(f) {
this.beforeRenderCallbacks.push(f);
return this;
}
onAfterRender(f) {
this.afterRenderCallbacks.push(f);
return this;
}
draw({ camera } = {}) {
if (camera) {
// Add empty matrix uniforms to program if unset
if (!this.program.uniforms.modelMatrix) {
Object.assign(this.program.uniforms, {
modelMatrix: { value: null },
viewMatrix: { value: null },
modelViewMatrix: { value: null },
normalMatrix: { value: null },
projectionMatrix: { value: null },
cameraPosition: { value: null },
});
}
// Set the matrix uniforms
this.program.uniforms.projectionMatrix.value = camera.projectionMatrix;
this.program.uniforms.cameraPosition.value = camera.worldPosition;
this.program.uniforms.viewMatrix.value = camera.viewMatrix;
this.modelViewMatrix.multiply(camera.viewMatrix, this.worldMatrix);
this.normalMatrix.getNormalMatrix(this.modelViewMatrix);
this.program.uniforms.modelMatrix.value = this.worldMatrix;
this.program.uniforms.modelViewMatrix.value = this.modelViewMatrix;
this.program.uniforms.normalMatrix.value = this.normalMatrix;
}
this.beforeRenderCallbacks.forEach((f) => f && f({ mesh: this, camera }));
// determine if faces need to be flipped - when mesh scaled negatively
let flipFaces = this.program.cullFace && this.worldMatrix.determinant() < 0;
this.program.use({ flipFaces });
this.geometry.draw({ mode: this.mode, program: this.program });
this.afterRenderCallbacks.forEach((f) => f && f({ mesh: this, camera }));
}
}

329
node_modules/ogl/src/core/Program.js generated vendored Normal file
View File

@@ -0,0 +1,329 @@
// TODO: upload empty texture if null ? maybe not
// TODO: upload identity matrix if null ?
// TODO: sampler Cube
let ID = 1;
// cache of typed arrays used to flatten uniform arrays
const arrayCacheF32 = {};
export class Program {
constructor(
gl,
{
vertex,
fragment,
uniforms = {},
transparent = false,
cullFace = gl.BACK,
frontFace = gl.CCW,
depthTest = true,
depthWrite = true,
depthFunc = gl.LEQUAL,
} = {}
) {
if (!gl.canvas) console.error('gl not passed as first argument to Program');
this.gl = gl;
this.uniforms = uniforms;
this.id = ID++;
if (!vertex) console.warn('vertex shader not supplied');
if (!fragment) console.warn('fragment shader not supplied');
// Store program state
this.transparent = transparent;
this.cullFace = cullFace;
this.frontFace = frontFace;
this.depthTest = depthTest;
this.depthWrite = depthWrite;
this.depthFunc = depthFunc;
this.blendFunc = {};
this.blendEquation = {};
this.stencilFunc = {};
this.stencilOp = {}
// set default blendFunc if transparent flagged
if (this.transparent && !this.blendFunc.src) {
if (this.gl.renderer.premultipliedAlpha) this.setBlendFunc(this.gl.ONE, this.gl.ONE_MINUS_SRC_ALPHA);
else this.setBlendFunc(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA);
}
// Create empty shaders and attach to program
this.vertexShader = gl.createShader(gl.VERTEX_SHADER);
this.fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
this.program = gl.createProgram();
gl.attachShader(this.program, this.vertexShader);
gl.attachShader(this.program, this.fragmentShader);
// Compile shaders with source
this.setShaders({ vertex, fragment });
}
setShaders({ vertex, fragment }) {
if (vertex) {
// compile vertex shader and log errors
this.gl.shaderSource(this.vertexShader, vertex);
this.gl.compileShader(this.vertexShader);
if (this.gl.getShaderInfoLog(this.vertexShader) !== '') {
console.warn(`${this.gl.getShaderInfoLog(this.vertexShader)}\nVertex Shader\n${addLineNumbers(vertex)}`);
}
}
if (fragment) {
// compile fragment shader and log errors
this.gl.shaderSource(this.fragmentShader, fragment);
this.gl.compileShader(this.fragmentShader);
if (this.gl.getShaderInfoLog(this.fragmentShader) !== '') {
console.warn(`${this.gl.getShaderInfoLog(this.fragmentShader)}\nFragment Shader\n${addLineNumbers(fragment)}`);
}
}
// compile program and log errors
this.gl.linkProgram(this.program);
if (!this.gl.getProgramParameter(this.program, this.gl.LINK_STATUS)) {
return console.warn(this.gl.getProgramInfoLog(this.program));
}
// Get active uniform locations
this.uniformLocations = new Map();
let numUniforms = this.gl.getProgramParameter(this.program, this.gl.ACTIVE_UNIFORMS);
for (let uIndex = 0; uIndex < numUniforms; uIndex++) {
let uniform = this.gl.getActiveUniform(this.program, uIndex);
this.uniformLocations.set(uniform, this.gl.getUniformLocation(this.program, uniform.name));
// split uniforms' names to separate array and struct declarations
const split = uniform.name.match(/(\w+)/g);
uniform.uniformName = split[0];
uniform.nameComponents = split.slice(1);
}
// Get active attribute locations
this.attributeLocations = new Map();
const locations = [];
const numAttribs = this.gl.getProgramParameter(this.program, this.gl.ACTIVE_ATTRIBUTES);
for (let aIndex = 0; aIndex < numAttribs; aIndex++) {
const attribute = this.gl.getActiveAttrib(this.program, aIndex);
const location = this.gl.getAttribLocation(this.program, attribute.name);
// Ignore special built-in inputs. eg gl_VertexID, gl_InstanceID
if (location === -1) continue;
locations[location] = attribute.name;
this.attributeLocations.set(attribute, location);
}
this.attributeOrder = locations.join('');
}
setBlendFunc(src, dst, srcAlpha, dstAlpha) {
this.blendFunc.src = src;
this.blendFunc.dst = dst;
this.blendFunc.srcAlpha = srcAlpha;
this.blendFunc.dstAlpha = dstAlpha;
if (src) this.transparent = true;
}
setBlendEquation(modeRGB, modeAlpha) {
this.blendEquation.modeRGB = modeRGB;
this.blendEquation.modeAlpha = modeAlpha;
}
setStencilFunc(func, ref, mask) {
this.stencilRef = ref;
this.stencilFunc.func = func;
this.stencilFunc.ref = ref;
this.stencilFunc.mask = mask;
}
setStencilOp(stencilFail, depthFail, depthPass) {
this.stencilOp.stencilFail = stencilFail;
this.stencilOp.depthFail = depthFail;
this.stencilOp.depthPass = depthPass;
}
applyState() {
if (this.depthTest) this.gl.renderer.enable(this.gl.DEPTH_TEST);
else this.gl.renderer.disable(this.gl.DEPTH_TEST);
if (this.cullFace) this.gl.renderer.enable(this.gl.CULL_FACE);
else this.gl.renderer.disable(this.gl.CULL_FACE);
if (this.blendFunc.src) this.gl.renderer.enable(this.gl.BLEND);
else this.gl.renderer.disable(this.gl.BLEND);
if (this.cullFace) this.gl.renderer.setCullFace(this.cullFace);
this.gl.renderer.setFrontFace(this.frontFace);
this.gl.renderer.setDepthMask(this.depthWrite);
this.gl.renderer.setDepthFunc(this.depthFunc);
if (this.blendFunc.src) this.gl.renderer.setBlendFunc(this.blendFunc.src, this.blendFunc.dst, this.blendFunc.srcAlpha, this.blendFunc.dstAlpha);
this.gl.renderer.setBlendEquation(this.blendEquation.modeRGB, this.blendEquation.modeAlpha);
if(this.stencilFunc.func || this.stencilOp.stencilFail) this.gl.renderer.enable(this.gl.STENCIL_TEST)
else this.gl.renderer.disable(this.gl.STENCIL_TEST)
this.gl.renderer.setStencilFunc(this.stencilFunc.func, this.stencilFunc.ref, this.stencilFunc.mask)
this.gl.renderer.setStencilOp(this.stencilOp.stencilFail, this.stencilOp.depthFail, this.stencilOp.depthPass)
}
use({ flipFaces = false } = {}) {
let textureUnit = -1;
const programActive = this.gl.renderer.state.currentProgram === this.id;
// Avoid gl call if program already in use
if (!programActive) {
this.gl.useProgram(this.program);
this.gl.renderer.state.currentProgram = this.id;
}
// Set only the active uniforms found in the shader
this.uniformLocations.forEach((location, activeUniform) => {
let uniform = this.uniforms[activeUniform.uniformName];
for (const component of activeUniform.nameComponents) {
if (!uniform) break;
if (component in uniform) {
uniform = uniform[component];
} else if (Array.isArray(uniform.value)) {
break;
} else {
uniform = undefined;
break;
}
}
if (!uniform) {
return warn(`Active uniform ${activeUniform.name} has not been supplied`);
}
if (uniform && uniform.value === undefined) {
return warn(`${activeUniform.name} uniform is missing a value parameter`);
}
if (uniform.value.texture) {
textureUnit = textureUnit + 1;
// Check if texture needs to be updated
uniform.value.update(textureUnit);
return setUniform(this.gl, activeUniform.type, location, textureUnit);
}
// For texture arrays, set uniform as an array of texture units instead of just one
if (uniform.value.length && uniform.value[0].texture) {
const textureUnits = [];
uniform.value.forEach((value) => {
textureUnit = textureUnit + 1;
value.update(textureUnit);
textureUnits.push(textureUnit);
});
return setUniform(this.gl, activeUniform.type, location, textureUnits);
}
setUniform(this.gl, activeUniform.type, location, uniform.value);
});
this.applyState();
if (flipFaces) this.gl.renderer.setFrontFace(this.frontFace === this.gl.CCW ? this.gl.CW : this.gl.CCW);
}
remove() {
this.gl.deleteProgram(this.program);
}
}
function setUniform(gl, type, location, value) {
value = value.length ? flatten(value) : value;
const setValue = gl.renderer.state.uniformLocations.get(location);
// Avoid redundant uniform commands
if (value.length) {
if (setValue === undefined || setValue.length !== value.length) {
// clone array to store as cache
gl.renderer.state.uniformLocations.set(location, value.slice(0));
} else {
if (arraysEqual(setValue, value)) return;
// Update cached array values
setValue.set ? setValue.set(value) : setArray(setValue, value);
gl.renderer.state.uniformLocations.set(location, setValue);
}
} else {
if (setValue === value) return;
gl.renderer.state.uniformLocations.set(location, value);
}
switch (type) {
case 5126:
return value.length ? gl.uniform1fv(location, value) : gl.uniform1f(location, value); // FLOAT
case 35664:
return gl.uniform2fv(location, value); // FLOAT_VEC2
case 35665:
return gl.uniform3fv(location, value); // FLOAT_VEC3
case 35666:
return gl.uniform4fv(location, value); // FLOAT_VEC4
case 35670: // BOOL
case 5124: // INT
case 35678: // SAMPLER_2D
case 36306: // U_SAMPLER_2D
case 35680: // SAMPLER_CUBE
case 36289: // SAMPLER_2D_ARRAY
return value.length ? gl.uniform1iv(location, value) : gl.uniform1i(location, value); // SAMPLER_CUBE
case 35671: // BOOL_VEC2
case 35667:
return gl.uniform2iv(location, value); // INT_VEC2
case 35672: // BOOL_VEC3
case 35668:
return gl.uniform3iv(location, value); // INT_VEC3
case 35673: // BOOL_VEC4
case 35669:
return gl.uniform4iv(location, value); // INT_VEC4
case 35674:
return gl.uniformMatrix2fv(location, false, value); // FLOAT_MAT2
case 35675:
return gl.uniformMatrix3fv(location, false, value); // FLOAT_MAT3
case 35676:
return gl.uniformMatrix4fv(location, false, value); // FLOAT_MAT4
}
}
function addLineNumbers(string) {
let lines = string.split('\n');
for (let i = 0; i < lines.length; i++) {
lines[i] = i + 1 + ': ' + lines[i];
}
return lines.join('\n');
}
function flatten(a) {
const arrayLen = a.length;
const valueLen = a[0].length;
if (valueLen === undefined) return a;
const length = arrayLen * valueLen;
let value = arrayCacheF32[length];
if (!value) arrayCacheF32[length] = value = new Float32Array(length);
for (let i = 0; i < arrayLen; i++) value.set(a[i], i * valueLen);
return value;
}
function arraysEqual(a, b) {
if (a.length !== b.length) return false;
for (let i = 0, l = a.length; i < l; i++) {
if (a[i] !== b[i]) return false;
}
return true;
}
function setArray(a, b) {
for (let i = 0, l = a.length; i < l; i++) {
a[i] = b[i];
}
}
let warnCount = 0;
function warn(message) {
if (warnCount > 100) return;
console.warn(message);
warnCount++;
if (warnCount > 100) console.warn('More than 100 program warnings - stopping logs.');
}

149
node_modules/ogl/src/core/RenderTarget.js generated vendored Normal file
View File

@@ -0,0 +1,149 @@
import { Texture } from './Texture.js'
export class RenderTarget {
constructor(
gl,
{
width = gl.canvas.width,
height = gl.canvas.height,
target = gl.FRAMEBUFFER,
color = 1, // number of color attachments
depth = true,
stencil = false,
depthTexture = false,
wrapS = gl.CLAMP_TO_EDGE,
wrapT = gl.CLAMP_TO_EDGE,
wrapR = gl.CLAMP_TO_EDGE,
minFilter = gl.LINEAR,
magFilter = minFilter,
type = gl.UNSIGNED_BYTE,
format = gl.RGBA,
internalFormat = format,
unpackAlignment,
premultiplyAlpha,
} = {}
) {
this.gl = gl;
this.width = width;
this.height = height;
this.depth = depth;
this.stencil = stencil;
this.buffer = this.gl.createFramebuffer();
this.target = target;
this.gl.renderer.bindFramebuffer(this);
this.textures = [];
const drawBuffers = [];
// create and attach required num of color textures
for (let i = 0; i < color; i++) {
this.textures.push(
new Texture(gl, {
width,
height,
wrapS,
wrapT,
wrapR,
minFilter,
magFilter,
type,
format,
internalFormat,
unpackAlignment,
premultiplyAlpha,
flipY: false,
generateMipmaps: false,
})
);
this.textures[i].update();
this.gl.framebufferTexture2D(this.target, this.gl.COLOR_ATTACHMENT0 + i, this.gl.TEXTURE_2D, this.textures[i].texture, 0 /* level */);
drawBuffers.push(this.gl.COLOR_ATTACHMENT0 + i);
}
// For multi-render targets shader access
if (drawBuffers.length > 1) this.gl.renderer.drawBuffers(drawBuffers);
// alias for majority of use cases
this.texture = this.textures[0];
// note depth textures break stencil - so can't use together
if (depthTexture && (this.gl.renderer.isWebgl2 || this.gl.renderer.getExtension('WEBGL_depth_texture'))) {
this.depthTexture = new Texture(gl, {
width,
height,
minFilter: this.gl.NEAREST,
magFilter: this.gl.NEAREST,
format: this.stencil ? this.gl.DEPTH_STENCIL : this.gl.DEPTH_COMPONENT,
internalFormat: gl.renderer.isWebgl2 ? (this.stencil ? this.gl.DEPTH24_STENCIL8 : this.gl.DEPTH_COMPONENT16) : this.gl.DEPTH_COMPONENT,
type: this.stencil ? this.gl.UNSIGNED_INT_24_8 : this.gl.UNSIGNED_INT,
});
this.depthTexture.update();
this.gl.framebufferTexture2D(this.target, this.stencil ? this.gl.DEPTH_STENCIL_ATTACHMENT : this.gl.DEPTH_ATTACHMENT, this.gl.TEXTURE_2D, this.depthTexture.texture, 0 /* level */);
} else {
// Render buffers
if (depth && !stencil) {
this.depthBuffer = this.gl.createRenderbuffer();
this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, this.depthBuffer);
this.gl.renderbufferStorage(this.gl.RENDERBUFFER, this.gl.DEPTH_COMPONENT16, width, height);
this.gl.framebufferRenderbuffer(this.target, this.gl.DEPTH_ATTACHMENT, this.gl.RENDERBUFFER, this.depthBuffer);
}
if (stencil && !depth) {
this.stencilBuffer = this.gl.createRenderbuffer();
this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, this.stencilBuffer);
this.gl.renderbufferStorage(this.gl.RENDERBUFFER, this.gl.STENCIL_INDEX8, width, height);
this.gl.framebufferRenderbuffer(this.target, this.gl.STENCIL_ATTACHMENT, this.gl.RENDERBUFFER, this.stencilBuffer);
}
if (depth && stencil) {
this.depthStencilBuffer = this.gl.createRenderbuffer();
this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, this.depthStencilBuffer);
this.gl.renderbufferStorage(this.gl.RENDERBUFFER, this.gl.DEPTH_STENCIL, width, height);
this.gl.framebufferRenderbuffer(this.target, this.gl.DEPTH_STENCIL_ATTACHMENT, this.gl.RENDERBUFFER, this.depthStencilBuffer);
}
}
this.gl.renderer.bindFramebuffer({ target: this.target });
}
setSize(width, height) {
if (this.width === width && this.height === height) return;
this.width = width;
this.height = height;
this.gl.renderer.bindFramebuffer(this);
for (let i = 0; i < this.textures.length; i++) {
this.textures[i].width = width;
this.textures[i].height = height;
this.textures[i].needsUpdate = true;
this.textures[i].update();
this.gl.framebufferTexture2D(this.target, this.gl.COLOR_ATTACHMENT0 + i, this.gl.TEXTURE_2D, this.textures[i].texture, 0 /* level */);
}
if (this.depthTexture) {
this.depthTexture.width = width;
this.depthTexture.height = height;
this.depthTexture.needsUpdate = true;
this.depthTexture.update();
this.gl.framebufferTexture2D(this.target, this.gl.DEPTH_ATTACHMENT, this.gl.TEXTURE_2D, this.depthTexture.texture, 0 /* level */);
} else {
if (this.depthBuffer) {
this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, this.depthBuffer);
this.gl.renderbufferStorage(this.gl.RENDERBUFFER, this.gl.DEPTH_COMPONENT16, width, height);
}
if (this.stencilBuffer) {
this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, this.stencilBuffer);
this.gl.renderbufferStorage(this.gl.RENDERBUFFER, this.gl.STENCIL_INDEX8, width, height);
}
if (this.depthStencilBuffer) {
this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, this.depthStencilBuffer);
this.gl.renderbufferStorage(this.gl.RENDERBUFFER, this.gl.DEPTH_STENCIL, width, height);
}
}
this.gl.renderer.bindFramebuffer({ target: this.target });
}
}

399
node_modules/ogl/src/core/Renderer.js generated vendored Normal file
View File

@@ -0,0 +1,399 @@
import { Vec3 } from '../math/Vec3.js';
// TODO: Handle context loss https://www.khronos.org/webgl/wiki/HandlingContextLost
// Not automatic - devs to use these methods manually
// gl.colorMask( colorMask, colorMask, colorMask, colorMask );
// gl.clearColor( r, g, b, a );
// gl.stencilMask( stencilMask );
// gl.stencilFunc( stencilFunc, stencilRef, stencilMask );
// gl.stencilOp( stencilFail, stencilZFail, stencilZPass );
// gl.clearStencil( stencil );
const tempVec3 = /* @__PURE__ */ new Vec3();
let ID = 1;
export class Renderer {
constructor({
canvas = document.createElement('canvas'),
width = 300,
height = 150,
dpr = 1,
alpha = false,
depth = true,
stencil = false,
antialias = false,
premultipliedAlpha = false,
preserveDrawingBuffer = false,
powerPreference = 'default',
autoClear = true,
webgl = 2,
} = {}) {
const attributes = { alpha, depth, stencil, antialias, premultipliedAlpha, preserveDrawingBuffer, powerPreference };
this.dpr = dpr;
this.alpha = alpha;
this.color = true;
this.depth = depth;
this.stencil = stencil;
this.premultipliedAlpha = premultipliedAlpha;
this.autoClear = autoClear;
this.id = ID++;
// Attempt WebGL2 unless forced to 1, if not supported fallback to WebGL1
if (webgl === 2) this.gl = canvas.getContext('webgl2', attributes);
this.isWebgl2 = !!this.gl;
if (!this.gl) this.gl = canvas.getContext('webgl', attributes);
if (!this.gl) console.error('unable to create webgl context');
// Attach renderer to gl so that all classes have access to internal state functions
this.gl.renderer = this;
// initialise size values
this.setSize(width, height);
// gl state stores to avoid redundant calls on methods used internally
this.state = {};
this.state.blendFunc = { src: this.gl.ONE, dst: this.gl.ZERO };
this.state.blendEquation = { modeRGB: this.gl.FUNC_ADD };
this.state.cullFace = false;
this.state.frontFace = this.gl.CCW;
this.state.depthMask = true;
this.state.depthFunc = this.gl.LEQUAL;
this.state.premultiplyAlpha = false;
this.state.flipY = false;
this.state.unpackAlignment = 4;
this.state.framebuffer = null;
this.state.viewport = { x: 0, y: 0, width: null, height: null };
this.state.textureUnits = [];
this.state.activeTextureUnit = 0;
this.state.boundBuffer = null;
this.state.uniformLocations = new Map();
this.state.currentProgram = null;
// store requested extensions
this.extensions = {};
// Initialise extra format types
if (this.isWebgl2) {
this.getExtension('EXT_color_buffer_float');
this.getExtension('OES_texture_float_linear');
} else {
this.getExtension('OES_texture_float');
this.getExtension('OES_texture_float_linear');
this.getExtension('OES_texture_half_float');
this.getExtension('OES_texture_half_float_linear');
this.getExtension('OES_element_index_uint');
this.getExtension('OES_standard_derivatives');
this.getExtension('EXT_sRGB');
this.getExtension('WEBGL_depth_texture');
this.getExtension('WEBGL_draw_buffers');
}
this.getExtension('WEBGL_compressed_texture_astc');
this.getExtension('EXT_texture_compression_bptc');
this.getExtension('WEBGL_compressed_texture_s3tc');
this.getExtension('WEBGL_compressed_texture_etc1');
this.getExtension('WEBGL_compressed_texture_pvrtc');
this.getExtension('WEBKIT_WEBGL_compressed_texture_pvrtc');
// Create method aliases using extension (WebGL1) or native if available (WebGL2)
this.vertexAttribDivisor = this.getExtension('ANGLE_instanced_arrays', 'vertexAttribDivisor', 'vertexAttribDivisorANGLE');
this.drawArraysInstanced = this.getExtension('ANGLE_instanced_arrays', 'drawArraysInstanced', 'drawArraysInstancedANGLE');
this.drawElementsInstanced = this.getExtension('ANGLE_instanced_arrays', 'drawElementsInstanced', 'drawElementsInstancedANGLE');
this.createVertexArray = this.getExtension('OES_vertex_array_object', 'createVertexArray', 'createVertexArrayOES');
this.bindVertexArray = this.getExtension('OES_vertex_array_object', 'bindVertexArray', 'bindVertexArrayOES');
this.deleteVertexArray = this.getExtension('OES_vertex_array_object', 'deleteVertexArray', 'deleteVertexArrayOES');
this.drawBuffers = this.getExtension('WEBGL_draw_buffers', 'drawBuffers', 'drawBuffersWEBGL');
// Store device parameters
this.parameters = {};
this.parameters.maxTextureUnits = this.gl.getParameter(this.gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS);
this.parameters.maxAnisotropy = this.getExtension('EXT_texture_filter_anisotropic')
? this.gl.getParameter(this.getExtension('EXT_texture_filter_anisotropic').MAX_TEXTURE_MAX_ANISOTROPY_EXT)
: 0;
}
setSize(width, height) {
this.width = width;
this.height = height;
this.gl.canvas.width = width * this.dpr;
this.gl.canvas.height = height * this.dpr;
if (!this.gl.canvas.style) return;
Object.assign(this.gl.canvas.style, {
width: width + 'px',
height: height + 'px',
});
}
setViewport(width, height, x = 0, y = 0) {
if (this.state.viewport.width === width && this.state.viewport.height === height) return;
this.state.viewport.width = width;
this.state.viewport.height = height;
this.state.viewport.x = x;
this.state.viewport.y = y;
this.gl.viewport(x, y, width, height);
}
setScissor(width, height, x = 0, y = 0) {
this.gl.scissor(x, y, width, height);
}
enable(id) {
if (this.state[id] === true) return;
this.gl.enable(id);
this.state[id] = true;
}
disable(id) {
if (this.state[id] === false) return;
this.gl.disable(id);
this.state[id] = false;
}
setBlendFunc(src, dst, srcAlpha, dstAlpha) {
if (
this.state.blendFunc.src === src &&
this.state.blendFunc.dst === dst &&
this.state.blendFunc.srcAlpha === srcAlpha &&
this.state.blendFunc.dstAlpha === dstAlpha
)
return;
this.state.blendFunc.src = src;
this.state.blendFunc.dst = dst;
this.state.blendFunc.srcAlpha = srcAlpha;
this.state.blendFunc.dstAlpha = dstAlpha;
if (srcAlpha !== undefined) this.gl.blendFuncSeparate(src, dst, srcAlpha, dstAlpha);
else this.gl.blendFunc(src, dst);
}
setBlendEquation(modeRGB, modeAlpha) {
modeRGB = modeRGB || this.gl.FUNC_ADD;
if (this.state.blendEquation.modeRGB === modeRGB && this.state.blendEquation.modeAlpha === modeAlpha) return;
this.state.blendEquation.modeRGB = modeRGB;
this.state.blendEquation.modeAlpha = modeAlpha;
if (modeAlpha !== undefined) this.gl.blendEquationSeparate(modeRGB, modeAlpha);
else this.gl.blendEquation(modeRGB);
}
setCullFace(value) {
if (this.state.cullFace === value) return;
this.state.cullFace = value;
this.gl.cullFace(value);
}
setFrontFace(value) {
if (this.state.frontFace === value) return;
this.state.frontFace = value;
this.gl.frontFace(value);
}
setDepthMask(value) {
if (this.state.depthMask === value) return;
this.state.depthMask = value;
this.gl.depthMask(value);
}
setDepthFunc(value) {
if (this.state.depthFunc === value) return;
this.state.depthFunc = value;
this.gl.depthFunc(value);
}
setStencilMask(value) {
if(this.state.stencilMask === value) return;
this.state.stencilMask = value;
this.gl.stencilMask(value)
}
setStencilFunc(func, ref, mask) {
if((this.state.stencilFunc === func) &&
(this.state.stencilRef === ref) &&
(this.state.stencilFuncMask === mask)
) return;
this.state.stencilFunc = func || this.gl.ALWAYS;
this.state.stencilRef = ref || 0;
this.state.stencilFuncMask = mask || 0;
this.gl.stencilFunc(func || this.gl.ALWAYS, ref || 0, mask || 0);
}
setStencilOp(stencilFail, depthFail, depthPass) {
if(this.state.stencilFail === stencilFail &&
this.state.stencilDepthFail === depthFail &&
this.state.stencilDepthPass === depthPass
) return;
this.state.stencilFail = stencilFail;
this.state.stencilDepthFail = depthFail;
this.state.stencilDepthPass = depthPass;
this.gl.stencilOp(stencilFail, depthFail, depthPass);
}
activeTexture(value) {
if (this.state.activeTextureUnit === value) return;
this.state.activeTextureUnit = value;
this.gl.activeTexture(this.gl.TEXTURE0 + value);
}
bindFramebuffer({ target = this.gl.FRAMEBUFFER, buffer = null } = {}) {
if (this.state.framebuffer === buffer) return;
this.state.framebuffer = buffer;
this.gl.bindFramebuffer(target, buffer);
}
getExtension(extension, webgl2Func, extFunc) {
// if webgl2 function supported, return func bound to gl context
if (webgl2Func && this.gl[webgl2Func]) return this.gl[webgl2Func].bind(this.gl);
// fetch extension once only
if (!this.extensions[extension]) {
this.extensions[extension] = this.gl.getExtension(extension);
}
// return extension if no function requested
if (!webgl2Func) return this.extensions[extension];
// Return null if extension not supported
if (!this.extensions[extension]) return null;
// return extension function, bound to extension
return this.extensions[extension][extFunc].bind(this.extensions[extension]);
}
sortOpaque(a, b) {
if (a.renderOrder !== b.renderOrder) {
return a.renderOrder - b.renderOrder;
} else if (a.program.id !== b.program.id) {
return a.program.id - b.program.id;
} else if (a.zDepth !== b.zDepth) {
return a.zDepth - b.zDepth;
} else {
return b.id - a.id;
}
}
sortTransparent(a, b) {
if (a.renderOrder !== b.renderOrder) {
return a.renderOrder - b.renderOrder;
}
if (a.zDepth !== b.zDepth) {
return b.zDepth - a.zDepth;
} else {
return b.id - a.id;
}
}
sortUI(a, b) {
if (a.renderOrder !== b.renderOrder) {
return a.renderOrder - b.renderOrder;
} else if (a.program.id !== b.program.id) {
return a.program.id - b.program.id;
} else {
return b.id - a.id;
}
}
getRenderList({ scene, camera, frustumCull, sort }) {
let renderList = [];
if (camera && frustumCull) camera.updateFrustum();
// Get visible
scene.traverse((node) => {
if (!node.visible) return true;
if (!node.draw) return;
if (frustumCull && node.frustumCulled && camera) {
if (!camera.frustumIntersectsMesh(node)) return;
}
renderList.push(node);
});
if (sort) {
const opaque = [];
const transparent = []; // depthTest true
const ui = []; // depthTest false
renderList.forEach((node) => {
// Split into the 3 render groups
if (!node.program.transparent) {
opaque.push(node);
} else if (node.program.depthTest) {
transparent.push(node);
} else {
ui.push(node);
}
node.zDepth = 0;
// Only calculate z-depth if renderOrder unset and depthTest is true
if (node.renderOrder !== 0 || !node.program.depthTest || !camera) return;
// update z-depth
node.worldMatrix.getTranslation(tempVec3);
tempVec3.applyMatrix4(camera.projectionViewMatrix);
node.zDepth = tempVec3.z;
});
opaque.sort(this.sortOpaque);
transparent.sort(this.sortTransparent);
ui.sort(this.sortUI);
renderList = opaque.concat(transparent, ui);
}
return renderList;
}
render({ scene, camera, target = null, update = true, sort = true, frustumCull = true, clear }) {
if (target === null) {
// make sure no render target bound so draws to canvas
this.bindFramebuffer();
this.setViewport(this.width * this.dpr, this.height * this.dpr);
} else {
// bind supplied render target and update viewport
this.bindFramebuffer(target);
this.setViewport(target.width, target.height);
}
if (clear || (this.autoClear && clear !== false)) {
// Ensure depth buffer writing is enabled so it can be cleared
if (this.depth && (!target || target.depth)) {
this.enable(this.gl.DEPTH_TEST);
this.setDepthMask(true);
}
// Same for stencil
if(this.stencil || (!target || target.stencil)) {
this.enable(this.gl.STENCIL_TEST);
this.setStencilMask(0xff)
}
this.gl.clear(
(this.color ? this.gl.COLOR_BUFFER_BIT : 0) |
(this.depth ? this.gl.DEPTH_BUFFER_BIT : 0) |
(this.stencil ? this.gl.STENCIL_BUFFER_BIT : 0)
);
}
// updates all scene graph matrices
if (update) scene.updateMatrixWorld();
// Update camera separately, in case not in scene graph
if (camera) camera.updateMatrixWorld();
// Get render list - entails culling and sorting
const renderList = this.getRenderList({ scene, camera, frustumCull, sort });
renderList.forEach((node) => {
node.draw({ camera });
});
}
}

209
node_modules/ogl/src/core/Texture.js generated vendored Normal file
View File

@@ -0,0 +1,209 @@
// TODO: delete texture
// TODO: use texSubImage2D for updates (video or when loaded)
// TODO: need? encoding = linearEncoding
// TODO: support non-compressed mipmaps uploads
const emptyPixel = new Uint8Array(4);
function isPowerOf2(value) {
return (value & (value - 1)) === 0;
}
let ID = 1;
export class Texture {
constructor(
gl,
{
image,
target = gl.TEXTURE_2D,
type = gl.UNSIGNED_BYTE,
format = gl.RGBA,
internalFormat = format,
wrapS = gl.CLAMP_TO_EDGE,
wrapT = gl.CLAMP_TO_EDGE,
wrapR = gl.CLAMP_TO_EDGE,
generateMipmaps = target === (gl.TEXTURE_2D || gl.TEXTURE_CUBE_MAP),
minFilter = generateMipmaps ? gl.NEAREST_MIPMAP_LINEAR : gl.LINEAR,
magFilter = gl.LINEAR,
premultiplyAlpha = false,
unpackAlignment = 4,
flipY = target == (gl.TEXTURE_2D || gl.TEXTURE_3D) ? true : false,
anisotropy = 0,
level = 0,
width, // used for RenderTargets or Data Textures
height = width,
length = 1,
} = {}
) {
this.gl = gl;
this.id = ID++;
this.image = image;
this.target = target;
this.type = type;
this.format = format;
this.internalFormat = internalFormat;
this.minFilter = minFilter;
this.magFilter = magFilter;
this.wrapS = wrapS;
this.wrapT = wrapT;
this.wrapR = wrapR;
this.generateMipmaps = generateMipmaps;
this.premultiplyAlpha = premultiplyAlpha;
this.unpackAlignment = unpackAlignment;
this.flipY = flipY;
this.anisotropy = Math.min(anisotropy, this.gl.renderer.parameters.maxAnisotropy);
this.level = level;
this.width = width;
this.height = height;
this.length = length;
this.texture = this.gl.createTexture();
this.store = {
image: null,
};
// Alias for state store to avoid redundant calls for global state
this.glState = this.gl.renderer.state;
// State store to avoid redundant calls for per-texture state
this.state = {};
this.state.minFilter = this.gl.NEAREST_MIPMAP_LINEAR;
this.state.magFilter = this.gl.LINEAR;
this.state.wrapS = this.gl.REPEAT;
this.state.wrapT = this.gl.REPEAT;
this.state.anisotropy = 0;
}
bind() {
// Already bound to active texture unit
if (this.glState.textureUnits[this.glState.activeTextureUnit] === this.id) return;
this.gl.bindTexture(this.target, this.texture);
this.glState.textureUnits[this.glState.activeTextureUnit] = this.id;
}
update(textureUnit = 0) {
const needsUpdate = !(this.image === this.store.image && !this.needsUpdate);
// Make sure that texture is bound to its texture unit
if (needsUpdate || this.glState.textureUnits[textureUnit] !== this.id) {
// set active texture unit to perform texture functions
this.gl.renderer.activeTexture(textureUnit);
this.bind();
}
if (!needsUpdate) return;
this.needsUpdate = false;
if (this.flipY !== this.glState.flipY) {
this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, this.flipY);
this.glState.flipY = this.flipY;
}
if (this.premultiplyAlpha !== this.glState.premultiplyAlpha) {
this.gl.pixelStorei(this.gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, this.premultiplyAlpha);
this.glState.premultiplyAlpha = this.premultiplyAlpha;
}
if (this.unpackAlignment !== this.glState.unpackAlignment) {
this.gl.pixelStorei(this.gl.UNPACK_ALIGNMENT, this.unpackAlignment);
this.glState.unpackAlignment = this.unpackAlignment;
}
if (this.minFilter !== this.state.minFilter) {
this.gl.texParameteri(this.target, this.gl.TEXTURE_MIN_FILTER, this.minFilter);
this.state.minFilter = this.minFilter;
}
if (this.magFilter !== this.state.magFilter) {
this.gl.texParameteri(this.target, this.gl.TEXTURE_MAG_FILTER, this.magFilter);
this.state.magFilter = this.magFilter;
}
if (this.wrapS !== this.state.wrapS) {
this.gl.texParameteri(this.target, this.gl.TEXTURE_WRAP_S, this.wrapS);
this.state.wrapS = this.wrapS;
}
if (this.wrapT !== this.state.wrapT) {
this.gl.texParameteri(this.target, this.gl.TEXTURE_WRAP_T, this.wrapT);
this.state.wrapT = this.wrapT;
}
if (this.wrapR !== this.state.wrapR) {
this.gl.texParameteri(this.target, this.gl.TEXTURE_WRAP_R, this.wrapR);
this.state.wrapR = this.wrapR;
}
if (this.anisotropy && this.anisotropy !== this.state.anisotropy) {
this.gl.texParameterf(this.target, this.gl.renderer.getExtension('EXT_texture_filter_anisotropic').TEXTURE_MAX_ANISOTROPY_EXT, this.anisotropy);
this.state.anisotropy = this.anisotropy;
}
if (this.image) {
if (this.image.width) {
this.width = this.image.width;
this.height = this.image.height;
}
if (this.target === this.gl.TEXTURE_CUBE_MAP) {
// For cube maps
for (let i = 0; i < 6; i++) {
this.gl.texImage2D(this.gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, this.level, this.internalFormat, this.format, this.type, this.image[i]);
}
} else if (ArrayBuffer.isView(this.image)) {
// Data texture
if (this.target === this.gl.TEXTURE_2D) {
this.gl.texImage2D(this.target, this.level, this.internalFormat, this.width, this.height, 0, this.format, this.type, this.image);
} else if (this.target === this.gl.TEXTURE_2D_ARRAY || this.target === this.gl.TEXTURE_3D) {
this.gl.texImage3D(this.target, this.level, this.internalFormat, this.width, this.height, this.length, 0, this.format, this.type, this.image);
}
} else if (this.image.isCompressedTexture) {
// Compressed texture
for (let level = 0; level < this.image.length; level++) {
this.gl.compressedTexImage2D(this.target, level, this.internalFormat, this.image[level].width, this.image[level].height, 0, this.image[level].data);
}
} else {
// Regular texture
if (this.target === this.gl.TEXTURE_2D) {
this.gl.texImage2D(this.target, this.level, this.internalFormat, this.format, this.type, this.image);
} else {
this.gl.texImage3D(this.target, this.level, this.internalFormat, this.width, this.height, this.length, 0, this.format, this.type, this.image);
}
}
if (this.generateMipmaps) {
// For WebGL1, if not a power of 2, turn off mips, set wrapping to clamp to edge and minFilter to linear
if (!this.gl.renderer.isWebgl2 && (!isPowerOf2(this.image.width) || !isPowerOf2(this.image.height))) {
this.generateMipmaps = false;
this.wrapS = this.wrapT = this.gl.CLAMP_TO_EDGE;
this.minFilter = this.gl.LINEAR;
} else {
this.gl.generateMipmap(this.target);
}
}
// Callback for when data is pushed to GPU
this.onUpdate && this.onUpdate();
} else {
if (this.target === this.gl.TEXTURE_CUBE_MAP) {
// Upload empty pixel for each side while no image to avoid errors while image or video loading
for (let i = 0; i < 6; i++) {
this.gl.texImage2D(this.gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, this.gl.RGBA, 1, 1, 0, this.gl.RGBA, this.gl.UNSIGNED_BYTE, emptyPixel);
}
} else if (this.width) {
// image intentionally left null for RenderTarget
if (this.target === this.gl.TEXTURE_2D) {
this.gl.texImage2D(this.target, this.level, this.internalFormat, this.width, this.height, 0, this.format, this.type, null);
} else {
this.gl.texImage3D(this.target, this.level, this.internalFormat, this.width, this.height, this.length, 0, this.format, this.type, null);
}
} else {
// Upload empty pixel if no image to avoid errors while image or video loading
this.gl.texImage2D(this.target, 0, this.gl.RGBA, 1, 1, 0, this.gl.RGBA, this.gl.UNSIGNED_BYTE, emptyPixel);
}
}
this.store.image = this.image;
}
}

81
node_modules/ogl/src/core/Transform.js generated vendored Normal file
View File

@@ -0,0 +1,81 @@
import { Vec3 } from '../math/Vec3.js';
import { Quat } from '../math/Quat.js';
import { Mat4 } from '../math/Mat4.js';
import { Euler } from '../math/Euler.js';
export class Transform {
constructor() {
this.parent = null;
this.children = [];
this.visible = true;
this.matrix = new Mat4();
this.worldMatrix = new Mat4();
this.matrixAutoUpdate = true;
this.worldMatrixNeedsUpdate = false;
this.position = new Vec3();
this.quaternion = new Quat();
this.scale = new Vec3(1);
this.rotation = new Euler();
this.up = new Vec3(0, 1, 0);
this.rotation._target.onChange = () => this.quaternion.fromEuler(this.rotation, true);
this.quaternion._target.onChange = () => this.rotation.fromQuaternion(this.quaternion, undefined, true);
}
setParent(parent, notifyParent = true) {
if (this.parent && parent !== this.parent) this.parent.removeChild(this, false);
this.parent = parent;
if (notifyParent && parent) parent.addChild(this, false);
}
addChild(child, notifyChild = true) {
if (!~this.children.indexOf(child)) this.children.push(child);
if (notifyChild) child.setParent(this, false);
}
removeChild(child, notifyChild = true) {
if (!!~this.children.indexOf(child)) this.children.splice(this.children.indexOf(child), 1);
if (notifyChild) child.setParent(null, false);
}
updateMatrixWorld(force) {
if (this.matrixAutoUpdate) this.updateMatrix();
if (this.worldMatrixNeedsUpdate || force) {
if (this.parent === null) this.worldMatrix.copy(this.matrix);
else this.worldMatrix.multiply(this.parent.worldMatrix, this.matrix);
this.worldMatrixNeedsUpdate = false;
force = true;
}
for (let i = 0, l = this.children.length; i < l; i++) {
this.children[i].updateMatrixWorld(force);
}
}
updateMatrix() {
this.matrix.compose(this.quaternion, this.position, this.scale);
this.worldMatrixNeedsUpdate = true;
}
traverse(callback) {
// Return true in callback to stop traversing children
if (callback(this)) return;
for (let i = 0, l = this.children.length; i < l; i++) {
this.children[i].traverse(callback);
}
}
decompose() {
this.matrix.decompose(this.quaternion._target, this.position, this.scale);
this.rotation.fromQuaternion(this.quaternion);
}
lookAt(target, invert = false) {
if (invert) this.matrix.lookAt(this.position, target, this.up);
else this.matrix.lookAt(target, this.position, this.up);
this.matrix.getRotation(this.quaternion._target);
this.rotation.fromQuaternion(this.quaternion);
}
}

48
node_modules/ogl/src/extras/Animation.js generated vendored Normal file
View File

@@ -0,0 +1,48 @@
import { Vec3 } from '../math/Vec3.js';
import { Quat } from '../math/Quat.js';
const prevPos = /* @__PURE__ */ new Vec3();
const prevRot = /* @__PURE__ */ new Quat();
const prevScl = /* @__PURE__ */ new Vec3();
const nextPos = /* @__PURE__ */ new Vec3();
const nextRot = /* @__PURE__ */ new Quat();
const nextScl = /* @__PURE__ */ new Vec3();
export class Animation {
constructor({ objects, data }) {
this.objects = objects;
this.data = data;
this.elapsed = 0;
this.weight = 1;
this.duration = data.frames.length - 1;
}
update(totalWeight = 1, isSet) {
const weight = isSet ? 1 : this.weight / totalWeight;
const elapsed = this.elapsed % this.duration;
const floorFrame = Math.floor(elapsed);
const blend = elapsed - floorFrame;
const prevKey = this.data.frames[floorFrame];
const nextKey = this.data.frames[(floorFrame + 1) % this.duration];
this.objects.forEach((object, i) => {
prevPos.fromArray(prevKey.position, i * 3);
prevRot.fromArray(prevKey.quaternion, i * 4);
prevScl.fromArray(prevKey.scale, i * 3);
nextPos.fromArray(nextKey.position, i * 3);
nextRot.fromArray(nextKey.quaternion, i * 4);
nextScl.fromArray(nextKey.scale, i * 3);
prevPos.lerp(nextPos, blend);
prevRot.slerp(nextRot, blend);
prevScl.lerp(nextScl, blend);
object.position.lerp(prevPos, weight);
object.quaternion.slerp(prevRot, weight);
object.scale.lerp(prevScl, weight);
});
}
}

61
node_modules/ogl/src/extras/BasisManager.js generated vendored Normal file
View File

@@ -0,0 +1,61 @@
let supportedFormat;
let id = 0;
export class BasisManager {
constructor(workerSrc, gl) {
if (!supportedFormat) supportedFormat = this.getSupportedFormat(gl);
this.onMessage = this.onMessage.bind(this);
this.queue = new Map();
this.initWorker(workerSrc);
}
getSupportedFormat(gl = document.createElement('canvas').getContext('webgl')) {
/* if (!!gl.getExtension('WEBGL_compressed_texture_etc')) {
return 'etc2';
} else */
if (!!gl.getExtension('WEBGL_compressed_texture_astc')) {
return 'astc';
} else if (!!gl.getExtension('EXT_texture_compression_bptc')) {
return 'bptc';
} else if (!!gl.getExtension('WEBGL_compressed_texture_s3tc')) {
return 's3tc';
} else if (!!gl.getExtension('WEBGL_compressed_texture_etc1')) {
return 'etc1';
} else if (!!gl.getExtension('WEBGL_compressed_texture_pvrtc') || !!gl.getExtension('WEBKIT_WEBGL_compressed_texture_pvrtc')) {
return 'pvrtc';
// } else if (!!gl.getExtension('WEBGL_compressed_texture_atc')) {
// return 'atc';
}
return 'none';
}
initWorker(workerSrc) {
this.worker = new Worker(workerSrc);
this.worker.onmessage = this.onMessage;
}
onMessage({ data }) {
const { id, error, image } = data;
if (error) {
console.log(error, id);
return;
}
const textureResolve = this.queue.get(id);
this.queue.delete(id);
image.isBasis = true;
textureResolve(image);
}
parseTexture(buffer) {
id++;
this.worker.postMessage({
id,
buffer,
supportedFormat,
});
let textureResolve;
const promise = new Promise((res) => (textureResolve = res));
this.queue.set(id, textureResolve);
return promise;
}
}

55
node_modules/ogl/src/extras/Box.js generated vendored Normal file
View File

@@ -0,0 +1,55 @@
import { Geometry } from '../core/Geometry.js';
import { Plane } from './Plane.js';
export class Box extends Geometry {
constructor(gl, { width = 1, height = 1, depth = 1, widthSegments = 1, heightSegments = 1, depthSegments = 1, attributes = {} } = {}) {
const wSegs = widthSegments;
const hSegs = heightSegments;
const dSegs = depthSegments;
const num = (wSegs + 1) * (hSegs + 1) * 2 + (wSegs + 1) * (dSegs + 1) * 2 + (hSegs + 1) * (dSegs + 1) * 2;
const numIndices = (wSegs * hSegs * 2 + wSegs * dSegs * 2 + hSegs * dSegs * 2) * 6;
const position = new Float32Array(num * 3);
const normal = new Float32Array(num * 3);
const uv = new Float32Array(num * 2);
const index = num > 65536 ? new Uint32Array(numIndices) : new Uint16Array(numIndices);
let i = 0;
let ii = 0;
// left, right
Plane.buildPlane(position, normal, uv, index, depth, height, width, dSegs, hSegs, 2, 1, 0, -1, -1, i, ii);
i += (dSegs + 1) * (hSegs + 1);
ii += dSegs * hSegs;
Plane.buildPlane(position, normal, uv, index, depth, height, -width, dSegs, hSegs, 2, 1, 0, 1, -1, i, ii);
i += (dSegs + 1) * (hSegs + 1);
ii += dSegs * hSegs;
// top, bottom
Plane.buildPlane(position, normal, uv, index, width, depth, height, dSegs, wSegs, 0, 2, 1, 1, 1, i, ii);
i += (wSegs + 1) * (dSegs + 1);
ii += wSegs * dSegs;
Plane.buildPlane(position, normal, uv, index, width, depth, -height, dSegs, wSegs, 0, 2, 1, 1, -1, i, ii);
i += (wSegs + 1) * (dSegs + 1);
ii += wSegs * dSegs;
// front, back
Plane.buildPlane(position, normal, uv, index, width, height, -depth, wSegs, hSegs, 0, 1, 2, -1, -1, i, ii);
i += (wSegs + 1) * (hSegs + 1);
ii += wSegs * hSegs;
Plane.buildPlane(position, normal, uv, index, width, height, depth, wSegs, hSegs, 0, 1, 2, 1, -1, i, ii);
Object.assign(attributes, {
position: { size: 3, data: position },
normal: { size: 3, data: normal },
uv: { size: 2, data: uv },
index: { data: index },
});
super(gl, attributes);
}
}

184
node_modules/ogl/src/extras/Curve.js generated vendored Normal file
View File

@@ -0,0 +1,184 @@
import { Vec3 } from '../math/Vec3.js';
const CATMULLROM = 'catmullrom';
const CUBICBEZIER = 'cubicbezier';
const QUADRATICBEZIER = 'quadraticbezier';
// temp
const _a0 = /* @__PURE__ */ new Vec3(),
_a1 = /* @__PURE__ */ new Vec3(),
_a2 = /* @__PURE__ */ new Vec3(),
_a3 = /* @__PURE__ */ new Vec3();
/**
* Get the control points of cubic bezier curve.
* @param {*} i
* @param {*} a
* @param {*} b
*/
function getCtrlPoint(points, i, a = 0.168, b = 0.168) {
if (i < 1) {
_a0.sub(points[1], points[0]).scale(a).add(points[0]);
} else {
_a0.sub(points[i + 1], points[i - 1])
.scale(a)
.add(points[i]);
}
if (i > points.length - 3) {
const last = points.length - 1;
_a1.sub(points[last - 1], points[last])
.scale(b)
.add(points[last]);
} else {
_a1.sub(points[i], points[i + 2])
.scale(b)
.add(points[i + 1]);
}
return [_a0.clone(), _a1.clone()];
}
function getQuadraticBezierPoint(t, p0, c0, p1) {
const k = 1 - t;
_a0.copy(p0).scale(k ** 2);
_a1.copy(c0).scale(2 * k * t);
_a2.copy(p1).scale(t ** 2);
const ret = new Vec3();
ret.add(_a0, _a1).add(_a2);
return ret;
}
function getCubicBezierPoint(t, p0, c0, c1, p1) {
const k = 1 - t;
_a0.copy(p0).scale(k ** 3);
_a1.copy(c0).scale(3 * k ** 2 * t);
_a2.copy(c1).scale(3 * k * t ** 2);
_a3.copy(p1).scale(t ** 3);
const ret = new Vec3();
ret.add(_a0, _a1).add(_a2).add(_a3);
return ret;
}
export class Curve {
constructor({ points = [new Vec3(0, 0, 0), new Vec3(0, 1, 0), new Vec3(1, 1, 0), new Vec3(1, 0, 0)], divisions = 12, type = CATMULLROM } = {}) {
this.points = points;
this.divisions = divisions;
this.type = type;
}
_getQuadraticBezierPoints(divisions = this.divisions) {
const points = [];
const count = this.points.length;
if (count < 3) {
console.warn('Not enough points provided.');
return [];
}
const p0 = this.points[0];
let c0 = this.points[1],
p1 = this.points[2];
for (let i = 0; i <= divisions; i++) {
const p = getQuadraticBezierPoint(i / divisions, p0, c0, p1);
points.push(p);
}
let offset = 3;
while (count - offset > 0) {
p0.copy(p1);
c0 = p1.scale(2).sub(c0);
p1 = this.points[offset];
for (let i = 1; i <= divisions; i++) {
const p = getQuadraticBezierPoint(i / divisions, p0, c0, p1);
points.push(p);
}
offset++;
}
return points;
}
_getCubicBezierPoints(divisions = this.divisions) {
const points = [];
const count = this.points.length;
if (count < 4) {
console.warn('Not enough points provided.');
return [];
}
let p0 = this.points[0],
c0 = this.points[1],
c1 = this.points[2],
p1 = this.points[3];
for (let i = 0; i <= divisions; i++) {
const p = getCubicBezierPoint(i / divisions, p0, c0, c1, p1);
points.push(p);
}
let offset = 4;
while (count - offset > 1) {
p0.copy(p1);
c0 = p1.scale(2).sub(c1);
c1 = this.points[offset];
p1 = this.points[offset + 1];
for (let i = 1; i <= divisions; i++) {
const p = getCubicBezierPoint(i / divisions, p0, c0, c1, p1);
points.push(p);
}
offset += 2;
}
return points;
}
_getCatmullRomPoints(divisions = this.divisions, a = 0.168, b = 0.168) {
const points = [];
const count = this.points.length;
if (count <= 2) {
return this.points;
}
let p0;
this.points.forEach((p, i) => {
if (i === 0) {
p0 = p;
} else {
const [c0, c1] = getCtrlPoint(this.points, i - 1, a, b);
const c = new Curve({
points: [p0, c0, c1, p],
type: CUBICBEZIER,
});
points.pop();
points.push(...c.getPoints(divisions));
p0 = p;
}
});
return points;
}
getPoints(divisions = this.divisions, a = 0.168, b = 0.168) {
const type = this.type;
if (type === QUADRATICBEZIER) {
return this._getQuadraticBezierPoints(divisions);
}
if (type === CUBICBEZIER) {
return this._getCubicBezierPoints(divisions);
}
if (type === CATMULLROM) {
return this._getCatmullRomPoints(divisions, a, b);
}
return this.points;
}
}
Curve.CATMULLROM = CATMULLROM;
Curve.CUBICBEZIER = CUBICBEZIER;
Curve.QUADRATICBEZIER = QUADRATICBEZIER;

124
node_modules/ogl/src/extras/Cylinder.js generated vendored Normal file
View File

@@ -0,0 +1,124 @@
import { Geometry } from '../core/Geometry.js';
import { Vec3 } from '../math/Vec3.js';
export class Cylinder extends Geometry {
constructor(
gl,
{
radiusTop = 0.5,
radiusBottom = 0.5,
height = 1,
radialSegments = 8,
heightSegments = 1,
openEnded = false,
thetaStart = 0,
thetaLength = Math.PI * 2,
attributes = {},
} = {}
) {
const rSegs = radialSegments;
const hSegs = heightSegments;
const tStart = thetaStart;
const tLength = thetaLength;
const numCaps = openEnded ? 0 : radiusBottom && radiusTop ? 2 : 1;
const num = (rSegs + 1) * (hSegs + 1 + numCaps) + numCaps;
const numIndices = rSegs * hSegs * 6 + numCaps * rSegs * 3;
const position = new Float32Array(num * 3);
const normal = new Float32Array(num * 3);
const uv = new Float32Array(num * 2);
const index = num > 65536 ? new Uint32Array(numIndices) : new Uint16Array(numIndices);
let i = 0;
let ii = 0;
const indexArray = [];
addHeight();
if (!openEnded) {
if (radiusTop) addCap(true);
if (radiusBottom) addCap(false);
}
function addHeight() {
let x, y;
const n = new Vec3();
const slope = (radiusBottom - radiusTop) / height;
for (y = 0; y <= hSegs; y++) {
const indexRow = [];
const v = y / hSegs;
const r = v * (radiusBottom - radiusTop) + radiusTop;
for (x = 0; x <= rSegs; x++) {
const u = x / rSegs;
const theta = u * tLength + tStart;
const sinTheta = Math.sin(theta);
const cosTheta = Math.cos(theta);
position.set([r * sinTheta, (0.5 - v) * height, r * cosTheta], i * 3);
n.set(sinTheta, slope, cosTheta).normalize();
normal.set([n.x, n.y, n.z], i * 3);
uv.set([u, 1 - v], i * 2);
indexRow.push(i++);
}
indexArray.push(indexRow);
}
for (x = 0; x < rSegs; x++) {
for (y = 0; y < hSegs; y++) {
const a = indexArray[y][x];
const b = indexArray[y + 1][x];
const c = indexArray[y + 1][x + 1];
const d = indexArray[y][x + 1];
index.set([a, b, d, b, c, d], ii * 3);
ii += 2;
}
}
}
function addCap(isTop) {
let x;
const r = isTop === true ? radiusTop : radiusBottom;
const sign = isTop === true ? 1 : -1;
const centerIndex = i;
position.set([0, 0.5 * height * sign, 0], i * 3);
normal.set([0, sign, 0], i * 3);
uv.set([0.5, 0.5], i * 2);
i++;
for (x = 0; x <= rSegs; x++) {
const u = x / rSegs;
const theta = u * tLength + tStart;
const cosTheta = Math.cos(theta);
const sinTheta = Math.sin(theta);
position.set([r * sinTheta, 0.5 * height * sign, r * cosTheta], i * 3);
normal.set([0, sign, 0], i * 3);
uv.set([cosTheta * 0.5 + 0.5, sinTheta * 0.5 * sign + 0.5], i * 2);
i++;
}
for (x = 0; x < rSegs; x++) {
const j = centerIndex + x + 1;
if (isTop) {
index.set([j, j + 1, centerIndex], ii * 3);
} else {
index.set([j + 1, j, centerIndex], ii * 3);
}
ii++;
}
}
Object.assign(attributes, {
position: { size: 3, data: position },
normal: { size: 3, data: normal },
uv: { size: 2, data: uv },
index: { data: index },
});
super(gl, attributes);
}
}

38
node_modules/ogl/src/extras/DracoManager.js generated vendored Normal file
View File

@@ -0,0 +1,38 @@
let id = 0;
export class DracoManager {
constructor(workerSrc) {
this.onMessage = this.onMessage.bind(this);
this.queue = new Map();
this.initWorker(workerSrc);
}
initWorker(workerSrc) {
this.worker = new Worker(workerSrc);
this.worker.onmessage = this.onMessage;
}
onMessage({ data }) {
const { id, error, geometry } = data;
if (error) {
console.log(error, id);
return;
}
const geometryResolve = this.queue.get(id);
this.queue.delete(id);
geometryResolve(geometry);
}
decodeGeometry(buffer, config) {
id++;
this.worker.postMessage({
id,
buffer,
config,
});
let geometryResolve;
const promise = new Promise((res) => (geometryResolve = res));
this.queue.set(id, geometryResolve);
return promise;
}
}

150
node_modules/ogl/src/extras/Flowmap.js generated vendored Normal file
View File

@@ -0,0 +1,150 @@
import { RenderTarget } from '../core/RenderTarget.js';
import { Program } from '../core/Program.js';
import { Mesh } from '../core/Mesh.js';
import { Vec2 } from '../math/Vec2.js';
import { Triangle } from './Triangle.js';
export class Flowmap {
constructor(
gl,
{
size = 128, // default size of the render targets
falloff = 0.3, // size of the stamp, percentage of the size
alpha = 1, // opacity of the stamp
dissipation = 0.98, // affects the speed that the stamp fades. Closer to 1 is slower
type, // Pass in gl.FLOAT to force it, defaults to gl.HALF_FLOAT
} = {}
) {
const _this = this;
this.gl = gl;
// output uniform containing render target textures
this.uniform = { value: null };
this.mask = {
read: null,
write: null,
// Helper function to ping pong the render targets and update the uniform
swap: () => {
let temp = _this.mask.read;
_this.mask.read = _this.mask.write;
_this.mask.write = temp;
_this.uniform.value = _this.mask.read.texture;
},
};
{
createFBOs();
this.aspect = 1;
this.mouse = new Vec2();
this.velocity = new Vec2();
this.mesh = initProgram();
}
function createFBOs() {
// Requested type not supported, fall back to half float
if (!type) type = gl.HALF_FLOAT || gl.renderer.extensions['OES_texture_half_float'].HALF_FLOAT_OES;
let minFilter = (() => {
if (gl.renderer.isWebgl2) return gl.LINEAR;
if (gl.renderer.extensions[`OES_texture_${type === gl.FLOAT ? '' : 'half_'}float_linear`]) return gl.LINEAR;
return gl.NEAREST;
})();
const options = {
width: size,
height: size,
type,
format: gl.RGBA,
internalFormat: gl.renderer.isWebgl2 ? (type === gl.FLOAT ? gl.RGBA32F : gl.RGBA16F) : gl.RGBA,
minFilter,
depth: false,
};
_this.mask.read = new RenderTarget(gl, options);
_this.mask.write = new RenderTarget(gl, options);
_this.mask.swap();
}
function initProgram() {
return new Mesh(gl, {
// Triangle that includes -1 to 1 range for 'position', and 0 to 1 range for 'uv'.
geometry: new Triangle(gl),
program: new Program(gl, {
vertex,
fragment,
uniforms: {
tMap: _this.uniform,
uFalloff: { value: falloff * 0.5 },
uAlpha: { value: alpha },
uDissipation: { value: dissipation },
// User needs to update these
uAspect: { value: 1 },
uMouse: { value: _this.mouse },
uVelocity: { value: _this.velocity },
},
depthTest: false,
}),
});
}
}
update() {
this.mesh.program.uniforms.uAspect.value = this.aspect;
this.gl.renderer.render({
scene: this.mesh,
target: this.mask.write,
clear: false,
});
this.mask.swap();
}
}
const vertex = /* glsl */ `
attribute vec2 uv;
attribute vec2 position;
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = vec4(position, 0, 1);
}
`;
const fragment = /* glsl */ `
precision highp float;
uniform sampler2D tMap;
uniform float uFalloff;
uniform float uAlpha;
uniform float uDissipation;
uniform float uAspect;
uniform vec2 uMouse;
uniform vec2 uVelocity;
varying vec2 vUv;
void main() {
vec4 color = texture2D(tMap, vUv) * uDissipation;
vec2 cursor = vUv - uMouse;
cursor.x *= uAspect;
vec3 stamp = vec3(uVelocity * vec2(1, -1), 1.0 - pow(1.0 - min(1.0, length(uVelocity)), 3.0));
float falloff = smoothstep(uFalloff, 0.0, length(cursor)) * uAlpha;
color.rgb = mix(color.rgb, stamp, vec3(falloff));
gl_FragColor = color;
}
`;

117
node_modules/ogl/src/extras/GLTFAnimation.js generated vendored Normal file
View File

@@ -0,0 +1,117 @@
import { Vec3 } from '../math/Vec3.js';
import { Quat } from '../math/Quat.js';
const tmpVec3A = /* @__PURE__ */ new Vec3();
const tmpVec3B = /* @__PURE__ */ new Vec3();
const tmpVec3C = /* @__PURE__ */ new Vec3();
const tmpVec3D = /* @__PURE__ */ new Vec3();
const tmpQuatA = /* @__PURE__ */ new Quat();
const tmpQuatB = /* @__PURE__ */ new Quat();
const tmpQuatC = /* @__PURE__ */ new Quat();
const tmpQuatD = /* @__PURE__ */ new Quat();
export class GLTFAnimation {
constructor(data, weight = 1) {
this.data = data;
this.elapsed = 0;
this.weight = weight;
// Set to false to not apply modulo to elapsed against duration
this.loop = true;
// Find starting time as exports from blender (perhaps others too) don't always start from 0
this.startTime = data.reduce((a, { times }) => Math.min(a, times[0]), Infinity);
// Get largest final time in all channels to calculate duration
this.endTime = data.reduce((a, { times }) => Math.max(a, times[times.length - 1]), 0);
this.duration = this.endTime - this.startTime;
}
update(totalWeight = 1, isSet) {
const weight = isSet ? 1 : this.weight / totalWeight;
const elapsed = !this.duration
? 0
: (this.loop ? this.elapsed % this.duration : Math.min(this.elapsed, this.duration - 0.001)) + this.startTime;
this.data.forEach(({ node, transform, interpolation, times, values }) => {
if (!this.duration) {
let val = tmpVec3A;
let size = 3;
if (transform === 'quaternion') {
val = tmpQuatA;
size = 4;
}
val.fromArray(values, 0);
if (size === 4) node[transform].slerp(val, weight);
else node[transform].lerp(val, weight);
return;
}
// Get index of two time values elapsed is between
const prevIndex =
Math.max(
1,
times.findIndex((t) => t > elapsed)
) - 1;
const nextIndex = prevIndex + 1;
// Get linear blend/alpha between the two
let alpha = (elapsed - times[prevIndex]) / (times[nextIndex] - times[prevIndex]);
if (interpolation === 'STEP') alpha = 0;
let prevVal = tmpVec3A;
let prevTan = tmpVec3B;
let nextTan = tmpVec3C;
let nextVal = tmpVec3D;
let size = 3;
if (transform === 'quaternion') {
prevVal = tmpQuatA;
prevTan = tmpQuatB;
nextTan = tmpQuatC;
nextVal = tmpQuatD;
size = 4;
}
if (interpolation === 'CUBICSPLINE') {
// Get the prev and next values from the indices
prevVal.fromArray(values, prevIndex * size * 3 + size * 1);
prevTan.fromArray(values, prevIndex * size * 3 + size * 2);
nextTan.fromArray(values, nextIndex * size * 3 + size * 0);
nextVal.fromArray(values, nextIndex * size * 3 + size * 1);
// interpolate for final value
prevVal = this.cubicSplineInterpolate(alpha, prevVal, prevTan, nextTan, nextVal);
if (size === 4) prevVal.normalize();
} else {
// Get the prev and next values from the indices
prevVal.fromArray(values, prevIndex * size);
nextVal.fromArray(values, nextIndex * size);
// interpolate for final value
if (size === 4) prevVal.slerp(nextVal, alpha);
else prevVal.lerp(nextVal, alpha);
}
// interpolate between multiple possible animations
if (size === 4) node[transform].slerp(prevVal, weight);
else node[transform].lerp(prevVal, weight);
});
}
cubicSplineInterpolate(t, prevVal, prevTan, nextTan, nextVal) {
const t2 = t * t;
const t3 = t2 * t;
const s2 = 3 * t2 - 2 * t3;
const s3 = t3 - t2;
const s0 = 1 - s2;
const s1 = s3 - t2 + t;
for (let i = 0; i < prevVal.length; i++) {
prevVal[i] = s0 * prevVal[i] + s1 * (1 - t) * prevTan[i] + s2 * nextVal[i] + s3 * t * nextTan[i];
}
return prevVal;
}
}

1058
node_modules/ogl/src/extras/GLTFLoader.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

66
node_modules/ogl/src/extras/GLTFSkin.js generated vendored Normal file
View File

@@ -0,0 +1,66 @@
import { Mesh } from '../core/Mesh.js';
import { Mat4 } from '../math/Mat4.js';
import { Texture } from '../core/Texture.js';
const tempMat4 = /* @__PURE__ */ new Mat4();
const identity = /* @__PURE__ */ new Mat4();
export class GLTFSkin extends Mesh {
constructor(gl, { skeleton, geometry, program, mode = gl.TRIANGLES } = {}) {
super(gl, { geometry, program, mode });
this.skeleton = skeleton;
this.program = program;
this.createBoneTexture();
}
createBoneTexture() {
if (!this.skeleton.joints.length) return;
const size = Math.max(4, Math.pow(2, Math.ceil(Math.log(Math.sqrt(this.skeleton.joints.length * 4)) / Math.LN2)));
this.boneMatrices = new Float32Array(size * size * 4);
this.boneTextureSize = size;
this.boneTexture = new Texture(this.gl, {
image: this.boneMatrices,
generateMipmaps: false,
type: this.gl.FLOAT,
internalFormat: this.gl.renderer.isWebgl2 ? this.gl.RGBA32F : this.gl.RGBA,
minFilter: this.gl.NEAREST,
magFilter: this.gl.NEAREST,
flipY: false,
width: size,
});
}
updateUniforms() {
// Update bone texture
this.skeleton.joints.forEach((bone, i) => {
// Find difference between current and bind pose
tempMat4.multiply(bone.worldMatrix, bone.bindInverse);
this.boneMatrices.set(tempMat4, i * 16);
});
this.boneTexture.needsUpdate = true;
// Reset for programs shared between multiple skins
this.program.uniforms.boneTexture.value = this.boneTexture;
this.program.uniforms.boneTextureSize.value = this.boneTextureSize;
}
draw({ camera } = {}) {
if (!this.program.uniforms.boneTexture) {
Object.assign(this.program.uniforms, {
boneTexture: { value: this.boneTexture },
boneTextureSize: { value: this.boneTextureSize },
});
}
this.updateUniforms();
// Switch the world matrix with identity to ignore any transforms
// on the mesh itself - only use skeleton's transforms
const _worldMatrix = this.worldMatrix;
this.worldMatrix = identity;
super.draw({ camera });
// Switch back to leave identity untouched
this.worldMatrix = _worldMatrix;
}
}

140
node_modules/ogl/src/extras/GPGPU.js generated vendored Normal file
View File

@@ -0,0 +1,140 @@
import { Program } from '../core/Program.js';
import { Mesh } from '../core/Mesh.js';
import { Texture } from '../core/Texture.js';
import { RenderTarget } from '../core/RenderTarget.js';
import { Triangle } from './Triangle.js';
export class GPGPU {
constructor(
gl,
{
// Always pass in array of vec4s (RGBA values within texture)
data = new Float32Array(16),
geometry = new Triangle(gl),
type, // Pass in gl.FLOAT to force it, defaults to gl.HALF_FLOAT
}
) {
this.gl = gl;
const initialData = data;
this.passes = [];
this.geometry = geometry;
this.dataLength = initialData.length / 4;
// Windows and iOS only like power of 2 textures
// Find smallest PO2 that fits data
this.size = Math.pow(2, Math.ceil(Math.log(Math.ceil(Math.sqrt(this.dataLength))) / Math.LN2));
// Create coords for output texture
this.coords = new Float32Array(this.dataLength * 2);
for (let i = 0; i < this.dataLength; i++) {
const x = (i % this.size) / this.size; // to add 0.5 to be center pixel ?
const y = Math.floor(i / this.size) / this.size;
this.coords.set([x, y], i * 2);
}
// Use original data if already correct length of PO2 texture, else copy to new array of correct length
const floatArray = (() => {
if (initialData.length === this.size * this.size * 4) {
return initialData;
} else {
const a = new Float32Array(this.size * this.size * 4);
a.set(initialData);
return a;
}
})();
// Create output texture uniform using input float texture with initial data
this.uniform = {
value: new Texture(gl, {
image: floatArray,
target: gl.TEXTURE_2D,
type: gl.FLOAT,
format: gl.RGBA,
internalFormat: gl.renderer.isWebgl2 ? gl.RGBA32F : gl.RGBA,
wrapS: gl.CLAMP_TO_EDGE,
wrapT: gl.CLAMP_TO_EDGE,
generateMipmaps: false,
minFilter: gl.NEAREST,
magFilter: gl.NEAREST,
width: this.size,
flipY: false,
}),
};
// Create FBOs
const options = {
width: this.size,
height: this.size,
type: type || gl.HALF_FLOAT || gl.renderer.extensions['OES_texture_half_float'].HALF_FLOAT_OES,
format: gl.RGBA,
internalFormat: gl.renderer.isWebgl2 ? (type === gl.FLOAT ? gl.RGBA32F : gl.RGBA16F) : gl.RGBA,
minFilter: gl.NEAREST,
depth: false,
unpackAlignment: 1,
};
this.fbo = {
read: new RenderTarget(gl, options),
write: new RenderTarget(gl, options),
swap: () => {
let temp = this.fbo.read;
this.fbo.read = this.fbo.write;
this.fbo.write = temp;
this.uniform.value = this.fbo.read.texture;
},
};
}
addPass({ vertex = defaultVertex, fragment = defaultFragment, uniforms = {}, textureUniform = 'tMap', enabled = true } = {}) {
uniforms[textureUniform] = this.uniform;
const program = new Program(this.gl, { vertex, fragment, uniforms });
const mesh = new Mesh(this.gl, { geometry: this.geometry, program });
const pass = {
mesh,
program,
uniforms,
enabled,
textureUniform,
};
this.passes.push(pass);
return pass;
}
render() {
const enabledPasses = this.passes.filter((pass) => pass.enabled);
enabledPasses.forEach((pass, i) => {
this.gl.renderer.render({
scene: pass.mesh,
target: this.fbo.write,
clear: false,
});
this.fbo.swap();
});
}
}
const defaultVertex = /* glsl */ `
attribute vec2 uv;
attribute vec2 position;
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = vec4(position, 0, 1);
}
`;
const defaultFragment = /* glsl */ `
precision highp float;
uniform sampler2D tMap;
varying vec2 vUv;
void main() {
gl_FragColor = texture2D(tMap, vUv);
}
`;

86
node_modules/ogl/src/extras/InstancedMesh.js generated vendored Normal file
View File

@@ -0,0 +1,86 @@
import { Transform } from '../core/Transform.js';
import { Mesh } from '../core/Mesh.js';
import { Vec4 } from '../math/Vec4.js';
export class InstancedMesh extends Mesh {
constructor(...args) {
super(...args);
// Skip renderer frustum culling
this.frustumCulled = false;
this.isInstancedMesh = true;
}
addFrustumCull() {
this.instanceTransforms = null;
this.instanceLightmapScaleOffset = null;
this.totalInstanceCount = 0;
this.frustumCullFunction = null;
this.instanceRenderList = null;
// Get instanced mesh
if (!this.geometry.attributes.instanceMatrix)
console.error(`mesh ${this.name ? `"${this.name}" ` : ``}missing instanceMatrix attribute; unable to frustum cull`);
// Make list of transforms from instanceMatrix
const matrixData = this.geometry.attributes.instanceMatrix.data;
this.instanceTransforms = [];
for (let i = 0, j = 0; i < matrixData.length; i += 16, j++) {
const transform = new Transform();
transform.index = j;
transform.matrix.fromArray(matrixData, i);
transform.decompose();
this.instanceTransforms.push(transform);
// Add transforms to parent to update world matrices
transform.setParent(this.parent);
}
this.totalInstanceCount = this.instanceTransforms.length;
// Check for lightmap attributes - attach to transform
if (!!this.geometry.attributes.lightmapScaleOffset) {
const lightmapData = this.geometry.attributes.lightmapScaleOffset.data;
for (let i = 0, j = 0; i < lightmapData.length; i += 4, j++) {
this.instanceTransforms[j].lightmapData = new Vec4().fromArray(lightmapData, i);
}
}
this.frustumCullFunction = ({ camera }) => {
// frustum cull transforms each frame - pass world matrix
this.instanceRenderList = [];
this.instanceTransforms.forEach((transform) => {
if (!camera.frustumIntersectsMesh(this, transform.worldMatrix)) return;
this.instanceRenderList.push(transform);
});
// update instanceMatrix and instancedCount with visible
this.instanceRenderList.forEach((transform, i) => {
transform.matrix.toArray(this.geometry.attributes.instanceMatrix.data, i * 16);
// Update lightmap attr
if (transform.lightmapData) {
transform.lightmapData.toArray(this.geometry.attributes.lightmapScaleOffset.data, i * 4);
this.geometry.attributes.lightmapScaleOffset.needsUpdate = true;
}
});
this.geometry.instancedCount = this.instanceRenderList.length;
this.geometry.attributes.instanceMatrix.needsUpdate = true;
};
this.onBeforeRender(this.frustumCullFunction);
}
removeFrustumCull() {
this.offBeforeRender(this.frustumCullFunction);
this.geometry.instancedCount = this.totalInstanceCount;
this.instanceTransforms.forEach((transform, i) => {
transform.matrix.toArray(this.geometry.attributes.instanceMatrix.data, i * 16);
// Update lightmap attr
if (transform.lightmapData) {
transform.lightmapData.toArray(this.geometry.attributes.lightmapScaleOffset.data, i * 4);
this.geometry.attributes.lightmapScaleOffset.needsUpdate = true;
}
});
this.geometry.attributes.instanceMatrix.needsUpdate = true;
}
}

70
node_modules/ogl/src/extras/KTXTexture.js generated vendored Normal file
View File

@@ -0,0 +1,70 @@
import { Texture } from '../core/Texture.js';
// TODO: Support cubemaps
// Generate textures using https://github.com/TimvanScherpenzeel/texture-compressor
export class KTXTexture extends Texture {
constructor(gl, { buffer, wrapS = gl.CLAMP_TO_EDGE, wrapT = gl.CLAMP_TO_EDGE, anisotropy = 0, minFilter, magFilter } = {}) {
super(gl, {
generateMipmaps: false,
wrapS,
wrapT,
anisotropy,
minFilter,
magFilter,
});
if (buffer) return this.parseBuffer(buffer);
}
parseBuffer(buffer) {
const ktx = new KhronosTextureContainer(buffer);
ktx.mipmaps.isCompressedTexture = true;
// Update texture
this.image = ktx.mipmaps;
this.internalFormat = ktx.glInternalFormat;
if (ktx.numberOfMipmapLevels > 1) {
if (this.minFilter === this.gl.LINEAR) this.minFilter = this.gl.NEAREST_MIPMAP_LINEAR;
} else {
if (this.minFilter === this.gl.NEAREST_MIPMAP_LINEAR) this.minFilter = this.gl.LINEAR;
}
// TODO: support cube maps
// ktx.numberOfFaces
}
}
function KhronosTextureContainer(buffer) {
const idCheck = [0xab, 0x4b, 0x54, 0x58, 0x20, 0x31, 0x31, 0xbb, 0x0d, 0x0a, 0x1a, 0x0a];
const id = new Uint8Array(buffer, 0, 12);
for (let i = 0; i < id.length; i++) if (id[i] !== idCheck[i]) return console.error('File missing KTX identifier');
// TODO: Is this always 4? Tested: [android, macos]
const size = Uint32Array.BYTES_PER_ELEMENT;
const head = new DataView(buffer, 12, 13 * size);
const littleEndian = head.getUint32(0, true) === 0x04030201;
const glType = head.getUint32(1 * size, littleEndian);
if (glType !== 0) return console.warn('only compressed formats currently supported');
this.glInternalFormat = head.getUint32(4 * size, littleEndian);
let width = head.getUint32(6 * size, littleEndian);
let height = head.getUint32(7 * size, littleEndian);
this.numberOfFaces = head.getUint32(10 * size, littleEndian);
this.numberOfMipmapLevels = Math.max(1, head.getUint32(11 * size, littleEndian));
const bytesOfKeyValueData = head.getUint32(12 * size, littleEndian);
this.mipmaps = [];
let offset = 12 + 13 * 4 + bytesOfKeyValueData;
for (let level = 0; level < this.numberOfMipmapLevels; level++) {
const levelSize = new Int32Array(buffer, offset, 1)[0]; // size per face, since not supporting array cubemaps
offset += 4; // levelSize field
for (let face = 0; face < this.numberOfFaces; face++) {
const data = new Uint8Array(buffer, offset, levelSize);
this.mipmaps.push({ data, width, height });
offset += levelSize;
offset += 3 - ((levelSize + 3) % 4); // add padding for odd sized image
}
width = width >> 1;
height = height >> 1;
}
}

40
node_modules/ogl/src/extras/NormalProgram.js generated vendored Normal file
View File

@@ -0,0 +1,40 @@
import { Program } from '../core/Program.js';
const vertex = /* glsl */ `
precision highp float;
precision highp int;
attribute vec3 position;
attribute vec3 normal;
uniform mat3 normalMatrix;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
varying vec3 vNormal;
void main() {
vNormal = normalize(normalMatrix * normal);
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`;
const fragment = /* glsl */ `
precision highp float;
precision highp int;
varying vec3 vNormal;
void main() {
gl_FragColor.rgb = normalize(vNormal);
gl_FragColor.a = 1.0;
}
`;
export function NormalProgram(gl) {
return new Program(gl, {
vertex: vertex,
fragment: fragment,
cullFace: false,
});
}

359
node_modules/ogl/src/extras/Orbit.js generated vendored Normal file
View File

@@ -0,0 +1,359 @@
// Based from ThreeJS' OrbitControls class, rewritten using es6 with some additions and subtractions.
// TODO: abstract event handlers so can be fed from other sources
// TODO: make scroll zoom more accurate than just >/< zero
// TODO: be able to pass in new camera position
import { Vec3 } from '../math/Vec3.js';
import { Vec2 } from '../math/Vec2.js';
const STATE = { NONE: -1, ROTATE: 0, DOLLY: 1, PAN: 2, DOLLY_PAN: 3 };
const tempVec3 = /* @__PURE__ */ new Vec3();
const tempVec2a = /* @__PURE__ */ new Vec2();
const tempVec2b = /* @__PURE__ */ new Vec2();
export function Orbit(
object,
{
element = document,
enabled = true,
target = new Vec3(),
ease = 0.25,
inertia = 0.85,
enableRotate = true,
rotateSpeed = 0.1,
autoRotate = false,
autoRotateSpeed = 1.0,
enableZoom = true,
zoomSpeed = 1,
zoomStyle = 'dolly',
enablePan = true,
panSpeed = 0.1,
minPolarAngle = 0,
maxPolarAngle = Math.PI,
minAzimuthAngle = -Infinity,
maxAzimuthAngle = Infinity,
minDistance = 0,
maxDistance = Infinity,
} = {}
) {
this.enabled = enabled;
this.target = target;
this.zoomStyle = zoomStyle;
// Catch attempts to disable - set to 1 so has no effect
ease = ease || 1;
inertia = inertia || 0;
this.minDistance = minDistance;
this.maxDistance = maxDistance;
// current position in sphericalTarget coordinates
const sphericalDelta = { radius: 1, phi: 0, theta: 0 };
const sphericalTarget = { radius: 1, phi: 0, theta: 0 };
const spherical = { radius: 1, phi: 0, theta: 0 };
const panDelta = new Vec3();
// Grab initial position values
const offset = new Vec3();
offset.copy(object.position).sub(this.target);
spherical.radius = sphericalTarget.radius = offset.distance();
spherical.theta = sphericalTarget.theta = Math.atan2(offset.x, offset.z);
spherical.phi = sphericalTarget.phi = Math.acos(Math.min(Math.max(offset.y / sphericalTarget.radius, -1), 1));
this.offset = offset;
this.update = () => {
if (autoRotate) {
handleAutoRotate();
}
// apply delta
sphericalTarget.radius *= sphericalDelta.radius;
sphericalTarget.theta += sphericalDelta.theta;
sphericalTarget.phi += sphericalDelta.phi;
// apply boundaries
sphericalTarget.theta = Math.max(minAzimuthAngle, Math.min(maxAzimuthAngle, sphericalTarget.theta));
sphericalTarget.phi = Math.max(minPolarAngle, Math.min(maxPolarAngle, sphericalTarget.phi));
sphericalTarget.radius = Math.max(this.minDistance, Math.min(this.maxDistance, sphericalTarget.radius));
// ease values
spherical.phi += (sphericalTarget.phi - spherical.phi) * ease;
spherical.theta += (sphericalTarget.theta - spherical.theta) * ease;
spherical.radius += (sphericalTarget.radius - spherical.radius) * ease;
// apply pan to target. As offset is relative to target, it also shifts
this.target.add(panDelta);
// apply rotation to offset
let sinPhiRadius = spherical.radius * Math.sin(Math.max(0.000001, spherical.phi));
offset.x = sinPhiRadius * Math.sin(spherical.theta);
offset.y = spherical.radius * Math.cos(spherical.phi);
offset.z = sinPhiRadius * Math.cos(spherical.theta);
// Apply updated values to object
object.position.copy(this.target).add(offset);
object.lookAt(this.target);
// Apply inertia to values
sphericalDelta.theta *= inertia;
sphericalDelta.phi *= inertia;
panDelta.multiply(inertia);
// Reset scale every frame to avoid applying scale multiple times
sphericalDelta.radius = 1;
};
// Updates internals with new position
this.forcePosition = () => {
offset.copy(object.position).sub(this.target);
spherical.radius = sphericalTarget.radius = offset.distance();
spherical.theta = sphericalTarget.theta = Math.atan2(offset.x, offset.z);
spherical.phi = sphericalTarget.phi = Math.acos(Math.min(Math.max(offset.y / sphericalTarget.radius, -1), 1));
object.lookAt(this.target);
};
// Everything below here just updates panDelta and sphericalDelta
// Using those two objects' values, the orbit is calculated
const rotateStart = new Vec2();
const panStart = new Vec2();
const dollyStart = new Vec2();
let state = STATE.NONE;
this.mouseButtons = { ORBIT: 0, ZOOM: 1, PAN: 2 };
function getZoomScale() {
return Math.pow(0.95, zoomSpeed);
}
function panLeft(distance, m) {
tempVec3.set(m[0], m[1], m[2]);
tempVec3.multiply(-distance);
panDelta.add(tempVec3);
}
function panUp(distance, m) {
tempVec3.set(m[4], m[5], m[6]);
tempVec3.multiply(distance);
panDelta.add(tempVec3);
}
const pan = (deltaX, deltaY) => {
let el = element === document ? document.body : element;
tempVec3.copy(object.position).sub(this.target);
let targetDistance = tempVec3.distance();
targetDistance *= Math.tan((((object.fov || 45) / 2) * Math.PI) / 180.0);
panLeft((2 * deltaX * targetDistance) / el.clientHeight, object.matrix);
panUp((2 * deltaY * targetDistance) / el.clientHeight, object.matrix);
};
const dolly = (dollyScale) => {
if (this.zoomStyle === 'dolly') sphericalDelta.radius /= dollyScale;
else {
object.fov /= dollyScale;
if (object.type === 'orthographic') object.orthographic();
else object.perspective();
}
};
function handleAutoRotate() {
const angle = ((2 * Math.PI) / 60 / 60) * autoRotateSpeed;
sphericalDelta.theta -= angle;
}
function handleMoveRotate(x, y) {
tempVec2a.set(x, y);
tempVec2b.sub(tempVec2a, rotateStart).multiply(rotateSpeed);
let el = element === document ? document.body : element;
sphericalDelta.theta -= (2 * Math.PI * tempVec2b.x) / el.clientHeight;
sphericalDelta.phi -= (2 * Math.PI * tempVec2b.y) / el.clientHeight;
rotateStart.copy(tempVec2a);
}
function handleMouseMoveDolly(e) {
tempVec2a.set(e.clientX, e.clientY);
tempVec2b.sub(tempVec2a, dollyStart);
if (tempVec2b.y > 0) {
dolly(getZoomScale());
} else if (tempVec2b.y < 0) {
dolly(1 / getZoomScale());
}
dollyStart.copy(tempVec2a);
}
function handleMovePan(x, y) {
tempVec2a.set(x, y);
tempVec2b.sub(tempVec2a, panStart).multiply(panSpeed);
pan(tempVec2b.x, tempVec2b.y);
panStart.copy(tempVec2a);
}
function handleTouchStartDollyPan(e) {
if (enableZoom) {
let dx = e.touches[0].pageX - e.touches[1].pageX;
let dy = e.touches[0].pageY - e.touches[1].pageY;
let distance = Math.sqrt(dx * dx + dy * dy);
dollyStart.set(0, distance);
}
if (enablePan) {
let x = 0.5 * (e.touches[0].pageX + e.touches[1].pageX);
let y = 0.5 * (e.touches[0].pageY + e.touches[1].pageY);
panStart.set(x, y);
}
}
function handleTouchMoveDollyPan(e) {
if (enableZoom) {
let dx = e.touches[0].pageX - e.touches[1].pageX;
let dy = e.touches[0].pageY - e.touches[1].pageY;
let distance = Math.sqrt(dx * dx + dy * dy);
tempVec2a.set(0, distance);
tempVec2b.set(0, Math.pow(tempVec2a.y / dollyStart.y, zoomSpeed));
dolly(tempVec2b.y);
dollyStart.copy(tempVec2a);
}
if (enablePan) {
let x = 0.5 * (e.touches[0].pageX + e.touches[1].pageX);
let y = 0.5 * (e.touches[0].pageY + e.touches[1].pageY);
handleMovePan(x, y);
}
}
const onMouseDown = (e) => {
if (!this.enabled) return;
switch (e.button) {
case this.mouseButtons.ORBIT:
if (enableRotate === false) return;
rotateStart.set(e.clientX, e.clientY);
state = STATE.ROTATE;
break;
case this.mouseButtons.ZOOM:
if (enableZoom === false) return;
dollyStart.set(e.clientX, e.clientY);
state = STATE.DOLLY;
break;
case this.mouseButtons.PAN:
if (enablePan === false) return;
panStart.set(e.clientX, e.clientY);
state = STATE.PAN;
break;
}
if (state !== STATE.NONE) {
window.addEventListener('mousemove', onMouseMove, false);
window.addEventListener('mouseup', onMouseUp, false);
}
};
const onMouseMove = (e) => {
if (!this.enabled) return;
switch (state) {
case STATE.ROTATE:
if (enableRotate === false) return;
handleMoveRotate(e.clientX, e.clientY);
break;
case STATE.DOLLY:
if (enableZoom === false) return;
handleMouseMoveDolly(e);
break;
case STATE.PAN:
if (enablePan === false) return;
handleMovePan(e.clientX, e.clientY);
break;
}
};
const onMouseUp = () => {
window.removeEventListener('mousemove', onMouseMove, false);
window.removeEventListener('mouseup', onMouseUp, false);
state = STATE.NONE;
};
const onMouseWheel = (e) => {
if (!this.enabled || !enableZoom || (state !== STATE.NONE && state !== STATE.ROTATE)) return;
e.stopPropagation();
e.preventDefault();
if (e.deltaY < 0) {
dolly(1 / getZoomScale());
} else if (e.deltaY > 0) {
dolly(getZoomScale());
}
};
const onTouchStart = (e) => {
if (!this.enabled) return;
e.preventDefault();
switch (e.touches.length) {
case 1:
if (enableRotate === false) return;
rotateStart.set(e.touches[0].pageX, e.touches[0].pageY);
state = STATE.ROTATE;
break;
case 2:
if (enableZoom === false && enablePan === false) return;
handleTouchStartDollyPan(e);
state = STATE.DOLLY_PAN;
break;
default:
state = STATE.NONE;
}
};
const onTouchMove = (e) => {
if (!this.enabled) return;
e.preventDefault();
e.stopPropagation();
switch (e.touches.length) {
case 1:
if (enableRotate === false) return;
handleMoveRotate(e.touches[0].pageX, e.touches[0].pageY);
break;
case 2:
if (enableZoom === false && enablePan === false) return;
handleTouchMoveDollyPan(e);
break;
default:
state = STATE.NONE;
}
};
const onTouchEnd = () => {
if (!this.enabled) return;
state = STATE.NONE;
};
const onContextMenu = (e) => {
if (!this.enabled) return;
e.preventDefault();
};
function addHandlers() {
element.addEventListener('contextmenu', onContextMenu, false);
element.addEventListener('mousedown', onMouseDown, false);
element.addEventListener('wheel', onMouseWheel, { passive: false });
element.addEventListener('touchstart', onTouchStart, { passive: false });
element.addEventListener('touchend', onTouchEnd, false);
element.addEventListener('touchmove', onTouchMove, { passive: false });
}
this.remove = function () {
element.removeEventListener('contextmenu', onContextMenu);
element.removeEventListener('mousedown', onMouseDown);
element.removeEventListener('wheel', onMouseWheel);
element.removeEventListener('touchstart', onTouchStart);
element.removeEventListener('touchend', onTouchEnd);
element.removeEventListener('touchmove', onTouchMove);
window.removeEventListener('mousemove', onMouseMove);
window.removeEventListener('mouseup', onMouseUp);
};
addHandlers();
}

67
node_modules/ogl/src/extras/Plane.js generated vendored Normal file
View File

@@ -0,0 +1,67 @@
import { Geometry } from '../core/Geometry.js';
export class Plane extends Geometry {
constructor(gl, { width = 1, height = 1, widthSegments = 1, heightSegments = 1, attributes = {} } = {}) {
const wSegs = widthSegments;
const hSegs = heightSegments;
// Determine length of arrays
const num = (wSegs + 1) * (hSegs + 1);
const numIndices = wSegs * hSegs * 6;
// Generate empty arrays once
const position = new Float32Array(num * 3);
const normal = new Float32Array(num * 3);
const uv = new Float32Array(num * 2);
const index = numIndices > 65536 ? new Uint32Array(numIndices) : new Uint16Array(numIndices);
Plane.buildPlane(position, normal, uv, index, width, height, 0, wSegs, hSegs);
Object.assign(attributes, {
position: { size: 3, data: position },
normal: { size: 3, data: normal },
uv: { size: 2, data: uv },
index: { data: index },
});
super(gl, attributes);
}
static buildPlane(position, normal, uv, index, width, height, depth, wSegs, hSegs, u = 0, v = 1, w = 2, uDir = 1, vDir = -1, i = 0, ii = 0) {
const io = i;
const segW = width / wSegs;
const segH = height / hSegs;
for (let iy = 0; iy <= hSegs; iy++) {
let y = iy * segH - height / 2;
for (let ix = 0; ix <= wSegs; ix++, i++) {
let x = ix * segW - width / 2;
position[i * 3 + u] = x * uDir;
position[i * 3 + v] = y * vDir;
position[i * 3 + w] = depth / 2;
normal[i * 3 + u] = 0;
normal[i * 3 + v] = 0;
normal[i * 3 + w] = depth >= 0 ? 1 : -1;
uv[i * 2] = ix / wSegs;
uv[i * 2 + 1] = 1 - iy / hSegs;
if (iy === hSegs || ix === wSegs) continue;
let a = io + ix + iy * (wSegs + 1);
let b = io + ix + (iy + 1) * (wSegs + 1);
let c = io + ix + (iy + 1) * (wSegs + 1) + 1;
let d = io + ix + iy * (wSegs + 1) + 1;
index[ii * 6] = a;
index[ii * 6 + 1] = b;
index[ii * 6 + 2] = d;
index[ii * 6 + 3] = b;
index[ii * 6 + 4] = c;
index[ii * 6 + 5] = d;
ii++;
}
}
}
}

183
node_modules/ogl/src/extras/Polyline.js generated vendored Normal file
View File

@@ -0,0 +1,183 @@
import { Geometry } from '../core/Geometry.js';
import { Program } from '../core/Program.js';
import { Mesh } from '../core/Mesh.js';
import { Vec2 } from '../math/Vec2.js';
import { Vec3 } from '../math/Vec3.js';
import { Color } from '../math/Color.js';
const tmp = /* @__PURE__ */ new Vec3();
export class Polyline {
constructor(
gl,
{
points, // Array of Vec3s
vertex = defaultVertex,
fragment = defaultFragment,
uniforms = {},
attributes = {}, // For passing in custom attribs
}
) {
this.gl = gl;
this.points = points;
this.count = points.length;
// Create buffers
this.position = new Float32Array(this.count * 3 * 2);
this.prev = new Float32Array(this.count * 3 * 2);
this.next = new Float32Array(this.count * 3 * 2);
const side = new Float32Array(this.count * 1 * 2);
const uv = new Float32Array(this.count * 2 * 2);
const index = new Uint16Array((this.count - 1) * 3 * 2);
// Set static buffers
for (let i = 0; i < this.count; i++) {
side.set([-1, 1], i * 2);
const v = i / (this.count - 1);
uv.set([0, v, 1, v], i * 4);
if (i === this.count - 1) continue;
const ind = i * 2;
index.set([ind + 0, ind + 1, ind + 2], (ind + 0) * 3);
index.set([ind + 2, ind + 1, ind + 3], (ind + 1) * 3);
}
const geometry = (this.geometry = new Geometry(
gl,
Object.assign(attributes, {
position: { size: 3, data: this.position },
prev: { size: 3, data: this.prev },
next: { size: 3, data: this.next },
side: { size: 1, data: side },
uv: { size: 2, data: uv },
index: { size: 1, data: index },
})
));
// Populate dynamic buffers
this.updateGeometry();
if (!uniforms.uResolution) this.resolution = uniforms.uResolution = { value: new Vec2() };
if (!uniforms.uDPR) this.dpr = uniforms.uDPR = { value: 1 };
if (!uniforms.uThickness) this.thickness = uniforms.uThickness = { value: 1 };
if (!uniforms.uColor) this.color = uniforms.uColor = { value: new Color('#000') };
if (!uniforms.uMiter) this.miter = uniforms.uMiter = { value: 1 };
// Set size uniforms' values
this.resize();
const program = (this.program = new Program(gl, {
vertex,
fragment,
uniforms,
}));
this.mesh = new Mesh(gl, { geometry, program });
}
updateGeometry() {
this.points.forEach((p, i) => {
p.toArray(this.position, i * 3 * 2);
p.toArray(this.position, i * 3 * 2 + 3);
if (!i) {
// If first point, calculate prev using the distance to 2nd point
tmp.copy(p)
.sub(this.points[i + 1])
.add(p);
tmp.toArray(this.prev, i * 3 * 2);
tmp.toArray(this.prev, i * 3 * 2 + 3);
} else {
p.toArray(this.next, (i - 1) * 3 * 2);
p.toArray(this.next, (i - 1) * 3 * 2 + 3);
}
if (i === this.points.length - 1) {
// If last point, calculate next using distance to 2nd last point
tmp.copy(p)
.sub(this.points[i - 1])
.add(p);
tmp.toArray(this.next, i * 3 * 2);
tmp.toArray(this.next, i * 3 * 2 + 3);
} else {
p.toArray(this.prev, (i + 1) * 3 * 2);
p.toArray(this.prev, (i + 1) * 3 * 2 + 3);
}
});
this.geometry.attributes.position.needsUpdate = true;
this.geometry.attributes.prev.needsUpdate = true;
this.geometry.attributes.next.needsUpdate = true;
}
// Only need to call if not handling resolution uniforms manually
resize() {
// Update automatic uniforms if not overridden
if (this.resolution) this.resolution.value.set(this.gl.canvas.width, this.gl.canvas.height);
if (this.dpr) this.dpr.value = this.gl.renderer.dpr;
}
}
const defaultVertex = /* glsl */ `
precision highp float;
attribute vec3 position;
attribute vec3 next;
attribute vec3 prev;
attribute vec2 uv;
attribute float side;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform vec2 uResolution;
uniform float uDPR;
uniform float uThickness;
uniform float uMiter;
varying vec2 vUv;
vec4 getPosition() {
mat4 mvp = projectionMatrix * modelViewMatrix;
vec4 current = mvp * vec4(position, 1);
vec4 nextPos = mvp * vec4(next, 1);
vec4 prevPos = mvp * vec4(prev, 1);
vec2 aspect = vec2(uResolution.x / uResolution.y, 1);
vec2 currentScreen = current.xy / current.w * aspect;
vec2 nextScreen = nextPos.xy / nextPos.w * aspect;
vec2 prevScreen = prevPos.xy / prevPos.w * aspect;
vec2 dir1 = normalize(currentScreen - prevScreen);
vec2 dir2 = normalize(nextScreen - currentScreen);
vec2 dir = normalize(dir1 + dir2);
vec2 normal = vec2(-dir.y, dir.x);
normal /= mix(1.0, max(0.3, dot(normal, vec2(-dir1.y, dir1.x))), uMiter);
normal /= aspect;
float pixelWidthRatio = 1.0 / (uResolution.y / uDPR);
float pixelWidth = current.w * pixelWidthRatio;
normal *= pixelWidth * uThickness;
current.xy -= normal * side;
return current;
}
void main() {
vUv = uv;
gl_Position = getPosition();
}
`;
const defaultFragment = /* glsl */ `
precision highp float;
uniform vec3 uColor;
varying vec2 vUv;
void main() {
gl_FragColor.rgb = uColor;
gl_FragColor.a = 1.0;
}
`;

146
node_modules/ogl/src/extras/Post.js generated vendored Normal file
View File

@@ -0,0 +1,146 @@
import { Program } from '../core/Program.js';
import { Mesh } from '../core/Mesh.js';
import { RenderTarget } from '../core/RenderTarget.js';
import { Triangle } from './Triangle.js';
export class Post {
constructor(
gl,
{
width,
height,
dpr,
wrapS = gl.CLAMP_TO_EDGE,
wrapT = gl.CLAMP_TO_EDGE,
minFilter = gl.LINEAR,
magFilter = gl.LINEAR,
geometry = new Triangle(gl),
targetOnly = null,
depth = true,
} = {}
) {
this.gl = gl;
this.passes = [];
this.geometry = geometry;
this.uniform = { value: null };
this.targetOnly = targetOnly;
if (dpr) this.dpr = dpr;
if (width) this.width = width;
if (height) this.height = height;
dpr = this.dpr || this.gl.renderer.dpr;
this.resolutionWidth = Math.floor(this.width || this.gl.renderer.width * dpr);
this.resolutionHeight = Math.floor(this.height || this.gl.renderer.height * dpr);
let options = {
dpr: this.dpr,
width: this.resolutionWidth,
height: this.resolutionHeight,
wrapS,
wrapT,
minFilter,
magFilter,
depth,
};
const fbo = (this.fbo = {
read: new RenderTarget(this.gl, options),
write: new RenderTarget(this.gl, options),
swap: () => {
let temp = fbo.read;
fbo.read = fbo.write;
fbo.write = temp;
},
});
}
addPass({ vertex = defaultVertex, fragment = defaultFragment, uniforms = {}, textureUniform = 'tMap', enabled = true } = {}) {
uniforms[textureUniform] = { value: this.fbo.read.texture };
const program = new Program(this.gl, { vertex, fragment, uniforms });
const mesh = new Mesh(this.gl, { geometry: this.geometry, program });
const pass = {
mesh,
program,
uniforms,
enabled,
textureUniform,
};
this.passes.push(pass);
return pass;
}
resize({ width, height, dpr } = {}) {
if (dpr) this.dpr = dpr;
if (width) this.width = width;
if (height) this.height = height;
dpr = this.dpr || this.gl.renderer.dpr;
this.resolutionWidth = Math.floor(this.width || this.gl.renderer.width * dpr);
this.resolutionHeight = Math.floor(this.height || this.gl.renderer.height * dpr);
this.fbo.read.setSize(this.resolutionWidth, this.resolutionHeight);
this.fbo.write.setSize(this.resolutionWidth, this.resolutionHeight);
}
// Uses same arguments as renderer.render, with addition of optional texture passed in to avoid scene render
render({ scene, camera, texture, target = null, update = true, sort = true, frustumCull = true, beforePostCallbacks }) {
const enabledPasses = this.passes.filter((pass) => pass.enabled);
if (!texture) {
this.gl.renderer.render({
scene,
camera,
target: enabledPasses.length || (!target && this.targetOnly) ? this.fbo.write : target,
update,
sort,
frustumCull,
});
this.fbo.swap();
// Callback after rendering scene, but before post effects
if (beforePostCallbacks) beforePostCallbacks.forEach((f) => f && f());
}
enabledPasses.forEach((pass, i) => {
pass.mesh.program.uniforms[pass.textureUniform].value = !i && texture ? texture : this.fbo.read.texture;
this.gl.renderer.render({
scene: pass.mesh,
target: i === enabledPasses.length - 1 && (target || !this.targetOnly) ? target : this.fbo.write,
clear: true,
});
this.fbo.swap();
});
this.uniform.value = this.fbo.read.texture;
}
}
const defaultVertex = /* glsl */ `
attribute vec2 uv;
attribute vec2 position;
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = vec4(position, 0, 1);
}
`;
const defaultFragment = /* glsl */ `
precision highp float;
uniform sampler2D tMap;
varying vec2 vUv;
void main() {
gl_FragColor = texture2D(tMap, vUv);
}
`;

362
node_modules/ogl/src/extras/Raycast.js generated vendored Normal file
View File

@@ -0,0 +1,362 @@
// TODO: barycentric code shouldn't be here, but where?
// TODO: SphereCast?
import { Vec2 } from '../math/Vec2.js';
import { Vec3 } from '../math/Vec3.js';
import { Mat4 } from '../math/Mat4.js';
const tempVec2a = /* @__PURE__ */ new Vec2();
const tempVec2b = /* @__PURE__ */ new Vec2();
const tempVec2c = /* @__PURE__ */ new Vec2();
const tempVec3a = /* @__PURE__ */ new Vec3();
const tempVec3b = /* @__PURE__ */ new Vec3();
const tempVec3c = /* @__PURE__ */ new Vec3();
const tempVec3d = /* @__PURE__ */ new Vec3();
const tempVec3e = /* @__PURE__ */ new Vec3();
const tempVec3f = /* @__PURE__ */ new Vec3();
const tempVec3g = /* @__PURE__ */ new Vec3();
const tempVec3h = /* @__PURE__ */ new Vec3();
const tempVec3i = /* @__PURE__ */ new Vec3();
const tempVec3j = /* @__PURE__ */ new Vec3();
const tempVec3k = /* @__PURE__ */ new Vec3();
const tempMat4 = /* @__PURE__ */ new Mat4();
export class Raycast {
constructor() {
this.origin = new Vec3();
this.direction = new Vec3();
}
// Set ray from mouse unprojection
castMouse(camera, mouse = [0, 0]) {
if (camera.type === 'orthographic') {
// Set origin
// Since camera is orthographic, origin is not the camera position
const { left, right, bottom, top, zoom } = camera;
const x = left / zoom + ((right - left) / zoom) * (mouse[0] * 0.5 + 0.5);
const y = bottom / zoom + ((top - bottom) / zoom) * (mouse[1] * 0.5 + 0.5);
this.origin.set(x, y, 0);
this.origin.applyMatrix4(camera.worldMatrix);
// Set direction
// https://community.khronos.org/t/get-direction-from-transformation-matrix-or-quat/65502/2
this.direction.x = -camera.worldMatrix[8];
this.direction.y = -camera.worldMatrix[9];
this.direction.z = -camera.worldMatrix[10];
} else {
// Set origin
camera.worldMatrix.getTranslation(this.origin);
// Set direction
this.direction.set(mouse[0], mouse[1], 0.5);
camera.unproject(this.direction);
this.direction.sub(this.origin).normalize();
}
}
intersectBounds(meshes, { maxDistance, output = [] } = {}) {
if (!Array.isArray(meshes)) meshes = [meshes];
const invWorldMat4 = tempMat4;
const origin = tempVec3a;
const direction = tempVec3b;
const hits = output;
hits.length = 0;
meshes.forEach((mesh) => {
// Create bounds
if (!mesh.geometry.bounds || mesh.geometry.bounds.radius === Infinity) mesh.geometry.computeBoundingSphere();
const bounds = mesh.geometry.bounds;
invWorldMat4.inverse(mesh.worldMatrix);
// Get max distance locally
let localMaxDistance;
if (maxDistance) {
direction.copy(this.direction).scaleRotateMatrix4(invWorldMat4);
localMaxDistance = maxDistance * direction.len();
}
// Take world space ray and make it object space to align with bounding box
origin.copy(this.origin).applyMatrix4(invWorldMat4);
direction.copy(this.direction).transformDirection(invWorldMat4);
// Break out early if bounds too far away from origin
if (maxDistance) {
if (origin.distance(bounds.center) - bounds.radius > localMaxDistance) return;
}
let localDistance = 0;
// Check origin isn't inside bounds before testing intersection
if (mesh.geometry.raycast === 'sphere') {
if (origin.distance(bounds.center) > bounds.radius) {
localDistance = this.intersectSphere(bounds, origin, direction);
if (!localDistance) return;
}
} else {
if (
origin.x < bounds.min.x ||
origin.x > bounds.max.x ||
origin.y < bounds.min.y ||
origin.y > bounds.max.y ||
origin.z < bounds.min.z ||
origin.z > bounds.max.z
) {
localDistance = this.intersectBox(bounds, origin, direction);
if (!localDistance) return;
}
}
if (maxDistance && localDistance > localMaxDistance) return;
// Create object on mesh to avoid generating lots of objects
if (!mesh.hit) mesh.hit = { localPoint: new Vec3(), point: new Vec3() };
mesh.hit.localPoint.copy(direction).multiply(localDistance).add(origin);
mesh.hit.point.copy(mesh.hit.localPoint).applyMatrix4(mesh.worldMatrix);
mesh.hit.distance = mesh.hit.point.distance(this.origin);
hits.push(mesh);
});
hits.sort((a, b) => a.hit.distance - b.hit.distance);
return hits;
}
intersectMeshes(meshes, { cullFace = true, maxDistance, includeUV = true, includeNormal = true, output = [] } = {}) {
// Test bounds first before testing geometry
const hits = this.intersectBounds(meshes, { maxDistance, output });
if (!hits.length) return hits;
const invWorldMat4 = tempMat4;
const origin = tempVec3a;
const direction = tempVec3b;
const a = tempVec3c;
const b = tempVec3d;
const c = tempVec3e;
const closestFaceNormal = tempVec3f;
const faceNormal = tempVec3g;
const barycoord = tempVec3h;
const uvA = tempVec2a;
const uvB = tempVec2b;
const uvC = tempVec2c;
for (let i = hits.length - 1; i >= 0; i--) {
const mesh = hits[i];
invWorldMat4.inverse(mesh.worldMatrix);
// Get max distance locally
let localMaxDistance;
if (maxDistance) {
direction.copy(this.direction).scaleRotateMatrix4(invWorldMat4);
localMaxDistance = maxDistance * direction.len();
}
// Take world space ray and make it object space to align with bounding box
origin.copy(this.origin).applyMatrix4(invWorldMat4);
direction.copy(this.direction).transformDirection(invWorldMat4);
let localDistance = 0;
let closestA, closestB, closestC;
const geometry = mesh.geometry;
const attributes = geometry.attributes;
const index = attributes.index;
const position = attributes.position;
const start = Math.max(0, geometry.drawRange.start);
const end = Math.min(index ? index.count : position.count, geometry.drawRange.start + geometry.drawRange.count);
// Data loaded shouldn't haave stride, only buffers
// const stride = position.stride ? position.stride / position.data.BYTES_PER_ELEMENT : position.size;
const stride = position.size;
for (let j = start; j < end; j += 3) {
// Position attribute indices for each triangle
const ai = index ? index.data[j] : j;
const bi = index ? index.data[j + 1] : j + 1;
const ci = index ? index.data[j + 2] : j + 2;
a.fromArray(position.data, ai * stride);
b.fromArray(position.data, bi * stride);
c.fromArray(position.data, ci * stride);
const distance = this.intersectTriangle(a, b, c, cullFace, origin, direction, faceNormal);
if (!distance) continue;
// Too far away
if (maxDistance && distance > localMaxDistance) continue;
if (!localDistance || distance < localDistance) {
localDistance = distance;
closestA = ai;
closestB = bi;
closestC = ci;
closestFaceNormal.copy(faceNormal);
}
}
if (!localDistance) hits.splice(i, 1);
// Update hit values from bounds-test
mesh.hit.localPoint.copy(direction).multiply(localDistance).add(origin);
mesh.hit.point.copy(mesh.hit.localPoint).applyMatrix4(mesh.worldMatrix);
mesh.hit.distance = mesh.hit.point.distance(this.origin);
// Add unique hit objects on mesh to avoid generating lots of objects
if (!mesh.hit.faceNormal) {
mesh.hit.localFaceNormal = new Vec3();
mesh.hit.faceNormal = new Vec3();
mesh.hit.uv = new Vec2();
mesh.hit.localNormal = new Vec3();
mesh.hit.normal = new Vec3();
}
// Add face normal data which is already computed
mesh.hit.localFaceNormal.copy(closestFaceNormal);
mesh.hit.faceNormal.copy(mesh.hit.localFaceNormal).transformDirection(mesh.worldMatrix);
// Optional data, opt out to optimise a bit if necessary
if (includeUV || includeNormal) {
// Calculate barycoords to find uv values at hit point
a.fromArray(position.data, closestA * 3);
b.fromArray(position.data, closestB * 3);
c.fromArray(position.data, closestC * 3);
this.getBarycoord(mesh.hit.localPoint, a, b, c, barycoord);
}
if (includeUV && attributes.uv) {
uvA.fromArray(attributes.uv.data, closestA * 2);
uvB.fromArray(attributes.uv.data, closestB * 2);
uvC.fromArray(attributes.uv.data, closestC * 2);
mesh.hit.uv.set(
uvA.x * barycoord.x + uvB.x * barycoord.y + uvC.x * barycoord.z,
uvA.y * barycoord.x + uvB.y * barycoord.y + uvC.y * barycoord.z
);
}
if (includeNormal && attributes.normal) {
a.fromArray(attributes.normal.data, closestA * 3);
b.fromArray(attributes.normal.data, closestB * 3);
c.fromArray(attributes.normal.data, closestC * 3);
mesh.hit.localNormal.set(
a.x * barycoord.x + b.x * barycoord.y + c.x * barycoord.z,
a.y * barycoord.x + b.y * barycoord.y + c.y * barycoord.z,
a.z * barycoord.x + b.z * barycoord.y + c.z * barycoord.z
);
mesh.hit.normal.copy(mesh.hit.localNormal).transformDirection(mesh.worldMatrix);
}
}
hits.sort((a, b) => a.hit.distance - b.hit.distance);
return hits;
}
intersectPlane(plane, origin = this.origin, direction = this.direction) {
const xminp = tempVec3a;
xminp.sub(plane.origin, origin);
const a = xminp.dot(plane.normal);
const b = direction.dot(plane.normal);
// Assuming we don't want to count a ray parallel to the plane as intersecting
if (b == 0) return 0;
const delta = a / b;
if (delta <= 0) return 0;
return origin.add(direction.scale(delta));
}
intersectSphere(sphere, origin = this.origin, direction = this.direction) {
const ray = tempVec3c;
ray.sub(sphere.center, origin);
const tca = ray.dot(direction);
const d2 = ray.dot(ray) - tca * tca;
const radius2 = sphere.radius * sphere.radius;
if (d2 > radius2) return 0;
const thc = Math.sqrt(radius2 - d2);
const t0 = tca - thc;
const t1 = tca + thc;
if (t0 < 0 && t1 < 0) return 0;
if (t0 < 0) return t1;
return t0;
}
// Ray AABB - Ray Axis aligned bounding box testing
intersectBox(box, origin = this.origin, direction = this.direction) {
let tmin, tmax, tYmin, tYmax, tZmin, tZmax;
const invdirx = 1 / direction.x;
const invdiry = 1 / direction.y;
const invdirz = 1 / direction.z;
const min = box.min;
const max = box.max;
tmin = ((invdirx >= 0 ? min.x : max.x) - origin.x) * invdirx;
tmax = ((invdirx >= 0 ? max.x : min.x) - origin.x) * invdirx;
tYmin = ((invdiry >= 0 ? min.y : max.y) - origin.y) * invdiry;
tYmax = ((invdiry >= 0 ? max.y : min.y) - origin.y) * invdiry;
if (tmin > tYmax || tYmin > tmax) return 0;
if (tYmin > tmin) tmin = tYmin;
if (tYmax < tmax) tmax = tYmax;
tZmin = ((invdirz >= 0 ? min.z : max.z) - origin.z) * invdirz;
tZmax = ((invdirz >= 0 ? max.z : min.z) - origin.z) * invdirz;
if (tmin > tZmax || tZmin > tmax) return 0;
if (tZmin > tmin) tmin = tZmin;
if (tZmax < tmax) tmax = tZmax;
if (tmax < 0) return 0;
return tmin >= 0 ? tmin : tmax;
}
intersectTriangle(a, b, c, backfaceCulling = true, origin = this.origin, direction = this.direction, normal = tempVec3g) {
// from https://github.com/mrdoob/three.js/blob/master/src/math/Ray.js
// which is from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h
const edge1 = tempVec3h;
const edge2 = tempVec3i;
const diff = tempVec3j;
edge1.sub(b, a);
edge2.sub(c, a);
normal.cross(edge1, edge2);
let DdN = direction.dot(normal);
if (!DdN) return 0;
let sign;
if (DdN > 0) {
if (backfaceCulling) return 0;
sign = 1;
} else {
sign = -1;
DdN = -DdN;
}
diff.sub(origin, a);
let DdQxE2 = sign * direction.dot(edge2.cross(diff, edge2));
if (DdQxE2 < 0) return 0;
let DdE1xQ = sign * direction.dot(edge1.cross(diff));
if (DdE1xQ < 0) return 0;
if (DdQxE2 + DdE1xQ > DdN) return 0;
let QdN = -sign * diff.dot(normal);
if (QdN < 0) return 0;
return QdN / DdN;
}
getBarycoord(point, a, b, c, target = tempVec3h) {
// From https://github.com/mrdoob/three.js/blob/master/src/math/Triangle.js
// static/instance method to calculate barycentric coordinates
// based on: http://www.blackpawn.com/texts/pointinpoly/default.html
const v0 = tempVec3i;
const v1 = tempVec3j;
const v2 = tempVec3k;
v0.sub(c, a);
v1.sub(b, a);
v2.sub(point, a);
const dot00 = v0.dot(v0);
const dot01 = v0.dot(v1);
const dot02 = v0.dot(v2);
const dot11 = v1.dot(v1);
const dot12 = v1.dot(v2);
const denom = dot00 * dot11 - dot01 * dot01;
if (denom === 0) return target.set(-2, -1, -1);
const invDenom = 1 / denom;
const u = (dot11 * dot02 - dot01 * dot12) * invDenom;
const v = (dot00 * dot12 - dot01 * dot02) * invDenom;
return target.set(1 - u - v, v, u);
}
}

124
node_modules/ogl/src/extras/Shadow.js generated vendored Normal file
View File

@@ -0,0 +1,124 @@
import { Camera } from '../core/Camera.js';
import { Program } from '../core/Program.js';
import { RenderTarget } from '../core/RenderTarget.js';
export class Shadow {
constructor(gl, { light = new Camera(gl), width = 1024, height = width }) {
this.gl = gl;
this.light = light;
this.target = new RenderTarget(gl, { width, height });
this.targetUniform = { value: this.target.texture };
this.depthProgram = new Program(gl, {
vertex: defaultVertex,
fragment: defaultFragment,
cullFace: false,
});
this.castMeshes = [];
}
add({
mesh,
receive = true,
cast = true,
vertex = defaultVertex,
fragment = defaultFragment,
uniformProjection = 'shadowProjectionMatrix',
uniformView = 'shadowViewMatrix',
uniformTexture = 'tShadow',
}) {
// Add uniforms to existing program
if (receive && !mesh.program.uniforms[uniformProjection]) {
mesh.program.uniforms[uniformProjection] = { value: this.light.projectionMatrix };
mesh.program.uniforms[uniformView] = { value: this.light.viewMatrix };
mesh.program.uniforms[uniformTexture] = this.targetUniform;
}
if (!cast) return;
this.castMeshes.push(mesh);
// Store program for when switching between depth override
mesh.colorProgram = mesh.program;
// Check if depth program already attached
if (mesh.depthProgram) return;
// Use global depth override if nothing custom passed in
if (vertex === defaultVertex && fragment === defaultFragment) {
mesh.depthProgram = this.depthProgram;
return;
}
// Create custom override program
mesh.depthProgram = new Program(this.gl, {
vertex,
fragment,
cullFace: false,
});
}
setSize({ width = 1024, height = width }) {
this.target = new RenderTarget(this.gl, { width, height });
this.targetUniform.value = this.target.texture;
}
render({ scene }) {
// For depth render, replace program with depth override.
// Hide meshes not casting shadows.
scene.traverse((node) => {
if (!node.draw) return;
if (!!~this.castMeshes.indexOf(node)) {
node.program = node.depthProgram;
} else {
node.isForceVisibility = node.visible;
node.visible = false;
}
});
// Render the depth shadow map using the light as the camera
this.gl.renderer.render({
scene,
camera: this.light,
target: this.target,
});
// Then switch the program back to the normal one
scene.traverse((node) => {
if (!node.draw) return;
if (!!~this.castMeshes.indexOf(node)) {
node.program = node.colorProgram;
} else {
node.visible = node.isForceVisibility;
}
});
}
}
const defaultVertex = /* glsl */ `
attribute vec3 position;
attribute vec2 uv;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
void main() {
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`;
const defaultFragment = /* glsl */ `
precision highp float;
vec4 packRGBA (float v) {
vec4 pack = fract(vec4(1.0, 255.0, 65025.0, 16581375.0) * v);
pack -= pack.yzww * vec2(1.0 / 255.0, 0.0).xxxy;
return pack;
}
void main() {
gl_FragColor = packRGBA(gl_FragCoord.z);
}
`;

105
node_modules/ogl/src/extras/Skin.js generated vendored Normal file
View File

@@ -0,0 +1,105 @@
import { Mesh } from '../core/Mesh.js';
import { Transform } from '../core/Transform.js';
import { Mat4 } from '../math/Mat4.js';
import { Texture } from '../core/Texture.js';
import { Animation } from './Animation.js';
const tempMat4 = /* @__PURE__ */ new Mat4();
export class Skin extends Mesh {
constructor(gl, { rig, geometry, program, mode = gl.TRIANGLES } = {}) {
super(gl, { geometry, program, mode });
this.createBones(rig);
this.createBoneTexture();
this.animations = [];
Object.assign(this.program.uniforms, {
boneTexture: { value: this.boneTexture },
boneTextureSize: { value: this.boneTextureSize },
});
}
createBones(rig) {
// Create root so that can simply update world matrix of whole skeleton
this.root = new Transform();
// Create bones
this.bones = [];
if (!rig.bones || !rig.bones.length) return;
for (let i = 0; i < rig.bones.length; i++) {
const bone = new Transform();
// Set initial values (bind pose)
bone.position.fromArray(rig.bindPose.position, i * 3);
bone.quaternion.fromArray(rig.bindPose.quaternion, i * 4);
bone.scale.fromArray(rig.bindPose.scale, i * 3);
this.bones.push(bone);
}
// Once created, set the hierarchy
rig.bones.forEach((data, i) => {
this.bones[i].name = data.name;
if (data.parent === -1) return this.bones[i].setParent(this.root);
this.bones[i].setParent(this.bones[data.parent]);
});
// Then update to calculate world matrices
this.root.updateMatrixWorld(true);
// Store inverse of bind pose to calculate differences
this.bones.forEach((bone) => {
bone.bindInverse = new Mat4(...bone.worldMatrix).inverse();
});
}
createBoneTexture() {
if (!this.bones.length) return;
const size = Math.max(4, Math.pow(2, Math.ceil(Math.log(Math.sqrt(this.bones.length * 4)) / Math.LN2)));
this.boneMatrices = new Float32Array(size * size * 4);
this.boneTextureSize = size;
this.boneTexture = new Texture(this.gl, {
image: this.boneMatrices,
generateMipmaps: false,
type: this.gl.FLOAT,
internalFormat: this.gl.renderer.isWebgl2 ? this.gl.RGBA32F : this.gl.RGBA,
minFilter: this.gl.NEAREST,
magFilter: this.gl.NEAREST,
flipY: false,
width: size,
});
}
addAnimation(data) {
const animation = new Animation({ objects: this.bones, data });
this.animations.push(animation);
return animation;
}
update() {
// Calculate combined animation weight
let total = 0;
this.animations.forEach((animation) => (total += animation.weight));
this.animations.forEach((animation, i) => {
// force first animation to set in order to reset frame
animation.update(total, i === 0);
});
}
draw({ camera } = {}) {
// Update world matrices manually, as not part of scene graph
this.root.updateMatrixWorld(true);
// Update bone texture
this.bones.forEach((bone, i) => {
// Find difference between current and bind pose
tempMat4.multiply(bone.worldMatrix, bone.bindInverse);
this.boneMatrices.set(tempMat4, i * 16);
});
if (this.boneTexture) this.boneTexture.needsUpdate = true;
super.draw({ camera });
}
}

99
node_modules/ogl/src/extras/Sphere.js generated vendored Normal file
View File

@@ -0,0 +1,99 @@
import { Geometry } from '../core/Geometry.js';
import { Vec3 } from '../math/Vec3.js';
export class Sphere extends Geometry {
constructor(
gl,
{
radius = 0.5,
widthSegments = 16,
heightSegments = Math.ceil(widthSegments * 0.5),
phiStart = 0,
phiLength = Math.PI * 2,
thetaStart = 0,
thetaLength = Math.PI,
attributes = {},
} = {}
) {
const wSegs = widthSegments;
const hSegs = heightSegments;
const pStart = phiStart;
const pLength = phiLength;
const tStart = thetaStart;
const tLength = thetaLength;
const num = (wSegs + 1) * (hSegs + 1);
const numIndices = wSegs * hSegs * 6;
const position = new Float32Array(num * 3);
const normal = new Float32Array(num * 3);
const uv = new Float32Array(num * 2);
const index = num > 65536 ? new Uint32Array(numIndices) : new Uint16Array(numIndices);
let i = 0;
let iv = 0;
let ii = 0;
let te = tStart + tLength;
const grid = [];
let n = new Vec3();
for (let iy = 0; iy <= hSegs; iy++) {
let vRow = [];
let v = iy / hSegs;
for (let ix = 0; ix <= wSegs; ix++, i++) {
let u = ix / wSegs;
let x = -radius * Math.cos(pStart + u * pLength) * Math.sin(tStart + v * tLength);
let y = radius * Math.cos(tStart + v * tLength);
let z = radius * Math.sin(pStart + u * pLength) * Math.sin(tStart + v * tLength);
position[i * 3] = x;
position[i * 3 + 1] = y;
position[i * 3 + 2] = z;
n.set(x, y, z).normalize();
normal[i * 3] = n.x;
normal[i * 3 + 1] = n.y;
normal[i * 3 + 2] = n.z;
uv[i * 2] = u;
uv[i * 2 + 1] = 1 - v;
vRow.push(iv++);
}
grid.push(vRow);
}
for (let iy = 0; iy < hSegs; iy++) {
for (let ix = 0; ix < wSegs; ix++) {
let a = grid[iy][ix + 1];
let b = grid[iy][ix];
let c = grid[iy + 1][ix];
let d = grid[iy + 1][ix + 1];
if (iy !== 0 || tStart > 0) {
index[ii * 3] = a;
index[ii * 3 + 1] = b;
index[ii * 3 + 2] = d;
ii++;
}
if (iy !== hSegs - 1 || te < Math.PI) {
index[ii * 3] = b;
index[ii * 3 + 1] = c;
index[ii * 3 + 2] = d;
ii++;
}
}
}
Object.assign(attributes, {
position: { size: 3, data: position },
normal: { size: 3, data: normal },
uv: { size: 2, data: uv },
index: { data: index },
});
super(gl, attributes);
}
}

240
node_modules/ogl/src/extras/Text.js generated vendored Normal file
View File

@@ -0,0 +1,240 @@
export function Text({
font,
text,
width = Infinity,
align = 'left',
size = 1,
letterSpacing = 0,
lineHeight = 1.4,
wordSpacing = 0,
wordBreak = false,
}) {
const _this = this;
let glyphs, buffers;
let fontHeight, baseline, scale;
const newline = /\n/;
const whitespace = /\s/;
{
parseFont();
createGeometry();
}
function parseFont() {
glyphs = {};
font.chars.forEach((d) => (glyphs[d.char] = d));
}
function createGeometry() {
fontHeight = font.common.lineHeight;
baseline = font.common.base;
// Use baseline so that actual text height is as close to 'size' value as possible
scale = size / baseline;
// Strip spaces and newlines to get actual character length for buffers
let chars = text.replace(/[ \n]/g, '');
let numChars = chars.length;
// Create output buffers
buffers = {
position: new Float32Array(numChars * 4 * 3),
uv: new Float32Array(numChars * 4 * 2),
id: new Float32Array(numChars * 4),
index: new Uint16Array(numChars * 6),
};
// Set values for buffers that don't require calculation
for (let i = 0; i < numChars; i++) {
buffers.id.set([i, i, i, i], i * 4);
buffers.index.set([i * 4, i * 4 + 2, i * 4 + 1, i * 4 + 1, i * 4 + 2, i * 4 + 3], i * 6);
}
layout();
}
function layout() {
const lines = [];
let cursor = 0;
let wordCursor = 0;
let wordWidth = 0;
let line = newLine();
function newLine() {
const line = {
width: 0,
glyphs: [],
};
lines.push(line);
wordCursor = cursor;
wordWidth = 0;
return line;
}
let maxTimes = 100;
let count = 0;
while (cursor < text.length && count < maxTimes) {
count++;
const char = text[cursor];
// Skip whitespace at start of line
if (!line.width && whitespace.test(char)) {
cursor++;
wordCursor = cursor;
wordWidth = 0;
continue;
}
// If newline char, skip to next line
if (newline.test(char)) {
cursor++;
line = newLine();
continue;
}
const glyph = glyphs[char] || glyphs[' '];
// Find any applicable kern pairs
if (line.glyphs.length) {
const prevGlyph = line.glyphs[line.glyphs.length - 1][0];
let kern = getKernPairOffset(glyph.id, prevGlyph.id) * scale;
line.width += kern;
wordWidth += kern;
}
// add char to line
line.glyphs.push([glyph, line.width]);
// calculate advance for next glyph
let advance = 0;
// If whitespace, update location of current word for line breaks
if (whitespace.test(char)) {
wordCursor = cursor;
wordWidth = 0;
// Add wordspacing
advance += wordSpacing * size;
} else {
// Add letterspacing
advance += letterSpacing * size;
}
advance += glyph.xadvance * scale;
line.width += advance;
wordWidth += advance;
// If width defined
if (line.width > width) {
// If can break words, undo latest glyph if line not empty and create new line
if (wordBreak && line.glyphs.length > 1) {
line.width -= advance;
line.glyphs.pop();
line = newLine();
continue;
// If not first word, undo current word and cursor and create new line
} else if (!wordBreak && wordWidth !== line.width) {
let numGlyphs = cursor - wordCursor + 1;
line.glyphs.splice(-numGlyphs, numGlyphs);
cursor = wordCursor;
line.width -= wordWidth;
line = newLine();
continue;
}
}
cursor++;
// Reset infinite loop catch
count = 0;
}
// Remove last line if empty
if (!line.width) lines.pop();
populateBuffers(lines);
}
function populateBuffers(lines) {
const texW = font.common.scaleW;
const texH = font.common.scaleH;
// For all fonts tested, a little offset was needed to be right on the baseline, hence 0.07.
let y = 0.07 * size;
let j = 0;
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
let line = lines[lineIndex];
for (let i = 0; i < line.glyphs.length; i++) {
const glyph = line.glyphs[i][0];
let x = line.glyphs[i][1];
if (align === 'center') {
x -= line.width * 0.5;
} else if (align === 'right') {
x -= line.width;
}
// If space, don't add to geometry
if (whitespace.test(glyph.char)) continue;
// Apply char sprite offsets
x += glyph.xoffset * scale;
y -= glyph.yoffset * scale;
// each letter is a quad. axis bottom left
let w = glyph.width * scale;
let h = glyph.height * scale;
buffers.position.set([x, y - h, 0, x, y, 0, x + w, y - h, 0, x + w, y, 0], j * 4 * 3);
let u = glyph.x / texW;
let uw = glyph.width / texW;
let v = 1.0 - glyph.y / texH;
let vh = glyph.height / texH;
buffers.uv.set([u, v - vh, u, v, u + uw, v - vh, u + uw, v], j * 4 * 2);
// Reset cursor to baseline
y += glyph.yoffset * scale;
j++;
}
y -= size * lineHeight;
}
_this.buffers = buffers;
_this.numLines = lines.length;
_this.height = _this.numLines * size * lineHeight;
_this.width = Math.max(...lines.map((line) => line.width));
}
function getKernPairOffset(id1, id2) {
for (let i = 0; i < font.kernings.length; i++) {
let k = font.kernings[i];
if (k.first < id1) continue;
if (k.second < id2) continue;
if (k.first > id1) return 0;
if (k.first === id1 && k.second > id2) return 0;
return k.amount;
}
return 0;
}
// Update buffers to layout with new layout
this.resize = function (options) {
({ width } = options);
layout();
};
// Completely change text (like creating new Text)
this.update = function (options) {
({ text } = options);
createGeometry();
};
}

80
node_modules/ogl/src/extras/Texture3D.js generated vendored Normal file
View File

@@ -0,0 +1,80 @@
import { Texture } from '../core/Texture.js';
export class Texture3D extends Texture {
constructor(gl, args) {
super(gl, {
...args,
target: gl.TEXTURE_3D,
width: args.width ? args.width : 2,
height: args.height ? args.height : 2,
});
const image = new Image();
image.crossOrigin = '*';
image.src = args.src;
image.onload = () => {
let canvas = document.createElement('canvas');
canvas.width = image.width;
canvas.height = image.height;
let ctx = canvas.getContext('2d');
ctx.scale(1, -1);
ctx.translate(0, -image.height);
ctx.drawImage(image, 0, 0);
const imageData = ctx.getImageData(0, 0, image.width, image.height).data;
canvas = null;
ctx = null;
let elementCount;
switch (this.format) {
case gl.RED:
elementCount = 1;
break;
case gl.RG:
elementCount = 2;
break;
case gl.RGB:
elementCount = 3;
break;
default:
elementCount = 4;
break;
}
const dataCount = this.width * this.height * this.length * elementCount;
const data = this.type === gl.UNSIGNED_BYTE ? new Uint8Array(dataCount) : new Float32Array(dataCount);
let dataIterator = 0;
for (let z = 0; z < this.length; z++) {
for (let y = 0; y < this.height; y++) {
for (let x = 0; x < this.width; x++) {
let zOffsetX = (z % args.tileCountX) * this.width;
let zOffsetY = Math.floor(z / args.tileCountX) * (this.width * this.height * args.tileCountX);
let index = x + zOffsetX + (y * image.width + zOffsetY);
const r = imageData[index * 4];
const g = imageData[index * 4 + 1];
const b = imageData[index * 4 + 2];
const a = imageData[index * 4 + 3];
let texel = [r, g, b, a];
for (let i = 0; i < elementCount; i++) {
if (this.type === this.gl.UNSIGNED_BYTE) {
data[dataIterator++] = texel[i];
} else {
data[dataIterator++] = texel[i] / 255;
}
}
}
}
}
this.image = data;
this.needsUpdate = true;
};
}
}

200
node_modules/ogl/src/extras/TextureLoader.js generated vendored Normal file
View File

@@ -0,0 +1,200 @@
import { Texture } from '../core/Texture.js';
import { KTXTexture } from './KTXTexture.js';
// For compressed textures, generate using https://github.com/TimvanScherpenzeel/texture-compressor
let cache = {};
const supportedExtensions = [];
export class TextureLoader {
static load(
gl,
{
src, // string or object of extension:src key-values
// {
// pvrtc: '...ktx',
// s3tc: '...ktx',
// etc: '...ktx',
// etc1: '...ktx',
// astc: '...ktx',
// webp: '...webp',
// jpg: '...jpg',
// png: '...png',
// }
// Only props relevant to KTXTexture
wrapS = gl.CLAMP_TO_EDGE,
wrapT = gl.CLAMP_TO_EDGE,
anisotropy = 0,
// For regular images
format = gl.RGBA,
internalFormat = format,
generateMipmaps = true,
minFilter = generateMipmaps ? gl.NEAREST_MIPMAP_LINEAR : gl.LINEAR,
magFilter = gl.LINEAR,
premultiplyAlpha = false,
unpackAlignment = 4,
flipY = true,
} = {}
) {
const support = this.getSupportedExtensions(gl);
let ext = 'none';
// If src is string, determine which format from the extension
if (typeof src === 'string') {
ext = src.split('.').pop().split('?')[0].toLowerCase();
}
// If src is object, use supported extensions and provided list to choose best option
// Get first supported match, so put in order of preference
if (typeof src === 'object') {
for (const prop in src) {
if (support.includes(prop.toLowerCase())) {
ext = prop.toLowerCase();
src = src[prop];
break;
}
}
}
// Stringify props
const cacheID = src + wrapS + wrapT + anisotropy + format + internalFormat + generateMipmaps + minFilter + magFilter + premultiplyAlpha + unpackAlignment + flipY + gl.renderer.id;
// Check cache for existing texture
if (cache[cacheID]) return cache[cacheID];
let texture;
switch (ext) {
case 'ktx':
case 'pvrtc':
case 's3tc':
case 'etc':
case 'etc1':
case 'astc':
// Load compressed texture using KTX format
texture = new KTXTexture(gl, {
src,
wrapS,
wrapT,
anisotropy,
minFilter,
magFilter,
});
texture.loaded = this.loadKTX(src, texture);
break;
case 'webp':
case 'jpg':
case 'jpeg':
case 'png':
texture = new Texture(gl, {
wrapS,
wrapT,
anisotropy,
format,
internalFormat,
generateMipmaps,
minFilter,
magFilter,
premultiplyAlpha,
unpackAlignment,
flipY,
});
texture.loaded = this.loadImage(gl, src, texture, flipY);
break;
default:
console.warn('No supported format supplied');
texture = new Texture(gl);
}
texture.ext = ext;
cache[cacheID] = texture;
return texture;
}
static getSupportedExtensions(gl) {
if (supportedExtensions.length) return supportedExtensions;
const extensions = {
pvrtc: gl.renderer.getExtension('WEBGL_compressed_texture_pvrtc') || gl.renderer.getExtension('WEBKIT_WEBGL_compressed_texture_pvrtc'),
s3tc: gl.renderer.getExtension('WEBGL_compressed_texture_s3tc'),
// etc: gl.renderer.getExtension('WEBGL_compressed_texture_etc'),
etc1: gl.renderer.getExtension('WEBGL_compressed_texture_etc1'),
astc: gl.renderer.getExtension('WEBGL_compressed_texture_astc'),
bc7: gl.renderer.getExtension('EXT_texture_compression_bptc'),
};
for (const ext in extensions) if (extensions[ext]) supportedExtensions.push(ext);
// Formats supported by all
supportedExtensions.push('png', 'jpg', 'webp');
return supportedExtensions;
}
static loadKTX(src, texture) {
return fetch(src)
.then((res) => res.arrayBuffer())
.then((buffer) => texture.parseBuffer(buffer));
}
static loadImage(gl, src, texture, flipY) {
return decodeImage(src, flipY).then((imgBmp) => {
// Catch non POT textures for WebGL1 and update params to avoid errors
if (!gl.renderer.isWebgl2 && (!powerOfTwo(imgBmp.width) || !powerOfTwo(imgBmp.height))) {
if (texture.generateMipmaps) texture.generateMipmaps = false;
if (texture.minFilter === gl.NEAREST_MIPMAP_LINEAR) texture.minFilter = gl.LINEAR;
if (texture.wrapS === gl.REPEAT) texture.wrapS = texture.wrapT = gl.CLAMP_TO_EDGE;
}
texture.image = imgBmp;
// For createImageBitmap, close once uploaded
texture.onUpdate = () => {
if (imgBmp.close) imgBmp.close();
texture.onUpdate = null;
};
return imgBmp;
});
}
static clearCache() {
cache = {};
}
}
function powerOfTwo(value) {
// (width & (width - 1)) !== 0
return Math.log2(value) % 1 === 0;
}
function decodeImage(src, flipY) {
return new Promise((resolve, reject) => {
if (isCreateImageBitmap()) {
fetch(src, { mode: 'cors' })
.then((r) => r.blob())
.then((b) => createImageBitmap(b, { imageOrientation: flipY ? 'flipY' : 'none', premultiplyAlpha: 'none' }))
.then(resolve)
.catch((err) => reject(err));
} else {
const img = new Image();
img.crossOrigin = '';
img.src = src;
img.onerror = ({ type }) => reject(`${type}: Loading image`);
img.onload = () => resolve(img);
}
});
}
function isCreateImageBitmap() {
const isChrome = navigator.userAgent.toLowerCase().includes('chrome');
if (!isChrome) return false;
try {
createImageBitmap;
} catch (e) {
return false;
}
return true;
}

70
node_modules/ogl/src/extras/Torus.js generated vendored Normal file
View File

@@ -0,0 +1,70 @@
// https://github.com/mrdoob/three.js/blob/master/src/geometries/TorusGeometry.js
import { Geometry } from '../core/Geometry.js';
import { Vec3 } from '../math/Vec3.js';
export class Torus extends Geometry {
constructor(gl, { radius = 0.5, tube = 0.2, radialSegments = 8, tubularSegments = 6, arc = Math.PI * 2, attributes = {} } = {}) {
const num = (radialSegments + 1) * (tubularSegments + 1);
const numIndices = radialSegments * tubularSegments * 6;
const vertices = new Float32Array(num * 3);
const normals = new Float32Array(num * 3);
const uvs = new Float32Array(num * 2);
const indices = num > 65536 ? new Uint32Array(numIndices) : new Uint16Array(numIndices);
const center = new Vec3();
const vertex = new Vec3();
const normal = new Vec3();
// generate vertices, normals and uvs
let idx = 0;
for (let j = 0; j <= radialSegments; j++) {
for (let i = 0; i <= tubularSegments; i++, idx++) {
const u = (i / tubularSegments) * arc;
const v = (j / radialSegments) * Math.PI * 2;
// vertex
vertex.x = (radius + tube * Math.cos(v)) * Math.cos(u);
vertex.y = (radius + tube * Math.cos(v)) * Math.sin(u);
vertex.z = tube * Math.sin(v);
vertices.set([vertex.x, vertex.y, vertex.z], idx * 3);
// normal
center.x = radius * Math.cos(u);
center.y = radius * Math.sin(u);
normal.sub(vertex, center).normalize();
normals.set([normal.x, normal.y, normal.z], idx * 3);
// uv
uvs.set([i / tubularSegments, j / radialSegments], idx * 2);
}
}
// generate indices
idx = 0;
for (let j = 1; j <= radialSegments; j++) {
for (let i = 1; i <= tubularSegments; i++, idx++) {
// indices
const a = (tubularSegments + 1) * j + i - 1;
const b = (tubularSegments + 1) * (j - 1) + i - 1;
const c = (tubularSegments + 1) * (j - 1) + i;
const d = (tubularSegments + 1) * j + i;
// faces
indices.set([a, b, d, b, c, d], idx * 6);
}
}
Object.assign(attributes, {
position: { size: 3, data: vertices },
normal: { size: 3, data: normals },
uv: { size: 2, data: uvs },
index: { data: indices },
});
super(gl, attributes);
}
}

12
node_modules/ogl/src/extras/Triangle.js generated vendored Normal file
View File

@@ -0,0 +1,12 @@
import { Geometry } from '../core/Geometry.js';
export class Triangle extends Geometry {
constructor(gl, { attributes = {} } = {}) {
Object.assign(attributes, {
position: { size: 2, data: new Float32Array([-1, -1, 3, -1, -1, 3]) },
uv: { size: 2, data: new Float32Array([0, 0, 2, 0, 0, 2]) },
});
super(gl, attributes);
}
}

97
node_modules/ogl/src/extras/Tube.js generated vendored Normal file
View File

@@ -0,0 +1,97 @@
import { Geometry } from '../core/Geometry.js';
import { Vec3 } from '../math/Vec3.js';
import { Vec2 } from '../math/Vec2.js';
// helper variables
const vertex = /* @__PURE__ */ new Vec3();
const normal = /* @__PURE__ */ new Vec3();
const uv = /* @__PURE__ */ new Vec2();
const point = /* @__PURE__ */ new Vec3();
export class Tube extends Geometry {
constructor(gl, { path, radius = 1, tubularSegments = 64, radialSegments = 8, closed = false, attributes = {} } = {}) {
super(gl, attributes);
this.path = path;
this.radius = radius;
this.tubularSegments = tubularSegments;
this.radialSegments = radialSegments;
this.closed = closed;
this.frenetFrames = path.computeFrenetFrames(tubularSegments, closed);
const numVertices = (tubularSegments + 1) * (radialSegments + 1);
const numIndices = tubularSegments * radialSegments * 6;
this.positions = new Float32Array(numVertices * 3);
this.normals = new Float32Array(numVertices * 3);
this.uvs = new Float32Array(numVertices * 2);
this.indices = numVertices > 65536 ? new Uint32Array(numIndices) : new Uint16Array(numIndices);
// create buffer data
this._generateAttributes();
this._generateIndices();
this.addAttribute('position', { size: 3, data: this.positions });
this.addAttribute('normal', { size: 3, data: this.normals });
this.addAttribute('uv', { size: 2, data: this.uvs });
this.setIndex({ data: this.indices });
}
_generateAttributes() {
for (let i = 0; i <= this.tubularSegments; i++) {
let ci = i;
if (i === this.tubularSegments) {
// if the geometry is not closed, generate the last row of vertices and normals
// at the regular position on the given path
// if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ)
ci = this.closed ? 0 : this.tubularSegments;
}
this.path.getPointAt(ci / this.tubularSegments, point);
// retrieve corresponding normal and binormal
const N = this.frenetFrames.normals[ci];
const B = this.frenetFrames.binormals[ci];
// generate normals and vertices for the current segment
for (let j = 0; j <= this.radialSegments; j++) {
const v = (j / this.radialSegments) * Math.PI * 2;
const sin = Math.sin(v);
const cos = -Math.cos(v);
const idx = i * (this.radialSegments + 1) + j;
// normal
normal.x = cos * N.x + sin * B.x;
normal.y = cos * N.y + sin * B.y;
normal.z = cos * N.z + sin * B.z;
// normal.normalize(); // ???
this.normals.set(normal, idx * 3);
// vertex
vertex.x = point.x + this.radius * normal.x;
vertex.y = point.y + this.radius * normal.y;
vertex.z = point.z + this.radius * normal.z;
this.positions.set(vertex, idx * 3);
// uv
uv.x = i / this.tubularSegments;
uv.y = j / this.radialSegments;
this.uvs.set(uv, idx * 2);
}
}
}
_generateIndices() {
for (let j = 1; j <= this.tubularSegments; j++) {
for (let i = 1; i <= this.radialSegments; i++) {
const a = (this.radialSegments + 1) * (j - 1) + (i - 1);
const b = (this.radialSegments + 1) * j + (i - 1);
const c = (this.radialSegments + 1) * j + i;
const d = (this.radialSegments + 1) * (j - 1) + i;
const idx = (j - 1) * this.radialSegments + (i - 1);
this.indices.set([a, b, d, b, c, d], idx * 6);
}
}
}
}

94
node_modules/ogl/src/extras/WireMesh.js generated vendored Normal file
View File

@@ -0,0 +1,94 @@
import { Mesh } from '../core/Mesh.js';
import { Program } from '../core/Program.js';
import { Geometry } from '../core/Geometry.js';
import { Color } from '../math/Color.js';
export class WireMesh extends Mesh {
constructor(gl, { geometry, wireColor = new Color(0, 0.75, 0.5), ...meshProps } = {}) {
const wireProgram = new Program(gl, {
vertex,
fragment,
uniforms: { wireColor: { value: wireColor } },
});
const positionArray = geometry.attributes.position.data;
const indices = [];
const hashSet = new Set();
function addUniqueIndices(idx) {
for (let i = 0; i < idx.length; i += 2) {
if (isUniqueEdgePosition(idx[i] * 3, idx[i + 1] * 3, positionArray, hashSet)) {
indices.push(idx[i], idx[i + 1]);
}
}
}
if (geometry.attributes.index) {
const idata = geometry.attributes.index.data;
for (let i = 0; i < idata.length; i += 3) {
// For every triangle, make three line pairs (start, end)
// prettier-ignore
addUniqueIndices([
idata[i], idata[i + 1],
idata[i + 1], idata[i + 2],
idata[i + 2], idata[i]
]);
}
} else {
const numVertices = Math.floor(positionArray.length / 3);
for (let i = 0; i < numVertices; i += 3) {
addUniqueIndices([i, i + 1, i + 1, i + 2, i + 2, i]);
}
}
const indicesTyped = indices.length > 65536 ? new Uint32Array(indices) : new Uint16Array(indices);
const wireGeometry = new Geometry(gl, {
position: { ...geometry.attributes.position },
index: { data: indicesTyped },
});
super(gl, { ...meshProps, mode: gl.LINES, geometry: wireGeometry, program: wireProgram });
}
}
// from https://github.com/mrdoob/three.js/blob/0c26bb4bb8220126447c8373154ac045588441de/src/geometries/WireframeGeometry.js#L116
function isUniqueEdgePosition(start, end, pos, hashSet) {
// prettier-ignore
const hash1 = [
pos[start], pos[start + 1], pos[start + 2],
pos[end], pos[end + 1], pos[end + 2]
].join('#');
// coincident edge
// prettier-ignore
const hash2 = [
pos[end], pos[end + 1], pos[end + 2],
pos[start], pos[start + 1], pos[start + 2]
].join('#');
const oldSize = hashSet.size;
hashSet.add(hash1);
hashSet.add(hash2);
return hashSet.size - oldSize === 2;
}
const vertex = /* glsl */ `
attribute vec3 position;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
void main() {
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`;
const fragment = /* glsl */ `
precision highp float;
uniform vec3 wireColor;
void main() {
gl_FragColor = vec4(wireColor, 1.0);
}
`;

67
node_modules/ogl/src/extras/helpers/AxesHelper.js generated vendored Normal file
View File

@@ -0,0 +1,67 @@
import { Mesh } from '../../core/Mesh.js';
import { Program } from '../../core/Program.js';
import { Geometry } from '../../core/Geometry.js';
import { Vec3 } from '../../math/Vec3.js';
export class AxesHelper extends Mesh {
constructor(
gl,
{
size = 1,
symmetric = false,
xColor = new Vec3(0.96, 0.21, 0.32),
yColor = new Vec3(0.44, 0.64, 0.11),
zColor = new Vec3(0.18, 0.52, 0.89),
...meshProps
} = {}
) {
const a = symmetric ? -size : 0;
const b = size;
// prettier-ignore
const vertices = new Float32Array([
a, 0, 0, b, 0, 0,
0, a, 0, 0, b, 0,
0, 0, a, 0, 0, b
]);
// prettier-ignore
const colors = new Float32Array([
...xColor, ...xColor,
...yColor, ...yColor,
...zColor, ...zColor
]);
const geometry = new Geometry(gl, {
position: { size: 3, data: vertices },
color: { size: 3, data: colors },
});
const program = new Program(gl, { vertex, fragment });
super(gl, { ...meshProps, mode: gl.LINES, geometry, program });
}
}
const vertex = /* glsl */ `
attribute vec3 position;
attribute vec3 color;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
varying vec3 vColor;
void main() {
vColor = color;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`;
const fragment = /* glsl */ `
precision highp float;
varying vec3 vColor;
void main() {
gl_FragColor = vec4(vColor, 1.0);
}
`;

View File

@@ -0,0 +1,104 @@
import { Mesh } from '../../core/Mesh.js';
import { Program } from '../../core/Program.js';
import { Geometry } from '../../core/Geometry.js';
import { Vec3 } from '../../math/Vec3.js';
import { Mat3 } from '../../math/Mat3.js';
const vA = /* @__PURE__ */ new Vec3();
const vB = /* @__PURE__ */ new Vec3();
const vC = /* @__PURE__ */ new Vec3();
const vCenter = /* @__PURE__ */ new Vec3();
const vNormal = /* @__PURE__ */ new Vec3();
export class FaceNormalsHelper extends Mesh {
constructor(object, { size = 0.1, color = new Vec3(0.15, 0.86, 0.86), ...meshProps } = {}) {
const gl = object.gl;
const positionData = object.geometry.attributes.position.data;
const sizeData = new Float32Array([0, size]);
const indexAttr = object.geometry.attributes.index;
const getIndex = indexAttr ? (i) => indexAttr.data[i] : (i) => i;
const numVertices = indexAttr ? indexAttr.data.length : Math.floor(positionData.length / 3);
const nNormals = Math.floor(numVertices / 3);
const positionsArray = new Float32Array(nNormals * 2 * 3);
const normalsArray = new Float32Array(nNormals * 2 * 3);
const sizeArray = new Float32Array(nNormals * 2);
for (let i = 0; i < numVertices; i += 3) {
vA.fromArray(positionData, getIndex(i + 0) * 3);
vB.fromArray(positionData, getIndex(i + 1) * 3);
vC.fromArray(positionData, getIndex(i + 2) * 3);
vCenter
.add(vA, vB)
.add(vC)
.multiply(1 / 3);
vA.sub(vA, vB);
vC.sub(vC, vB);
vNormal.cross(vC, vA).normalize();
// duplicate position and normal for line start and end point
const i2 = i * 2;
positionsArray.set(vCenter, i2);
positionsArray.set(vCenter, i2 + 3);
normalsArray.set(vNormal, i2);
normalsArray.set(vNormal, i2 + 3);
sizeArray.set(sizeData, (i / 3) * 2);
}
const geometry = new Geometry(gl, {
position: { size: 3, data: positionsArray },
normal: { size: 3, data: normalsArray },
size: { size: 1, data: sizeArray },
});
const program = new Program(gl, {
vertex,
fragment,
uniforms: {
color: { value: color },
worldNormalMatrix: { value: new Mat3() },
objectWorldMatrix: { value: object.worldMatrix },
},
});
super(gl, { ...meshProps, mode: gl.LINES, geometry, program });
this.object = object;
}
draw(arg) {
this.program.uniforms.worldNormalMatrix.value.getNormalMatrix(this.object.worldMatrix);
super.draw(arg);
}
}
const vertex = /* glsl */ `
attribute vec3 position;
attribute vec3 normal;
attribute float size;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;
uniform mat4 objectWorldMatrix;
uniform mat3 worldNormalMatrix;
void main() {
vec3 n = normalize(worldNormalMatrix * normal) * size;
vec3 p = (objectWorldMatrix * vec4(position, 1.0)).xyz;
gl_Position = projectionMatrix * viewMatrix * vec4(p + n, 1.0);
}
`;
const fragment = /* glsl */ `
precision highp float;
uniform vec3 color;
void main() {
gl_FragColor = vec4(color, 1.0);
}
`;

52
node_modules/ogl/src/extras/helpers/GridHelper.js generated vendored Normal file
View File

@@ -0,0 +1,52 @@
import { Mesh } from '../../core/Mesh.js';
import { Program } from '../../core/Program.js';
import { Geometry } from '../../core/Geometry.js';
import { Vec3 } from '../../math/Vec3.js';
export class GridHelper extends Mesh {
constructor(gl, { size = 10, divisions = 10, color = new Vec3(0.75, 0.75, 0.75), ...meshProps } = {}) {
const numVertices = (size + 1) * 2 * 2;
const vertices = new Float32Array(numVertices * 3);
const hs = size / 2;
for (let i = 0; i <= divisions; i++) {
const t = i / divisions;
const o = t * size - hs;
vertices.set([o, 0, -hs, o, 0, hs], i * 12);
vertices.set([-hs, 0, o, hs, 0, o], i * 12 + 6);
}
const geometry = new Geometry(gl, {
position: { size: 3, data: vertices },
});
const program = new Program(gl, {
vertex,
fragment,
uniforms: {
color: { value: color },
},
});
super(gl, { ...meshProps, mode: gl.LINES, geometry, program });
}
}
const vertex = /* glsl */ `
attribute vec3 position;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
void main() {
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`;
const fragment = /* glsl */ `
precision highp float;
uniform vec3 color;
void main() {
gl_FragColor = vec4(color, 1.0);
}
`;

View File

@@ -0,0 +1,86 @@
import { Mesh } from '../../core/Mesh.js';
import { Program } from '../../core/Program.js';
import { Geometry } from '../../core/Geometry.js';
import { Vec3 } from '../../math/Vec3.js';
import { Mat3 } from '../../math/Mat3.js';
export class VertexNormalsHelper extends Mesh {
constructor(object, { size = 0.1, color = new Vec3(0.86, 0.16, 0.86), ...meshProps } = {}) {
const gl = object.gl;
const nNormals = object.geometry.attributes.normal.count;
const positionsArray = new Float32Array(nNormals * 2 * 3);
const normalsArray = new Float32Array(nNormals * 2 * 3);
const sizeArray = new Float32Array(nNormals * 2);
const normalData = object.geometry.attributes.normal.data;
const positionData = object.geometry.attributes.position.data;
const sizeData = new Float32Array([0, size]);
for (let i = 0; i < nNormals; i++) {
const i6 = i * 6;
const i3 = i * 3;
// duplicate position and normal for line start and end point
const pSub = positionData.subarray(i3, i3 + 3);
positionsArray.set(pSub, i6);
positionsArray.set(pSub, i6 + 3);
const nSub = normalData.subarray(i3, i3 + 3);
normalsArray.set(nSub, i6);
normalsArray.set(nSub, i6 + 3);
sizeArray.set(sizeData, i * 2);
}
const geometry = new Geometry(gl, {
position: { size: 3, data: positionsArray },
normal: { size: 3, data: normalsArray },
size: { size: 1, data: sizeArray },
});
const program = new Program(gl, {
vertex,
fragment,
uniforms: {
color: { value: color },
worldNormalMatrix: { value: new Mat3() },
objectWorldMatrix: { value: object.worldMatrix },
},
});
super(gl, { ...meshProps, mode: gl.LINES, geometry, program });
this.object = object;
}
draw(arg) {
this.program.uniforms.worldNormalMatrix.value.getNormalMatrix(this.object.worldMatrix);
super.draw(arg);
}
}
const vertex = /* glsl */ `
attribute vec3 position;
attribute vec3 normal;
attribute float size;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;
uniform mat4 objectWorldMatrix;
uniform mat3 worldNormalMatrix;
void main() {
vec3 n = normalize(worldNormalMatrix * normal) * size;
vec3 p = (objectWorldMatrix * vec4(position, 1.0)).xyz;
gl_Position = projectionMatrix * viewMatrix * vec4(p + n, 1.0);
}
`;
const fragment = /* glsl */ `
precision highp float;
uniform vec3 color;
void main() {
gl_FragColor = vec4(color, 1.0);
}
`;

52
node_modules/ogl/src/extras/path/BaseSegment.js generated vendored Normal file
View File

@@ -0,0 +1,52 @@
/**
* Abstract base class for path segments.
* This class contains common methods for all segments types.
*/
export default class BaseSegment {
constructor() {
this._len = -1;
this.tiltStart = 0;
this.tiltEnd = 0;
}
/**
* Get segment length.
* @returns {number} segment length
*/
getLength() {
if (this._len < 0) {
this.updateLength();
}
return this._len;
}
/**
* Get tilt angle at t
* @param {number} t Distance at time t in range [0 .. 1]
* @returns {number} Tilt angle at t
*/
getTiltAt(t) {
return this.tiltStart * (1 - t) * this.tiltEnd * t;
}
/**
* Creates a clone of this instance
* @returns {BaseSegment} cloned instance
*/
clone() {
return new this.constructor().copy(this);
}
/**
* Copies another segment object to this instance.
* @param {BaseSegment} source reference object
* @returns {BaseSegment} copy of source object
*/
copy(source) {
this._len = source._len;
this.tiltStart = source.tiltStart;
this.tiltEnd = source.tiltEnd;
return this;
}
}

92
node_modules/ogl/src/extras/path/CubicBezierSegment.js generated vendored Normal file
View File

@@ -0,0 +1,92 @@
import BaseSegment from './BaseSegment.js';
import { Vec3 } from '../../math/Vec3.js';
import { T_VALUES, C_VALUES } from './utils.js';
const tempVec3 = /* @__PURE__ */ new Vec3();
function cubicBezier(t, p0, p1, p2, p3) {
const k = 1 - t;
// prettier-ignore
return (
(k * k * k * p0) +
(3 * k * k * t * p1) +
(3 * k * t * t * p2) +
(t * t * t * p3)
);
}
function cubicBezierDeriv(t, p0, p1, p2, p3) {
const k = 1 - t;
// prettier-ignore
return (
(3 * k * k * (p1 - p0)) +
(6 * k * t * (p2 - p1)) +
(3 * t * t * (p3 - p2))
);
}
export default class CubicBezierSegment extends BaseSegment {
constructor(p0, p1, p2, p3, tiltStart = 0, tiltEnd = 0) {
super();
this.p0 = p0;
this.p1 = p1;
this.p2 = p2;
this.p3 = p3;
this.tiltStart = tiltStart;
this.tiltEnd = tiltEnd;
this._len = -1;
}
/**
* Updates the segment length. You must call this method every time you change the curve's control points.
*/
updateLength() {
// from https://github.com/Pomax/bezierjs/blob/d19695f3cc3ce383cf38ce4643f467deca7edb92/src/utils.js#L265
const z = 0.5;
const len = T_VALUES.length;
let sum = 0;
for (let i = 0, t; i < len; i++) {
t = z * T_VALUES[i] + z;
sum += C_VALUES[i] * this.getDerivativeAt(t, tempVec3).len();
}
this._len = z * sum;
}
/**
* Get point at relative position in curve according to segment length.
* @param {number} t Distance at time t in range [0 .. 1]
* @param {Vec3} out Optional Vec3 to output
* @returns {Vec3} Point at relative position
*/
getPointAt(t, out = new Vec3()) {
out.x = cubicBezier(t, this.p0.x, this.p1.x, this.p2.x, this.p3.x);
out.y = cubicBezier(t, this.p0.y, this.p1.y, this.p2.y, this.p3.y);
out.z = cubicBezier(t, this.p0.z, this.p1.z, this.p2.z, this.p3.z);
return out;
}
getDerivativeAt(t, out = new Vec3()) {
out.x = cubicBezierDeriv(t, this.p0.x, this.p1.x, this.p2.x, this.p3.x);
out.y = cubicBezierDeriv(t, this.p0.y, this.p1.y, this.p2.y, this.p3.y);
out.z = cubicBezierDeriv(t, this.p0.z, this.p1.z, this.p2.z, this.p3.z);
return out;
}
/**
* Returns a unit vector tangent at t
* @param {number} t Distance at time t in range [0 .. 1]
* @param {Vec3} out Optional Vec3 to output
* @returns {Vec3} A unit vector
*/
getTangentAt(t, out = new Vec3()) {
return this.getDerivativeAt(t, out).normalize();
}
lastPoint() {
return this.p3;
}
}

50
node_modules/ogl/src/extras/path/LineSegment.js generated vendored Normal file
View File

@@ -0,0 +1,50 @@
import BaseSegment from './BaseSegment.js';
import { Vec3 } from '../../math/Vec3.js';
import { lerp as lerp3 } from '../../math/functions/Vec3Func.js';
const tempVec3 = /* @__PURE__ */ new Vec3();
export default class LineSegment extends BaseSegment {
constructor(p0, p1, tiltStart = 0, tiltEnd = 0) {
super();
this.p0 = p0;
this.p1 = p1;
this.tiltStart = tiltStart;
this.tiltEnd = tiltEnd;
this._len = -1;
}
/**
* Updates the segment length. You must call this method every time you change the curve's control points.
*/
updateLength() {
this._len = tempVec3.sub(this.p1, this.p0).len();
}
/**
* Get point at relative position in curve according to segment length.
* @param {number} t Distance at time t in range [0 .. 1]
* @param {Vec3} out Optional Vec3 to output
* @returns {Vec3} Point at relative position
*/
getPointAt(t, out = new Vec3()) {
lerp3(out, this.p0, this.p1, t);
return out;
}
/**
* Returns a unit vector tangent at t
* @param {number} t Distance at time t in range [0 .. 1]
* @param {Vec3} out Optional Vec3 to output
* @returns {Vec3} A unit vector
*/
getTangentAt(t, out = new Vec3()) {
return out.sub(this.p1, this.p0).normalize();
}
lastPoint() {
return this.p1;
}
}

263
node_modules/ogl/src/extras/path/Path.js generated vendored Normal file
View File

@@ -0,0 +1,263 @@
import { Vec3 } from '../../math/Vec3.js';
import { Mat4 } from '../../math/Mat4.js';
import CubicBezierSegment from './CubicBezierSegment.js';
import QuadraticBezierSegment from './QuadraticBezierSegment.js';
import LineSegment from './LineSegment.js';
import { clamp, toDegrees, toRadian, mat4fromRotationSinCos, rotateNormalBinormal } from './utils.js';
const tempVec3 = /* @__PURE__ */ new Vec3();
const tempMat4 = /* @__PURE__ */ new Mat4();
function throwIfNullProperty(property, message) {
if (this[property] == null) throw new Error(message);
}
export class Path {
constructor() {
this._segments = [];
this._lengthOffsets = null;
this._totalLength = -1;
this._lastPoint = null;
this._lastTilt = 0;
this._assertLastPoint = throwIfNullProperty.bind(this, '_lastPoint', 'Can`t get previous point of curve. Did you forget moveTo command?');
this.tiltFunction = null;
}
moveTo(p, tilt = 0) {
this._totalLength = -1;
this._lastPoint = p;
this._lastTilt = tilt;
}
bezierCurveTo(cp1, cp2, p, tilt = 0) {
this._assertLastPoint();
const seg = new CubicBezierSegment(this._lastPoint, cp1, cp2, p, this._lastTilt, tilt);
this.addSegment(seg);
return this;
}
quadraticCurveTo(cp, p, tilt = 0) {
this._assertLastPoint();
const seg = new QuadraticBezierSegment(this._lastPoint, cp, p, this._lastTilt, tilt);
this.addSegment(seg);
return this;
}
lineTo(p, tilt = 0) {
this._assertLastPoint();
const seg = new LineSegment(this._lastPoint, p, this._lastTilt, tilt);
this.addSegment(seg);
return this;
}
addSegment(segment) {
this._totalLength = -1;
this._lastPoint = segment.lastPoint();
this._lastTilt = segment.tiltEnd;
this._segments.push(segment);
return this;
}
getSegments() {
return this._segments;
}
updateLength() {
const n = this._segments.length;
this._lengthOffsets = new Array(n);
let offset = 0;
for (let i = 0; i < n; i++) {
this._lengthOffsets[i] = offset;
offset += this._segments[i].getLength();
}
this._totalLength = offset;
}
getLength() {
if (this._totalLength < 0) {
this.updateLength();
}
return this._totalLength;
}
/**
* Finding a path segment at a given absolute length distance
* @param {number} len absolute length distance
* @returns {[number, number]} [_segment index_, _relative segment distance_]
*/
findSegmentIndexAtLength(len) {
const totalLength = this.getLength();
if (len <= 0) {
return [0, 0];
}
if (len >= totalLength) {
return [this._segments.length - 1, 1];
}
let start = 0;
let end = this._lengthOffsets.length - 1;
let index = -1;
let mid;
while (start <= end) {
mid = Math.ceil((start + end) / 2);
if (mid === 0 || mid === this._lengthOffsets.length - 1 || (len >= this._lengthOffsets[mid] && len < this._lengthOffsets[mid + 1])) {
index = mid;
break;
} else if (len < this._lengthOffsets[mid]) {
end = mid - 1;
} else {
start = mid + 1;
}
}
const seg = this._segments[index];
const segLen = seg.getLength();
const t = (len - this._lengthOffsets[index]) / segLen;
return [index, t];
}
getPointAtLength(len, out = new Vec3()) {
const [i, t] = this.findSegmentIndexAtLength(len);
return this._segments[i].getPointAt(t, out);
}
getPointAt(t, out = new Vec3()) {
const totalLength = this.getLength();
return this.getPointAtLength(t * totalLength, out);
}
getTangentAtLength(len, out = new Vec3()) {
const [i, t] = this.findSegmentIndexAtLength(len);
return this._segments[i].getTangentAt(t, out);
}
getTangentAt(t, out = new Vec3()) {
const totalLength = this.getLength();
return this.getTangentAtLength(t * totalLength, out);
}
getTiltAtLength(len) {
const [i, t] = this.findSegmentIndexAtLength(len);
return this._segments[i].getTiltAt(t);
}
getTiltAt(t) {
const totalLength = this.getLength();
return this.getTiltAtLength(t * totalLength);
}
/**
* Get sequence of points using `getPointAt(t)`
* @param {number} divisions number of subdivisions
* @returns {Vec3[]} array of points
*/
getPoints(divisions = 64) {
const points = new Array(divisions + 1);
for (let i = 0; i <= divisions; i++) {
points[i] = this.getPointAt(i / divisions);
}
return points;
}
/**
* Generates the Frenet Frames.
* See http://www.cs.indiana.edu/pub/techreports/TR425.pdf
* @param {number} divisions number of subdivisions
* @returns {{tangents: Vec3[], normals: Vec3[], binormals: Vec3[]}} Object with tangents, normals and binormals arrays
*/
computeFrenetFrames(divisions = 64, closed = false) {
const tangents = new Array(divisions + 1);
const tilts = new Array(divisions + 1);
const tiltFunction = this.tiltFunction ?? ((a) => a);
// compute the tangent vectors and tilt for each segment on the curve
const totalLength = this.getLength();
for (let i = 0; i <= divisions; i++) {
const [si, st] = this.findSegmentIndexAtLength((totalLength * i) / divisions);
const segment = this._segments[si];
tangents[i] = segment.getTangentAt(st);
tilts[i] = tiltFunction(segment.getTiltAt(st), i / divisions, this);
}
const tx = Math.abs(tangents[0].x);
const ty = Math.abs(tangents[0].y);
const tz = Math.abs(tangents[0].z);
const normal = new Vec3();
if (tx < ty && tx < tz) {
normal.set(1, 0, 0);
} else if (ty < tx && ty < tz) {
normal.set(0, 1, 0);
} else {
normal.set(0, 0, 1);
}
// select an initial normal vector perpendicular to the first tangent vector,
// and in the direction of the minimum tangent xyz component
const normals = new Array(divisions + 1);
const binormals = new Array(divisions + 1);
normals[0] = new Vec3();
binormals[0] = new Vec3();
tempVec3.cross(tangents[0], normal).normalize();
normals[0].cross(tangents[0], tempVec3);
binormals[0].cross(tangents[0], normals[0]);
// compute the slowly-varying normal vector for each segment on the curve
for (let i = 1; i < tangents.length; i++) {
normals[i] = normals[i - 1].clone();
binormals[i] = new Vec3();
tempVec3.cross(tangents[i - 1], tangents[i]);
const crossLen = tempVec3.len();
if (crossLen > Number.EPSILON) {
tempVec3.scale(1 / crossLen); // nomalize
const cosTheta = clamp(tangents[i - 1].dot(tangents[i]), -1, 1); // clamp for floating pt errors
const sinTheta = clamp(crossLen, -1, 1);
mat4fromRotationSinCos(tempMat4, tempVec3, sinTheta, cosTheta);
normals[i].applyMatrix4(tempMat4);
}
binormals[i].cross(tangents[i], normals[i]);
}
// add tilt twisting
for (let i = 0; i < tilts.length; i++) {
rotateNormalBinormal(toRadian(tilts[i]), normals[i], binormals[i]);
}
// if the curve is closed, postprocess the vectors so the first and last normal vectors are the same
if (closed === true) {
const normalLast = normals[normals.length - 1];
let step = Math.acos(clamp(normals[0].dot(normalLast), -1, 1)) / (normals.length - 1);
if (tangents[0].dot(tempVec3.cross(normals[0], normalLast)) > 0) {
step = -step;
}
for (let i = 1; i < normals.length - 1; i++) {
const angle = step * i;
rotateNormalBinormal(angle, normals[i], binormals[i]);
tilts[i] += toDegrees(angle);
}
normals[normals.length - 1] = normals[0].clone();
binormals[binormals.length - 1] = binormals[0].clone();
}
return { tangents, normals, binormals, tilts };
}
}

View File

@@ -0,0 +1,80 @@
import BaseSegment from './BaseSegment.js';
import { Vec3 } from '../../math/Vec3.js';
import { T_VALUES, C_VALUES } from './utils.js';
const tempVec3 = /* @__PURE__ */ new Vec3();
function quadraticBezier(t, p0, p1, p2) {
const k = 1 - t;
return k * k * p0 + 2 * k * t * p1 + t * t * p2;
}
function quadraticBezierDeriv(t, p0, p1, p2) {
const k = 1 - t;
return 2 * k * (p1 - p0) + 2 * t * (p2 - p1);
}
export default class QuadraticBezierSegment extends BaseSegment {
constructor(p0, p1, p2, tiltStart = 0, tiltEnd = 0) {
super();
this.p0 = p0;
this.p1 = p1;
this.p2 = p2;
this.tiltStart = tiltStart;
this.tiltEnd = tiltEnd;
this._len = -1;
}
/**
* Updates the segment length. You must call this method every time you change the curve's control points.
*/
updateLength() {
// from https://github.com/Pomax/bezierjs/blob/d19695f3cc3ce383cf38ce4643f467deca7edb92/src/utils.js#L265
const z = 0.5;
const len = T_VALUES.length;
let sum = 0;
for (let i = 0, t; i < len; i++) {
t = z * T_VALUES[i] + z;
sum += C_VALUES[i] * this.getDerivativeAt(t, tempVec3).len();
}
this._len = z * sum;
}
/**
* Get point at relative position in curve according to segment length.
* @param {number} t Distance at time t in range [0 .. 1]
* @param {Vec3} out Optional Vec3 to output
* @returns {Vec3} Point at relative position
*/
getPointAt(t, out = new Vec3()) {
out.x = quadraticBezier(t, this.p0.x, this.p1.x, this.p2.x);
out.y = quadraticBezier(t, this.p0.y, this.p1.y, this.p2.y);
out.z = quadraticBezier(t, this.p0.z, this.p1.z, this.p2.z);
return out;
}
getDerivativeAt(t, out = new Vec3()) {
out.x = quadraticBezierDeriv(t, this.p0.x, this.p1.x, this.p2.x);
out.y = quadraticBezierDeriv(t, this.p0.y, this.p1.y, this.p2.y);
out.z = quadraticBezierDeriv(t, this.p0.z, this.p1.z, this.p2.z);
return out;
}
/**
* Returns a unit vector tangent at t
* @param {number} t Distance at time t in range [0 .. 1]
* @param {Vec3} out Optional Vec3 to output
* @returns {Vec3} A unit vector
*/
getTangentAt(t, out = new Vec3()) {
return this.getDerivativeAt(t, out).normalize();
}
lastPoint() {
return this.p2;
}
}

101
node_modules/ogl/src/extras/path/utils.js generated vendored Normal file
View File

@@ -0,0 +1,101 @@
// from https://github.com/Pomax/bezierjs/blob/d19695f3cc3ce383cf38ce4643f467deca7edb92/src/utils.js#L26
// Legendre-Gauss abscissae with n=24 (x_i values, defined at i=n as the roots of the nth order Legendre polynomial Pn(x))
export const T_VALUES = [
-0.0640568928626056260850430826247450385909, 0.0640568928626056260850430826247450385909, -0.1911188674736163091586398207570696318404,
0.1911188674736163091586398207570696318404, -0.3150426796961633743867932913198102407864, 0.3150426796961633743867932913198102407864,
-0.4337935076260451384870842319133497124524, 0.4337935076260451384870842319133497124524, -0.5454214713888395356583756172183723700107,
0.5454214713888395356583756172183723700107, -0.6480936519369755692524957869107476266696, 0.6480936519369755692524957869107476266696,
-0.7401241915785543642438281030999784255232, 0.7401241915785543642438281030999784255232, -0.8200019859739029219539498726697452080761,
0.8200019859739029219539498726697452080761, -0.8864155270044010342131543419821967550873, 0.8864155270044010342131543419821967550873,
-0.9382745520027327585236490017087214496548, 0.9382745520027327585236490017087214496548, -0.9747285559713094981983919930081690617411,
0.9747285559713094981983919930081690617411, -0.9951872199970213601799974097007368118745, 0.9951872199970213601799974097007368118745,
];
// Legendre-Gauss weights with n=24 (w_i values, defined by a function linked to in the Bezier primer article)
export const C_VALUES = [
0.1279381953467521569740561652246953718517, 0.1279381953467521569740561652246953718517, 0.1258374563468282961213753825111836887264,
0.1258374563468282961213753825111836887264, 0.121670472927803391204463153476262425607, 0.121670472927803391204463153476262425607,
0.1155056680537256013533444839067835598622, 0.1155056680537256013533444839067835598622, 0.1074442701159656347825773424466062227946,
0.1074442701159656347825773424466062227946, 0.0976186521041138882698806644642471544279, 0.0976186521041138882698806644642471544279,
0.086190161531953275917185202983742667185, 0.086190161531953275917185202983742667185, 0.0733464814110803057340336152531165181193,
0.0733464814110803057340336152531165181193, 0.0592985849154367807463677585001085845412, 0.0592985849154367807463677585001085845412,
0.0442774388174198061686027482113382288593, 0.0442774388174198061686027482113382288593, 0.0285313886289336631813078159518782864491,
0.0285313886289336631813078159518782864491, 0.0123412297999871995468056670700372915759, 0.0123412297999871995468056670700372915759,
];
/**
* Convert Degree To Radian
* @param {number} a Angle in Degrees
* @returns {number} a Angle in Radians
*/
export const toRadian = (a) => (a * Math.PI) / 180;
/**
* Convert Radian To Degree
* @param {number} a Angle in Radians
* @returns {number} a Angle in Radian
*/
export const toDegrees = (a) => (180 * a) / Math.PI;
export const clamp = (val, min, max) => Math.max(min, Math.min(val, max));
export const lerp = (t, v0, v1) => v0 * (t - 1) + v1 * t;
/**
* Fills a rotation matrix with the given sine and cosine of the angle around the given axis
* This function helps to avoid inverse trigonometry
* @param {Mat4} out mat4 receiving operation result
* @param {Vec3} axis the axis to rotate around. Should be normalized
* @param {number} sin sine of rotation angle
* @param {number} cos cosine of rotation angle
* @returns {Mat4} out
*/
export function mat4fromRotationSinCos(out, axis, sin, cos) {
const x = axis[0];
const y = axis[1];
const z = axis[2];
const t = 1 - cos;
out[0] = x * x * t + cos;
out[1] = y * x * t + z * sin;
out[2] = z * x * t - y * sin;
out[3] = 0;
out[4] = x * y * t - z * sin;
out[5] = y * y * t + cos;
out[6] = z * y * t + x * sin;
out[7] = 0;
out[8] = x * z * t + y * sin;
out[9] = y * z * t - x * sin;
out[10] = z * z * t + cos;
out[11] = 0;
out[12] = 0;
out[13] = 0;
out[14] = 0;
out[15] = 1;
return out;
}
/**
* Rotates the normal and binormal around its tangent by the given angle.
*
* see: https://en.wikipedia.org/wiki/Rodrigues%27_rotation_formula
* @param {number} angle rotation angle
* @param {Vec3} norm unit normal vector
* @param {Vec3} binorm unit binormal vector
* @param {Vec3} outNorm optional normal output vector. If not present then normal vector changes in place
* @param {Vec3} outBinorm optional binormal output vector. If not present then binormal vector changes in place
*/
export function rotateNormalBinormal(angle, norm, binorm, outNorm = norm, outBinorm = binorm) {
const s = Math.sin(angle);
const c = Math.cos(angle);
const nx = c * norm.x + s * binorm.x;
const ny = c * norm.y + s * binorm.y;
const nz = c * norm.z + s * binorm.z;
const bx = c * binorm.x - s * norm.x;
const by = c * binorm.y - s * norm.y;
const bz = c * binorm.z - s * norm.z;
outNorm.set(nx, ny, nz);
outBinorm.set(bx, by, bz);
}

55
node_modules/ogl/src/index.js generated vendored Normal file
View File

@@ -0,0 +1,55 @@
// Core
export { Geometry } from './core/Geometry.js';
export { Program } from './core/Program.js';
export { Renderer } from './core/Renderer.js';
export { Camera } from './core/Camera.js';
export { Transform } from './core/Transform.js';
export { Mesh } from './core/Mesh.js';
export { Texture } from './core/Texture.js';
export { RenderTarget } from './core/RenderTarget.js';
// Maths
export { Color } from './math/Color.js';
export { Euler } from './math/Euler.js';
export { Mat3 } from './math/Mat3.js';
export { Mat4 } from './math/Mat4.js';
export { Quat } from './math/Quat.js';
export { Vec2 } from './math/Vec2.js';
export { Vec3 } from './math/Vec3.js';
export { Vec4 } from './math/Vec4.js';
// Extras
export { Plane } from './extras/Plane.js';
export { Box } from './extras/Box.js';
export { Sphere } from './extras/Sphere.js';
export { Cylinder } from './extras/Cylinder.js';
export { Triangle } from './extras/Triangle.js';
export { Torus } from './extras/Torus.js';
export { Orbit } from './extras/Orbit.js';
export { Raycast } from './extras/Raycast.js';
export { Curve } from './extras/Curve.js';
export { Path } from './extras/path/Path.js';
export { Tube } from './extras/Tube.js';
export { Post } from './extras/Post.js';
export { Skin } from './extras/Skin.js';
export { Animation } from './extras/Animation.js';
export { Text } from './extras/Text.js';
export { NormalProgram } from './extras/NormalProgram.js';
export { Flowmap } from './extras/Flowmap.js';
export { GPGPU } from './extras/GPGPU.js';
export { Polyline } from './extras/Polyline.js';
export { Shadow } from './extras/Shadow.js';
export { KTXTexture } from './extras/KTXTexture.js';
export { TextureLoader } from './extras/TextureLoader.js';
export { GLTFLoader } from './extras/GLTFLoader.js';
export { GLTFSkin } from './extras/GLTFSkin.js';
export { GLTFAnimation } from './extras/GLTFAnimation.js';
export { DracoManager } from './extras/DracoManager.js';
export { BasisManager } from './extras/BasisManager.js';
export { WireMesh } from './extras/WireMesh.js';
export { AxesHelper } from './extras/helpers/AxesHelper.js';
export { GridHelper } from './extras/helpers/GridHelper.js';
export { VertexNormalsHelper } from './extras/helpers/VertexNormalsHelper.js';
export { FaceNormalsHelper } from './extras/helpers/FaceNormalsHelper.js';
export { InstancedMesh } from './extras/InstancedMesh.js';
export { Texture3D } from './extras/Texture3D.js';

54
node_modules/ogl/src/math/Color.js generated vendored Executable file
View File

@@ -0,0 +1,54 @@
import * as ColorFunc from './functions/ColorFunc.js';
// Color stored as an array of RGB decimal values (between 0 > 1)
// Constructor and set method accept following formats:
// new Color() - Empty (defaults to black)
// new Color([0.2, 0.4, 1.0]) - Decimal Array (or another Color instance)
// new Color(0.7, 0.0, 0.1) - Decimal RGB values
// new Color('#ff0000') - Hex string
// new Color('#ccc') - Short-hand Hex string
// new Color(0x4f27e8) - Number
// new Color('red') - Color name string (short list in ColorFunc.js)
export class Color extends Array {
constructor(color) {
if (Array.isArray(color)) return super(...color);
return super(...ColorFunc.parseColor(...arguments));
}
get r() {
return this[0];
}
get g() {
return this[1];
}
get b() {
return this[2];
}
set r(v) {
this[0] = v;
}
set g(v) {
this[1] = v;
}
set b(v) {
this[2] = v;
}
set(color) {
if (Array.isArray(color)) return this.copy(color);
return this.copy(ColorFunc.parseColor(...arguments));
}
copy(v) {
this[0] = v[0];
this[1] = v[1];
this[2] = v[2];
return this;
}
}

103
node_modules/ogl/src/math/Euler.js generated vendored Executable file
View File

@@ -0,0 +1,103 @@
import * as EulerFunc from './functions/EulerFunc.js';
import { Mat4 } from './Mat4.js';
const tmpMat4 = /* @__PURE__ */ new Mat4();
export class Euler extends Array {
constructor(x = 0, y = x, z = x, order = 'YXZ') {
super(x, y, z);
this.order = order;
this.onChange = () => {};
// Keep reference to proxy target to avoid triggering onChange internally
this._target = this;
// Return a proxy to trigger onChange when array elements are edited directly
const triggerProps = ['0', '1', '2'];
return new Proxy(this, {
set(target, property) {
const success = Reflect.set(...arguments);
if (success && triggerProps.includes(property)) target.onChange();
return success;
},
});
}
get x() {
return this[0];
}
get y() {
return this[1];
}
get z() {
return this[2];
}
set x(v) {
this._target[0] = v;
this.onChange();
}
set y(v) {
this._target[1] = v;
this.onChange();
}
set z(v) {
this._target[2] = v;
this.onChange();
}
set(x, y = x, z = x) {
if (x.length) return this.copy(x);
this._target[0] = x;
this._target[1] = y;
this._target[2] = z;
this.onChange();
return this;
}
copy(v) {
this._target[0] = v[0];
this._target[1] = v[1];
this._target[2] = v[2];
this.onChange();
return this;
}
reorder(order) {
this._target.order = order;
this.onChange();
return this;
}
fromRotationMatrix(m, order = this.order) {
EulerFunc.fromRotationMatrix(this._target, m, order);
this.onChange();
return this;
}
fromQuaternion(q, order = this.order, isInternal) {
tmpMat4.fromQuaternion(q);
this._target.fromRotationMatrix(tmpMat4, order);
// Avoid infinite recursion
if (!isInternal) this.onChange();
return this;
}
fromArray(a, o = 0) {
this._target[0] = a[o];
this._target[1] = a[o + 1];
this._target[2] = a[o + 2];
return this;
}
toArray(a = [], o = 0) {
a[o] = this[0];
a[o + 1] = this[1];
a[o + 2] = this[2];
return a;
}
}

73
node_modules/ogl/src/math/Mat3.js generated vendored Executable file
View File

@@ -0,0 +1,73 @@
import * as Mat3Func from './functions/Mat3Func.js';
export class Mat3 extends Array {
constructor(m00 = 1, m01 = 0, m02 = 0, m10 = 0, m11 = 1, m12 = 0, m20 = 0, m21 = 0, m22 = 1) {
super(m00, m01, m02, m10, m11, m12, m20, m21, m22);
return this;
}
set(m00, m01, m02, m10, m11, m12, m20, m21, m22) {
if (m00.length) return this.copy(m00);
Mat3Func.set(this, m00, m01, m02, m10, m11, m12, m20, m21, m22);
return this;
}
translate(v, m = this) {
Mat3Func.translate(this, m, v);
return this;
}
rotate(v, m = this) {
Mat3Func.rotate(this, m, v);
return this;
}
scale(v, m = this) {
Mat3Func.scale(this, m, v);
return this;
}
multiply(ma, mb) {
if (mb) {
Mat3Func.multiply(this, ma, mb);
} else {
Mat3Func.multiply(this, this, ma);
}
return this;
}
identity() {
Mat3Func.identity(this);
return this;
}
copy(m) {
Mat3Func.copy(this, m);
return this;
}
fromMatrix4(m) {
Mat3Func.fromMat4(this, m);
return this;
}
fromQuaternion(q) {
Mat3Func.fromQuat(this, q);
return this;
}
fromBasis(vec3a, vec3b, vec3c) {
this.set(vec3a[0], vec3a[1], vec3a[2], vec3b[0], vec3b[1], vec3b[2], vec3c[0], vec3c[1], vec3c[2]);
return this;
}
inverse(m = this) {
Mat3Func.invert(this, m);
return this;
}
getNormalMatrix(m) {
Mat3Func.normalFromMat4(this, m);
return this;
}
}

216
node_modules/ogl/src/math/Mat4.js generated vendored Executable file
View File

@@ -0,0 +1,216 @@
import * as Mat4Func from './functions/Mat4Func.js';
export class Mat4 extends Array {
constructor(
m00 = 1,
m01 = 0,
m02 = 0,
m03 = 0,
m10 = 0,
m11 = 1,
m12 = 0,
m13 = 0,
m20 = 0,
m21 = 0,
m22 = 1,
m23 = 0,
m30 = 0,
m31 = 0,
m32 = 0,
m33 = 1
) {
super(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33);
return this;
}
get x() {
return this[12];
}
get y() {
return this[13];
}
get z() {
return this[14];
}
get w() {
return this[15];
}
set x(v) {
this[12] = v;
}
set y(v) {
this[13] = v;
}
set z(v) {
this[14] = v;
}
set w(v) {
this[15] = v;
}
set(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
if (m00.length) return this.copy(m00);
Mat4Func.set(this, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33);
return this;
}
translate(v, m = this) {
Mat4Func.translate(this, m, v);
return this;
}
rotate(v, axis, m = this) {
Mat4Func.rotate(this, m, v, axis);
return this;
}
scale(v, m = this) {
Mat4Func.scale(this, m, typeof v === 'number' ? [v, v, v] : v);
return this;
}
add(ma, mb) {
if (mb) Mat4Func.add(this, ma, mb);
else Mat4Func.add(this, this, ma);
return this;
}
sub(ma, mb) {
if (mb) Mat4Func.subtract(this, ma, mb);
else Mat4Func.subtract(this, this, ma);
return this;
}
multiply(ma, mb) {
if (!ma.length) {
Mat4Func.multiplyScalar(this, this, ma);
} else if (mb) {
Mat4Func.multiply(this, ma, mb);
} else {
Mat4Func.multiply(this, this, ma);
}
return this;
}
identity() {
Mat4Func.identity(this);
return this;
}
copy(m) {
Mat4Func.copy(this, m);
return this;
}
fromPerspective({ fov, aspect, near, far } = {}) {
Mat4Func.perspective(this, fov, aspect, near, far);
return this;
}
fromOrthogonal({ left, right, bottom, top, near, far }) {
Mat4Func.ortho(this, left, right, bottom, top, near, far);
return this;
}
fromQuaternion(q) {
Mat4Func.fromQuat(this, q);
return this;
}
setPosition(v) {
this.x = v[0];
this.y = v[1];
this.z = v[2];
return this;
}
inverse(m = this) {
Mat4Func.invert(this, m);
return this;
}
compose(q, pos, scale) {
Mat4Func.compose(this, q, pos, scale);
return this;
}
decompose(q, pos, scale) {
Mat4Func.decompose(this, q, pos, scale);
return this;
}
getRotation(q) {
Mat4Func.getRotation(q, this);
return this;
}
getTranslation(pos) {
Mat4Func.getTranslation(pos, this);
return this;
}
getScaling(scale) {
Mat4Func.getScaling(scale, this);
return this;
}
getMaxScaleOnAxis() {
return Mat4Func.getMaxScaleOnAxis(this);
}
lookAt(eye, target, up) {
Mat4Func.targetTo(this, eye, target, up);
return this;
}
determinant() {
return Mat4Func.determinant(this);
}
fromArray(a, o = 0) {
this[0] = a[o];
this[1] = a[o + 1];
this[2] = a[o + 2];
this[3] = a[o + 3];
this[4] = a[o + 4];
this[5] = a[o + 5];
this[6] = a[o + 6];
this[7] = a[o + 7];
this[8] = a[o + 8];
this[9] = a[o + 9];
this[10] = a[o + 10];
this[11] = a[o + 11];
this[12] = a[o + 12];
this[13] = a[o + 13];
this[14] = a[o + 14];
this[15] = a[o + 15];
return this;
}
toArray(a = [], o = 0) {
a[o] = this[0];
a[o + 1] = this[1];
a[o + 2] = this[2];
a[o + 3] = this[3];
a[o + 4] = this[4];
a[o + 5] = this[5];
a[o + 6] = this[6];
a[o + 7] = this[7];
a[o + 8] = this[8];
a[o + 9] = this[9];
a[o + 10] = this[10];
a[o + 11] = this[11];
a[o + 12] = this[12];
a[o + 13] = this[13];
a[o + 14] = this[14];
a[o + 15] = this[15];
return a;
}
}

168
node_modules/ogl/src/math/Quat.js generated vendored Executable file
View File

@@ -0,0 +1,168 @@
import * as QuatFunc from './functions/QuatFunc.js';
export class Quat extends Array {
constructor(x = 0, y = 0, z = 0, w = 1) {
super(x, y, z, w);
this.onChange = () => {};
// Keep reference to proxy target to avoid triggering onChange internally
this._target = this;
// Return a proxy to trigger onChange when array elements are edited directly
const triggerProps = ['0', '1', '2', '3'];
return new Proxy(this, {
set(target, property) {
const success = Reflect.set(...arguments);
if (success && triggerProps.includes(property)) target.onChange();
return success;
},
});
}
get x() {
return this[0];
}
get y() {
return this[1];
}
get z() {
return this[2];
}
get w() {
return this[3];
}
set x(v) {
this._target[0] = v;
this.onChange();
}
set y(v) {
this._target[1] = v;
this.onChange();
}
set z(v) {
this._target[2] = v;
this.onChange();
}
set w(v) {
this._target[3] = v;
this.onChange();
}
identity() {
QuatFunc.identity(this._target);
this.onChange();
return this;
}
set(x, y, z, w) {
if (x.length) return this.copy(x);
QuatFunc.set(this._target, x, y, z, w);
this.onChange();
return this;
}
rotateX(a) {
QuatFunc.rotateX(this._target, this._target, a);
this.onChange();
return this;
}
rotateY(a) {
QuatFunc.rotateY(this._target, this._target, a);
this.onChange();
return this;
}
rotateZ(a) {
QuatFunc.rotateZ(this._target, this._target, a);
this.onChange();
return this;
}
inverse(q = this._target) {
QuatFunc.invert(this._target, q);
this.onChange();
return this;
}
conjugate(q = this._target) {
QuatFunc.conjugate(this._target, q);
this.onChange();
return this;
}
copy(q) {
QuatFunc.copy(this._target, q);
this.onChange();
return this;
}
normalize(q = this._target) {
QuatFunc.normalize(this._target, q);
this.onChange();
return this;
}
multiply(qA, qB) {
if (qB) {
QuatFunc.multiply(this._target, qA, qB);
} else {
QuatFunc.multiply(this._target, this._target, qA);
}
this.onChange();
return this;
}
dot(v) {
return QuatFunc.dot(this._target, v);
}
fromMatrix3(matrix3) {
QuatFunc.fromMat3(this._target, matrix3);
this.onChange();
return this;
}
fromEuler(euler, isInternal) {
QuatFunc.fromEuler(this._target, euler, euler.order);
// Avoid infinite recursion
if (!isInternal) this.onChange();
return this;
}
fromAxisAngle(axis, a) {
QuatFunc.setAxisAngle(this._target, axis, a);
this.onChange();
return this;
}
slerp(q, t) {
QuatFunc.slerp(this._target, this._target, q, t);
this.onChange();
return this;
}
fromArray(a, o = 0) {
this._target[0] = a[o];
this._target[1] = a[o + 1];
this._target[2] = a[o + 2];
this._target[3] = a[o + 3];
this.onChange();
return this;
}
toArray(a = [], o = 0) {
a[o] = this[0];
a[o + 1] = this[1];
a[o + 2] = this[2];
a[o + 3] = this[3];
return a;
}
}

147
node_modules/ogl/src/math/Vec2.js generated vendored Executable file
View File

@@ -0,0 +1,147 @@
import * as Vec2Func from './functions/Vec2Func.js';
export class Vec2 extends Array {
constructor(x = 0, y = x) {
super(x, y);
return this;
}
get x() {
return this[0];
}
get y() {
return this[1];
}
set x(v) {
this[0] = v;
}
set y(v) {
this[1] = v;
}
set(x, y = x) {
if (x.length) return this.copy(x);
Vec2Func.set(this, x, y);
return this;
}
copy(v) {
Vec2Func.copy(this, v);
return this;
}
add(va, vb) {
if (vb) Vec2Func.add(this, va, vb);
else Vec2Func.add(this, this, va);
return this;
}
sub(va, vb) {
if (vb) Vec2Func.subtract(this, va, vb);
else Vec2Func.subtract(this, this, va);
return this;
}
multiply(v) {
if (v.length) Vec2Func.multiply(this, this, v);
else Vec2Func.scale(this, this, v);
return this;
}
divide(v) {
if (v.length) Vec2Func.divide(this, this, v);
else Vec2Func.scale(this, this, 1 / v);
return this;
}
inverse(v = this) {
Vec2Func.inverse(this, v);
return this;
}
// Can't use 'length' as Array.prototype uses it
len() {
return Vec2Func.length(this);
}
distance(v) {
if (v) return Vec2Func.distance(this, v);
else return Vec2Func.length(this);
}
squaredLen() {
return this.squaredDistance();
}
squaredDistance(v) {
if (v) return Vec2Func.squaredDistance(this, v);
else return Vec2Func.squaredLength(this);
}
negate(v = this) {
Vec2Func.negate(this, v);
return this;
}
cross(va, vb) {
if (vb) return Vec2Func.cross(va, vb);
return Vec2Func.cross(this, va);
}
scale(v) {
Vec2Func.scale(this, this, v);
return this;
}
normalize() {
Vec2Func.normalize(this, this);
return this;
}
dot(v) {
return Vec2Func.dot(this, v);
}
equals(v) {
return Vec2Func.exactEquals(this, v);
}
applyMatrix3(mat3) {
Vec2Func.transformMat3(this, this, mat3);
return this;
}
applyMatrix4(mat4) {
Vec2Func.transformMat4(this, this, mat4);
return this;
}
lerp(v, a) {
Vec2Func.lerp(this, this, v, a);
return this;
}
smoothLerp(v, decay, dt) {
Vec2Func.smoothLerp(this, this, v, decay, dt);
return this;
}
clone() {
return new Vec2(this[0], this[1]);
}
fromArray(a, o = 0) {
this[0] = a[o];
this[1] = a[o + 1];
return this;
}
toArray(a = [], o = 0) {
a[o] = this[0];
a[o + 1] = this[1];
return a;
}
}

184
node_modules/ogl/src/math/Vec3.js generated vendored Executable file
View File

@@ -0,0 +1,184 @@
import * as Vec3Func from './functions/Vec3Func.js';
export class Vec3 extends Array {
constructor(x = 0, y = x, z = x) {
super(x, y, z);
return this;
}
get x() {
return this[0];
}
get y() {
return this[1];
}
get z() {
return this[2];
}
set x(v) {
this[0] = v;
}
set y(v) {
this[1] = v;
}
set z(v) {
this[2] = v;
}
set(x, y = x, z = x) {
if (x.length) return this.copy(x);
Vec3Func.set(this, x, y, z);
return this;
}
copy(v) {
Vec3Func.copy(this, v);
return this;
}
add(va, vb) {
if (vb) Vec3Func.add(this, va, vb);
else Vec3Func.add(this, this, va);
return this;
}
sub(va, vb) {
if (vb) Vec3Func.subtract(this, va, vb);
else Vec3Func.subtract(this, this, va);
return this;
}
multiply(v) {
if (v.length) Vec3Func.multiply(this, this, v);
else Vec3Func.scale(this, this, v);
return this;
}
divide(v) {
if (v.length) Vec3Func.divide(this, this, v);
else Vec3Func.scale(this, this, 1 / v);
return this;
}
inverse(v = this) {
Vec3Func.inverse(this, v);
return this;
}
// Can't use 'length' as Array.prototype uses it
len() {
return Vec3Func.length(this);
}
distance(v) {
if (v) return Vec3Func.distance(this, v);
else return Vec3Func.length(this);
}
squaredLen() {
return Vec3Func.squaredLength(this);
}
squaredDistance(v) {
if (v) return Vec3Func.squaredDistance(this, v);
else return Vec3Func.squaredLength(this);
}
negate(v = this) {
Vec3Func.negate(this, v);
return this;
}
cross(va, vb) {
if (vb) Vec3Func.cross(this, va, vb);
else Vec3Func.cross(this, this, va);
return this;
}
scale(v) {
Vec3Func.scale(this, this, v);
return this;
}
normalize() {
Vec3Func.normalize(this, this);
return this;
}
dot(v) {
return Vec3Func.dot(this, v);
}
equals(v) {
return Vec3Func.exactEquals(this, v);
}
applyMatrix3(mat3) {
Vec3Func.transformMat3(this, this, mat3);
return this;
}
applyMatrix4(mat4) {
Vec3Func.transformMat4(this, this, mat4);
return this;
}
scaleRotateMatrix4(mat4) {
Vec3Func.scaleRotateMat4(this, this, mat4);
return this;
}
applyQuaternion(q) {
Vec3Func.transformQuat(this, this, q);
return this;
}
angle(v) {
return Vec3Func.angle(this, v);
}
lerp(v, t) {
Vec3Func.lerp(this, this, v, t);
return this;
}
smoothLerp(v, decay, dt) {
Vec3Func.smoothLerp(this, this, v, decay, dt);
return this;
}
clone() {
return new Vec3(this[0], this[1], this[2]);
}
fromArray(a, o = 0) {
this[0] = a[o];
this[1] = a[o + 1];
this[2] = a[o + 2];
return this;
}
toArray(a = [], o = 0) {
a[o] = this[0];
a[o + 1] = this[1];
a[o + 2] = this[2];
return a;
}
transformDirection(mat4) {
const x = this[0];
const y = this[1];
const z = this[2];
this[0] = mat4[0] * x + mat4[4] * y + mat4[8] * z;
this[1] = mat4[1] * x + mat4[5] * y + mat4[9] * z;
this[2] = mat4[2] * x + mat4[6] * y + mat4[10] * z;
return this.normalize();
}
}

81
node_modules/ogl/src/math/Vec4.js generated vendored Executable file
View File

@@ -0,0 +1,81 @@
import * as Vec4Func from './functions/Vec4Func.js';
export class Vec4 extends Array {
constructor(x = 0, y = x, z = x, w = x) {
super(x, y, z, w);
return this;
}
get x() {
return this[0];
}
get y() {
return this[1];
}
get z() {
return this[2];
}
get w() {
return this[3];
}
set x(v) {
this[0] = v;
}
set y(v) {
this[1] = v;
}
set z(v) {
this[2] = v;
}
set w(v) {
this[3] = v;
}
set(x, y = x, z = x, w = x) {
if (x.length) return this.copy(x);
Vec4Func.set(this, x, y, z, w);
return this;
}
copy(v) {
Vec4Func.copy(this, v);
return this;
}
normalize() {
Vec4Func.normalize(this, this);
return this;
}
multiply(v) {
Vec4Func.scale(this, this, v);
return this;
}
dot(v) {
return Vec4Func.dot(this, v);
}
fromArray(a, o = 0) {
this[0] = a[o];
this[1] = a[o + 1];
this[2] = a[o + 2];
this[3] = a[o + 3];
return this;
}
toArray(a = [], o = 0) {
a[o] = this[0];
a[o + 1] = this[1];
a[o + 2] = this[2];
a[o + 3] = this[3];
return a;
}
}

43
node_modules/ogl/src/math/functions/ColorFunc.js generated vendored Normal file
View File

@@ -0,0 +1,43 @@
const NAMES = {
black: '#000000',
white: '#ffffff',
red: '#ff0000',
green: '#00ff00',
blue: '#0000ff',
fuchsia: '#ff00ff',
cyan: '#00ffff',
yellow: '#ffff00',
orange: '#ff8000',
};
export function hexToRGB(hex) {
if (hex.length === 4) hex = hex[0] + hex[1] + hex[1] + hex[2] + hex[2] + hex[3] + hex[3];
const rgb = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
if (!rgb) console.warn(`Unable to convert hex string ${hex} to rgb values`);
return [parseInt(rgb[1], 16) / 255, parseInt(rgb[2], 16) / 255, parseInt(rgb[3], 16) / 255];
}
export function numberToRGB(num) {
num = parseInt(num);
return [((num >> 16) & 255) / 255, ((num >> 8) & 255) / 255, (num & 255) / 255];
}
export function parseColor(color) {
// Empty
if (color === undefined) return [0, 0, 0];
// Decimal
if (arguments.length === 3) return arguments;
// Number
if (!isNaN(color)) return numberToRGB(color);
// Hex
if (color[0] === '#') return hexToRGB(color);
// Names
if (NAMES[color.toLowerCase()]) return hexToRGB(NAMES[color.toLowerCase()]);
console.warn('Color format not recognised');
return [0, 0, 0];
}

60
node_modules/ogl/src/math/functions/EulerFunc.js generated vendored Normal file
View File

@@ -0,0 +1,60 @@
// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
export function fromRotationMatrix(out, m, order = 'YXZ') {
if (order === 'XYZ') {
out[1] = Math.asin(Math.min(Math.max(m[8], -1), 1));
if (Math.abs(m[8]) < 0.99999) {
out[0] = Math.atan2(-m[9], m[10]);
out[2] = Math.atan2(-m[4], m[0]);
} else {
out[0] = Math.atan2(m[6], m[5]);
out[2] = 0;
}
} else if (order === 'YXZ') {
out[0] = Math.asin(-Math.min(Math.max(m[9], -1), 1));
if (Math.abs(m[9]) < 0.99999) {
out[1] = Math.atan2(m[8], m[10]);
out[2] = Math.atan2(m[1], m[5]);
} else {
out[1] = Math.atan2(-m[2], m[0]);
out[2] = 0;
}
} else if (order === 'ZXY') {
out[0] = Math.asin(Math.min(Math.max(m[6], -1), 1));
if (Math.abs(m[6]) < 0.99999) {
out[1] = Math.atan2(-m[2], m[10]);
out[2] = Math.atan2(-m[4], m[5]);
} else {
out[1] = 0;
out[2] = Math.atan2(m[1], m[0]);
}
} else if (order === 'ZYX') {
out[1] = Math.asin(-Math.min(Math.max(m[2], -1), 1));
if (Math.abs(m[2]) < 0.99999) {
out[0] = Math.atan2(m[6], m[10]);
out[2] = Math.atan2(m[1], m[0]);
} else {
out[0] = 0;
out[2] = Math.atan2(-m[4], m[5]);
}
} else if (order === 'YZX') {
out[2] = Math.asin(Math.min(Math.max(m[1], -1), 1));
if (Math.abs(m[1]) < 0.99999) {
out[0] = Math.atan2(-m[9], m[5]);
out[1] = Math.atan2(-m[2], m[0]);
} else {
out[0] = 0;
out[1] = Math.atan2(m[8], m[10]);
}
} else if (order === 'XZY') {
out[2] = Math.asin(-Math.min(Math.max(m[4], -1), 1));
if (Math.abs(m[4]) < 0.99999) {
out[0] = Math.atan2(m[6], m[5]);
out[1] = Math.atan2(m[8], m[0]);
} else {
out[0] = Math.atan2(-m[9], m[10]);
out[1] = 0;
}
}
return out;
}

502
node_modules/ogl/src/math/functions/Mat3Func.js generated vendored Executable file
View File

@@ -0,0 +1,502 @@
const EPSILON = 0.000001;
/**
* Copies the upper-left 3x3 values into the given mat3.
*
* @param {mat3} out the receiving 3x3 matrix
* @param {mat4} a the source 4x4 matrix
* @returns {mat3} out
*/
export function fromMat4(out, a) {
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[4];
out[4] = a[5];
out[5] = a[6];
out[6] = a[8];
out[7] = a[9];
out[8] = a[10];
return out;
}
/**
* Calculates a 3x3 matrix from the given quaternion
*
* @param {mat3} out mat3 receiving operation result
* @param {quat} q Quaternion to create matrix from
*
* @returns {mat3} out
*/
export function fromQuat(out, q) {
let x = q[0],
y = q[1],
z = q[2],
w = q[3];
let x2 = x + x;
let y2 = y + y;
let z2 = z + z;
let xx = x * x2;
let yx = y * x2;
let yy = y * y2;
let zx = z * x2;
let zy = z * y2;
let zz = z * z2;
let wx = w * x2;
let wy = w * y2;
let wz = w * z2;
out[0] = 1 - yy - zz;
out[3] = yx - wz;
out[6] = zx + wy;
out[1] = yx + wz;
out[4] = 1 - xx - zz;
out[7] = zy - wx;
out[2] = zx - wy;
out[5] = zy + wx;
out[8] = 1 - xx - yy;
return out;
}
/**
* Copy the values from one mat3 to another
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the source matrix
* @returns {mat3} out
*/
export function copy(out, a) {
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
out[4] = a[4];
out[5] = a[5];
out[6] = a[6];
out[7] = a[7];
out[8] = a[8];
return out;
}
/**
* Set the components of a mat3 to the given values
*
* @param {mat3} out the receiving matrix
* @returns {mat3} out
*/
export function set(out, m00, m01, m02, m10, m11, m12, m20, m21, m22) {
out[0] = m00;
out[1] = m01;
out[2] = m02;
out[3] = m10;
out[4] = m11;
out[5] = m12;
out[6] = m20;
out[7] = m21;
out[8] = m22;
return out;
}
/**
* Set a mat3 to the identity matrix
*
* @param {mat3} out the receiving matrix
* @returns {mat3} out
*/
export function identity(out) {
out[0] = 1;
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[4] = 1;
out[5] = 0;
out[6] = 0;
out[7] = 0;
out[8] = 1;
return out;
}
/**
* Transpose the values of a mat3
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the source matrix
* @returns {mat3} out
*/
export function transpose(out, a) {
// If we are transposing ourselves we can skip a few steps but have to cache some values
if (out === a) {
let a01 = a[1],
a02 = a[2],
a12 = a[5];
out[1] = a[3];
out[2] = a[6];
out[3] = a01;
out[5] = a[7];
out[6] = a02;
out[7] = a12;
} else {
out[0] = a[0];
out[1] = a[3];
out[2] = a[6];
out[3] = a[1];
out[4] = a[4];
out[5] = a[7];
out[6] = a[2];
out[7] = a[5];
out[8] = a[8];
}
return out;
}
/**
* Inverts a mat3
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the source matrix
* @returns {mat3} out
*/
export function invert(out, a) {
let a00 = a[0],
a01 = a[1],
a02 = a[2];
let a10 = a[3],
a11 = a[4],
a12 = a[5];
let a20 = a[6],
a21 = a[7],
a22 = a[8];
let b01 = a22 * a11 - a12 * a21;
let b11 = -a22 * a10 + a12 * a20;
let b21 = a21 * a10 - a11 * a20;
// Calculate the determinant
let det = a00 * b01 + a01 * b11 + a02 * b21;
if (!det) {
return null;
}
det = 1.0 / det;
out[0] = b01 * det;
out[1] = (-a22 * a01 + a02 * a21) * det;
out[2] = (a12 * a01 - a02 * a11) * det;
out[3] = b11 * det;
out[4] = (a22 * a00 - a02 * a20) * det;
out[5] = (-a12 * a00 + a02 * a10) * det;
out[6] = b21 * det;
out[7] = (-a21 * a00 + a01 * a20) * det;
out[8] = (a11 * a00 - a01 * a10) * det;
return out;
}
/**
* Calculates the determinant of a mat3
*
* @param {mat3} a the source matrix
* @returns {Number} determinant of a
*/
export function determinant(a) {
let a00 = a[0],
a01 = a[1],
a02 = a[2];
let a10 = a[3],
a11 = a[4],
a12 = a[5];
let a20 = a[6],
a21 = a[7],
a22 = a[8];
return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
}
/**
* Multiplies two mat3's
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the first operand
* @param {mat3} b the second operand
* @returns {mat3} out
*/
export function multiply(out, a, b) {
let a00 = a[0],
a01 = a[1],
a02 = a[2];
let a10 = a[3],
a11 = a[4],
a12 = a[5];
let a20 = a[6],
a21 = a[7],
a22 = a[8];
let b00 = b[0],
b01 = b[1],
b02 = b[2];
let b10 = b[3],
b11 = b[4],
b12 = b[5];
let b20 = b[6],
b21 = b[7],
b22 = b[8];
out[0] = b00 * a00 + b01 * a10 + b02 * a20;
out[1] = b00 * a01 + b01 * a11 + b02 * a21;
out[2] = b00 * a02 + b01 * a12 + b02 * a22;
out[3] = b10 * a00 + b11 * a10 + b12 * a20;
out[4] = b10 * a01 + b11 * a11 + b12 * a21;
out[5] = b10 * a02 + b11 * a12 + b12 * a22;
out[6] = b20 * a00 + b21 * a10 + b22 * a20;
out[7] = b20 * a01 + b21 * a11 + b22 * a21;
out[8] = b20 * a02 + b21 * a12 + b22 * a22;
return out;
}
/**
* Translate a mat3 by the given vector
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the matrix to translate
* @param {vec2} v vector to translate by
* @returns {mat3} out
*/
export function translate(out, a, v) {
let a00 = a[0],
a01 = a[1],
a02 = a[2],
a10 = a[3],
a11 = a[4],
a12 = a[5],
a20 = a[6],
a21 = a[7],
a22 = a[8],
x = v[0],
y = v[1];
out[0] = a00;
out[1] = a01;
out[2] = a02;
out[3] = a10;
out[4] = a11;
out[5] = a12;
out[6] = x * a00 + y * a10 + a20;
out[7] = x * a01 + y * a11 + a21;
out[8] = x * a02 + y * a12 + a22;
return out;
}
/**
* Rotates a mat3 by the given angle
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the matrix to rotate
* @param {Number} rad the angle to rotate the matrix by
* @returns {mat3} out
*/
export function rotate(out, a, rad) {
let a00 = a[0],
a01 = a[1],
a02 = a[2],
a10 = a[3],
a11 = a[4],
a12 = a[5],
a20 = a[6],
a21 = a[7],
a22 = a[8],
s = Math.sin(rad),
c = Math.cos(rad);
out[0] = c * a00 + s * a10;
out[1] = c * a01 + s * a11;
out[2] = c * a02 + s * a12;
out[3] = c * a10 - s * a00;
out[4] = c * a11 - s * a01;
out[5] = c * a12 - s * a02;
out[6] = a20;
out[7] = a21;
out[8] = a22;
return out;
}
/**
* Scales the mat3 by the dimensions in the given vec2
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the matrix to rotate
* @param {vec2} v the vec2 to scale the matrix by
* @returns {mat3} out
**/
export function scale(out, a, v) {
let x = v[0],
y = v[1];
out[0] = x * a[0];
out[1] = x * a[1];
out[2] = x * a[2];
out[3] = y * a[3];
out[4] = y * a[4];
out[5] = y * a[5];
out[6] = a[6];
out[7] = a[7];
out[8] = a[8];
return out;
}
/**
* Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix
*
* @param {mat3} out mat3 receiving operation result
* @param {mat4} a Mat4 to derive the normal matrix from
*
* @returns {mat3} out
*/
export function normalFromMat4(out, a) {
let a00 = a[0],
a01 = a[1],
a02 = a[2],
a03 = a[3];
let a10 = a[4],
a11 = a[5],
a12 = a[6],
a13 = a[7];
let a20 = a[8],
a21 = a[9],
a22 = a[10],
a23 = a[11];
let a30 = a[12],
a31 = a[13],
a32 = a[14],
a33 = a[15];
let b00 = a00 * a11 - a01 * a10;
let b01 = a00 * a12 - a02 * a10;
let b02 = a00 * a13 - a03 * a10;
let b03 = a01 * a12 - a02 * a11;
let b04 = a01 * a13 - a03 * a11;
let b05 = a02 * a13 - a03 * a12;
let b06 = a20 * a31 - a21 * a30;
let b07 = a20 * a32 - a22 * a30;
let b08 = a20 * a33 - a23 * a30;
let b09 = a21 * a32 - a22 * a31;
let b10 = a21 * a33 - a23 * a31;
let b11 = a22 * a33 - a23 * a32;
// Calculate the determinant
let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
if (!det) {
return null;
}
det = 1.0 / det;
out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
return out;
}
/**
* Generates a 2D projection matrix with the given bounds
*
* @param {mat3} out mat3 frustum matrix will be written into
* @param {number} width Width of your gl context
* @param {number} height Height of gl context
* @returns {mat3} out
*/
export function projection(out, width, height) {
out[0] = 2 / width;
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[4] = -2 / height;
out[5] = 0;
out[6] = -1;
out[7] = 1;
out[8] = 1;
return out;
}
/**
* Adds two mat3's
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the first operand
* @param {mat3} b the second operand
* @returns {mat3} out
*/
export function add(out, a, b) {
out[0] = a[0] + b[0];
out[1] = a[1] + b[1];
out[2] = a[2] + b[2];
out[3] = a[3] + b[3];
out[4] = a[4] + b[4];
out[5] = a[5] + b[5];
out[6] = a[6] + b[6];
out[7] = a[7] + b[7];
out[8] = a[8] + b[8];
return out;
}
/**
* Subtracts matrix b from matrix a
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the first operand
* @param {mat3} b the second operand
* @returns {mat3} out
*/
export function subtract(out, a, b) {
out[0] = a[0] - b[0];
out[1] = a[1] - b[1];
out[2] = a[2] - b[2];
out[3] = a[3] - b[3];
out[4] = a[4] - b[4];
out[5] = a[5] - b[5];
out[6] = a[6] - b[6];
out[7] = a[7] - b[7];
out[8] = a[8] - b[8];
return out;
}
/**
* Multiply each element of the matrix by a scalar.
*
* @param {mat3} out the receiving matrix
* @param {mat3} a the matrix to scale
* @param {Number} b amount to scale the matrix's elements by
* @returns {mat3} out
*/
export function multiplyScalar(out, a, b) {
out[0] = a[0] * b;
out[1] = a[1] * b;
out[2] = a[2] * b;
out[3] = a[3] * b;
out[4] = a[4] * b;
out[5] = a[5] * b;
out[6] = a[6] * b;
out[7] = a[7] * b;
out[8] = a[8] * b;
return out;
}

1054
node_modules/ogl/src/math/functions/Mat4Func.js generated vendored Executable file

File diff suppressed because it is too large Load Diff

410
node_modules/ogl/src/math/functions/QuatFunc.js generated vendored Executable file
View File

@@ -0,0 +1,410 @@
import * as vec4 from './Vec4Func.js';
/**
* Set a quat to the identity quaternion
*
* @param {quat} out the receiving quaternion
* @returns {quat} out
*/
export function identity(out) {
out[0] = 0;
out[1] = 0;
out[2] = 0;
out[3] = 1;
return out;
}
/**
* Sets a quat from the given angle and rotation axis,
* then returns it.
*
* @param {quat} out the receiving quaternion
* @param {vec3} axis the axis around which to rotate
* @param {Number} rad the angle in radians
* @returns {quat} out
**/
export function setAxisAngle(out, axis, rad) {
rad = rad * 0.5;
let s = Math.sin(rad);
out[0] = s * axis[0];
out[1] = s * axis[1];
out[2] = s * axis[2];
out[3] = Math.cos(rad);
return out;
}
/**
* Multiplies two quats
*
* @param {quat} out the receiving quaternion
* @param {quat} a the first operand
* @param {quat} b the second operand
* @returns {quat} out
*/
export function multiply(out, a, b) {
let ax = a[0],
ay = a[1],
az = a[2],
aw = a[3];
let bx = b[0],
by = b[1],
bz = b[2],
bw = b[3];
out[0] = ax * bw + aw * bx + ay * bz - az * by;
out[1] = ay * bw + aw * by + az * bx - ax * bz;
out[2] = az * bw + aw * bz + ax * by - ay * bx;
out[3] = aw * bw - ax * bx - ay * by - az * bz;
return out;
}
/**
* Rotates a quaternion by the given angle about the X axis
*
* @param {quat} out quat receiving operation result
* @param {quat} a quat to rotate
* @param {number} rad angle (in radians) to rotate
* @returns {quat} out
*/
export function rotateX(out, a, rad) {
rad *= 0.5;
let ax = a[0],
ay = a[1],
az = a[2],
aw = a[3];
let bx = Math.sin(rad),
bw = Math.cos(rad);
out[0] = ax * bw + aw * bx;
out[1] = ay * bw + az * bx;
out[2] = az * bw - ay * bx;
out[3] = aw * bw - ax * bx;
return out;
}
/**
* Rotates a quaternion by the given angle about the Y axis
*
* @param {quat} out quat receiving operation result
* @param {quat} a quat to rotate
* @param {number} rad angle (in radians) to rotate
* @returns {quat} out
*/
export function rotateY(out, a, rad) {
rad *= 0.5;
let ax = a[0],
ay = a[1],
az = a[2],
aw = a[3];
let by = Math.sin(rad),
bw = Math.cos(rad);
out[0] = ax * bw - az * by;
out[1] = ay * bw + aw * by;
out[2] = az * bw + ax * by;
out[3] = aw * bw - ay * by;
return out;
}
/**
* Rotates a quaternion by the given angle about the Z axis
*
* @param {quat} out quat receiving operation result
* @param {quat} a quat to rotate
* @param {number} rad angle (in radians) to rotate
* @returns {quat} out
*/
export function rotateZ(out, a, rad) {
rad *= 0.5;
let ax = a[0],
ay = a[1],
az = a[2],
aw = a[3];
let bz = Math.sin(rad),
bw = Math.cos(rad);
out[0] = ax * bw + ay * bz;
out[1] = ay * bw - ax * bz;
out[2] = az * bw + aw * bz;
out[3] = aw * bw - az * bz;
return out;
}
/**
* Performs a spherical linear interpolation between two quat
*
* @param {quat} out the receiving quaternion
* @param {quat} a the first operand
* @param {quat} b the second operand
* @param {Number} t interpolation amount between the two inputs
* @returns {quat} out
*/
export function slerp(out, a, b, t) {
// benchmarks:
// http://jsperf.com/quaternion-slerp-implementations
let ax = a[0],
ay = a[1],
az = a[2],
aw = a[3];
let bx = b[0],
by = b[1],
bz = b[2],
bw = b[3];
let omega, cosom, sinom, scale0, scale1;
// calc cosine
cosom = ax * bx + ay * by + az * bz + aw * bw;
// adjust signs (if necessary)
if (cosom < 0.0) {
cosom = -cosom;
bx = -bx;
by = -by;
bz = -bz;
bw = -bw;
}
// calculate coefficients
if (1.0 - cosom > 0.000001) {
// standard case (slerp)
omega = Math.acos(cosom);
sinom = Math.sin(omega);
scale0 = Math.sin((1.0 - t) * omega) / sinom;
scale1 = Math.sin(t * omega) / sinom;
} else {
// "from" and "to" quaternions are very close
// ... so we can do a linear interpolation
scale0 = 1.0 - t;
scale1 = t;
}
// calculate final values
out[0] = scale0 * ax + scale1 * bx;
out[1] = scale0 * ay + scale1 * by;
out[2] = scale0 * az + scale1 * bz;
out[3] = scale0 * aw + scale1 * bw;
return out;
}
/**
* Calculates the inverse of a quat
*
* @param {quat} out the receiving quaternion
* @param {quat} a quat to calculate inverse of
* @returns {quat} out
*/
export function invert(out, a) {
let a0 = a[0],
a1 = a[1],
a2 = a[2],
a3 = a[3];
let dot = a0 * a0 + a1 * a1 + a2 * a2 + a3 * a3;
let invDot = dot ? 1.0 / dot : 0;
// TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
out[0] = -a0 * invDot;
out[1] = -a1 * invDot;
out[2] = -a2 * invDot;
out[3] = a3 * invDot;
return out;
}
/**
* Calculates the conjugate of a quat
* If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
*
* @param {quat} out the receiving quaternion
* @param {quat} a quat to calculate conjugate of
* @returns {quat} out
*/
export function conjugate(out, a) {
out[0] = -a[0];
out[1] = -a[1];
out[2] = -a[2];
out[3] = a[3];
return out;
}
/**
* Creates a quaternion from the given 3x3 rotation matrix.
*
* NOTE: The resultant quaternion is not normalized, so you should be sure
* to renormalize the quaternion yourself where necessary.
*
* @param {quat} out the receiving quaternion
* @param {mat3} m rotation matrix
* @returns {quat} out
* @function
*/
export function fromMat3(out, m) {
// Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
// article "Quaternion Calculus and Fast Animation".
let fTrace = m[0] + m[4] + m[8];
let fRoot;
if (fTrace > 0.0) {
// |w| > 1/2, may as well choose w > 1/2
fRoot = Math.sqrt(fTrace + 1.0); // 2w
out[3] = 0.5 * fRoot;
fRoot = 0.5 / fRoot; // 1/(4w)
out[0] = (m[5] - m[7]) * fRoot;
out[1] = (m[6] - m[2]) * fRoot;
out[2] = (m[1] - m[3]) * fRoot;
} else {
// |w| <= 1/2
let i = 0;
if (m[4] > m[0]) i = 1;
if (m[8] > m[i * 3 + i]) i = 2;
let j = (i + 1) % 3;
let k = (i + 2) % 3;
fRoot = Math.sqrt(m[i * 3 + i] - m[j * 3 + j] - m[k * 3 + k] + 1.0);
out[i] = 0.5 * fRoot;
fRoot = 0.5 / fRoot;
out[3] = (m[j * 3 + k] - m[k * 3 + j]) * fRoot;
out[j] = (m[j * 3 + i] + m[i * 3 + j]) * fRoot;
out[k] = (m[k * 3 + i] + m[i * 3 + k]) * fRoot;
}
return out;
}
/**
* Creates a quaternion from the given euler angle x, y, z.
*
* @param {quat} out the receiving quaternion
* @param {vec3} euler Angles to rotate around each axis in degrees.
* @param {String} order detailing order of operations. Default 'XYZ'.
* @returns {quat} out
* @function
*/
export function fromEuler(out, euler, order = 'YXZ') {
let sx = Math.sin(euler[0] * 0.5);
let cx = Math.cos(euler[0] * 0.5);
let sy = Math.sin(euler[1] * 0.5);
let cy = Math.cos(euler[1] * 0.5);
let sz = Math.sin(euler[2] * 0.5);
let cz = Math.cos(euler[2] * 0.5);
if (order === 'XYZ') {
out[0] = sx * cy * cz + cx * sy * sz;
out[1] = cx * sy * cz - sx * cy * sz;
out[2] = cx * cy * sz + sx * sy * cz;
out[3] = cx * cy * cz - sx * sy * sz;
} else if (order === 'YXZ') {
out[0] = sx * cy * cz + cx * sy * sz;
out[1] = cx * sy * cz - sx * cy * sz;
out[2] = cx * cy * sz - sx * sy * cz;
out[3] = cx * cy * cz + sx * sy * sz;
} else if (order === 'ZXY') {
out[0] = sx * cy * cz - cx * sy * sz;
out[1] = cx * sy * cz + sx * cy * sz;
out[2] = cx * cy * sz + sx * sy * cz;
out[3] = cx * cy * cz - sx * sy * sz;
} else if (order === 'ZYX') {
out[0] = sx * cy * cz - cx * sy * sz;
out[1] = cx * sy * cz + sx * cy * sz;
out[2] = cx * cy * sz - sx * sy * cz;
out[3] = cx * cy * cz + sx * sy * sz;
} else if (order === 'YZX') {
out[0] = sx * cy * cz + cx * sy * sz;
out[1] = cx * sy * cz + sx * cy * sz;
out[2] = cx * cy * sz - sx * sy * cz;
out[3] = cx * cy * cz - sx * sy * sz;
} else if (order === 'XZY') {
out[0] = sx * cy * cz - cx * sy * sz;
out[1] = cx * sy * cz - sx * cy * sz;
out[2] = cx * cy * sz + sx * sy * cz;
out[3] = cx * cy * cz + sx * sy * sz;
}
return out;
}
/**
* Copy the values from one quat to another
*
* @param {quat} out the receiving quaternion
* @param {quat} a the source quaternion
* @returns {quat} out
* @function
*/
export const copy = vec4.copy;
/**
* Set the components of a quat to the given values
*
* @param {quat} out the receiving quaternion
* @param {Number} x X component
* @param {Number} y Y component
* @param {Number} z Z component
* @param {Number} w W component
* @returns {quat} out
* @function
*/
export const set = vec4.set;
/**
* Adds two quat's
*
* @param {quat} out the receiving quaternion
* @param {quat} a the first operand
* @param {quat} b the second operand
* @returns {quat} out
* @function
*/
export const add = vec4.add;
/**
* Scales a quat by a scalar number
*
* @param {quat} out the receiving vector
* @param {quat} a the vector to scale
* @param {Number} b amount to scale the vector by
* @returns {quat} out
* @function
*/
export const scale = vec4.scale;
/**
* Calculates the dot product of two quat's
*
* @param {quat} a the first operand
* @param {quat} b the second operand
* @returns {Number} dot product of a and b
* @function
*/
export const dot = vec4.dot;
/**
* Performs a linear interpolation between two quat's
*
* @param {quat} out the receiving quaternion
* @param {quat} a the first operand
* @param {quat} b the second operand
* @param {Number} t interpolation amount between the two inputs
* @returns {quat} out
* @function
*/
export const lerp = vec4.lerp;
/**
* Calculates the length of a quat
*
* @param {quat} a vector to calculate length of
* @returns {Number} length of a
*/
export const length = vec4.length;
/**
* Normalize a quat
*
* @param {quat} out the receiving quaternion
* @param {quat} a quaternion to normalize
* @returns {quat} out
* @function
*/
export const normalize = vec4.normalize;

332
node_modules/ogl/src/math/functions/Vec2Func.js generated vendored Executable file
View File

@@ -0,0 +1,332 @@
const EPSILON = 0.000001;
/**
* Copy the values from one vec2 to another
*
* @param {vec2} out the receiving vector
* @param {vec2} a the source vector
* @returns {vec2} out
*/
export function copy(out, a) {
out[0] = a[0];
out[1] = a[1];
return out;
}
/**
* Set the components of a vec2 to the given values
*
* @param {vec2} out the receiving vector
* @param {Number} x X component
* @param {Number} y Y component
* @returns {vec2} out
*/
export function set(out, x, y) {
out[0] = x;
out[1] = y;
return out;
}
/**
* Adds two vec2's
*
* @param {vec2} out the receiving vector
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {vec2} out
*/
export function add(out, a, b) {
out[0] = a[0] + b[0];
out[1] = a[1] + b[1];
return out;
}
/**
* Subtracts vector b from vector a
*
* @param {vec2} out the receiving vector
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {vec2} out
*/
export function subtract(out, a, b) {
out[0] = a[0] - b[0];
out[1] = a[1] - b[1];
return out;
}
/**
* Multiplies two vec2's
*
* @param {vec2} out the receiving vector
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {vec2} out
*/
export function multiply(out, a, b) {
out[0] = a[0] * b[0];
out[1] = a[1] * b[1];
return out;
}
/**
* Divides two vec2's
*
* @param {vec2} out the receiving vector
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {vec2} out
*/
export function divide(out, a, b) {
out[0] = a[0] / b[0];
out[1] = a[1] / b[1];
return out;
}
/**
* Scales a vec2 by a scalar number
*
* @param {vec2} out the receiving vector
* @param {vec2} a the vector to scale
* @param {Number} b amount to scale the vector by
* @returns {vec2} out
*/
export function scale(out, a, b) {
out[0] = a[0] * b;
out[1] = a[1] * b;
return out;
}
/**
* Calculates the euclidian distance between two vec2's
*
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {Number} distance between a and b
*/
export function distance(a, b) {
var x = b[0] - a[0],
y = b[1] - a[1];
return Math.sqrt(x * x + y * y);
}
/**
* Calculates the squared euclidian distance between two vec2's
*
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {Number} squared distance between a and b
*/
export function squaredDistance(a, b) {
var x = b[0] - a[0],
y = b[1] - a[1];
return x * x + y * y;
}
/**
* Calculates the length of a vec2
*
* @param {vec2} a vector to calculate length of
* @returns {Number} length of a
*/
export function length(a) {
var x = a[0],
y = a[1];
return Math.sqrt(x * x + y * y);
}
/**
* Calculates the squared length of a vec2
*
* @param {vec2} a vector to calculate squared length of
* @returns {Number} squared length of a
*/
export function squaredLength(a) {
var x = a[0],
y = a[1];
return x * x + y * y;
}
/**
* Negates the components of a vec2
*
* @param {vec2} out the receiving vector
* @param {vec2} a vector to negate
* @returns {vec2} out
*/
export function negate(out, a) {
out[0] = -a[0];
out[1] = -a[1];
return out;
}
/**
* Returns the inverse of the components of a vec2
*
* @param {vec2} out the receiving vector
* @param {vec2} a vector to invert
* @returns {vec2} out
*/
export function inverse(out, a) {
out[0] = 1.0 / a[0];
out[1] = 1.0 / a[1];
return out;
}
/**
* Normalize a vec2
*
* @param {vec2} out the receiving vector
* @param {vec2} a vector to normalize
* @returns {vec2} out
*/
export function normalize(out, a) {
var x = a[0],
y = a[1];
var len = x * x + y * y;
if (len > 0) {
//TODO: evaluate use of glm_invsqrt here?
len = 1 / Math.sqrt(len);
}
out[0] = a[0] * len;
out[1] = a[1] * len;
return out;
}
/**
* Calculates the dot product of two vec2's
*
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {Number} dot product of a and b
*/
export function dot(a, b) {
return a[0] * b[0] + a[1] * b[1];
}
/**
* Computes the cross product of two vec2's
* Note that the cross product returns a scalar
*
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @returns {Number} cross product of a and b
*/
export function cross(a, b) {
return a[0] * b[1] - a[1] * b[0];
}
/**
* Performs a linear interpolation between two vec2's
*
* @param {vec2} out the receiving vector
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @param {Number} t interpolation amount between the two inputs
* @returns {vec2} out
*/
export function lerp(out, a, b, t) {
var ax = a[0],
ay = a[1];
out[0] = ax + t * (b[0] - ax);
out[1] = ay + t * (b[1] - ay);
return out;
}
/**
* Performs a frame rate independant, linear interpolation between two vec2's
*
* @param {vec2} out the receiving vector
* @param {vec2} a the first operand
* @param {vec2} b the second operand
* @param {Number} decay decay constant for interpolation. useful range between 1 and 25, from slow to fast.
* @param {Number} dt delta time
* @returns {vec2} out
*/
export function smoothLerp(out, a, b, decay, dt) {
const exp = Math.exp(-decay * dt);
let ax = a[0];
let ay = a[1];
out[0] = b[0] + (ax - b[0]) * exp;
out[1] = b[1] + (ay - b[1]) * exp;
return out;
}
/**
* Transforms the vec2 with a mat2
*
* @param {vec2} out the receiving vector
* @param {vec2} a the vector to transform
* @param {mat2} m matrix to transform with
* @returns {vec2} out
*/
export function transformMat2(out, a, m) {
var x = a[0],
y = a[1];
out[0] = m[0] * x + m[2] * y;
out[1] = m[1] * x + m[3] * y;
return out;
}
/**
* Transforms the vec2 with a mat2d
*
* @param {vec2} out the receiving vector
* @param {vec2} a the vector to transform
* @param {mat2d} m matrix to transform with
* @returns {vec2} out
*/
export function transformMat2d(out, a, m) {
var x = a[0],
y = a[1];
out[0] = m[0] * x + m[2] * y + m[4];
out[1] = m[1] * x + m[3] * y + m[5];
return out;
}
/**
* Transforms the vec2 with a mat3
* 3rd vector component is implicitly '1'
*
* @param {vec2} out the receiving vector
* @param {vec2} a the vector to transform
* @param {mat3} m matrix to transform with
* @returns {vec2} out
*/
export function transformMat3(out, a, m) {
var x = a[0],
y = a[1];
out[0] = m[0] * x + m[3] * y + m[6];
out[1] = m[1] * x + m[4] * y + m[7];
return out;
}
/**
* Transforms the vec2 with a mat4
* 3rd vector component is implicitly '0'
* 4th vector component is implicitly '1'
*
* @param {vec2} out the receiving vector
* @param {vec2} a the vector to transform
* @param {mat4} m matrix to transform with
* @returns {vec2} out
*/
export function transformMat4(out, a, m) {
let x = a[0];
let y = a[1];
out[0] = m[0] * x + m[4] * y + m[12];
out[1] = m[1] * x + m[5] * y + m[13];
return out;
}
/**
* Returns whether or not the vectors exactly have the same elements in the same position (when compared with ===)
*
* @param {vec2} a The first vector.
* @param {vec2} b The second vector.
* @returns {Boolean} True if the vectors are equal, false otherwise.
*/
export function exactEquals(a, b) {
return a[0] === b[0] && a[1] === b[1];
}

421
node_modules/ogl/src/math/functions/Vec3Func.js generated vendored Executable file
View File

@@ -0,0 +1,421 @@
const EPSILON = 0.000001;
/**
* Calculates the length of a vec3
*
* @param {vec3} a vector to calculate length of
* @returns {Number} length of a
*/
export function length(a) {
let x = a[0];
let y = a[1];
let z = a[2];
return Math.sqrt(x * x + y * y + z * z);
}
/**
* Copy the values from one vec3 to another
*
* @param {vec3} out the receiving vector
* @param {vec3} a the source vector
* @returns {vec3} out
*/
export function copy(out, a) {
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
return out;
}
/**
* Set the components of a vec3 to the given values
*
* @param {vec3} out the receiving vector
* @param {Number} x X component
* @param {Number} y Y component
* @param {Number} z Z component
* @returns {vec3} out
*/
export function set(out, x, y, z) {
out[0] = x;
out[1] = y;
out[2] = z;
return out;
}
/**
* Adds two vec3's
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {vec3} out
*/
export function add(out, a, b) {
out[0] = a[0] + b[0];
out[1] = a[1] + b[1];
out[2] = a[2] + b[2];
return out;
}
/**
* Subtracts vector b from vector a
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {vec3} out
*/
export function subtract(out, a, b) {
out[0] = a[0] - b[0];
out[1] = a[1] - b[1];
out[2] = a[2] - b[2];
return out;
}
/**
* Multiplies two vec3's
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {vec3} out
*/
export function multiply(out, a, b) {
out[0] = a[0] * b[0];
out[1] = a[1] * b[1];
out[2] = a[2] * b[2];
return out;
}
/**
* Divides two vec3's
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {vec3} out
*/
export function divide(out, a, b) {
out[0] = a[0] / b[0];
out[1] = a[1] / b[1];
out[2] = a[2] / b[2];
return out;
}
/**
* Scales a vec3 by a scalar number
*
* @param {vec3} out the receiving vector
* @param {vec3} a the vector to scale
* @param {Number} b amount to scale the vector by
* @returns {vec3} out
*/
export function scale(out, a, b) {
out[0] = a[0] * b;
out[1] = a[1] * b;
out[2] = a[2] * b;
return out;
}
/**
* Calculates the euclidian distance between two vec3's
*
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {Number} distance between a and b
*/
export function distance(a, b) {
let x = b[0] - a[0];
let y = b[1] - a[1];
let z = b[2] - a[2];
return Math.sqrt(x * x + y * y + z * z);
}
/**
* Calculates the squared euclidian distance between two vec3's
*
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {Number} squared distance between a and b
*/
export function squaredDistance(a, b) {
let x = b[0] - a[0];
let y = b[1] - a[1];
let z = b[2] - a[2];
return x * x + y * y + z * z;
}
/**
* Calculates the squared length of a vec3
*
* @param {vec3} a vector to calculate squared length of
* @returns {Number} squared length of a
*/
export function squaredLength(a) {
let x = a[0];
let y = a[1];
let z = a[2];
return x * x + y * y + z * z;
}
/**
* Negates the components of a vec3
*
* @param {vec3} out the receiving vector
* @param {vec3} a vector to negate
* @returns {vec3} out
*/
export function negate(out, a) {
out[0] = -a[0];
out[1] = -a[1];
out[2] = -a[2];
return out;
}
/**
* Returns the inverse of the components of a vec3
*
* @param {vec3} out the receiving vector
* @param {vec3} a vector to invert
* @returns {vec3} out
*/
export function inverse(out, a) {
out[0] = 1.0 / a[0];
out[1] = 1.0 / a[1];
out[2] = 1.0 / a[2];
return out;
}
/**
* Normalize a vec3
*
* @param {vec3} out the receiving vector
* @param {vec3} a vector to normalize
* @returns {vec3} out
*/
export function normalize(out, a) {
let x = a[0];
let y = a[1];
let z = a[2];
let len = x * x + y * y + z * z;
if (len > 0) {
//TODO: evaluate use of glm_invsqrt here?
len = 1 / Math.sqrt(len);
}
out[0] = a[0] * len;
out[1] = a[1] * len;
out[2] = a[2] * len;
return out;
}
/**
* Calculates the dot product of two vec3's
*
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {Number} dot product of a and b
*/
export function dot(a, b) {
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
}
/**
* Computes the cross product of two vec3's
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {vec3} out
*/
export function cross(out, a, b) {
let ax = a[0],
ay = a[1],
az = a[2];
let bx = b[0],
by = b[1],
bz = b[2];
out[0] = ay * bz - az * by;
out[1] = az * bx - ax * bz;
out[2] = ax * by - ay * bx;
return out;
}
/**
* Performs a linear interpolation between two vec3's
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @param {Number} t interpolation amount between the two inputs
* @returns {vec3} out
*/
export function lerp(out, a, b, t) {
let ax = a[0];
let ay = a[1];
let az = a[2];
out[0] = ax + t * (b[0] - ax);
out[1] = ay + t * (b[1] - ay);
out[2] = az + t * (b[2] - az);
return out;
}
/**
* Performs a frame rate independant, linear interpolation between two vec3's
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @param {Number} decay decay constant for interpolation. useful range between 1 and 25, from slow to fast.
* @param {Number} dt delta time
* @returns {vec3} out
*/
export function smoothLerp(out, a, b, decay, dt) {
const exp = Math.exp(-decay * dt);
let ax = a[0];
let ay = a[1];
let az = a[2];
out[0] = b[0] + (ax - b[0]) * exp;
out[1] = b[1] + (ay - b[1]) * exp;
out[2] = b[2] + (az - b[2]) * exp;
return out;
}
/**
* Transforms the vec3 with a mat4.
* 4th vector component is implicitly '1'
*
* @param {vec3} out the receiving vector
* @param {vec3} a the vector to transform
* @param {mat4} m matrix to transform with
* @returns {vec3} out
*/
export function transformMat4(out, a, m) {
let x = a[0],
y = a[1],
z = a[2];
let w = m[3] * x + m[7] * y + m[11] * z + m[15];
w = w || 1.0;
out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;
out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w;
out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w;
return out;
}
/**
* Same as above but doesn't apply translation.
* Useful for rays.
*/
export function scaleRotateMat4(out, a, m) {
let x = a[0],
y = a[1],
z = a[2];
let w = m[3] * x + m[7] * y + m[11] * z + m[15];
w = w || 1.0;
out[0] = (m[0] * x + m[4] * y + m[8] * z) / w;
out[1] = (m[1] * x + m[5] * y + m[9] * z) / w;
out[2] = (m[2] * x + m[6] * y + m[10] * z) / w;
return out;
}
/**
* Transforms the vec3 with a mat3.
*
* @param {vec3} out the receiving vector
* @param {vec3} a the vector to transform
* @param {mat3} m the 3x3 matrix to transform with
* @returns {vec3} out
*/
export function transformMat3(out, a, m) {
let x = a[0],
y = a[1],
z = a[2];
out[0] = x * m[0] + y * m[3] + z * m[6];
out[1] = x * m[1] + y * m[4] + z * m[7];
out[2] = x * m[2] + y * m[5] + z * m[8];
return out;
}
/**
* Transforms the vec3 with a quat
*
* @param {vec3} out the receiving vector
* @param {vec3} a the vector to transform
* @param {quat} q quaternion to transform with
* @returns {vec3} out
*/
export function transformQuat(out, a, q) {
// benchmarks: https://jsperf.com/quaternion-transform-vec3-implementations-fixed
let x = a[0],
y = a[1],
z = a[2];
let qx = q[0],
qy = q[1],
qz = q[2],
qw = q[3];
let uvx = qy * z - qz * y;
let uvy = qz * x - qx * z;
let uvz = qx * y - qy * x;
let uuvx = qy * uvz - qz * uvy;
let uuvy = qz * uvx - qx * uvz;
let uuvz = qx * uvy - qy * uvx;
let w2 = qw * 2;
uvx *= w2;
uvy *= w2;
uvz *= w2;
uuvx *= 2;
uuvy *= 2;
uuvz *= 2;
out[0] = x + uvx + uuvx;
out[1] = y + uvy + uuvy;
out[2] = z + uvz + uuvz;
return out;
}
/**
* Get the angle between two 3D vectors
* @param {vec3} a The first operand
* @param {vec3} b The second operand
* @returns {Number} The angle in radians
*/
export const angle = (function () {
const tempA = [0, 0, 0];
const tempB = [0, 0, 0];
return function (a, b) {
copy(tempA, a);
copy(tempB, b);
normalize(tempA, tempA);
normalize(tempB, tempB);
let cosine = dot(tempA, tempB);
if (cosine > 1.0) {
return 0;
} else if (cosine < -1.0) {
return Math.PI;
} else {
return Math.acos(cosine);
}
};
})();
/**
* Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===)
*
* @param {vec3} a The first vector.
* @param {vec3} b The second vector.
* @returns {Boolean} True if the vectors are equal, false otherwise.
*/
export function exactEquals(a, b) {
return a[0] === b[0] && a[1] === b[1] && a[2] === b[2];
}

135
node_modules/ogl/src/math/functions/Vec4Func.js generated vendored Executable file
View File

@@ -0,0 +1,135 @@
const EPSILON = 0.000001;
/**
* Copy the values from one vec4 to another
*
* @param {vec4} out the receiving vector
* @param {vec4} a the source vector
* @returns {vec4} out
*/
export function copy(out, a) {
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
return out;
}
/**
* Set the components of a vec4 to the given values
*
* @param {vec4} out the receiving vector
* @param {Number} x X component
* @param {Number} y Y component
* @param {Number} z Z component
* @param {Number} w W component
* @returns {vec4} out
*/
export function set(out, x, y, z, w) {
out[0] = x;
out[1] = y;
out[2] = z;
out[3] = w;
return out;
}
/**
* Adds two vec4's
*
* @param {vec4} out the receiving vector
* @param {vec4} a the first operand
* @param {vec4} b the second operand
* @returns {vec4} out
*/
export function add(out, a, b) {
out[0] = a[0] + b[0];
out[1] = a[1] + b[1];
out[2] = a[2] + b[2];
out[3] = a[3] + b[3];
return out;
}
/**
* Scales a vec4 by a scalar number
*
* @param {vec4} out the receiving vector
* @param {vec4} a the vector to scale
* @param {Number} b amount to scale the vector by
* @returns {vec4} out
*/
export function scale(out, a, b) {
out[0] = a[0] * b;
out[1] = a[1] * b;
out[2] = a[2] * b;
out[3] = a[3] * b;
return out;
}
/**
* Calculates the length of a vec4
*
* @param {vec4} a vector to calculate length of
* @returns {Number} length of a
*/
export function length(a) {
let x = a[0];
let y = a[1];
let z = a[2];
let w = a[3];
return Math.sqrt(x * x + y * y + z * z + w * w);
}
/**
* Normalize a vec4
*
* @param {vec4} out the receiving vector
* @param {vec4} a vector to normalize
* @returns {vec4} out
*/
export function normalize(out, a) {
let x = a[0];
let y = a[1];
let z = a[2];
let w = a[3];
let len = x * x + y * y + z * z + w * w;
if (len > 0) {
len = 1 / Math.sqrt(len);
}
out[0] = x * len;
out[1] = y * len;
out[2] = z * len;
out[3] = w * len;
return out;
}
/**
* Calculates the dot product of two vec4's
*
* @param {vec4} a the first operand
* @param {vec4} b the second operand
* @returns {Number} dot product of a and b
*/
export function dot(a, b) {
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
}
/**
* Performs a linear interpolation between two vec4's
*
* @param {vec4} out the receiving vector
* @param {vec4} a the first operand
* @param {vec4} b the second operand
* @param {Number} t interpolation amount between the two inputs
* @returns {vec4} out
*/
export function lerp(out, a, b, t) {
let ax = a[0];
let ay = a[1];
let az = a[2];
let aw = a[3];
out[0] = ax + t * (b[0] - ax);
out[1] = ay + t * (b[1] - ay);
out[2] = az + t * (b[2] - az);
out[3] = aw + t * (b[3] - aw);
return out;
}

74
node_modules/ogl/types/core/Camera.d.ts generated vendored Normal file
View File

@@ -0,0 +1,74 @@
import { Transform } from './Transform.js';
import { Mat4 } from '../math/Mat4.js';
import { Vec3 } from '../math/Vec3.js';
import type { OGLRenderingContext } from './Renderer.js';
import type { Vec3Tuple } from '../math/Vec3.js';
import type { Mesh } from './Mesh.js';
export interface CameraOptions {
near: number;
far: number;
fov: number;
aspect: number;
left: number;
right: number;
bottom: number;
top: number;
zoom: number;
}
export interface PerspectiveOptions extends Pick<CameraOptions, 'near' | 'far' | 'fov' | 'aspect'> {}
export interface OrthographicOptions extends Pick<CameraOptions, 'near' | 'far' | 'left' | 'right' | 'bottom' | 'top' | 'zoom'> {}
export type CameraType = 'perspective' | 'orthographic';
/**
* A perspective or orthographic camera.
* @see {@link https://github.com/oframe/ogl/blob/master/src/core/Camera.js | Source}
*/
export class Camera extends Transform {
projectionMatrix: Mat4;
viewMatrix: Mat4;
projectionViewMatrix: Mat4;
worldPosition: Vec3;
type: CameraType;
near: number;
far: number;
fov: number;
aspect: number;
left: number;
right: number;
bottom: number;
top: number;
zoom: number;
frustum: (Vec3 & {
constant: number;
})[];
constructor(gl: OGLRenderingContext, options?: Partial<CameraOptions>);
perspective(options?: Partial<PerspectiveOptions>): this;
orthographic(options?: Partial<OrthographicOptions>): this;
updateMatrixWorld(): this;
updateProjectionMatrix(): this;
lookAt(target: Vec3 | Vec3Tuple): this;
project(v: Vec3): this;
unproject(v: Vec3): this;
updateFrustum(): void;
frustumIntersectsMesh(node: Mesh, worldMatrix?: Mat4): boolean;
frustumIntersectsSphere(center: Vec3, radius: number): boolean;
}

99
node_modules/ogl/types/core/Geometry.d.ts generated vendored Normal file
View File

@@ -0,0 +1,99 @@
import { Vec3 } from '../math/Vec3.js';
import type { OGLRenderingContext, RenderState } from './Renderer.js';
import type { Program } from './Program.js';
export type AttributeMap = Record<string, Partial<Attribute>>;
export type AttributeData =
| Float32Array
| Uint32Array
| Uint16Array
| Int16Array
| Uint8Array
| Int8Array;
export interface Attribute {
data: AttributeData;
size: number;
instanced: null | number | boolean;
type: GLenum;
normalized: boolean;
buffer: WebGLBuffer;
stride: number;
offset: number;
count: number;
target: number;
id: number;
divisor: number;
needsUpdate: boolean;
usage: number;
}
export interface Bounds {
min: Vec3;
max: Vec3;
center: Vec3;
scale: Vec3;
radius: number;
}
export type GeometryRaycast = 'sphere' | 'box';
/**
* A mesh, line, or point geometry.
* @see {@link https://github.com/oframe/ogl/blob/master/src/core/Geometry.js | Source}
*/
export class Geometry {
gl: OGLRenderingContext;
attributes: AttributeMap;
id: number;
VAOs: {
[programKey: string]: WebGLVertexArrayObject;
};
drawRange: {
start: number;
count: number;
};
instancedCount: number;
glState: RenderState;
isInstanced: boolean;
bounds: Bounds;
// Set from gltf loader
extras?: Record<string, any>;
extensions?: Record<string, any>;
raycast?: GeometryRaycast; // User defined
constructor(gl: OGLRenderingContext, attributes?: AttributeMap);
addAttribute(key: string, attr: Partial<Attribute>): number | undefined;
updateAttribute(attr: Partial<Attribute>): void;
setIndex(attr: Partial<Attribute>): void;
setDrawRange(start: number, count: number): void;
setInstancedCount(value: number): void;
createVAO(program: Program): void;
bindAttributes(program: Program): void;
draw(options: { program: Program; mode?: number }): void;
getPosition(): Partial<Attribute>;
computeBoundingBox(attr?: Partial<Attribute>): void;
computeBoundingSphere(attr?: Partial<Attribute>): void;
remove(): void;
}

67
node_modules/ogl/types/core/Mesh.d.ts generated vendored Normal file
View File

@@ -0,0 +1,67 @@
import { Transform } from './Transform.js';
import { Mat3 } from '../math/Mat3.js';
import { Mat4 } from '../math/Mat4.js';
import type { OGLRenderingContext } from './Renderer.js';
import type { Vec2 } from '../math/Vec2.js';
import type { Vec3 } from '../math/Vec3.js';
import type { Geometry } from './Geometry.js';
import type { Program } from './Program.js';
import type { Camera } from './Camera.js';
export interface MeshOptions<
TGeometry extends Geometry = Geometry,
TProgram extends Program = Program,
> {
geometry: TGeometry;
program: TProgram;
mode: GLenum;
frustumCulled: boolean;
renderOrder: number;
}
export type MeshRenderCallback = (renderInfo: { mesh: Mesh; camera?: Camera }) => any;
export interface RaycastHit {
localPoint: Vec3;
distance: number;
point: Vec3;
faceNormal: Vec3;
localFaceNormal: Vec3;
uv: Vec2;
localNormal: Vec3;
normal: Vec3;
}
/**
* Represents a {@link https://en.wikipedia.org/wiki/Polygon_mesh | polygon mesh}.
* @see {@link https://github.com/oframe/ogl/blob/master/src/core/Mesh.js | Source}
*/
export class Mesh<
TGeometry extends Geometry = Geometry,
TProgram extends Program = Program,
> extends Transform {
gl: OGLRenderingContext;
id: number;
geometry: TGeometry;
program: TProgram;
mode: GLenum;
frustumCulled: boolean;
renderOrder: number;
modelViewMatrix: Mat4;
normalMatrix: Mat3;
beforeRenderCallbacks: MeshRenderCallback[];
afterRenderCallbacks: MeshRenderCallback[];
hit?: Partial<RaycastHit>; // Set from raycaster
constructor(gl: OGLRenderingContext, options?: Partial<MeshOptions>);
onBeforeRender(f: MeshRenderCallback): this;
onAfterRender(f: MeshRenderCallback): this;
draw(options?: { camera?: Camera }): void;
}

63
node_modules/ogl/types/core/Program.d.ts generated vendored Normal file
View File

@@ -0,0 +1,63 @@
import type { OGLRenderingContext, BlendFunc, BlendEquation } from './Renderer';
export interface ProgramOptions {
vertex: string;
fragment: string;
uniforms: Record<string, any>;
transparent: boolean;
cullFace: GLenum | false | null;
frontFace: GLenum;
depthTest: boolean;
depthWrite: boolean;
depthFunc: GLenum;
}
export interface UniformInfo extends WebGLActiveInfo {
uniformName: string;
nameComponents: string[];
isStruct: boolean;
isStructArray: boolean;
structIndex: number;
structProperty: string;
}
/**
* A WebGL program.
* @see {@link https://github.com/oframe/ogl/blob/master/src/core/Program.js | Source}
*/
export class Program {
gl: OGLRenderingContext;
uniforms: Record<string, any>;
id: number;
transparent: boolean;
cullFace: GLenum | false | null;
frontFace: GLenum;
depthTest: boolean;
depthWrite: boolean;
depthFunc: GLenum;
blendFunc: BlendFunc;
blendEquation: BlendEquation;
vertexShader: WebGLShader;
fragmentShader: WebGLShader;
program: WebGLProgram;
uniformLocations: Map<UniformInfo, WebGLUniformLocation>;
attributeLocations: Map<WebGLActiveInfo, GLint>;
attributeOrder: string;
constructor(gl: OGLRenderingContext, options?: Partial<ProgramOptions>);
setShaders(options: { vertex: string; fragment: string }): void;
setBlendFunc(src: GLenum, dst: GLenum, srcAlpha?: GLenum, dstAlpha?: GLenum): void;
setBlendEquation(modeRGB: GLenum, modeAlpha: GLenum): void;
applyState(): void;
use(options?: { flipFaces?: boolean }): void;
remove(): void;
}

46
node_modules/ogl/types/core/RenderTarget.d.ts generated vendored Normal file
View File

@@ -0,0 +1,46 @@
import { Texture } from './Texture.js';
import type { OGLRenderingContext } from './Renderer.js';
export interface RenderTargetOptions {
width: number;
height: number;
target: GLenum;
color: number;
depth: boolean;
stencil: boolean;
depthTexture: boolean;
wrapS: GLenum;
wrapT: GLenum;
minFilter: GLenum;
magFilter: GLenum;
type: GLenum;
format: GLenum;
internalFormat: GLenum;
unpackAlignment: number;
premultiplyAlpha: boolean;
}
/**
* A render target.
* @see {@link https://github.com/oframe/ogl/blob/master/src/core/RenderTarget.js | Source}
*/
export class RenderTarget {
gl: OGLRenderingContext;
width: number;
height: number;
depth: boolean;
buffer: WebGLFramebuffer;
target: number;
textures: Texture[];
texture: Texture;
depthTexture: Texture;
depthBuffer: WebGLRenderbuffer;
stencilBuffer: WebGLRenderbuffer;
depthStencilBuffer: WebGLRenderbuffer;
constructor(gl: OGLRenderingContext, options?: Partial<RenderTargetOptions>);
setSize(width: number, height: number): void;
}

158
node_modules/ogl/types/core/Renderer.d.ts generated vendored Normal file
View File

@@ -0,0 +1,158 @@
import type { Camera } from './Camera.js';
import type { Transform } from './Transform.js';
import type { Mesh } from './Mesh.js';
import type { RenderTarget } from './RenderTarget.js';
export type OGLRenderingContext = (WebGL2RenderingContext | WebGLRenderingContext) & {
renderer: Renderer;
canvas: HTMLCanvasElement;
};
export interface RendererOptions {
canvas: HTMLCanvasElement;
width: number;
height: number;
dpr: number;
alpha: boolean;
depth: boolean;
stencil: boolean;
antialias: boolean;
premultipliedAlpha: boolean;
preserveDrawingBuffer: boolean;
powerPreference: string;
autoClear: boolean;
webgl: number;
}
export interface DeviceParameters {
maxTextureUnits?: number;
maxAnisotropy?: number;
}
export interface BlendFunc {
src: GLenum;
dst: GLenum;
srcAlpha?: GLenum;
dstAlpha?: GLenum;
}
export interface BlendEquation {
modeRGB: GLenum;
modeAlpha?: GLenum;
}
export interface Viewport {
x: number;
y: number;
width: number | null;
height: number | null;
}
export interface RenderState {
blendFunc: BlendFunc;
blendEquation: BlendEquation;
cullFace: GLenum | false | null;
frontFace: number;
depthMask: boolean;
depthFunc: number;
premultiplyAlpha: boolean;
flipY: boolean;
unpackAlignment: number;
viewport: Viewport;
textureUnits: number[];
activeTextureUnit: number;
framebuffer: WebGLFramebuffer | null;
boundBuffer?: WebGLBuffer | null;
uniformLocations: Map<WebGLUniformLocation, number | number[]>;
currentProgram: number | null;
}
export interface RendererSortable extends Mesh {
zDepth: number;
}
/**
* The WebGL renderer.
* @see {@link https://github.com/oframe/ogl/blob/master/src/core/Renderer.js | Source}
*/
export class Renderer {
dpr: number;
alpha: boolean;
color: boolean;
depth: boolean;
stencil: boolean;
premultipliedAlpha: boolean;
autoClear: boolean;
id: number;
gl: OGLRenderingContext;
isWebgl2: boolean;
state: RenderState;
extensions: Record<string, any>;
vertexAttribDivisor: Function;
drawArraysInstanced: Function;
drawElementsInstanced: Function;
createVertexArray: Function;
bindVertexArray: Function;
deleteVertexArray: Function;
drawBuffers: Function;
parameters: DeviceParameters;
width: number;
height: number;
currentGeometry?: string | null; // Set from geometry
constructor(options?: Partial<RendererOptions>);
setSize(width: number, height: number): void;
setViewport(width: number, height: number, x?: number, y?: number): void;
setScissor(width: number, height: number, x?: number, y?: number): void;
enable(id: GLenum): void;
disable(id: GLenum): void;
setBlendFunc(src: GLenum, dst: GLenum, srcAlpha?: GLenum, dstAlpha?: GLenum): void;
setBlendEquation(modeRGB: GLenum, modeAlpha: GLenum): void;
setCullFace(value: GLenum): void;
setFrontFace(value: GLenum): void;
setDepthMask(value: GLboolean): void;
setDepthFunc(value: GLenum): void;
activeTexture(value: number): void;
bindFramebuffer(options?: { target?: GLenum; buffer?: WebGLFramebuffer | null }): void;
getExtension(extension: string, webgl2Func?: keyof WebGL2RenderingContext, extFunc?: string): Function | null;
sortOpaque(a: RendererSortable, b: RendererSortable): number;
sortTransparent(a: RendererSortable, b: RendererSortable): number;
sortUI(a: RendererSortable, b: RendererSortable): number;
getRenderList(options: { scene: Transform; camera?: Camera; frustumCull: boolean; sort: boolean }): Mesh[];
render(
options: Partial<{
scene: Transform;
camera: Camera;
target: RenderTarget;
update: boolean;
sort: boolean;
frustumCull: boolean;
clear: boolean;
}>,
): void;
}

97
node_modules/ogl/types/core/Texture.d.ts generated vendored Normal file
View File

@@ -0,0 +1,97 @@
import type { OGLRenderingContext, RenderState } from './Renderer';
export type CompressedImage = {
isCompressedTexture?: boolean;
data: Uint8Array;
width: number;
height: number;
}[];
export type ImageRepresentation =
| HTMLImageElement
| HTMLCanvasElement
| HTMLVideoElement
| HTMLImageElement[]
| HTMLCanvasElement[]
| ArrayBufferView
| CompressedImage;
export interface TextureOptions {
image: ImageRepresentation;
target: number;
type: number;
format: number;
internalFormat: number;
wrapS: number;
wrapT: number;
wrapR: number;
generateMipmaps: boolean;
minFilter: number;
magFilter: number;
premultiplyAlpha: boolean;
unpackAlignment: number;
flipY: boolean;
anisotropy: number;
level: number;
width: number;
height: number;
length: number;
}
/**
* A surface, reflection, or refraction map.
* @see {@link https://github.com/oframe/ogl/blob/master/src/core/Texture.js | Source}
*/
export class Texture {
gl: OGLRenderingContext;
id: number;
image?: ImageRepresentation;
target: number;
type: number;
format: number;
internalFormat: number;
minFilter: number;
magFilter: number;
wrapS: number;
wrapT: number;
wrapR: number;
generateMipmaps: boolean;
premultiplyAlpha: boolean;
unpackAlignment: number;
flipY: boolean;
anisotropy: number;
level: number;
width: number;
height: number;
length: number;
texture: WebGLTexture;
store: {
image?: ImageRepresentation | null;
};
glState: RenderState;
state: {
minFilter: number;
magFilter: number;
wrapS: number;
wrapT: number;
anisotropy: number;
};
needsUpdate: boolean;
// Set from texture loader
onUpdate?: () => void | null;
ext?: string;
name?: string;
loaded?: Promise<Texture>;
constructor(gl: OGLRenderingContext, options?: Partial<TextureOptions>);
bind(): void;
update(textureUnit?: number): void;
}

140
node_modules/ogl/types/core/Transform.d.ts generated vendored Normal file
View File

@@ -0,0 +1,140 @@
import type { Euler } from '../math/Euler.js';
import type { Mat4 } from '../math/Mat4.js';
import type { Quat } from '../math/Quat.js';
import type { Vec3, Vec3Tuple } from '../math/Vec3.js';
import type { GLTFLoader } from '../extras/GLTFLoader.d.js';
/**
* The base class for most objects and provides a set of properties and methods for manipulating
* objects in 3D space.
* @see {@link https://github.com/oframe/ogl/blob/master/src/core/Transform.js | Source}
*/
export class Transform {
/**
* The parent.
* @see {@link https://en.wikipedia.org/wiki/Scene_graph | scene graph}.
*/
parent: Transform | null;
/**
* An array with the children.
*/
children: Transform[];
/**
* The visibility.
*/
visible: boolean;
/**
* The local transform matrix.
*/
matrix: Mat4;
/**
* The world transform matrix.
*/
worldMatrix: Mat4;
/**
* When set, it updates the local transform matrix every frame and also updates the worldMatrix
* property.
* @defaultValue `true`
*/
matrixAutoUpdate: boolean;
/**
* When set, it updates the world transform matrix in that frame and resets this property to
* false.
* @defaultValue `false`
*/
worldMatrixNeedsUpdate: boolean;
/**
* The local position.
*/
position: Vec3;
/**
* The local rotation as a {@link Quat | Quaternion}.
*/
quaternion: Quat;
/**
* The local scale.
* @defaultValue `new Vec3(1)`
*/
scale: Vec3;
/**
* The local rotation as {@link Euler | Euler angles}.
*/
rotation: Euler;
/**
* Up vector used by the {@link lookAt | lookAt} method.
* @defaultValue `new Vec3(0, 1, 0)`
*/
up: Vec3;
/**
* Set from {@link GLTFLoader | GLTF Loader}.
*/
name?: string;
extras?: Record<string, any>;
extensions?: Record<string, any>;
/**
* Creates a new transform object.
*/
constructor();
/**
* Sets the parent.
* @param {Transform | null} parent The parent.
* @param {boolean} [notifyParent=true] Adds this as a child of the parent.
*/
setParent(parent: Transform | null, notifyParent?: boolean): void;
/**
* Adds a child.
* @param {Transform} child The child.
* @param {boolean} [notifyChild=true] Sets the parent of the child to this.
*/
addChild(child: Transform, notifyChild?: boolean): void;
/**
* Removes a child.
* @param {Transform} child The child.
* @param {boolean} [notifyChild=true] Sets the parent of the child to null.
*/
removeChild(child: Transform, notifyChild?: boolean): void;
/**
* Updates the world transform matrix.
*/
updateMatrixWorld(force?: boolean): void;
/**
* Updates the local transform matrix.
*/
updateMatrix(): void;
/**
* Executes the callback on this transform object and all descendants.
* @param {Function} callback The callback.
*/
traverse(callback: (node: Transform) => boolean | void): void;
/**
* Decomposes this transform object into it's position, quaternion and scale components.
*/
decompose(): void;
/**
* Rotates this transform object to face a target vector.
* @param {Vec3 | Vec3Tuple} target A target vector to look at.
* @param {boolean} [invert=false] Invert the local position and target vector.
*/
lookAt(target: Vec3 | Vec3Tuple, invert?: boolean): void;
}

36
node_modules/ogl/types/extras/Animation.d.ts generated vendored Normal file
View File

@@ -0,0 +1,36 @@
import { Vec3 } from '../math/Vec3.js';
import { Quat } from '../math/Quat.js';
import type { OGLRenderingContext } from '../core/Renderer.js';
import type { BoneTransform } from './Skin.js';
export interface AnimationFrame {
position: Vec3;
quaternion: Quat;
scale: Vec3;
}
export interface AnimationData {
frames: AnimationFrame[];
}
export interface AnimationOptions {
objects: BoneTransform[];
data: AnimationData;
}
/**
* A class for animation.
* @see {@link https://github.com/oframe/ogl/blob/master/src/extras/Animation.js | Source}
*/
export class Animation {
objects: BoneTransform[];
data: AnimationData;
elapsed: number;
weight: number;
duration: number;
constructor(gl: OGLRenderingContext, options?: Partial<AnimationOptions>);
update(totalWeight?: number, isSet?: boolean): void;
}

27
node_modules/ogl/types/extras/BasisManager.d.ts generated vendored Normal file
View File

@@ -0,0 +1,27 @@
import type { OGLRenderingContext } from '../core/Renderer.js';
export type BasisManagerFormat = 'astc' | 'bptc' | 's3tc' | 'etc1' | 'pvrtc' | 'none';
export type BasisImage = (Uint8Array | Uint16Array) & {
width: number;
height: number;
isCompressedTexture: boolean;
internalFormat: number;
isBasis: boolean;
};
/**
* A {@link https://github.com/BinomialLLC/basis_universal | Basis Universal GPU Texture} loader.
* @see {@link https://github.com/oframe/ogl/blob/master/src/extras/BasisManager.js | Source}
*/
export class BasisManager {
constructor(workerSrc: string | URL, gl?: OGLRenderingContext);
getSupportedFormat(gl?: OGLRenderingContext): BasisManagerFormat;
initWorker(workerSrc: string | URL): void;
onMessage(event: { data: { id: number; error: string; image: BasisImage } }): void;
parseTexture(buffer: ArrayBuffer): Promise<BasisImage>;
}

22
node_modules/ogl/types/extras/Box.d.ts generated vendored Normal file
View File

@@ -0,0 +1,22 @@
import { Geometry } from '../core/Geometry.js';
import type { OGLRenderingContext } from '../core/Renderer.js';
import type { AttributeMap } from '../core/Geometry.js';
export interface BoxOptions {
width: number;
height: number;
depth: number;
widthSegments: number;
heightSegments: number;
depthSegments: number;
attributes: AttributeMap;
}
/**
* A box geometry.
* @see {@link https://github.com/oframe/ogl/blob/master/src/extras/Box.js | Source}
*/
export class Box extends Geometry {
constructor(gl: OGLRenderingContext, options?: Partial<BoxOptions>);
}

27
node_modules/ogl/types/extras/Curve.d.ts generated vendored Normal file
View File

@@ -0,0 +1,27 @@
import { Vec3 } from '../math/Vec3.js';
export type CurveType = 'catmullrom' | 'cubicbezier' | 'quadraticbezier';
export interface CurveOptions {
points: Vec3[];
divisions: number;
type: CurveType;
}
/**
* A class for creating curves.
* @see {@link https://github.com/oframe/ogl/blob/master/src/extras/Curve.js | Source}
*/
export class Curve {
static CATMULLROM: 'catmullrom';
static CUBICBEZIER: 'cubicbezier';
static QUADRATICBEZIER: 'quadraticbezier';
points: Vec3[];
divisions: number;
type: CurveType;
constructor(options?: Partial<CurveOptions>);
getPoints(divisions?: number, a?: number, b?: number): Vec3[];
}

24
node_modules/ogl/types/extras/Cylinder.d.ts generated vendored Normal file
View File

@@ -0,0 +1,24 @@
import { Geometry } from '../core/Geometry.js';
import type { OGLRenderingContext } from '../core/Renderer.js';
import type { AttributeMap } from '../core/Geometry.js';
export interface CylinderOptions {
radiusTop: number;
radiusBottom: number;
height: number;
radialSegments: number;
heightSegments: number;
openEnded: boolean;
thetaStart: number;
thetaLength: number;
attributes: AttributeMap;
}
/**
* A cylinder geometry.
* @see {@link https://github.com/oframe/ogl/blob/master/src/extras/Cylinder.js | Source}
*/
export class Cylinder extends Geometry {
constructor(gl: OGLRenderingContext, options?: Partial<CylinderOptions>);
}

48
node_modules/ogl/types/extras/DracoManager.d.ts generated vendored Normal file
View File

@@ -0,0 +1,48 @@
import type { AttributeData } from '../core/Geometry.js';
export type AttributeIds = Record<string, number>;
export type AttributeTypes = Record<string,
| 'Float32Array'
| 'Uint32Array'
| 'Uint16Array'
| 'Int16Array'
| 'Uint8Array'
| 'Int8Array'
>;
export interface DecodeGeometryConfig {
attributeIds: AttributeIds;
attributeTypes: AttributeTypes;
}
export interface IndexResult {
array: Uint32Array;
itemSize: number;
}
export interface AttributeResult {
name: string;
array: AttributeData;
itemSize: number;
normalized?: boolean;
}
export interface GeometryData {
index: IndexResult;
attributes: AttributeResult[];
}
/**
* A {@link https://github.com/google/draco | Draco 3D Data Compression} loader.
* @see {@link https://github.com/oframe/ogl/blob/master/src/extras/DracoManager.js | Source}
*/
export class DracoManager {
constructor(workerSrc: string | URL);
initWorker(workerSrc: string | URL): void;
onMessage(event: { data: { id: number; error: string; geometry: GeometryData } }): void;
decodeGeometry(buffer: ArrayBuffer, config: DecodeGeometryConfig): Promise<GeometryData>;
}

39
node_modules/ogl/types/extras/Flowmap.d.ts generated vendored Normal file
View File

@@ -0,0 +1,39 @@
import { RenderTarget } from '../core/RenderTarget.js';
import { Mesh } from '../core/Mesh.js';
import { Vec2 } from '../math/Vec2.js';
import type { OGLRenderingContext } from '../core/Renderer.js';
export interface FlowmapOptions {
size: number;
falloff: number;
alpha: number;
dissipation: number;
type: number;
}
/**
* Mouse flowmap.
* @see {@link https://github.com/oframe/ogl/blob/master/src/extras/Flowmap.js | Source}
*/
export class Flowmap {
gl: OGLRenderingContext;
uniform: { value: RenderTarget['texture'] | null };
mask: {
read: RenderTarget;
write: RenderTarget;
swap: () => void;
};
aspect: number;
mouse: Vec2;
velocity: Vec2;
mesh: Mesh;
constructor(gl: OGLRenderingContext, options?: Partial<FlowmapOptions>);
update(): void;
}

27
node_modules/ogl/types/extras/GLTFAnimation.d.ts generated vendored Normal file
View File

@@ -0,0 +1,27 @@
export interface GLTFAnimationData {
node: any;
transform: any;
interpolation: any;
times: any;
values: any;
}
/**
* A class for animation.
* @see {@link https://github.com/oframe/ogl/blob/master/src/extras/GLTFAnimation.js | Source}
*/
export class GLTFAnimation {
data: GLTFAnimationData[];
elapsed: number;
weight: number;
loop: boolean;
startTime: number;
endTime: number;
duration: number;
constructor(data: GLTFAnimationData[], weight?: number);
update(totalWeight?: number, isSet?: boolean): void;
cubicSplineInterpolate(t: number, prevVal: any, prevTan: any, nextTan: any, nextVal: any): any;
}

175
node_modules/ogl/types/extras/GLTFLoader.d.ts generated vendored Normal file
View File

@@ -0,0 +1,175 @@
import { Geometry } from '../core/Geometry.js';
import { Transform } from '../core/Transform.js';
import { Texture } from '../core/Texture.js';
import { Mesh } from '../core/Mesh.js';
import { GLTFAnimation } from './GLTFAnimation.js';
import { Mat4 } from '../math/Mat4.js';
import { Vec3 } from '../math/Vec3.js';
import { NormalProgram } from './NormalProgram.js';
import { InstancedMesh } from './InstancedMesh.js';
import type { OGLRenderingContext } from '../core/Renderer.js';
import type { Camera } from '../core/Camera.js';
import type { Color } from '../math/Color.js';
import type { DracoManager } from './DracoManager.js';
import type { BasisManager } from './BasisManager.js';
import type { GLTFSkinSkeleton } from './GLTFSkin.js';
export interface GLTFAnimationReference {
name: string;
animation: GLTFAnimation;
}
export interface GLTFLightOptions {
name: string;
color: { value: Color };
direction: { value: Vec3 };
position: { value: Vec3 };
distance: { value: number };
decay: { value: number };
}
export interface GLTFLights {
directional: Partial<GLTFLightOptions>[];
point: Partial<GLTFLightOptions>[];
spot: Partial<GLTFLightOptions>[];
}
export interface GLTFAccessor {
data: ArrayLike<number>;
size: number;
type: number | string;
normalized: boolean;
buffer: WebGLBuffer;
stride: number;
offset: number;
count: number;
min: number;
max: number;
}
export interface GLTFSkinReference {
inverseBindMatrices: GLTFAccessor;
skeleton: GLTFSkinSkeleton;
joints: { worldMatrix: Mat4; bindInverse: Mat4 }[];
}
export interface GLTFMaterial {
name: string;
extensions: Record<string, any>;
extras: Record<string, any>;
baseColorFactor: [number, number, number, number];
baseColorTexture: { texture: Texture; scale: number };
metallicFactor: number;
roughnessFactor: number;
metallicRoughnessTexture: { texture: Texture; scale: number };
normalTexture: { texture: Texture; scale: number };
occlusionTexture: { texture: Texture; scale: number };
emissiveTexture: { texture: Texture; scale: number };
emissiveFactor: [number, number, number];
alphaMode: string;
alphaCutoff: number;
doubleSided: boolean;
}
export interface GLTFProgram extends NormalProgram {
gltfMaterial: GLTFMaterial;
}
export interface GLTFPrimitive {
geometry: Geometry;
program: GLTFProgram;
mode: number;
}
export interface GLTFMesh {
primitives: (InstancedMesh | Mesh)[];
weights: number[];
name: string;
}
export interface GLTFDescription {} // TODO: remove?
export interface GLTF {
json: GLTFDescription;
buffers: ArrayBuffer[];
bufferViews: ArrayBufferView[];
images: (HTMLImageElement | ImageBitmap)[];
textures: Texture[];
materials: GLTFMaterial[];
meshes: GLTFMesh[];
nodes: (InstancedMesh | Mesh)[];
lights: GLTFLights;
animations: GLTFAnimationReference[];
scenes: Transform[][];
scene: Transform[];
}
/**
* The {@link https://www.khronos.org/gltf/ | glTF (Graphics Language Transmission Format)} loader.
* @see {@link https://github.com/oframe/ogl/blob/master/src/extras/GLTFLoader.js | Source}
*/
export class GLTFLoader {
static setDracoManager(manager: DracoManager): void;
static setBasisManager(manager: BasisManager): void;
static load(gl: OGLRenderingContext, src: string): Promise<GLTF>;
static parse(gl: OGLRenderingContext, desc: GLTFDescription, dir: string): Promise<GLTF>;
static parseDesc(src: string): Promise<GLTFDescription>;
static unpackGLB(glb: ArrayBuffer): GLTFDescription;
static resolveURI(uri: string, dir: string): string;
static loadBuffers(desc: GLTFDescription, dir: string): Promise<ArrayBuffer[]> | null;
static parseBufferViews(gl: OGLRenderingContext, desc: GLTFDescription, buffers: ArrayBuffer[]): ArrayBufferView[] | null;
static parseImages(gl: OGLRenderingContext, desc: GLTFDescription, dir: string, bufferViews: ArrayBufferView[]): Promise<(HTMLImageElement | ImageBitmap)[]> | null;
static parseTextures(gl: OGLRenderingContext, desc: GLTFDescription, images: (HTMLImageElement | ImageBitmap)[]): Texture[] | null;
static createTexture(
gl: OGLRenderingContext,
desc: GLTFDescription,
images: (HTMLImageElement | ImageBitmap)[],
options: { sample: number; source: number; name: string; extensions: Record<string, any>; extras: Record<string, any> },
): Texture;
static parseMaterials(gl: OGLRenderingContext, desc: GLTFDescription, textures: Texture[]): GLTFMaterial[] | null;
static parseSkins(gl: OGLRenderingContext, desc: GLTFDescription, bufferViews: ArrayBufferView[]): GLTFSkinReference[] | null;
static parseMeshes(gl: OGLRenderingContext, desc: GLTFDescription, bufferViews: ArrayBufferView[], materials: GLTFMaterial[], skins: GLTFSkinReference[]): GLTFMesh[] | null;
static parsePrimitives(
gl: OGLRenderingContext,
primitives: object[],
desc: GLTFDescription,
bufferViews: ArrayBufferView[],
materials: GLTFMaterial[],
numInstances: number,
isLightmap: boolean,
): GLTFPrimitive[];
static parseAccessor(index: number, desc: GLTFDescription, bufferViews: ArrayBufferView[]): GLTFAccessor;
static parseNodes(
gl: OGLRenderingContext,
desc: GLTFDescription,
meshes: GLTFMesh[],
skins: GLTFSkinReference[],
images: (HTMLImageElement | ImageBitmap)[],
): [(InstancedMesh | Mesh)[], (Camera | Transform)[]] | null;
static populateSkins(skins: GLTFSkinReference[], nodes: (InstancedMesh | Mesh)[]): void;
static parseAnimations(gl: OGLRenderingContext, desc: GLTFDescription, nodes: (InstancedMesh | Mesh)[], bufferViews: ArrayBufferView[]): GLTFAnimationReference[] | null;
static parseScenes(desc: GLTFDescription, nodes: (InstancedMesh | Mesh)[]): Transform[] | null;
static parseLights(gl: OGLRenderingContext, desc: GLTFDescription, nodes: (InstancedMesh | Mesh)[], scenes: Transform[]): GLTFLights;
}

40
node_modules/ogl/types/extras/GLTFSkin.d.ts generated vendored Normal file
View File

@@ -0,0 +1,40 @@
import { Mesh } from '../core/Mesh.js';
import { Mat4 } from '../math/Mat4.js';
import { Texture } from '../core/Texture.js';
import type { OGLRenderingContext } from '../core/Renderer.js';
import type { Geometry } from '../core/Geometry.js';
import type { Program } from '../core/Program.js';
import type { Camera } from '../core/Camera.js';
export interface GLTFSkinSkeleton {
joints: { worldMatrix: Mat4; bindInverse: Mat4 }[];
}
export interface GLTFSkinOptions {
skeleton: GLTFSkinSkeleton;
geometry: Geometry;
program: Program;
mode: GLenum;
}
/**
* A mesh with a skeleton and bones for animation.
* @see {@link https://github.com/oframe/ogl/blob/master/src/extras/GLTFSkin.js | Source}
*/
export class GLTFSkin<TProgram extends Program = Program> extends Mesh {
skeleton: GLTFSkinSkeleton;
program: TProgram;
boneMatrices: Float32Array;
boneTextureSize: number;
boneTexture: Texture;
constructor(gl: OGLRenderingContext, options?: Partial<GLTFSkinOptions>);
createBoneTexture(): void;
updateUniforms(): void;
override draw(options?: { camera?: Camera }): void;
}

49
node_modules/ogl/types/extras/GPGPU.d.ts generated vendored Normal file
View File

@@ -0,0 +1,49 @@
import { Program } from '../core/Program.js';
import { Mesh } from '../core/Mesh.js';
import { Texture } from '../core/Texture.js';
import { RenderTarget } from '../core/RenderTarget.js';
import { Triangle } from './Triangle.js';
import type { OGLRenderingContext } from '../core/Renderer.js';
export interface GPGPUOptions {
data: Float32Array;
geometry: Triangle;
type: Texture['type'];
}
export interface GPGPUPass {
mesh: Mesh;
program: Program;
uniforms: Record<string, any>;
enabled: boolean;
textureUniform: string;
vertex: string;
fragment: string;
}
/**
* A class for {@link https://en.wikipedia.org/wiki/General-purpose_computing_on_graphics_processing_units | GPGPU (General Purpose GPU)} calculations.
* @see {@link https://github.com/oframe/ogl/blob/master/src/extras/GPGPU.js | Source}
*/
export class GPGPU {
gl: OGLRenderingContext;
passes: GPGPUPass[];
geometry: Triangle;
dataLength: number;
size: number;
coords: Float32Array;
uniform: { value: any };
fbo: {
read: RenderTarget;
write: RenderTarget;
swap: () => void;
};
constructor(gl: OGLRenderingContext, options?: Partial<GPGPUOptions>);
addPass(options?: Partial<GPGPUPass>): GPGPUPass;
render(): void;
}

13
node_modules/ogl/types/extras/InstancedMesh.d.ts generated vendored Normal file
View File

@@ -0,0 +1,13 @@
import { Mesh } from '../core/Mesh.js';
/**
* A special version of {@link Mesh | Mesh} with instanced frustum culling.
* @see {@link https://github.com/oframe/ogl/blob/master/src/extras/InstancedMesh.js | Source}
*/
export class InstancedMesh extends Mesh {
readonly isInstancedMesh: true;
addFrustumCull(): void;
removeFrustumCull(): void;
}

23
node_modules/ogl/types/extras/KTXTexture.d.ts generated vendored Normal file
View File

@@ -0,0 +1,23 @@
import { Texture } from '../core/Texture.js';
import type { OGLRenderingContext } from '../core/Renderer.js';
export interface KTXTextureOptions {
buffer: ArrayBuffer;
src: string;
wrapS: number;
wrapT: number;
anisotropy: number;
minFilter: number;
magFilter: number;
}
/**
* A {@link https://github.com/KhronosGroup/KTX-Specification | KTX 2.0 GPU Texture} container.
* @see {@link https://github.com/oframe/ogl/blob/master/src/extras/KTXTexture.js | Source}
*/
export class KTXTexture extends Texture {
constructor(gl: OGLRenderingContext, options?: Partial<KTXTextureOptions>);
parseBuffer(buffer: ArrayBuffer): void;
}

12
node_modules/ogl/types/extras/NormalProgram.d.ts generated vendored Normal file
View File

@@ -0,0 +1,12 @@
import { Program } from '../core/Program.js';
import type { OGLRenderingContext } from '../core/Renderer.js';
import type { ProgramOptions } from '../core/Program.js';
/**
* A normal program.
* @see {@link https://github.com/oframe/ogl/blob/master/src/extras/NormalProgram.js | Source}
*/
export class NormalProgram extends Program {
constructor(gl: OGLRenderingContext, options?: Partial<ProgramOptions>);
}

53
node_modules/ogl/types/extras/Orbit.d.ts generated vendored Normal file
View File

@@ -0,0 +1,53 @@
import { Vec3 } from '../math/Vec3.js';
import type { Camera } from '../core/Camera.js';
export type ZoomStyle = 'dolly' | 'fov';
export interface OrbitOptions {
element: HTMLElement;
enabled: boolean;
target: Vec3;
ease: number;
inertia: number;
enableRotate: boolean;
rotateSpeed: number;
autoRotate: boolean;
autoRotateSpeed: number;
enableZoom: boolean;
zoomSpeed: number;
zoomStyle: ZoomStyle;
enablePan: boolean;
panSpeed: number;
minPolarAngle: number;
maxPolarAngle: number;
minAzimuthAngle: number;
maxAzimuthAngle: number;
minDistance: number;
maxDistance: number;
}
/**
* Orbit controls based on the three.js `OrbitControls` class, rewritten using ES6 with some
* additions and subtractions.
* @see {@link https://github.com/oframe/ogl/blob/master/src/extras/Orbit.js | Source}
* @see {@link https://github.com/mrdoob/three.js/blob/master/examples/jsm/controls/OrbitControls.js | `OrbitControls` Source}
*/
export class Orbit {
enabled: boolean;
target: Vec3;
zoomStyle: ZoomStyle;
minDistance: number;
maxDistance: number;
offset: Vec3;
constructor(object: Camera, options?: Partial<OrbitOptions>);
update(): void;
forcePosition(): void;
remove(): void;
}

39
node_modules/ogl/types/extras/Plane.d.ts generated vendored Normal file
View File

@@ -0,0 +1,39 @@
import { Geometry } from '../core/Geometry.js';
import type { OGLRenderingContext } from '../core/Renderer.js';
import type { AttributeMap } from '../core/Geometry.js';
export interface PlaneOptions {
width: number;
height: number;
widthSegments: number;
heightSegments: number;
attributes: AttributeMap;
}
/**
* A plane geometry.
* @see {@link https://github.com/oframe/ogl/blob/master/src/extras/Plane.js | Source}
*/
export class Plane extends Geometry {
constructor(gl: OGLRenderingContext, options?: Partial<PlaneOptions>);
static buildPlane(
position: Float32Array,
normal: Float32Array,
uv: Float32Array,
index: Uint32Array | Uint16Array,
width: number,
height: number,
depth: number,
wSegs: number,
hSegs: number,
u: number,
v: number,
w: number,
uDir: number,
vDir: number,
i: number,
ii: number,
): void;
}

49
node_modules/ogl/types/extras/Polyline.d.ts generated vendored Normal file
View File

@@ -0,0 +1,49 @@
import { Geometry } from '../core/Geometry.js';
import { Program } from '../core/Program.js';
import { Mesh } from '../core/Mesh.js';
import { Vec2 } from '../math/Vec2.js';
import { Vec3 } from '../math/Vec3.js';
import { Color } from '../math/Color.js';
import type { OGLRenderingContext } from '../core/Renderer.js';
import type { AttributeMap } from '../core/Geometry.js';
export interface PolylineOptions {
points: Vec3[];
vertex: string;
fragment: string;
uniforms: Record<string, any>;
attributes: AttributeMap;
}
/**
* A polyline mesh.
* @see {@link https://github.com/oframe/ogl/blob/master/src/extras/Polyline.js | Source}
*/
export class Polyline {
gl: OGLRenderingContext;
points: Vec3[];
count: number;
position: Float32Array;
prev: Float32Array;
next: Float32Array;
geometry: Geometry;
resolution: { value: Vec2 };
dpr: { value: number };
thickness: { value: number };
color: { value: Color };
miter: { value: number };
program: Program;
mesh: Mesh;
constructor(gl: OGLRenderingContext, options?: Partial<PolylineOptions>);
updateGeometry(): void;
resize(): void;
}

85
node_modules/ogl/types/extras/Post.d.ts generated vendored Normal file
View File

@@ -0,0 +1,85 @@
import { Program } from '../core/Program.js';
import { Mesh } from '../core/Mesh.js';
import { RenderTarget } from '../core/RenderTarget.js';
import { Triangle } from './Triangle.js';
import type { OGLRenderingContext } from '../core/Renderer.js';
import type { Camera } from '../core/Camera.js';
import type { Transform } from '../core/Transform.js';
import type { Texture } from '../core/Texture.js';
export interface PostOptions {
width: number;
height: number;
dpr: number;
wrapS: GLenum;
wrapT: GLenum;
minFilter: GLenum;
magFilter: GLenum;
geometry: Triangle;
targetOnly: boolean;
depth: boolean;
}
export interface Pass {
mesh: Mesh;
program: Program;
uniforms: Record<string, any>;
enabled: boolean;
textureUniform: string;
vertex: string;
fragment: string;
}
/**
* A class for managing post-processing shader passes.
* @see {@link https://github.com/oframe/ogl/blob/master/src/extras/Post.js | Source}
*/
export class Post {
gl: OGLRenderingContext;
passes: Pass[];
geometry: Triangle;
uniform: { value: any };
targetOnly: boolean;
dpr: number;
width: number;
height: number;
resolutionWidth: number;
resolutionHeight: number;
fbo: {
read: RenderTarget;
write: RenderTarget;
swap: () => void;
};
constructor(gl: OGLRenderingContext, options?: Partial<PostOptions>);
addPass(options?: Partial<Pass>): Pass;
resize(
options?: Partial<{
width: number;
height: number;
dpr: number;
}>,
): void;
render(
options: Partial<{
scene: Transform;
camera: Camera;
texture: Texture;
target: RenderTarget;
update: boolean;
sort: boolean;
frustumCull: boolean;
beforePostCallbacks: Function[];
}>,
): void;
}

43
node_modules/ogl/types/extras/Raycast.d.ts generated vendored Normal file
View File

@@ -0,0 +1,43 @@
import { Vec2 } from '../math/Vec2.js';
import { Vec3 } from '../math/Vec3.js';
import type { Vec2Tuple } from '../math/Vec2.js';
import type { Bounds } from '../core/Geometry.js';
import type { Camera } from '../core/Camera.js';
import type { Mesh } from '../core/Mesh.js';
/**
* A class to assist with {@link https://en.wikipedia.org/wiki/Ray_casting | raycasting}.
* @see {@link https://github.com/oframe/ogl/blob/master/src/extras/Raycast.js | Source}
*/
export class Raycast {
origin: Vec3;
direction: Vec3;
constructor();
castMouse(camera: Camera, mouse?: Vec2 | Vec2Tuple): void;
intersectBounds(meshes: Mesh | Mesh[], options?: { maxDistance?: number; output?: Mesh[] }): Mesh[];
intersectMeshes(
meshes: Mesh[],
options?: {
cullFace?: boolean;
maxDistance?: number;
includeUV?: boolean;
includeNormal?: boolean;
output?: Mesh[];
},
): Mesh[];
intersectPlane(plane: { origin: Vec3; normal: Vec3 }, origin?: Vec3, direction?: Vec3): Vec3;
intersectSphere(sphere: Bounds, origin?: Vec3, direction?: Vec3): number;
intersectBox(box: Bounds, origin?: Vec3, direction?: Vec3): number;
intersectTriangle(a: Vec3, b: Vec3, c: Vec3, backfaceCulling?: boolean, origin?: Vec3, direction?: Vec3, normal?: Vec3): number;
getBarycoord(point: Vec3, a: Vec3, b: Vec3, c: Vec3, target?: Vec3): Vec3;
}

47
node_modules/ogl/types/extras/Shadow.d.ts generated vendored Normal file
View File

@@ -0,0 +1,47 @@
import { Camera } from '../core/Camera.js';
import { Program } from '../core/Program.js';
import { RenderTarget } from '../core/RenderTarget.js';
import type { OGLRenderingContext } from '../core/Renderer.js';
import type { Transform } from '../core/Transform.js';
import type { Mesh } from '../core/Mesh.js';
export interface ShadowOptions {
light: Camera;
width: number;
height: number;
}
/**
* Shadow map.
* @see {@link https://github.com/oframe/ogl/blob/master/src/extras/Shadow.js | Source}
*/
export class Shadow {
gl: OGLRenderingContext;
light: Camera;
target: RenderTarget;
targetUniform: { value: RenderTarget['texture'] | null };
depthProgram: Program;
castMeshes: Mesh[];
constructor(gl: OGLRenderingContext, options?: Partial<ShadowOptions>);
add(options: {
mesh: Mesh;
receive?: boolean;
cast?: boolean;
vertex?: string;
fragment?: string;
uniformProjection?: string;
uniformView?: string;
uniformTexture?: string;
}): void;
setSize(options: { width?: number; height?: number }): void;
render(options: { scene: Transform }): void;
}

56
node_modules/ogl/types/extras/Skin.d.ts generated vendored Normal file
View File

@@ -0,0 +1,56 @@
import { Mesh } from '../core/Mesh.js';
import { Transform } from '../core/Transform.js';
import { Mat4 } from '../math/Mat4.js';
import { Texture } from '../core/Texture.js';
import { Animation } from './Animation.js';
import type { OGLRenderingContext } from '../core/Renderer.js';
import type { Quat } from '../math/Quat.js';
import type { Vec3 } from '../math/Vec3.js';
import type { Geometry } from '../core/Geometry.js';
import type { Program } from '../core/Program.js';
import type { Camera } from '../core/Camera.js';
export interface SkinRig {
bindPose: { position: Vec3; quaternion: Quat; scale: Vec3 };
bones: { name: string; parent: Transform }[];
}
export interface SkinOptions {
rig: SkinRig;
geometry: Geometry;
program: Program;
mode: GLenum;
}
export interface BoneTransform extends Transform {
name: string;
bindInverse: Mat4;
}
/**
* A mesh with a skeleton and bones for animation.
* @see {@link https://github.com/oframe/ogl/blob/master/src/extras/Skin.js | Source}
*/
export class Skin extends Mesh {
root: Transform;
bones: Transform[];
boneMatrices: Float32Array;
boneTextureSize: number;
boneTexture: Texture;
animations: Animation[];
constructor(gl: OGLRenderingContext, options?: Partial<SkinOptions>);
createBones(rig: SkinRig): void;
createBoneTexture(): void;
addAnimation(data: Animation['data']): Animation;
update(): void;
override draw(options?: { camera?: Camera }): void;
}

23
node_modules/ogl/types/extras/Sphere.d.ts generated vendored Normal file
View File

@@ -0,0 +1,23 @@
import { Geometry } from '../core/Geometry.js';
import type { OGLRenderingContext } from '../core/Renderer.js';
import type { AttributeMap } from '../core/Geometry.js';
export interface SphereOptions {
radius: number;
widthSegments: number;
heightSegments: number;
phiStart: number;
phiLength: number;
thetaStart: number;
thetaLength: number;
attributes: AttributeMap;
}
/**
* A sphere geometry.
* @see {@link https://github.com/oframe/ogl/blob/master/src/extras/Sphere.js | Source}
*/
export class Sphere extends Geometry {
constructor(gl: OGLRenderingContext, options?: Partial<SphereOptions>);
}

35
node_modules/ogl/types/extras/Text.d.ts generated vendored Normal file
View File

@@ -0,0 +1,35 @@
export type TextAlign = 'left' | 'right' | 'center';
export interface TextOptions {
font: object;
text: string;
width: number;
align: TextAlign;
size: number;
letterSpacing: number;
lineHeight: number;
wordSpacing: number;
wordBreak: boolean;
}
/**
* A text geometry.
* @see {@link https://github.com/oframe/ogl/blob/master/src/extras/Text.js | Source}
*/
export class Text {
buffers: {
position: Float32Array;
uv: Float32Array;
id: Float32Array;
index: Uint32Array | Uint16Array;
};
numLines: number;
height: number;
width: number;
constructor(options?: Partial<TextOptions>);
resize(options: { width: number }): void;
update(options: { text: string }): void;
}

17
node_modules/ogl/types/extras/Texture3D.d.ts generated vendored Normal file
View File

@@ -0,0 +1,17 @@
import { Texture } from '../core/Texture.js';
import type { OGLRenderingContext } from '../core/Renderer.js';
import type { TextureOptions } from '../core/Texture.js';
export interface Texture3DOptions extends TextureOptions {
src: string;
tileCountX: number;
}
/**
* A class for rearranging a flat 3D texture from software like Houdini.
* @see {@link https://github.com/oframe/ogl/blob/master/src/extras/Texture3D.js | Source}
*/
export class Texture3D extends Texture {
constructor(gl: OGLRenderingContext, options?: Partial<Texture3DOptions>);
}

19
node_modules/ogl/types/extras/TextureLoader.d.ts generated vendored Normal file
View File

@@ -0,0 +1,19 @@
import { Texture } from '../core/Texture.js';
import type { OGLRenderingContext } from '../core/Renderer.js';
/**
* The texture loader.
* @see {@link https://github.com/oframe/ogl/blob/master/src/extras/TextureLoader.js | Source}
*/
export class TextureLoader {
static load(gl: OGLRenderingContext, options?: object): Texture;
static getSupportedExtensions(gl: OGLRenderingContext): string[];
static loadKTX(src: string, texture: Texture): Promise<void>;
static loadImage(gl: OGLRenderingContext, src: string, texture: Texture, flipY: boolean): Promise<HTMLImageElement | ImageBitmap>;
static clearCache(): void;
}

21
node_modules/ogl/types/extras/Torus.d.ts generated vendored Normal file
View File

@@ -0,0 +1,21 @@
import { Geometry } from '../core/Geometry.js';
import type { OGLRenderingContext } from '../core/Renderer.js';
import type { AttributeMap } from '../core/Geometry.js';
export interface TorusOptions {
radius: number;
tube: number;
radialSegments: number;
tubularSegments: number;
arc: number;
attributes: AttributeMap;
}
/**
* A torus geometry.
* @see {@link https://github.com/oframe/ogl/blob/master/src/extras/Torus.js | Source}
*/
export class Torus extends Geometry {
constructor(gl: OGLRenderingContext, options?: Partial<TorusOptions>);
}

Some files were not shown because too many files have changed in this diff Show More