import { Utils } from '../common/Utils';
import { MathUtils } from '../math/MathUtils';
import { BaseLineSegmentsHelperComponent } from './BaseLineSegmentsHelperComponent';
const __ = {
private: Symbol('private'),
}
let _vec3 = MathUtils.createVec3();
let _mat4 = MathUtils.createMat4();
/**
* @class FrustumHelperComponent
* The frustum helper component.
* @memberof THING
* @extends THING.BaseLineSegmentsHelperComponent
*/
class FrustumHelperComponent extends BaseLineSegmentsHelperComponent {
/**
* The frustum view helper, can show frustum of frustum.
*/
constructor() {
super();
this[__.private] = {};
let _private = this[__.private];
_private.pointsMap = {};
_private.projectionMatrix = MathUtils.createMat4();
}
// #region Private Functions
_addPoint(id, color) {
let _private = this[__.private];
_private.pointsMap[id] = _private.pointsMap[id] || [];
_private.pointsMap[id].push(this.points.length);
this.addPoint([0, 0, 0], color);
}
_addLine(a, b, color) {
this._addPoint(a, color);
this._addPoint(b, color);
}
_setPoint(point, projectionMatrixInverse, x, y, z) {
let _private = this[__.private];
const indexBuffer = _private.pointsMap[point];
if (!indexBuffer) {
return;
}
MathUtils.vec3.set(_vec3, x, y, z);
MathUtils.vec3.transformMat4(_vec3, _vec3, projectionMatrixInverse);
for (let i = 0, l = indexBuffer.length; i < l; i++) {
let index = indexBuffer[i];
let points = this.points[index];
points[0] = _vec3[0];
points[1] = _vec3[1];
points[2] = _vec3[2];
}
}
_updateProjectionMatrix() {
let _private = this[__.private];
_private.projectionMatrix = this.object.projectionMatrix;
}
_updateFrustumView() {
let _private = this[__.private];
this._updateProjectionMatrix();
MathUtils.mat4.invert(_mat4, _private.projectionMatrix);
const w = 1, h = 1;
// center / target
this._setPoint('c', _mat4, 0, 0, -1);
this._setPoint('t', _mat4, 0, 0, 1);
// near
this._setPoint('n1', _mat4, -w, -h, -1);
this._setPoint('n2', _mat4, w, -h, -1);
this._setPoint('n3', _mat4, -w, h, -1);
this._setPoint('n4', _mat4, w, h, -1);
// far
this._setPoint('f1', _mat4, -w, -h, 1);
this._setPoint('f2', _mat4, w, -h, 1);
this._setPoint('f3', _mat4, -w, h, 1);
this._setPoint('f4', _mat4, w, h, 1);
// up
this._setPoint('u1', _mat4, w * 0.7, h * 1.1, -1);
this._setPoint('u2', _mat4, -w * 0.7, h * 1.1, -1);
this._setPoint('u3', _mat4, 0, h * 2, -1);
// cross
this._setPoint('cf1', _mat4, -w, 0, 1);
this._setPoint('cf2', _mat4, w, 0, 1);
this._setPoint('cf3', _mat4, 0, -h, 1);
this._setPoint('cf4', _mat4, 0, h, 1);
this._setPoint('cn1', _mat4, -w, 0, -1);
this._setPoint('cn2', _mat4, w, 0, -1);
this._setPoint('cn3', _mat4, 0, -h, -1);
this._setPoint('cn4', _mat4, 0, h, -1);
// Update points
this.lineSegments.setPoints(this.points);
}
// #endregion
// #region BaseComponent Interface
onAdd(object) {
super.onAdd(object);
// Initialize points and colors
const colorFrustum = Utils.parseColor(0xffaa00);
const colorCone = Utils.parseColor(0xff0000);
const colorUp = Utils.parseColor(0x00aaff);
const colorTarget = Utils.parseColor(0xffffff);
const colorCross = Utils.parseColor(0x333333);
// near
this._addLine('n1', 'n2', colorFrustum);
this._addLine('n2', 'n4', colorFrustum);
this._addLine('n4', 'n3', colorFrustum);
this._addLine('n3', 'n1', colorFrustum);
// far
this._addLine('f1', 'f2', colorFrustum);
this._addLine('f2', 'f4', colorFrustum);
this._addLine('f4', 'f3', colorFrustum);
this._addLine('f3', 'f1', colorFrustum);
// sides
this._addLine('n1', 'f1', colorFrustum);
this._addLine('n2', 'f2', colorFrustum);
this._addLine('n3', 'f3', colorFrustum);
this._addLine('n4', 'f4', colorFrustum);
// cone
this._addLine('p', 'n1', colorCone);
this._addLine('p', 'n2', colorCone);
this._addLine('p', 'n3', colorCone);
this._addLine('p', 'n4', colorCone);
// up
this._addLine('u1', 'u2', colorUp);
this._addLine('u2', 'u3', colorUp);
this._addLine('u3', 'u1', colorUp);
// target
this._addLine('c', 't', colorTarget);
this._addLine('p', 'c', colorCross);
// cross
this._addLine('cn1', 'cn2', colorCross);
this._addLine('cn3', 'cn4', colorCross);
this._addLine('cf1', 'cf2', colorCross);
this._addLine('cf3', 'cf4', colorCross);
// Update points and colors
this.lineSegments.setSize(this.points.length * 3);
this.lineSegments.setColors(this.colors);
// Update default options
this.lineSegments.setVisible(false);
Utils.markAsDebugNode(this.lineSegments);
}
onUpdate(deltaTime) {
this._updateFrustumView();
}
// #endregion
// #region Accessors
get projectionMatrix() {
let _private = this[__.private];
return _private.projectionMatrix;
}
set projectionMatrix(value) {
let _private = this[__.private];
_private.projectionMatrix = value;
}
/**
* Show/Hide helper.
* @type {Boolean}
*/
get visible() {
return this.lineSegments.getVisible();
}
set visible(value) {
this.lineSegments.setVisible(value);
}
// #endregion
}
export { FrustumHelperComponent }