@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
197 lines (159 loc) • 5.08 kB
JavaScript
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;
}
}