初始化

This commit is contained in:
SmallMain
2022-06-25 00:23:03 +08:00
commit ef0589e8e5
2264 changed files with 617829 additions and 0 deletions

View File

@@ -0,0 +1,503 @@
// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
import { Vec3, Mat4, lerp, Vec4 } from '../../core/value-types';
import { Ray } from '../../core/geom-utils';
import enums from '../enums';
let _tmp_mat4 = new Mat4();
let _matView = new Mat4();
let _matViewInv = new Mat4();
let _matProj = new Mat4();
let _matViewProj = new Mat4();
let _matInvViewProj = new Mat4();
let _tmp_v3 = new Vec3();
let _tmp2_v3 = new Vec3();
/**
* A representation of a camera instance
*/
export default class Camera {
_poolID = -1;
_node = null;
_projection = enums.PROJ_PERSPECTIVE;
// priority. the smaller one will be rendered first
_priority = 0;
// clear options
_color = new Vec4(0.2, 0.3, 0.47, 1);
_depth = 1;
_stencil = 0;
_clearFlags = enums.CLEAR_COLOR | enums.CLEAR_DEPTH;
_clearModel = null;
// stages & framebuffer
_stages = [];
_framebuffer = null;
// projection properties
_near = 0.01;
_far = 1000.0;
_fov = Math.PI / 4.0; // vertical fov
_rect = {
x: 0, y: 0, w: 1, h: 1
};
// ortho properties
_orthoHeight = 10;
_cullingMask = 0xffffffff;
// culling mask
get cullingMask () {
return this._cullingMask;
}
set cullingMask (mask) {
this._cullingMask = mask;
}
setCullingMask (mask) {
this._cullingMask = mask;
}
/**
* Get the hosting node of this camera
* @returns {Node} the hosting node
*/
getNode () {
return this._node;
}
/**
* Set the hosting node of this camera
* @param {Node} node the hosting node
*/
setNode (node) {
this._node = node;
}
/**
* Get the projection type of the camera
* @returns {number} camera projection type
*/
getType () {
return this._projection;
}
/**
* Set the projection type of the camera
* @param {number} type camera projection type
*/
setType (type) {
this._projection = type;
}
/**
* Get the priority of the camera
* @returns {number} camera priority
*/
getPriority () {
return this._priority;
}
/**
* Set the priority of the camera
* @param {number} priority camera priority
*/
setPriority (priority) {
this._priority = priority;
}
/**
* Get the orthogonal height of the camera
* @returns {number} camera height
*/
getOrthoHeight () {
return this._orthoHeight;
}
/**
* Set the orthogonal height of the camera
* @param {number} val camera height
*/
setOrthoHeight (val) {
this._orthoHeight = val;
}
/**
* Get the field of view of the camera
* @returns {number} camera field of view
*/
getFov () {
return this._fov;
}
/**
* Set the field of view of the camera
* @param {number} fov camera field of view
*/
setFov (fov) {
this._fov = fov;
}
/**
* Get the near clipping distance of the camera
* @returns {number} camera near clipping distance
*/
getNear () {
return this._near;
}
/**
* Set the near clipping distance of the camera
* @param {number} near camera near clipping distance
*/
setNear (near) {
this._near = near;
}
/**
* Get the far clipping distance of the camera
* @returns {number} camera far clipping distance
*/
getFar () {
return this._far;
}
/**
* Set the far clipping distance of the camera
* @param {number} far camera far clipping distance
*/
setFar (far) {
this._far = far;
}
/**
* Get the clear color of the camera
* @returns {Vec4} out the receiving color vector
*/
getColor (out) {
return Vec4.copy(out, this._color);
}
/**
* Set the clear color of the camera
* @param {number} r red channel of camera clear color
* @param {number} g green channel of camera clear color
* @param {number} b blue channel of camera clear color
* @param {number} a alpha channel of camera clear color
*/
setColor (r, g, b, a) {
Vec4.set(this._color, r, g, b, a);
}
/**
* Get the clear depth of the camera
* @returns {number} camera clear depth
*/
getDepth () {
return this._depth;
}
/**
* Set the clear depth of the camera
* @param {number} depth camera clear depth
*/
setDepth (depth) {
this._depth = depth;
}
/**
* Get the clearing stencil value of the camera
* @returns {number} camera clearing stencil value
*/
getStencil () {
return this._stencil;
}
/**
* Set the clearing stencil value of the camera
* @param {number} stencil camera clearing stencil value
*/
setStencil (stencil) {
this._stencil = stencil;
}
/**
* Get the clearing flags of the camera
* @returns {number} camera clearing flags
*/
getClearFlags () {
return this._clearFlags;
}
/**
* Set the clearing flags of the camera
* @param {number} flags camera clearing flags
*/
setClearFlags (flags) {
this._clearFlags = flags;
}
/**
* Get the rect of the camera
* @param {Object} out the receiving object
* @returns {Object} camera rect
*/
getRect (out) {
out.x = this._rect.x;
out.y = this._rect.y;
out.w = this._rect.w;
out.h = this._rect.h;
return out;
}
/**
* Set the rect of the camera
* @param {Number} x - [0,1]
* @param {Number} y - [0,1]
* @param {Number} w - [0,1]
* @param {Number} h - [0,1]
*/
setRect (x, y, w, h) {
this._rect.x = x;
this._rect.y = y;
this._rect.w = w;
this._rect.h = h;
}
/**
* Get the stages of the camera
* @returns {string[]} camera stages
*/
getStages () {
return this._stages;
}
/**
* Set the stages of the camera
* @param {string[]} stages camera stages
*/
setStages (stages) {
this._stages = stages;
}
/**
* Get the framebuffer of the camera
* @returns {FrameBuffer} camera framebuffer
*/
getFramebuffer () {
return this._framebuffer;
}
/**
* Set the framebuffer of the camera
* @param {FrameBuffer} framebuffer camera framebuffer
*/
setFrameBuffer (framebuffer) {
this._framebuffer = framebuffer;
}
_calcMatrices (width, height) {
// view matrix
this._node.getWorldRT(_matViewInv);
Mat4.invert(_matView, _matViewInv);
// projection matrix
let aspect = width / height;
if (this._projection === enums.PROJ_PERSPECTIVE) {
Mat4.perspective(_matProj,
this._fov,
aspect,
this._near,
this._far
);
} else {
let x = this._orthoHeight * aspect;
let y = this._orthoHeight;
Mat4.ortho(_matProj,
-x, x, -y, y, this._near, this._far
);
}
// view-projection
Mat4.mul(_matViewProj, _matProj, _matView);
// inv view-projection
Mat4.invert(_matInvViewProj, _matViewProj);
}
/**
* extract a view of this camera
* @param {View} out the receiving view
* @param {number} width framebuffer width
* @param {number} height framebuffer height
*/
extractView (out, width, height) {
if (this._framebuffer) {
width = this._framebuffer._width;
height = this._framebuffer._height;
}
// priority
out._priority = this._priority;
// rect
out._rect.x = this._rect.x * width;
out._rect.y = this._rect.y * height;
out._rect.w = this._rect.w * width;
out._rect.h = this._rect.h * height;
// clear opts
this.getColor(out._color);
out._depth = this._depth;
out._stencil = this._stencil;
out._clearFlags = this._clearFlags;
out._clearModel = this._clearModel;
// stages & framebuffer
out._stages = this._stages;
out._framebuffer = this._framebuffer;
this._calcMatrices(width, height);
Mat4.copy(out._matView, _matView);
Mat4.copy(out._matViewInv, _matViewInv);
Mat4.copy(out._matProj, _matProj);
Mat4.copy(out._matViewProj, _matViewProj);
Mat4.copy(out._matInvViewProj, _matInvViewProj);
out._cullingMask = this._cullingMask;
}
/**
* transform a screen position to a world space ray
* @param {number} x the screen x position to be transformed
* @param {number} y the screen y position to be transformed
* @param {number} width framebuffer width
* @param {number} height framebuffer height
* @param {Ray} out the resulting ray
* @returns {Ray} the resulting ray
*/
screenPointToRay (x, y, width, height, out) {
if (!cc.geomUtils) return out;
out = out || new Ray();
this._calcMatrices(width, height);
let cx = this._rect.x * width;
let cy = this._rect.y * height;
let cw = this._rect.w * width;
let ch = this._rect.h * height;
// far plane intersection
Vec3.set(_tmp2_v3, (x - cx) / cw * 2 - 1, (y - cy) / ch * 2 - 1, 1);
Vec3.transformMat4(_tmp2_v3, _tmp2_v3, _matInvViewProj);
if (this._projection === enums.PROJ_PERSPECTIVE) {
// camera origin
this._node.getWorldPosition(_tmp_v3);
} else {
// near plane intersection
Vec3.set(_tmp_v3, (x - cx) / cw * 2 - 1, (y - cy) / ch * 2 - 1, -1);
Vec3.transformMat4(_tmp_v3, _tmp_v3, _matInvViewProj);
}
return Ray.fromPoints(out, _tmp_v3, _tmp2_v3);
}
/**
* transform a screen position to world space
* @param {Vec3} out the resulting vector
* @param {Vec3} screenPos the screen position to be transformed
* @param {number} width framebuffer width
* @param {number} height framebuffer height
* @returns {Vec3} the resulting vector
*/
screenToWorld (out, screenPos, width, height) {
this._calcMatrices(width, height);
let cx = this._rect.x * width;
let cy = this._rect.y * height;
let cw = this._rect.w * width;
let ch = this._rect.h * height;
if (this._projection === enums.PROJ_PERSPECTIVE) {
// calculate screen pos in far clip plane
Vec3.set(out,
(screenPos.x - cx) / cw * 2 - 1,
(screenPos.y - cy) / ch * 2 - 1,
0.9999
);
// transform to world
Vec3.transformMat4(out, out, _matInvViewProj);
// lerp to depth z
this._node.getWorldPosition(_tmp_v3);
Vec3.lerp(out, _tmp_v3, out, lerp(this._near / this._far, 1, screenPos.z));
} else {
Vec3.set(out,
(screenPos.x - cx) / cw * 2 - 1,
(screenPos.y - cy) / ch * 2 - 1,
screenPos.z * 2 - 1
);
// transform to world
Vec3.transformMat4(out, out, _matInvViewProj);
}
return out;
}
/**
* transform a world space position to screen space
* @param {Vec3} out the resulting vector
* @param {Vec3} worldPos the world space position to be transformed
* @param {number} width framebuffer width
* @param {number} height framebuffer height
* @returns {Vec3} the resulting vector
*/
worldToScreen (out, worldPos, width, height) {
this._calcMatrices(width, height);
let cx = this._rect.x * width;
let cy = this._rect.y * height;
let cw = this._rect.w * width;
let ch = this._rect.h * height;
Vec3.transformMat4(out, worldPos, _matViewProj);
out.x = cx + (out.x + 1) * 0.5 * cw;
out.y = cy + (out.y + 1) * 0.5 * ch;
out.z = out.z * 0.5 + 0.5;
return out;
}
/**
* transform a world space matrix to screen space
* @param {Mat4} out the resulting vector
* @param {Mat4} worldMatrix the world space matrix to be transformed
* @param {number} width framebuffer width
* @param {number} height framebuffer height
* @returns {Mat4} the resulting vector
*/
worldMatrixToScreen (out, worldMatrix, width, height) {
this._calcMatrices(width, height);
Mat4.mul(out, _matViewProj, worldMatrix);
let halfWidth = width / 2;
let halfHeight = height / 2;
Mat4.identity(_tmp_mat4);
Mat4.transform(_tmp_mat4, _tmp_mat4, Vec3.set(_tmp_v3, halfWidth, halfHeight, 0));
Mat4.scale(_tmp_mat4, _tmp_mat4, Vec3.set(_tmp_v3, halfWidth, halfHeight, 1));
Mat4.mul(out, _tmp_mat4, out);
return out;
}
}

