import { MathUtils } from '../math/MathUtils';
let _position = MathUtils.createVec3();
let _scale = MathUtils.createVec3();
let _quat_0 = MathUtils.createQuat();
let _quat_1 = MathUtils.createQuat();
let _angles = MathUtils.createVec3();
let _mat4_0 = MathUtils.createMat4();
let _mat4_1 = MathUtils.createMat4();
let _mat4_2 = MathUtils.createMat4();
/**
* @class NodeObject
* The node object.
* @memberof THING
* @public
*/
class NodeObject {
/**
* The sub node object that to get meshes from renderable object in scene.
* @param {Object} param The initial parameters.
*/
constructor(param = {}) {
let node = param['node'];
let renderableNode = param['renderableNode'];
this._name = node.name;
this._position = [];
this._quaternion = [];
this._scale = [];
MathUtils.decomposeFromMat4(node.matrix, this._position, this._quaternion, this._scale);
this._renderableNode = renderableNode;
this._node = node;
}
// #region Private
_updateMatrix() {
let node = this._node;
let matrix = MathUtils.composeToMat4(this._position, this._quaternion, this._scale, _mat4_0);
this._renderableNode.setSubNodeMatrix(node, matrix);
}
// #endregion
// #region Coordinates Transform
/**
* Convert local position to self position.
* @param {Array<Number>} position The local position.
* @param {Boolean} [ignoreScale=false] True indicates ignore scale factor.
* @returns {Array<Number>}
* @public
*/
localToSelf(position, ignoreScale = false) {
let worldPosition = this.localToWorld(position, ignoreScale);
return this.worldToSelf(worldPosition, ignoreScale);
}
/**
* Convert self position to local position.
* @param {Array<Number>} position The self position.
* @param {Boolean} [ignoreScale=false] True indicates ignore scale factor.
* @returns {Array<Number>}
* @public
*/
selfToLocal(position, ignoreScale = false) {
let worldPosition = this.selfToWorld(position, ignoreScale);
return this.worldToLocal(worldPosition, ignoreScale);
}
/**
* Convert world position to self position.
* @param {Array<Number>} position The world position.
* @param {Boolean} [ignoreScale=false] True indicates ignore scale factor.
* @returns {Array<Number>}
* @public
*/
worldToSelf(position, ignoreScale = false) {
return MathUtils.worldToSelf(this.matrixWorld, position, ignoreScale);
}
/**
* Convert self position to world position.
* @param {Array<Number>} position The self position.
* @param {Boolean} [ignoreScale=false] True indicates ignore scale factor.
* @returns {Array<Number>}
* @public
*/
selfToWorld(position, ignoreScale = false) {
return MathUtils.selfToWorld(this.matrixWorld, position, ignoreScale);
}
/**
* Convert local position to world position.
* @param {Array<Number>} position The local position.
* @param {Boolean} [ignoreScale=false] True indicates ignore scale factor.
* @returns {Array<Number>}
* @public
*/
localToWorld(position, ignoreScale = false) {
let root = this._node.root;
if (root) {
return root.selfToWorld(_position, position, ignoreScale);
}
else {
return position;
}
}
/**
* Convert world position to local position.
* @param {Array<Number>} position The world position.
* @param {Boolean} [ignoreScale=false] True indicates ignore scale factor.
* @returns {Array<Number>}
* @public
*/
worldToLocal(position, ignoreScale = false) {
let root = this._node.root;
if (root) {
return root.worldToSelf(_position, position, ignoreScale);
}
else {
return position;
}
}
// #endregion
// #region Common
get name() {
return this._name;
}
get node() {
return this._node;
}
get isRenderable() {
return !!this._node.isRenderable;
}
// #endregion
// #region Transform
rotateX(angle) {
let quat = MathUtils.getQuatFromAngles([angle, 0, 0]);
MathUtils.quat.multiply(quat, this._quaternion, quat);
this.localQuaternion = quat;
}
rotateY(angle) {
let quat = MathUtils.getQuatFromAngles([0, angle, 0]);
MathUtils.quat.multiply(quat, this._quaternion, quat);
this.localQuaternion = quat;
}
rotateZ(angle) {
let quat = MathUtils.getQuatFromAngles([0, 0, angle]);
MathUtils.quat.multiply(quat, this._quaternion, quat);
this.localQuaternion = quat;
}
/**
* Get the up direction of world space.
* @type {Array<Number>}
* @private
*/
get up() {
const matrixWorld = this.matrixWorld;
return MathUtils.normalizeVector([matrixWorld[4], matrixWorld[5], matrixWorld[6]]);
}
/**
* Get the forward direction in world space.
* @type {Array<Number>}
* @private
*/
get forward() {
const matrixWorld = this.matrixWorld;
return MathUtils.normalizeVector([matrixWorld[8], matrixWorld[9], matrixWorld[10]]);
}
/**
* Get the cross direction in world space.
* @type {Array<Number>}
* @private
*/
get cross() {
let up = this.up;
let forward = this.forward;
let target = [0, 0, 0];
MathUtils.vec3.cross(target, up, forward);
MathUtils.vec3.normalize(target, target);
return target;
}
/**
* Get/Set local position.
* @type {Array<Number>}
* @example
* object.body.nodes[0].localPosition = [10, 10, 10];
* @public
*/
get localPosition() {
return this._position;
}
set localPosition(value) {
this._position = value.slice(0);
this._updateMatrix();
}
/**
* Get/Set local quaternion.
* @type {Array<Number>}
* @example
* object.body.nodes[0].localQuaternion = THING.Math.getQuatFromAngles([45, 45, 45]);
* @public
*/
get localQuaternion() {
return this._quaternion;
}
set localQuaternion(value) {
this._quaternion = value.slice(0);
this._updateMatrix();
}
/**
* Get/Set local angles.
* @type {Array<Number>}
* @example
* object.body.nodes[0].localAngles = [45, 45, 45];
* @public
*/
get localAngles() {
return MathUtils.getAnglesFromQuat(this.localQuaternion, _angles);
}
set localAngles(value) {
this.localQuaternion = MathUtils.getQuatFromAngles(value, _quat_1);
}
/**
* Get/Set local scale.
* @type {Array<Number>}
* @example
* object.body.nodes[0].localScale = [3, 3, 3];
* @public
*/
get localScale() {
return this._scale;
}
set localScale(value) {
this._scale = value.slice(0);
this._updateMatrix();
}
/**
* Get/Set world position.
* @type {Array<Number>}
* @example
* object.body.nodes[0].position = [10, 10, 10];
* @public
*/
get position() {
MathUtils.decomposeFromMat4(this.matrixWorld, _position, _quat_0, _scale);
return _position;
}
set position(value) {
MathUtils.decomposeFromMat4(this.matrixWorld, _position, _quat_0, _scale);
let matrixWorld = MathUtils.composeToMat4(value, _quat_0, _scale, _mat4_2);
this.matrixWorld = matrixWorld;
}
/**
* Get/Set world quaternion.
* @type {Array<Number>}
* @example
* object.body.nodes[0].quaternion = THING.Math.getQuatFromAngles([45, 45, 45]);
* @public
*/
get quaternion() {
MathUtils.decomposeFromMat4(this.matrixWorld, _position, _quat_0, _scale);
return _quat_0;
}
set quaternion(value) {
MathUtils.decomposeFromMat4(this.matrixWorld, _position, _quat_0, _scale);
let matrixWorld = MathUtils.composeToMat4(_position, value, _scale, _mat4_2);
this.matrixWorld = matrixWorld;
}
/**
* Get/Set world angles.
* @type {Array<Number>}
* @example
* object.body.nodes[0].angles = [45, 45, 45];
* @public
*/
get angles() {
return MathUtils.getAnglesFromQuat(this.quaternion, _angles);
}
set angles(value) {
this.quaternion = MathUtils.getQuatFromAngles(value, _quat_1);
}
/**
* Get/Set world rotation.
* @type {Array<Number>}
* @example
* object.body.nodes[0].rotation = [45, 45, 45];
* @public
*/
get rotation() {
return MathUtils.getAnglesFromQuat(this.quaternion, _angles);
}
set rotation(value) {
this.quaternion = MathUtils.getQuatFromAngles(value, _quat_1);
}
/**
* Get/Set world scale.
* @type {Array<Number>}
* @example
* object.body.nodes[0].scale = [3, 3, 3];
* @public
*/
get scale() {
MathUtils.decomposeFromMat4(this.matrixWorld, _position, _quat_0, _scale);
return _scale;
}
set scale(value) {
MathUtils.decomposeFromMat4(this.matrixWorld, _position, _quat_0, _scale);
let matrixWorld = MathUtils.composeToMat4(_position, _quat_0, value, _mat4_2);
this.matrixWorld = matrixWorld;
}
/**
* Get/Set matrix.
* @type {Array<Number>}
* @example
* object.body.nodes[0].matrix = THING.Math.composeToMat4([10, 10, 10], [0, 0, 0, 1], [2, 2, 2]);
* @public
*/
get matrix() {
let node = this._node;
return node.matrix;
}
set matrix(value) {
let node = this._node;
this._renderableNode.setSubNodeMatrix(node, value);
MathUtils.decomposeFromMat4(value, this._position, this._quaternion, this._scale);
}
/**
* Get/Set matrix world.
* @type {Array<Number>}
* @example
* object.body.nodes[0].matrixWorld = THING.Math.composeToMat4([10, 10, 10], [0, 0, 0, 1], [2, 2, 2]);
* @public
*/
get matrixWorld() {
let node = this._node;
let root = node.root;
root.updateMatrixWorld();
root.getMatrixWorld(_mat4_0);
return MathUtils.mat4.multiply(_mat4_0, _mat4_0, node.matrix).slice(0);
}
set matrixWorld(value) {
let node = this._node;
let root = node.root;
root.updateMatrixWorld();
root.getMatrixWorld(_mat4_0);
MathUtils.mat4.invert(_mat4_1, _mat4_0);
MathUtils.mat4.multiply(_mat4_1, _mat4_1, value);
this._renderableNode.setSubNodeMatrix(node, _mat4_1);
MathUtils.decomposeFromMat4(_mat4_1, this._position, this._quaternion, this._scale);
}
// #endregion
get isSubNodeObject() {
Utils.warn(`Please use .isNodeObject`);
return true;
}
get isNodeObject() {
return true;
}
}
export { NodeObject }