UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

197 lines (159 loc) 5.08 kB
import { Frustum } from "three"; import { array_copy } from "../../../../core/collection/array/array_copy.js"; import { array_remove_first } from "../../../../core/collection/array/array_remove_first.js"; import Signal from "../../../../core/events/signal/Signal.js"; import { AABB3 } from "../../../../core/geom/3d/aabb/AABB3.js"; import { read_three_planes_to_array } from "../../../../core/geom/3d/frustum/read_three_planes_to_array.js"; import { frustum_from_camera } from "../../ecs/camera/frustum_from_camera.js"; import { compare_three_objects } from "../../three/compare_three_objects.js"; import { IncrementalDeltaSet } from "../visibility/IncrementalDeltaSet.js"; import { CameraViewFlags } from "./CameraViewFlags.js"; const DEFAULT_FLAGS = CameraViewFlags.Active | CameraViewFlags.AdaptivePlaneNear | CameraViewFlags.AdaptivePlaneFar; const scratch_frustum = new Frustum(); const scratch_mat4 = new Float32Array(16); export class CameraView { constructor() { /** * Human-readable name, used for development/debugging purposes * Not guaranteed to be unique, do not rely on it as an ID * @type {string} */ this.name = ''; /** * @deprecated * @type {null|THREE.Camera} * @private */ this.__camera = null; /** * Frustum planes * Format: x,y,z,constant * @type {Float32Array} */ this.frustum = new Float32Array(24); /** * 4x4 projection matrix * @type {Float32Array} */ this.projection_matrix = new Float32Array(16); /** * * @type {AABB3} */ this.bounding_box = new AABB3(); /** * * @type {IncrementalDeltaSet<THREE.Object3D>} */ this.visible_objects = new IncrementalDeltaSet(compare_three_objects); /** * * @type {number} */ this.flags = DEFAULT_FLAGS; this.on = { preVisibilityBuild: new Signal(), postVisibilityBuild: new Signal(), preRender: new Signal() }; /** * * @type {Array<{transform:function(Float32Array, Float32Array):void, context:*}>} */ this.projection_modifiers = []; } addProjectionModifier(mod) { this.projection_modifiers.push(mod); } removeProjectionModifier(mod) { return array_remove_first(this.projection_modifiers, mod); } /** * * @param {THREE.Camera} camera */ set_from_camera(camera) { this.__camera = camera; // read frustum frustum_from_camera(camera, scratch_frustum, false); // update view definition read_three_planes_to_array(scratch_frustum.planes, this.frustum); // read projection matrix // TODO array_copy(camera.projectionMatrix.elements, 0, this.projection_matrix, 0, 16); let ts = this.projection_matrix; let td = scratch_mat4; for (let i = 0; i < this.projection_modifiers.length; i++) { const modifier = this.projection_modifiers[i]; modifier.transform.call(modifier.context, ts, td); const swap = ts; ts = td; td = swap; } if (ts !== this.projection_matrix) { array_copy(ts, 0, this.projection_matrix, 0, 16); } array_copy(this.projection_matrix, 0, this.__camera.projectionMatrix.elements, 0, 16); } /** * @deprecated * @return {Camera|null} */ get camera() { return this.__camera; } /** * * @param {RenderLayerManager} layers * @param {VisibilityComputer} computer */ build_visibility(layers, computer) { // signal this.on.preVisibilityBuild.send0(); this.visible_objects.initializeUpdate(); computer.output = this.visible_objects; computer.view = this; computer.build(layers); this.visible_objects.finalizeUpdate(); // signal this.on.postVisibilityBuild.send0(); } /** * * @param {number|CameraViewFlags} flag * @returns {void} */ setFlag(flag) { this.flags |= flag; } /** * * @param {number|CameraViewFlags} flag * @returns {void} */ clearFlag(flag) { this.flags &= ~flag; } /** * * @param {number|CameraViewFlags} flag * @param {boolean} value */ writeFlag(flag, value) { if (value) { this.setFlag(flag); } else { this.clearFlag(flag); } } /** * * @param {number|CameraViewFlags} flag * @returns {boolean} */ getFlag(flag) { return (this.flags & flag) === flag; } }