View File

@@ -0,0 +1,485 @@
// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
import { Mat4, Mat3, Vec3, toRadian } from '../../core/value-types';
import gfx from '../gfx';
import enums from '../enums';
const _forward = cc.v3(0, 0, -1);
let _m4_tmp = cc.mat4();
let _m3_tmp = Mat3.create();
let _transformedLightDirection = cc.v3(0, 0, 0);
// compute light viewProjMat for shadow.
function _computeSpotLightViewProjMatrix(light, outView, outProj) {
// view matrix
light._node.getWorldRT(outView);
Mat4.invert(outView, outView);
// proj matrix
Mat4.perspective(outProj, light._spotAngle * light._spotAngleScale, 1, light._shadowMinDepth, light._shadowMaxDepth);
}
function _computeDirectionalLightViewProjMatrix(light, outView, outProj) {
// view matrix
light._node.getWorldRT(outView);
Mat4.invert(outView, outView);
// TODO: should compute directional light frustum based on rendered meshes in scene.
// proj matrix
let halfSize = light._shadowFrustumSize / 2;
Mat4.ortho(outProj, -halfSize, halfSize, -halfSize, halfSize, light._shadowMinDepth, light._shadowMaxDepth);
}
function _computePointLightViewProjMatrix(light, outView, outProj) {
// view matrix
light._node.getWorldRT(outView);
Mat4.invert(outView, outView);
// The transformation from Cartesian to polar coordinates is not a linear function,
// so it cannot be achieved by means of a fixed matrix multiplication.
// Here we just use a nearly 180 degree perspective matrix instead.
Mat4.perspective(outProj, toRadian(179), 1, light._shadowMinDepth, light._shadowMaxDepth);
}
/**
* A representation of a light source.
* Could be a point light, a spot light or a directional light.
*/
export default class Light {
/**
* Setup a default directional light with no shadows
*/
constructor() {
this._poolID = -1;
this._node = null;
this._type = enums.LIGHT_DIRECTIONAL;
this._color = new Vec3(1, 1, 1);
this._intensity = 1;
// used for spot and point light
this._range = 1;
// used for spot light, default to 60 degrees
this._spotAngle = toRadian(60);
this._spotExp = 1;
// cached for uniform
this._directionUniform = new Float32Array(3);
this._positionUniform = new Float32Array(3);
this._colorUniform = new Float32Array([this._color.x * this._intensity, this._color.y * this._intensity, this._color.z * this._intensity]);
this._spotUniform = new Float32Array([Math.cos(this._spotAngle * 0.5), this._spotExp]);
// shadow params
this._shadowType = enums.SHADOW_NONE;
this._shadowFrameBuffer = null;
this._shadowMap = null;
this._shadowMapDirty = false;
this._shadowDepthBuffer = null;
this._shadowResolution = 1024;
this._shadowBias = 0.0005;
this._shadowDarkness = 1;
this._shadowMinDepth = 1;
this._shadowMaxDepth = 1000;
this._frustumEdgeFalloff = 0; // used by directional and spot light.
this._viewProjMatrix = cc.mat4();
this._spotAngleScale = 1; // used for spot light.
this._shadowFrustumSize = 50; // used for directional light.
}
/**
* Get the hosting node of this camera
* @returns {Node} the hosting node
*/
getNode() {
return this._node;
}
/**
* Set the hosting node of this camera
* @param {Node} node the hosting node
*/
setNode(node) {
this._node = node;
}
/**
* set the color of the light source
* @param {number} r red channel of the light color
* @param {number} g green channel of the light color
* @param {number} b blue channel of the light color
*/
setColor(r, g, b) {
Vec3.set(this._color, r, g, b);
this._colorUniform[0] = r * this._intensity;
this._colorUniform[1] = g * this._intensity;
this._colorUniform[2] = b * this._intensity;
}
/**
* get the color of the light source
* @returns {Vec3} the light color
*/
get color() {
return this._color;
}
/**
* set the intensity of the light source
* @param {number} val the light intensity
*/
setIntensity(val) {
this._intensity = val;
this._colorUniform[0] = val * this._color.x;
this._colorUniform[1] = val * this._color.y;
this._colorUniform[2] = val * this._color.z;
}
/**
* get the intensity of the light source
* @returns {number} the light intensity
*/
get intensity() {
return this._intensity;
}
/**
* set the type of the light source
* @param {number} type light source type
*/
setType(type) {
this._type = type;
}
/**
* get the type of the light source
* @returns {number} light source type
*/
get type() {
return this._type;
}
/**
* set the spot light angle
* @param {number} val spot light angle
*/
setSpotAngle(val) {
this._spotAngle = val;
this._spotUniform[0] = Math.cos(this._spotAngle * 0.5);
}
/**
* get the spot light angle
* @returns {number} spot light angle
*/
get spotAngle() {
return this._spotAngle;
}
/**
* set the spot light exponential
* @param {number} val spot light exponential
*/
setSpotExp(val) {
this._spotExp = val;
this._spotUniform[1] = val;
}
/**
* get the spot light exponential
* @returns {number} spot light exponential
*/
get spotExp() {
return this._spotExp;
}
/**
* set the range of the light source
* @param {number} val light source range
*/
setRange(val) {
this._range = val;
}
/**
* get the range of the light source
* @returns {number} range of the light source
*/
get range() {
return this._range;
}
/**
* set the shadow type of the light source
* @param {number} type light source shadow type
*/
setShadowType(type) {
if (this._shadowType === enums.SHADOW_NONE && type !== enums.SHADOW_NONE) {
this._shadowMapDirty = true;
}
this._shadowType = type;
}
/**
* get the shadow type of the light source
* @returns {number} light source shadow type
*/
get shadowType() {
return this._shadowType;
}
/**
* get the shadowmap of the light source
* @returns {Texture2D} light source shadowmap
*/
get shadowMap() {
return this._shadowMap;
}
/**
* get the view-projection matrix of the light source
* @returns {Mat4} light source view-projection matrix
*/
get viewProjMatrix() {
return this._viewProjMatrix;
}
/**
* set the shadow resolution of the light source
* @param {number} val light source shadow resolution
*/
setShadowResolution(val) {
if (this._shadowResolution !== val) {
this._shadowMapDirty = true;
}
this._shadowResolution = val;
}
/**
* get the shadow resolution of the light source
* @returns {number} light source shadow resolution
*/
get shadowResolution() {
return this._shadowResolution;
}
/**
* set the shadow bias of the light source
* @param {number} val light source shadow bias
*/
setShadowBias(val) {
this._shadowBias = val;
}
/**
* get the shadow bias of the light source
* @returns {number} light source shadow bias
*/
get shadowBias() {
return this._shadowBias;
}
/**
* set the shadow darkness of the light source
* @param {number} val light source shadow darkness
*/
setShadowDarkness(val) {
this._shadowDarkness = val;
}
/**
* get the shadow darkness of the light source
* @returns {number} light source shadow darkness
*/
get shadowDarkness() {
return this._shadowDarkness;
}
/**
* set the shadow min depth of the light source
* @param {number} val light source shadow min depth
*/
setShadowMinDepth(val) {
this._shadowMinDepth = val;
}
/**
* get the shadow min depth of the light source
* @returns {number} light source shadow min depth
*/
get shadowMinDepth() {
if (this._type === enums.LIGHT_DIRECTIONAL) {
return 1.0;
}
return this._shadowMinDepth;
}
/**
* set the shadow max depth of the light source
* @param {number} val light source shadow max depth
*/
setShadowMaxDepth(val) {
this._shadowMaxDepth = val;
}
/**
* get the shadow max depth of the light source
* @returns {number} light source shadow max depth
*/
get shadowMaxDepth() {
if (this._type === enums.LIGHT_DIRECTIONAL) {
return 1.0;
}
return this._shadowMaxDepth;
}
/**
* set the frustum edge falloff of the light source
* @param {number} val light source frustum edge falloff
*/
setFrustumEdgeFalloff(val) {
this._frustumEdgeFalloff = val;
}
/**
* get the frustum edge falloff of the light source
* @returns {number} light source frustum edge falloff
*/
get frustumEdgeFalloff() {
return this._frustumEdgeFalloff;
}
/**
* set the shadow frustum size of the light source
* @param {number} val light source shadow frustum size
*/
setShadowFrustumSize(val) {
this._shadowFrustumSize = val;
}
/**
* get the shadow frustum size of the light source
* @returns {number} light source shadow frustum size
*/
get shadowFrustumSize() {
return this._shadowFrustumSize;
}
/**
* extract a view of this light source
* @param {View} out the receiving view
* @param {string[]} stages the stages using the view
*/
extractView(out, stages) {
// TODO: view should not handle light.
out._shadowLight = this;
// priority. TODO: use varying value for shadow view?
out._priority = -1;
// rect
out._rect.x = 0;
out._rect.y = 0;
out._rect.w = this._shadowResolution;
out._rect.h = this._shadowResolution;
// clear opts
Vec3.set(out._color, 1, 1, 1);
out._depth = 1;
out._stencil = 1;
out._clearFlags = enums.CLEAR_COLOR | enums.CLEAR_DEPTH;
// stages & framebuffer
out._stages = stages;
out._framebuffer = this._shadowFrameBuffer;
// view projection matrix
switch(this._type) {
case enums.LIGHT_SPOT:
_computeSpotLightViewProjMatrix(this, out._matView, out._matProj);
break;
case enums.LIGHT_DIRECTIONAL:
_computeDirectionalLightViewProjMatrix(this, out._matView, out._matProj);
break;
case enums.LIGHT_POINT:
_computePointLightViewProjMatrix(this, out._matView, out._matProj);
break;
case enums.LIGHT_AMBIENT:
break;
default:
console.warn('shadow of this light type is not supported');
}
// view-projection
Mat4.mul(out._matViewProj, out._matProj, out._matView);
this._viewProjMatrix = out._matViewProj;
Mat4.invert(out._matInvViewProj, out._matViewProj);
// update view's frustum
// out._frustum.update(out._matViewProj, out._matInvViewProj);
out._cullingMask = 0xffffffff;
}
_updateLightPositionAndDirection() {
this._node.getWorldMatrix(_m4_tmp);
Mat3.fromMat4(_m3_tmp, _m4_tmp);
Vec3.transformMat3(_transformedLightDirection, _forward, _m3_tmp);
Vec3.toArray(this._directionUniform, _transformedLightDirection);
let pos = this._positionUniform;
let m = _m4_tmp.m;
pos[0] = m[12];
pos[1] = m[13];
pos[2] = m[14];
}
_generateShadowMap(device) {
this._shadowMap = new gfx.Texture2D(device, {
width: this._shadowResolution,
height: this._shadowResolution,
format: gfx.TEXTURE_FMT_RGBA8,
wrapS: gfx.WRAP_CLAMP,
wrapT: gfx.WRAP_CLAMP,
});
this._shadowDepthBuffer = new gfx.RenderBuffer(device,
gfx.RB_FMT_D16,
this._shadowResolution,
this._shadowResolution
);
this._shadowFrameBuffer = new gfx.FrameBuffer(device, this._shadowResolution, this._shadowResolution, {
colors: [this._shadowMap],
depth: this._shadowDepthBuffer,
});
}
_destroyShadowMap() {
if (this._shadowMap) {
this._shadowMap.destroy();
this._shadowDepthBuffer.destroy();
this._shadowFrameBuffer.destroy();
this._shadowMap = null;
this._shadowDepthBuffer = null;
this._shadowFrameBuffer = null;
}
}
/**
* update the light source
* @param {Device} device the rendering device
*/
update(device) {
this._updateLightPositionAndDirection();
if (this._shadowType === enums.SHADOW_NONE) {
this._destroyShadowMap();
} else if (this._shadowMapDirty) {
this._destroyShadowMap();
this._generateShadowMap(device);
this._shadowMapDirty = false;
}
}
}

