Last active
January 4, 2024 10:48
-
-
Save McNull/0a043285f5c88c533b8b43b1dbcc8915 to your computer and use it in GitHub Desktop.
three.js utils
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export class ArrayPool<T> { | |
private _array: T[]; | |
private _length: number; | |
private _capacity: number; | |
private _factory: () => T; | |
constructor(initialCapacity: number = 10, factory: () => T) { | |
this._array = new Array<T>(initialCapacity); | |
this._length = 0; | |
this._capacity = initialCapacity; | |
this._factory = factory; | |
this.fill(0, initialCapacity); | |
} | |
private fill(from: number, to: number, array: T[] = this._array) { | |
for (let i = from; i < to; i++) { | |
array[i] = this._factory(); | |
} | |
} | |
set length(value: number) { | |
if (value > this._capacity) { | |
const newCapacity = Math.max(this._capacity * 2, value); | |
console.log(`Resizing array from ${this._capacity} to ${newCapacity}`); | |
const newArray = new Array<T>(newCapacity); | |
for (let i = 0; i < this._capacity; i++) { | |
newArray[i] = this._array[i]; | |
} | |
this.fill(this._capacity, newCapacity, newArray); | |
this._array = newArray; | |
this._capacity = newCapacity; | |
} | |
this._length = value; | |
} | |
get length(): number { | |
return this._length; | |
} | |
get capacity(): number { | |
return this._capacity; | |
} | |
get(index: number): T { | |
if (index < 0 || index >= this._length) { | |
throw new Error(`Index out of bounds: ${index}`); | |
} | |
return this._array[index]; | |
} | |
claim(): T { | |
this.length++; | |
return this._array[this._length - 1]; | |
} | |
forEach(callback: (value: T, index: number) => boolean | void) { | |
for (let i = 0; i < this._length; i++) { | |
if(callback(this._array[i], i) === false) { | |
break; | |
} | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as THREE from "three"; | |
import { OrbitControls as _OrbitControls } from "three/examples/jsm/Addons.js"; | |
const STORAGE_KEY = 'orbit-controls-state'; | |
export class OrbitControls extends _OrbitControls { | |
constructor(object: THREE.Camera, domElement?: HTMLElement) { | |
super(object, domElement); | |
} | |
init() { | |
this.mouseButtons = { | |
LEFT: THREE.MOUSE.ROTATE, | |
MIDDLE: THREE.MOUSE.PAN, | |
RIGHT: THREE.MOUSE.DOLLY | |
}; | |
this.zoomSpeed = -2.0; | |
this.loadState(); | |
window.addEventListener("beforeunload", () => { | |
this.persistState(); | |
}); | |
} | |
loadState() { | |
if(localStorage.getItem(STORAGE_KEY)) { | |
const cs = JSON.parse(localStorage.getItem(STORAGE_KEY)); | |
this.target0.set(cs.target0.x, cs.target0.y, cs.target0.z); | |
this.position0.set(cs.position0.x, cs.position0.y, cs.position0.z); | |
this.zoom0 = cs.zoom0; | |
this.reset(); | |
}; | |
} | |
persistState() { | |
this.saveState(); | |
const { target0, position0, zoom0 } = this; | |
const cs = { target0, position0, zoom0 }; | |
localStorage.setItem(STORAGE_KEY, JSON.stringify(cs)); | |
} | |
clearState() { | |
localStorage.removeItem(STORAGE_KEY); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export class Random { | |
static X = 2**31-1; | |
static Y = 16807; | |
static Z = 1/(Random.X-1); | |
constructor(seed: number = 1234567890) { | |
this.seed = seed; | |
} | |
next(min = 0.0, max = 1.0) : number { | |
this._seed = this._seed * Random.Y % Random.X; | |
const r = (this._seed - 1) * Random.Z; | |
return min + r * (max - min); | |
} | |
nextInt(min = 0, max = 1) : number { | |
return Math.floor(this.next(min, max)); | |
} | |
private _seed: number; | |
set seed(value: number) { | |
this._seed = value % Random.X; | |
if (this._seed <= 0) { | |
this._seed += Random.X - 1; | |
} | |
} | |
get seed() : number { | |
return this._seed; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export class Timer { | |
startTime: number = 0; | |
deltaTime: number = 0; | |
elapsedTime: number = 0; | |
fps: number = 0; | |
frames: number = 0; | |
private _lastTime: number = 0; | |
private _lastFpsTime: number = 0; | |
private _fpsFrameCount: number = 0; | |
private _pauseTime: number = 0; | |
private _pauseStartTime: number = 0; | |
private _paused: boolean = false; | |
get paused() : boolean { | |
return this._paused; | |
} | |
set paused(value: boolean) { | |
if(value !== this._paused) { | |
this._paused = value; | |
if(this._paused) { | |
// pause the timer | |
this._pauseStartTime = performance.now() * 0.001; | |
this.deltaTime = 0; | |
} else { | |
// resume the timer | |
const now = performance.now() * 0.001; | |
this._pauseTime += now - this._pauseStartTime; | |
} | |
} | |
} | |
start() { | |
this.reset(); | |
const now = performance.now() * 0.001; | |
this.startTime = now; | |
this._lastTime = now; | |
this._lastFpsTime = now; | |
} | |
update() { | |
if(this._paused) { | |
return; | |
} | |
const now = performance.now() * 0.001 - this._pauseTime; | |
this.deltaTime = now - this._lastTime; | |
this.elapsedTime = now - this.startTime; | |
this._lastTime = now; | |
this.frames++; | |
this._fpsFrameCount++; | |
if (now - this._lastFpsTime >= 1.0) { | |
this.fps = this._fpsFrameCount / (now - this._lastFpsTime); | |
this._lastFpsTime = now; | |
this._fpsFrameCount = 0; | |
} | |
} | |
reset() { | |
this.startTime = 0; | |
this.deltaTime = 0; | |
this.elapsedTime = 0; | |
this.fps = 0; | |
this.frames = 0; | |
this._lastTime = 0; | |
this._lastFpsTime = 0; | |
this._fpsFrameCount = 0; | |
this._pauseTime = 0; | |
this._pauseStartTime = 0; | |
this._paused = false; | |
} | |
} | |
export function pauseOnInactiveTab(timer: Timer) { | |
document.addEventListener("visibilitychange", () => { | |
timer.paused = document.hidden; | |
}); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export class Vec2 { | |
constructor(public x: number = 0, public y: number = 0) {} | |
clone(out: Vec2 = new Vec2()): Vec2 { | |
out.x = this.x; | |
out.y = this.y; | |
return out; | |
} | |
set(x: number, y: number): Vec2 { | |
this.x = x; | |
this.y = y; | |
return this; | |
} | |
add(v: Vec2, out: Vec2 = this): Vec2 { | |
out.x = this.x + v.x; | |
out.y = this.y + v.y; | |
return out; | |
} | |
subtract(v: Vec2, out: Vec2 = this): Vec2 { | |
out.x = this.x - v.x; | |
out.y = this.y - v.y; | |
return out; | |
} | |
scale(s: number, out: Vec2 = this): Vec2 { | |
out.x = this.x * s; | |
out.y = this.y * s; | |
return out; | |
} | |
dot(v: Vec2): number { | |
return this.x * v.x + this.y * v.y; | |
} | |
sqrLength(): number { | |
return this.dot(this); | |
} | |
length(): number { | |
return Math.sqrt(this.sqrLength()); | |
} | |
normalize(out: Vec2 = this): Vec2 { | |
const len = this.length(); | |
if (len > 0) { | |
out.scale(1 / len); | |
} | |
return out; | |
} | |
sqrDistance(v: Vec2): number { | |
const dx = this.x - v.x; | |
const dy = this.y - v.y; | |
return dx * dx + dy * dy; | |
} | |
distance(v: Vec2): number { | |
return Math.sqrt(this.sqrDistance(v)); | |
} | |
negate(out: Vec2 = this): Vec2 { | |
out.x = -this.x; | |
out.y = -this.y; | |
return out; | |
} | |
lerp(v: Vec2, t: number, out: Vec2 = this): Vec2 { | |
const ax = this.x; | |
const ay = this.y; | |
out.x = ax + t * (v.x - ax); | |
out.y = ay + t * (v.y - ay); | |
return out; | |
} | |
toString(): string { | |
return `(${this.x}, ${this.y})`; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment