UNPKG

the-world-engine

Version:

three.js based, unity like game engine for browser

624 lines (620 loc) 17.9 kB
import { Matrix4, Object3D, Quaternion, Vector3 } from "three/src/Three"; import { ObservableEuler } from "../math/ObservableEuler"; import { ObservableQuaternion } from "../math/ObservableQuaternion"; import { ObservableVector3 } from "../math/ObservableVector3"; export class Transform { static _transformObject3D=class extends Object3D { updateMatrix() { this.userData.ts(); } updateMatrixWorld(t) { this.userData.ss(); } updateWorldMatrix(t, s) { this.userData.ss(); if (s) { const t = this.children; for (let s = 0, i = t.length; s < i; ++s) { t[s].updateWorldMatrix(false, true); } } } }; es; bt; L; rs; hs; os; ns; ls; fs=false; cs=false; us=false; _s=false; ds=false; ps=this.vs.bind(this); bs=this.gs.bind(this); Rs=this.Ts.bind(this); Os=this.ws.bind(this); xs=this.Cs.bind(this); Ws=this.Ms.bind(this); Bs=this.Ps.bind(this); Ls=this.ys.bind(this); constructor(t, s, i) { this.L = s; this.rs = i; this.es = new Transform._transformObject3D; this.es.matrixAutoUpdate = true; this.es.userData = this; s.scene.unsafeGetThreeScene().add(this.es); Object.defineProperties(this.es, { position: { writable: true }, rotation: { writable: true }, quaternion: { writable: true }, scale: { writable: true } }); const e = this.ps; const r = this.bs; const h = new ObservableVector3; h.onBeforeGetComponent(e); h.onBeforeChange(r); this.es.position = h; const o = new ObservableEuler; o.onBeforeGetComponent(e); o.onBeforeChange(r); o._onChange(this.Rs); this.es.rotation = o; const n = new ObservableQuaternion; n.onBeforeGetComponent(e); n.onBeforeChange(r); n._onChange(this.Os); this.es.quaternion = n; const a = new ObservableVector3(1, 1, 1); a.onBeforeGetComponent(e); a.onBeforeChange(r); this.es.scale = a; this.bt = t; const l = this.xs; const f = this.Ws; const c = new ObservableVector3; c.onBeforeGetComponent(l); c.onBeforeChange(f); this.hs = c; const u = new ObservableEuler; u.onBeforeGetComponent(l); u.onBeforeChange(f); u._onChange(this.Bs); this.os = u; const _ = new ObservableQuaternion; _.onBeforeGetComponent(l); _.onBeforeChange(f); _._onChange(this.Ls); this.ns = _; const d = new ObservableVector3(1, 1, 1); d.onBeforeGetComponent(l); d.onBeforeChange(f); this.ls = d; this.Fs(); } js=false; vs() { if (this.js) return; this.Vs(); } gs() { if (this.js) return; this.Vs(); this.Es(); this.ds = false; this.cs = true; this.Fs(); this.Ss(); this.Us(); } Ts() { if (this.js) return; this.es.quaternion.setFromEuler(this.es.rotation, false); } ws() { if (this.js) return; this.es.rotation.setFromQuaternion(this.es.quaternion, undefined, false); } Cs() { if (this.js) return; this.As(); } Ms() { if (this.js) return; this.As(); this.Es(); this._s = false; this.ds = true; this.cs = true; this.Fs(); this.Ds(); this.Us(); } Ps() { if (this.js) return; this.ns.setFromEuler(this.os, false); } ys() { if (this.js) return; this.os.setFromQuaternion(this.ns, undefined, false); } Ss() { this._s = true; const t = this.es.children; for (let s = 0, i = t.length; s < i; ++s) { const i = t[s]; if (i.userData instanceof Transform) { i.userData.Ss(); } } } Ds() { const t = this.es.children; for (let s = 0, i = t.length; s < i; ++s) { const i = t[s]; if (i.userData instanceof Transform) { i.userData.Ss(); } } } Fs() { this.L.transformMatrixProcessor.enqueueTransformToUpdate(this); this.Ns(); } Ns() { this.us = true; const t = this.es.children; for (let s = 0, i = t.length; s < i; ++s) { const i = t[s]; if (i.userData instanceof Transform) { i.userData.Ns(); } } } Us() { this.fs = true; const t = this.es.children; for (let s = 0, i = t.length; s < i; ++s) { const i = t[s]; if (i.userData instanceof Transform) { i.userData.Us(); } } } static _matrix4Buffer=new Matrix4; Vs() { if (!this.ds) return; if (this.cs) { if (this.us) { this.js = true; this.es.matrixWorld.compose(this.hs, this.ns, this.ls); this.js = false; this.us = false; this.bt.gameObjectEventContainer.invokeOnWorldMatrixUpdated(); } const t = this.parent; if (t) { t.ss(); const s = Transform._matrix4Buffer.copy(t.es.matrixWorld).invert(); this.es.matrix.multiplyMatrices(this.es.matrixWorld, s); } else { this.es.matrix.copy(this.es.matrixWorld); } this.cs = false; } this.js = true; this.es.matrix.decompose(this.localPosition, this.localRotation, this.localScale); this.localEulerAngles.setFromQuaternion(this.localRotation, undefined, false); this.js = false; this.ds = false; } As() { if (!this._s) return; this.ss(); this.js = true; this.es.matrixWorld.decompose(this.hs, this.ns, this.ls); this.os.setFromQuaternion(this.ns, undefined, false); this.js = false; this._s = false; } ss() { if (!this.us) return; const t = this.es.matrix; if (!this.cs) { const s = this.parent; if (s) { s.ss(); this.es.matrixWorld.multiplyMatrices(s.es.matrixWorld, t); } else { this.es.matrixWorld.copy(t); } } else if (!this.ds) { if (this.cs) { this.js = true; t.compose(this.localPosition, this.localRotation, this.localScale); this.js = false; this.cs = false; } const s = this.parent; if (s) { s.ss(); this.es.matrixWorld.multiplyMatrices(s.es.matrixWorld, t); } else { this.es.matrixWorld.copy(t); } } else { this.js = true; this.es.matrixWorld.compose(this.hs, this.ns, this.ls); this.js = false; } this.us = false; this.bt.gameObjectEventContainer.invokeOnWorldMatrixUpdated(); } ts() { if (!this.cs) return; const t = this.es.matrix; if (!this.us) { const t = this.parent; if (t) { t.ss(); const s = Transform._matrix4Buffer.copy(t.es.matrixWorld).invert(); this.es.matrix.multiplyMatrices(this.es.matrixWorld, s); } else { this.es.matrix.copy(this.es.matrixWorld); } } else if (!this._s) { if (this.us) { this.js = true; this.es.matrixWorld.compose(this.hs, this.ns, this.ls); this.js = false; this.us = false; this.bt.gameObjectEventContainer.invokeOnWorldMatrixUpdated(); } const t = this.parent; if (t) { t.ss(); const s = Transform._matrix4Buffer.copy(t.es.matrixWorld).invert(); this.es.matrix.multiplyMatrices(this.es.matrixWorld, s); } else { this.es.matrix.copy(this.es.matrixWorld); } } else { this.js = true; t.compose(this.localPosition, this.localRotation, this.localScale); this.js = false; } this.cs = false; } Qs() { this.Vs(); const t = this.es.children; for (let s = 0, i = t.length; s < i; ++s) { const i = t[s]; if (i.userData instanceof Transform) { i.userData.Qs(); } } } Es() { const t = this.es.children; for (let s = 0, i = t.length; s < i; ++s) { const i = t[s]; if (i.userData instanceof Transform) { i.userData.Vs(); i.userData.Es(); } } } isRegisteredToProcessor=false; tryUpdateWorldMatrixRecursivelyFromThisToChildren() { if (!this.bt.exists) return false; return this.Gs(); } Gs() { this.ss(); const t = this.es.children; for (let s = 0, i = t.length; s < i; ++s) { const i = t[s]; if (i.userData instanceof Transform) { i.userData.Gs(); } } return true; } foreachChild(t) { const s = this.es.children; for (let i = 0, e = s.length; i < e; ++i) { const e = s[i]; if (e.userData instanceof Transform) { t(e.userData); } } } iterateChild(t) { const s = this.es.children; for (let i = 0, e = s.length; i < e; ++i) { const e = s[i]; if (e.userData instanceof Transform) { if (!t(e.userData)) break; } } } get parent() { if (this.es.parent.isScene) return null; return this.es.parent.userData; } set parent(t) { this.setParent(t); } setParent(t, s = true) { if (t) { const i = this.parent; this.Qs(); this.Fs(); this.Ss(); if (s) { t.getWorldToLocalMatrix(this.es.matrix).multiply(this.es.matrixWorld); } this.es.removeFromParent(); t.es.add(this.es); this.rs(i, t); } else { const t = this.parent; this.Qs(); this.Fs(); this.Ss(); if (s) { this.es.matrix.copy(this.es.matrixWorld); } this.es.removeFromParent(); this.L.scene.unsafeGetThreeScene().add(this.es); this.rs(t, null); } } get children() { const t = []; const s = this.es.children; for (let i = 0, e = s.length; i < e; ++i) { const e = s[i]; if (e.userData instanceof Transform) { t.push(e.userData); } } return t; } get gameObject() { return this.bt; } static _vector3Buffer=new Vector3; getForward(t) { this.ss(); const s = this.es.matrixWorld.elements; return t ? t.set(s[8], s[9], s[10]) : new Vector3(s[8], s[9], s[10]); } setForward(t) { this.L.transformMatrixProcessor.enqueueTransformToUpdate(this); this.ss(); this.Es(); this.cs = true; this.ds = true; this.Ds(); this.Ss(); this._s = true; const s = this.es.matrixWorld.elements; const i = Transform._vector3Buffer.copy(t).normalize(); s[8] = i.x; s[9] = i.y; s[10] = i.z; } getRight(t) { this.ss(); const s = this.es.matrixWorld.elements; return t ? t.set(s[0], s[1], s[2]) : new Vector3(s[0], s[1], s[2]); } setRight(t) { this.L.transformMatrixProcessor.enqueueTransformToUpdate(this); this.ss(); this.Es(); this.cs = true; this.ds = true; this.Ds(); this.Ss(); this._s = true; const s = this.es.matrixWorld.elements; const i = Transform._vector3Buffer.copy(t).normalize(); s[0] = i.x; s[1] = i.y; s[2] = i.z; } getUp(t) { this.ss(); const s = this.es.matrixWorld.elements; return t ? t.set(s[4], s[5], s[6]) : new Vector3(s[4], s[5], s[6]); } setUp(t) { this.L.transformMatrixProcessor.enqueueTransformToUpdate(this); this.ss(); this.Es(); this.cs = true; this.ds = true; this.Ds(); this.Ss(); this._s = true; const s = this.es.matrixWorld.elements; const i = Transform._vector3Buffer.copy(t).normalize(); s[4] = i.x; s[5] = i.y; s[6] = i.z; } get localPosition() { return this.es.position; } get localEulerAngles() { return this.es.rotation; } get localRotation() { return this.es.quaternion; } get localScale() { return this.es.scale; } get position() { return this.hs; } get eulerAngles() { return this.os; } get rotation() { return this.ns; } get lossyScale() { return this.ls; } get hasChanged() { return this.fs; } set hasChanged(t) { this.fs = t; } getWorldToLocalMatrix(t) { this.ss(); return t ? t.copy(this.es.matrixWorld).invert() : this.es.matrixWorld.clone().invert(); } getLocalToWorldMatrix(t) { this.ss(); return t ? t.copy(this.es.matrixWorld) : this.es.matrixWorld.clone(); } transformPoint(t) { this.ss(); return t.applyMatrix4(this.es.matrixWorld); } inverseTransformPoint(t) { this.ss(); return t.applyMatrix4(Transform._matrix4Buffer.copy(this.es.matrixWorld).invert()); } transformDirection(t) { const s = Transform._matrix4Buffer.copy(this.es.matrixWorld).makeScale(1, 1, 1); return t.transformDirection(s); } inverseTransformDirection(t) { const s = Transform._matrix4Buffer.copy(this.es.matrixWorld).makeScale(1, 1, 1).invert(); return t.transformDirection(s); } transformVector(t) { return t.transformDirection(this.es.matrixWorld); } inverseTransformVector(t) { return t.transformDirection(Transform._matrix4Buffer.copy(this.es.matrixWorld).invert()); } isChildOf(t) { if (this === t) return true; const s = this.parent; if (s) return s.isChildOf(t); return false; } static _quaternionBuffer=new Quaternion; lookAt(t) { const s = this.parent; Transform._vector3Buffer.setFromMatrixPosition(this.es.matrixWorld); const i = Transform._matrix4Buffer.lookAt(Transform._vector3Buffer, t, this.es.up); this.es.quaternion.setFromRotationMatrix(i); if (s) { i.extractRotation(s.es.matrixWorld); const t = Transform._quaternionBuffer.setFromRotationMatrix(i); this.es.quaternion.premultiply(t.invert()); } } setRotationFromAxisAngle(t, s) { this.es.setRotationFromAxisAngle(t, s); } setRotationFromEuler(t) { this.es.setRotationFromEuler(t); } setRotationFromMatrix(t) { this.es.setRotationFromMatrix(t); } setRotationFromQuaternion(t) { this.es.setRotationFromQuaternion(t); } rotateOnAxis(t, s) { this.es.rotateOnAxis(t, s); return this; } rotateOnWorldAxis(t, s) { this.es.rotateOnWorldAxis(t, s); return this; } rotateX(t) { this.es.rotateX(t); return this; } rotateY(t) { this.es.rotateY(t); return this; } rotateZ(t) { this.es.rotateZ(t); return this; } translateOnAxis(t, s) { this.es.translateOnAxis(t, s); return this; } translateX(t) { this.es.translateX(t); return this; } translateY(t) { this.es.translateY(t); return this; } translateZ(t) { this.es.translateZ(t); return this; } unsafeGetObject3D() { return this.es; } enqueueRenderAttachedObject3D(t) { this.L.transformMatrixProcessor.enqueueRenderObject(t); } dequeueRenderAttachedObject3D(t) { this.L.transformMatrixProcessor.dequeueRenderObject(t); } static updateRawObject3DWorldMatrixRecursively(t) { if (t.matrixAutoUpdate) t.updateMatrix(); if (t.parent) { t.matrixWorld.multiplyMatrices(t.parent.matrixWorld, t.matrix); } else { t.matrixWorld.copy(t.matrix); } const s = t.children; for (let t = 0, i = s.length; t < i; ++t) { Transform.updateRawObject3DWorldMatrixRecursivelyInternal(s[t]); } } static updateRawObject3DWorldMatrixRecursivelyInternal(t) { if (t.matrixAutoUpdate) t.updateMatrix(); t.matrixWorld.multiplyMatrices(t.parent.matrixWorld, t.matrix); const s = t.children; for (let t = 0, i = s.length; t < i; ++t) { Transform.updateRawObject3DWorldMatrixRecursivelyInternal(s[t]); } } toJSON() { return {}; } }