UNPKG

mylingo3d

Version:

Lingo3D is a React/Vue 3d game development framework that ships with a complete visual editor

310 lines 11 kB
import { CameraHelper, Quaternion } from "three"; import ObjectManager from "../ObjectManager"; import { debounceInstance, last } from "@lincode/utils"; import { scaleDown } from "../../../engine/constants"; import { ray, euler, quaternion, quaternion_, halfPi } from "../../utils/reusables"; import pillShape from "../PhysicsObjectManager/cannon/shapes/pillShape"; import { deg2Rad } from "@lincode/math"; import { MIN_POLAR_ANGLE, MAX_POLAR_ANGLE } from "../../../globals"; import { Reactive } from "@lincode/reactivity"; import { Cancellable } from "@lincode/promiselikes"; import mainCamera from "../../../engine/mainCamera"; import scene from "../../../engine/scene"; import { onSelectionTarget, emitSelectionTarget } from "../../../events/onSelectionTarget"; import { bokehDefault } from "../../../states/useBokeh"; import { bokehApertureDefault } from "../../../states/useBokehAperture"; import { bokehFocusDefault } from "../../../states/useBokehFocus"; import { bokehMaxBlurDefault } from "../../../states/useBokehMaxBlur"; import { setBokehRefresh } from "../../../states/useBokehRefresh"; import { pushCameraList, pullCameraList } from "../../../states/useCameraList"; import { getCameraRendered } from "../../../states/useCameraRendered"; import { pullCameraStack, getCameraStack, pushCameraStack } from "../../../states/useCameraStack"; import makeCameraSprite from "../utils/makeCameraSprite"; import getWorldPosition from "../../utils/getWorldPosition"; import getWorldQuaternion from "../../utils/getWorldQuaternion"; import getWorldDirection from "../../utils/getWorldDirection"; export default class CameraBase extends ObjectManager { camera; _physicsShape = pillShape; midObject3d = this.outerObject3d; constructor(camera) { super(); this.camera = camera; this.object3d.add(camera); camera.userData.manager = this; pushCameraList(camera); this.then(() => { pullCameraStack(camera); pullCameraList(camera); }); this.createEffect(() => { if (getCameraRendered() !== mainCamera || getCameraRendered() === camera) return; const helper = new CameraHelper(camera); scene.add(helper); const sprite = makeCameraSprite(); helper.add(sprite.outerObject3d); const handle = onSelectionTarget(({ target }) => { target === sprite && emitSelectionTarget(this); }); return () => { helper.dispose(); scene.remove(helper); sprite.dispose(); handle.cancel(); }; }, [getCameraRendered]); } lookAt(a0, a1, a2) { super.lookAt(a0, a1, a2); const angle = euler.setFromQuaternion(this.outerObject3d.quaternion); angle.x += Math.PI; angle.z += Math.PI; this.outerObject3d.setRotationFromEuler(angle); } get fov() { return this.camera.fov; } set fov(val) { this.camera.fov = val; this.camera.updateProjectionMatrix?.(); } get zoom() { return this.camera.zoom; } set zoom(val) { this.camera.zoom = val; this.camera.updateProjectionMatrix?.(); } get near() { return this.camera.near; } set near(val) { this.camera.near = val; this.camera.updateProjectionMatrix?.(); } get far() { return this.camera.far; } set far(val) { this.camera.far = val; this.camera.updateProjectionMatrix?.(); } get active() { return last(getCameraStack()) === this.camera; } set active(val) { pullCameraStack(this.camera); val && pushCameraStack(this.camera); } get transition() { return this.camera.userData.transition; } set transition(val) { this.camera.userData.transition = val; } get bokeh() { return this.camera.userData.bokeh ?? bokehDefault; } set bokeh(val) { this.camera.userData.bokeh = val; setBokehRefresh({}); } get bokehFocus() { return this.camera.userData.bokehFocus ?? bokehFocusDefault; } set bokehFocus(val) { this.camera.userData.bokehFocus = val; setBokehRefresh({}); } get bokehMaxBlur() { return this.camera.userData.bokehMaxBlur ?? bokehMaxBlurDefault; } set bokehMaxBlur(val) { this.camera.userData.bokehMaxBlur = val; setBokehRefresh({}); } get bokehAperture() { return this.camera.userData.bokehAperture ?? bokehApertureDefault; } set bokehAperture(val) { this.camera.userData.bokehAperture = val; setBokehRefresh({}); } getRay() { return ray.set(getWorldPosition(this.camera), getWorldDirection(this.camera)); } append(object) { this._append(object); this.camera.add(object.outerObject3d); } attach(object) { this._append(object); this.camera.attach(object.outerObject3d); } get width() { return super.width; } set width(val) { const num = val * scaleDown; this.object3d.scale.x = num; this.camera.scale.x = 1 / num; } get height() { return super.height; } set height(val) { const num = val * scaleDown; this.object3d.scale.y = num; this.camera.scale.y = 1 / num; } get depth() { return super.depth; } set depth(val) { const num = val * scaleDown; this.object3d.scale.z = num; this.camera.scale.z = 1 / num; } orbitMode; _gyrate(movementX, movementY, inner) { const manager = inner ? this.object3d : this.midObject3d; euler.setFromQuaternion(manager.quaternion); euler.y -= movementX * 0.002; euler.y = Math.max(halfPi - this._maxAzimuthAngle * deg2Rad, Math.min(halfPi - this._minAzimuthAngle * deg2Rad, euler.y)); euler.x -= movementY * 0.002; euler.x = Math.max(halfPi - this._maxPolarAngle * deg2Rad, Math.min(halfPi - this._minPolarAngle * deg2Rad, euler.x)); manager.setRotationFromEuler(euler); !inner && this.rotationUpdate?.updateXYZ(); } gyrateHandle; gyrate(movementX, movementY, noDamping) { if (this.enableDamping) { movementX *= 0.5; movementY *= 0.5; } if (this.orbitMode) this._gyrate(movementX, movementY); else { this._gyrate(movementX, 0); this._gyrate(0, movementY, true); } if (!this.enableDamping || noDamping || !(movementX || movementY)) return; this.gyrateHandle?.cancel(); let factor = 1; const handle = (this.gyrateHandle = this.beforeRender(() => { factor *= 0.95; this._gyrate(movementX * factor, movementY * factor); factor <= 0.001 && handle.cancel(); })); } static updateAngle = debounceInstance((target) => target.gyrate(0, 0), 0, "trailing"); updateAngle() { CameraBase.updateAngle(this, this); } _minPolarAngle = MIN_POLAR_ANGLE; get minPolarAngle() { return this._minPolarAngle; } set minPolarAngle(val) { this._minPolarAngle = val; this.updateAngle(); } _maxPolarAngle = MAX_POLAR_ANGLE; get maxPolarAngle() { return this._maxPolarAngle; } set maxPolarAngle(val) { this._maxPolarAngle = val; this.updateAngle(); } _minAzimuthAngle = -Infinity; get minAzimuthAngle() { return this._minAzimuthAngle; } set minAzimuthAngle(val) { this._minAzimuthAngle = val; this.updateAngle(); } _maxAzimuthAngle = Infinity; get maxAzimuthAngle() { return this._maxAzimuthAngle; } set maxAzimuthAngle(val) { this._maxAzimuthAngle = val; this.updateAngle(); } setPolarAngle(angle) { const { _minPolarAngle, _maxPolarAngle } = this; this.minPolarAngle = this.maxPolarAngle = angle; this.queueMicrotask(() => { this.minPolarAngle = _minPolarAngle; this.maxPolarAngle = _maxPolarAngle; }); } setAzimuthAngle(angle) { const { _minAzimuthAngle, _maxAzimuthAngle } = this; this.minAzimuthAngle = this.maxAzimuthAngle = angle; this.queueMicrotask(() => { this.minAzimuthAngle = _minAzimuthAngle; this.maxAzimuthAngle = _maxAzimuthAngle; }); } _polarAngle; get polarAngle() { return this._polarAngle; } set polarAngle(val) { this._polarAngle = val; val && this.setPolarAngle(val); } _azimuthAngle; get azimuthAngle() { return this._azimuthAngle; } set azimuthAngle(val) { this._azimuthAngle = val; val && this.setAzimuthAngle(val); } enableDamping = false; mouseControlState = new Reactive(false); mouseControlInit; get mouseControl() { return this.mouseControlState.get(); } set mouseControl(val) { this.mouseControlState.set(val); if (!val || this.mouseControlInit) return; this.mouseControlInit = true; import("./enableMouseControl").then((module) => module.default.call(this)); } _gyroControl; get gyroControl() { return !!this._gyroControl; } set gyroControl(val) { this._gyroControl = val; const deviceEuler = euler; const deviceQuaternion = quaternion; const screenTransform = quaternion_; const worldTransform = new Quaternion(-Math.sqrt(0.5), 0, 0, Math.sqrt(0.5)); const quat = getWorldQuaternion(this.object3d); const orient = 0; const cb = (e) => { this.object3d.quaternion.copy(quat); deviceEuler.set((e.beta ?? 0) * deg2Rad, (e.alpha ?? 0) * deg2Rad, -(e.gamma ?? 0) * deg2Rad, "YXZ"); this.object3d.quaternion.multiply(deviceQuaternion.setFromEuler(deviceEuler)); const minusHalfAngle = -orient * 0.5; screenTransform.set(0, Math.sin(minusHalfAngle), 0, Math.cos(minusHalfAngle)); this.object3d.quaternion.multiply(screenTransform); this.object3d.quaternion.multiply(worldTransform); }; val && window.addEventListener("deviceorientation", cb); this.cancelHandle("gyroControl", val && (() => new Cancellable(() => window.removeEventListener("deviceorientation", cb)))); } } //# sourceMappingURL=index.js.map