View File

@@ -0,0 +1,65 @@
// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
/**
* A representation of a model
*/
export default class Model {
/**
* Setup a default empty model
*/
constructor() {
this._type = 'default';
this._poolID = -1;
this._node = null;
this._inputAssembler = null;
this._effect = null;
this._viewID = -1;
this._cameraID = -1;
this._userKey = -1;
this._castShadow = false;
this._boundingShape = null;
}
/**
* Set the hosting node of this model
* @param {Node} node the hosting node
*/
setNode(node) {
this._node = node;
}
/**
* Set the input assembler
* @param {InputAssembler} ia
*/
setInputAssembler(ia) {
this._inputAssembler = ia;
}
/**
* Set the model effect
* @param {?Effect} effect the effect to use
*/
setEffect(effect) {
this._effect = effect;
}
/**
* Set the user key
* @param {number} key
*/
setUserKey(key) {
this._userKey = key;
}
/**
* Extract a drawing item
* @param {Object} out the receiving item
*/
extractDrawItem(out) {
out.model = this;
out.node = this._node;
out.ia = this._inputAssembler;
out.effect = this._effect;
}
}

View File

@@ -0,0 +1,181 @@
// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
import { FixedArray } from '../memop';
/**
* A representation of the scene
*/
class Scene {
/**
* Setup a default empty scene
*/
constructor(app) {
this._lights = new FixedArray(16);
this._models = new FixedArray(16);
this._cameras = new FixedArray(16);
this._debugCamera = null;
this._app = app;
// NOTE: we don't use pool for views (because it's less changed and it doesn't have poolID)
this._views = [];
}
_add(pool, item) {
if (item._poolID !== -1) {
return;
}
pool.push(item);
item._poolID = pool.length - 1;
}
_remove(pool, item) {
if (item._poolID === -1) {
return;
}
pool.data[pool.length-1]._poolID = item._poolID;
pool.fastRemove(item._poolID);
item._poolID = -1;
}
/**
* reset the model viewIDs
*/
reset() {
for (let i = 0; i < this._models.length; ++i) {
let model = this._models.data[i];
model._viewID = -1;
}
}
/**
* Set the debug camera
* @param {Camera} cam the debug camera
*/
setDebugCamera(cam) {
this._debugCamera = cam;
}
/**
* Get the count of registered cameras
* @returns {number} camera count
*/
getCameraCount() {
return this._cameras.length;
}
/**
* Get the specified camera
* @param {number} idx camera index
* @returns {Camera} the specified camera
*/
getCamera(idx) {
return this._cameras.data[idx];
}
/**
* register a camera
* @param {Camera} camera the new camera
*/
addCamera(camera) {
this._add(this._cameras, camera);
}
/**
* remove a camera
* @param {Camera} camera the camera to be removed
*/
removeCamera(camera) {
this._remove(this._cameras, camera);
}
/**
* Get the count of registered model
* @returns {number} model count
*/
getModelCount() {
return this._models.length;
}
/**
* Get the specified model
* @param {number} idx model index
* @returns {Model} the specified model
*/
getModel(idx) {
return this._models.data[idx];
}
/**
* register a model
* @param {Model} model the new model
*/
addModel(model) {
this._add(this._models, model);
}
/**
* remove a model
* @param {Model} model the model to be removed
*/
removeModel(model) {
this._remove(this._models, model);
}
/**
* Get the count of registered light
* @returns {number} light count
*/
getLightCount() {
return this._lights.length;
}
/**
* Get the specified light
* @param {number} idx light index
* @returns {Light} the specified light
*/
getLight(idx) {
return this._lights.data[idx];
}
/**
* register a light
* @param {Light} light the new light
*/
addLight(light) {
this._add(this._lights, light);
}
/**
* remove a light
* @param {Light} light the light to be removed
*/
removeLight(light) {
this._remove(this._lights, light);
}
/**
* register a view
* @param {View} view the new view
*/
addView(view) {
if (this._views.indexOf(view) === -1) {
this._views.push(view);
}
}
/**
* remove a view
* @param {View} view the view to be removed
*/
removeView(view) {
let idx = this._views.indexOf(view);
if (idx !== -1) {
this._views.splice(idx, 1);
}
}
}
export default Scene;