Object3D.js

import * as glm from 'gl-matrix';
import Vector3 from '../math/Vector3';
import uuid from '../utils/UIID'

class Object3D {
  /**
    * Constructs a new Object3D
    * @property {boolean} visible=true
    * @property {string} uuid
    * @property {object} position
    * @property {object} rotation
    * @property {object} scale
    * @property {object} parent=null
    * @property {array} children
    * @property {array} matrix
    * @property {array} matrixWorld
    * @property {array} positionWorld
    */
  constructor() {
    this.visible = true;
    this.uuid = uuid();

    this._needUpdate = true;

    this.position = new Vector3();

    this.rotation = new Vector3();

    this.scale = new Vector3(1,1,1);

    this.position.onChange(()=> {
      this._needUpdate = true;
      // console.log('cc');
    });
    this.rotation.onChange (() => {
      this._needUpdate = true;
    });
    this.scale.onChange (() => {
      this._needUpdate = true;
    });

    this._matrix = glm.mat4.create();
    this._matrixWorld = glm.mat4.create();
    this._matrixRotation = glm.mat4.create();
    this._matrixScale = glm.mat4.create();
    this._matrixTranslation = glm.mat4.create();
    this._matrixIdentity = glm.mat4.create();

    this.parent = null;
    this.children = [];
  }
  _updateMatrix() {
    if(!this.visible) {
      return;
    }

    glm.mat4.rotateX(this._matrixRotation, this._matrixIdentity, this.rotation.x);
    glm.mat4.rotateY(this._matrixRotation, this._matrixRotation, this.rotation.y);
    glm.mat4.rotateZ(this._matrixRotation, this._matrixRotation, this.rotation.z);

    glm.mat4.scale(this._matrixScale, this._matrixIdentity, this.scale.get());
    glm.mat4.translate(this._matrixTranslation, this._matrixIdentity, this.position.get());

    glm.mat4.mul(this._matrix, this._matrixTranslation, this._matrixRotation);
    glm.mat4.mul(this._matrix, this._matrix, this._matrixScale);
    this._updateMatrixWorld();
    this._needUpdate = false;

  }
  _updateMatrixWorld() {
    if(!this.visible) {
      return;
    }

    if (this.parent) {
      glm.mat4.multiply(this._matrixWorld, this.parent._matrixWorld, this._matrix);
    } else {
      glm.mat4.copy(this._matrixWorld, this._matrix);
    }

    for (let i = 0, l = this.children.length; i < l; i += 1) {
      this.children[i]._updateMatrixWorld();
    }
  }
  get positionWorld() {
    if (!this.parent) return this.position.get();
    return [this.parent.position.x + this.position.x, this.parent.position.y + this.position.y, this.parent.position.z + this.position.z];
  }
  get matrixWorld() {
    if (this._needUpdate) this._updateMatrix();
    return this._matrixWorld;
  }
  get matrix() {
    if (this._needUpdate) this._updateMatrix();
    return this._matrix;
  }
  /**
  * @func  addChild
  * @description  Add a child to the object
  * @param {object} child an Object3D
  * @memberof Object3D.prototype
  */
  addChild(object) {
    if(object.parent) {
      const ndx = object.parent.children.indexOf(this);
      if(ndx >= 0) {
        object.parent.children.splice(ndx, 1);
      }
    }
    object.parent = this;
    this.children.push(object);
  }
}

export default Object3D;