import { Utils } from '../common/Utils';
import { MathUtils } from '../math/MathUtils';
import { NodeObject } from './NodeObject';
import { Style } from '../resources/Style';
import { StyleModifier } from '../resources/StyleModifier';
const __ = {
private: Symbol('private'),
}
let _vec3 = MathUtils.createVec3();
let _scale = MathUtils.createVec3();
let _quat = MathUtils.createQuat();
let _mat4 = MathUtils.createMat4();
let _identity = MathUtils.createMat4();
let _axis = [0, 0, 0];
const _defaultOptions = {};
/**
* BodyObject - 自身对象
*
* 负责管理对象的可渲染节点及变换。
*
* @class BodyObject
* @memberof THING
* @public
*/
class BodyObject {
/**
* 自身对象类,负责管理对象的可渲染节点及变换
*/
constructor() {
this[__.private] = {};
let _private = this[__.private];
_private.app = null;
_private.node = null;
_private.object = null;
_private.pivotNode = null;
_private.rootNode = null;
_private.renderableNode = null;
_private.style = null;
_private.sharedStyle = null;
}
// #region Private
_createParentNode(name, node, isKeepTransform = true) {
const _private = this[__.private];
// Create parent node
let parentNode = Utils.createObject('Node', { app: _private.app });
parentNode.setName(name);
parentNode.setAttribute('MatrixUpdateMode', node.getAttribute('MatrixUpdateMode'));
// Link to root node
if (node.getParent()) {
node.getParent().add(parentNode);
}
// Keep transform
if (isKeepTransform) {
parentNode.setMatrix(node.getMatrix(_mat4));
node.setMatrix(_identity);
}
parentNode.add(node);
// Copy user data
let toUserData = parentNode.getUserData();
let fromUserData = node.getUserData();
for (let key in fromUserData) {
toUserData[key] = fromUserData[key];
}
return parentNode;
}
_updateNode() {
let _private = this[__.private];
_private.node = _private.rootNode || _private.pivotNode || _private.renderableNode;
}
_updateNodeOptions(options = _defaultOptions) {
let _private = this[__.private];
let renderableNode = _private.renderableNode;
// Set the local scale
let localScale = options['localScale'];
if (localScale) {
if (localScale[0] != 1 || localScale[1] != 1 || localScale[2] != 1) {
this.createRootNode();
MathUtils.vec3.multiply(_vec3, renderableNode.getScale(_vec3), localScale);
renderableNode.setScale(_vec3);
}
}
// Set the local position(offset)
let localPosition = options['localPosition'];
if (localPosition) {
if (localPosition[0] != 0 || localPosition[1] != 0 || localPosition[2] != 0) {
this.createRootNode();
MathUtils.vec3.add(_vec3, renderableNode.getPosition(_vec3), localPosition)
renderableNode.setPosition(_vec3);
}
}
// Set the local angles
let localAngles = options['localAngles'];
if (localAngles) {
if (localAngles[0] != 0 || localAngles[1] != 0 || localAngles[2] != 0) {
this.createRootNode();
MathUtils.quat.multiply(_quat, renderableNode.getQuaternion(_quat), MathUtils.getQuatFromAngles(localAngles));
renderableNode.setQuaternion(_quat);
}
}
}
_getNodeByName(name, rootNode, filter, complete) {
let _private = this[__.private];
let nodes = this._getSubNodes(_private.renderableNode, rootNode);
for (let i = 0; i < nodes.length; i++) {
let node = nodes[i];
if (filter) {
if (!filter(node)) {
continue;
}
}
if (node.name == name) {
if (complete) {
return complete(node);
}
else {
return node;
}
}
}
return null;
}
// #endregion
// #region BaseComponent
dispose() {
let _private = this[__.private];
// Unbind sub node for renderable node
let renderableNode = this.getRenderableNode();
if (renderableNode) {
renderableNode.unbindSubNode();
}
// Unapply current style
if (_private.style) {
_private.style.dispose();
_private.style = null;
}
if (_private.rootNode) {
_private.rootNode.dispose();
}
else if (_private.pivotNode) {
_private.pivotNode.dispose();
}
else if (_private.renderableNode) {
_private.renderableNode.dispose();
}
if (_private.sharedStyle) {
_private.sharedStyle.release();
_private.sharedStyle = null;
}
_private.rootNode = null;
_private.pivotNode = null;
_private.renderableNode = null;
_private.node = null;
_private.object = null;
}
// #endregion
init(object, options = _defaultOptions) {
let _private = this[__.private];
_private.object = object;
_private.app = object.app;
let node = options['node'];
let rootNode = options['rootNode'];
let renderableNode = options['renderableNode'];
let nodeType = options['nodeType'] || 'Node';
if (rootNode || renderableNode) {
_private.rootNode = rootNode;
_private.renderableNode = renderableNode || rootNode;
}
else {
let app = object.app;
let nodePool = app.resourceManager.getNodePool();
_private.renderableNode = nodePool ? nodePool.alloc() : Utils.createObject(nodeType, { app });
if (node) {
_private.renderableNode.add(node);
}
}
// Update current node
this._updateNode();
// Update node options
let bodyOptions = options['body'];
if (bodyOptions) {
this._updateNodeOptions(bodyOptions);
}
// Bind renderable node with object
let userData = _private.node.getUserData();
userData['baseObject_orderID'] = _private.object.orderId;
}
translateOnAxis(axis, distance) {
MathUtils.vec3.normalize(_axis, axis);
MathUtils.vec3.transformQuat(_vec3, _axis, this.localQuaternion);
MathUtils.vec3.scale(_vec3, _vec3, distance);
let position = this.localPosition;
this.localPosition = MathUtils.addVector(position, _vec3);
}
translateX(distance) {
this.translateOnAxis(Utils.xAxis, distance);
}
translateY(distance) {
this.translateOnAxis(Utils.yAxis, distance);
}
translateZ(distance) {
this.translateOnAxis(Utils.zAxis, distance);
}
// #region State
/**
* 获取/设置可见状态。
* @type {boolean}
* @example
* let object = new THING.Object3D();
* let ret = object.body.visible == true;
* // @expect(ret == true)
* object.body.visible = false;
* ret = object.body.visible == false;
* // @expect(ret == true)
* @public
*/
get visible() {
let _private = this[__.private];
return _private.renderableNode.getVisible();
}
set visible(value) {
let _private = this[__.private];
_private.renderableNode.setVisible(value);
}
// #endregion
// #region Transform
/**
* 获取/设置父空间的本地(偏移)位置。
* @type {Array<number>}
* @example
* let object = new THING.Object3D();
* let ret = object.body.localPosition[1] == 0;
* // @expect(ret == true)
* object.body.localPosition = [0, 10, 0];
* ret = object.body.localPosition[1] == 10;
* // @expect(ret == true)
* @public
*/
get localPosition() {
let _private = this[__.private];
let target = [0, 0, 0];
return _private.renderableNode.getPosition(target);
}
set localPosition(value) {
let _private = this[__.private];
this.createRootNode();
_private.renderableNode.setPosition(value);
}
/**
* 获取/设置惯性空间的四元数。
* @type {Array<number>}
* @example
* let object = new THING.Object3D();
* let ret = object.body.localQuaternion[1] == 0;
* // @expect(ret == true)
* object.body.localQuaternion = [0, 10, 0, 1];
* ret = object.body.localQuaternion[1] == 10;
* // @expect(ret == true)
* object.body.localQuaternion = [0, 10, 0, 1];
* @public
*/
get localQuaternion() {
let _private = this[__.private];
let target = [0, 0, 0, 1]
return _private.renderableNode.getQuaternion(target);
}
set localQuaternion(value) {
let _private = this[__.private];
this.createRootNode();
_private.renderableNode.setQuaternion(value);
}
get quaternion() {
let _private = this[__.private];
let target = [0, 0, 0, 1]
return _private.renderableNode.getWorldQuaternion(target);
}
set quaternion(value) {
let _private = this[__.private];
this.createRootNode();
_private.renderableNode.setWorldQuaternion(value);
}
/**
* 获取/设置惯性空间的旋转。
* 欧拉角('XYZ'),单位为 degree(度)。
* @type {Array<number>}
* @example
* let object = new THING.Object3D();
* let ret = object.body.localRotation[1] == 0;
* // @expect(ret == true)
* object.body.localRotation = [0, 10, 0];
* ret = object.body.localRotation[1] == 10;
* // @expect(ret == true)
* @public
*/
get localRotation() {
return this.localAngles;
}
set localRotation(value) {
this.localAngles = value;
}
/**
* 获取/设置本地角度。
* 欧拉角('XYZ'),单位为 degree(度)。
* @type {Array<number>}
* @public
*/
get localAngles() {
let _private = this[__.private];
let target = [0, 0, 0, 1]
return MathUtils.getAnglesFromQuat(_private.renderableNode.getQuaternion(target));
}
set localAngles(value) {
let _private = this[__.private];
this.createRootNode();
_private.renderableNode.setQuaternion(MathUtils.getQuatFromAngles(value));
}
/**
* 获取/设置自身坐标系的缩放。
* @type {Array<number>}
* @example
* let object = new THING.Object3D();
* let ret = object.body.localScale[1] == 1;
* // @expect(ret == true)
* object.body.localScale = [10, 10, 10];
* ret = object.body.localScale[1] == 10;
* // @expect(ret == true)
* @public
*/
get localScale() {
let _private = this[__.private];
let target = [1, 1, 1];
return _private.renderableNode.getScale(target);
}
set localScale(value) {
let _private = this[__.private];
this.createRootNode();
_private.renderableNode.setScale(value);
// Update privot
if (_private.pivotNode) {
_private.object.setPivot(_private.object.pivot)
}
}
/**
* 获取/设置世界坐标系的位置。
* @type {Array<number>}
* @example
* let object = new THING.Object3D();
* let ret = object.body.position[1] == 0;
* // @expect(ret == true)
* object.body.position = [10, 10, 10];
* ret = object.body.position[1] == 10;
* // @expect(ret == true)
* @public
*/
get position() {
let _private = this[__.private];
let target = [0, 0, 0];
return _private.renderableNode.getWorldPosition(target);
}
set position(value) {
let _private = this[__.private];
this.createRootNode();
_private.renderableNode.setWorldPosition(value);
}
/**
* 获取/设置世界空间的旋转。
* 欧拉角('XYZ'),单位为 degree(度)。
* @type {Array<number>}
* @example
* let object = new THING.Object3D();
* let ret = object.body.rotation[1] == 0;
* // @expect(ret == true)
* object.body.rotation = [10, 10, 10];
* ret = object.body.rotation[1] == 10;
* // @expect(ret == true)
* @public
*/
get rotation() {
return this.angles;
}
set rotation(value) {
this.angles = value;
}
/**
* 获取/设置世界角度。
* 欧拉角('XYZ'),单位为 degree(度)。
* @type {Array<number>}
* @public
*/
get angles() {
let _private = this[__.private];
let target = [0, 0, 0, 1]
return MathUtils.getAnglesFromQuat(_private.renderableNode.getWorldQuaternion(target));
}
set angles(value) {
let _private = this[__.private];
this.createRootNode();
_private.renderableNode.setWorldQuaternion(MathUtils.getQuatFromAngles(value));
}
/**
* 获取/设置世界坐标系的缩放。
* @type {Array<number>}
* @example
* let object = new THING.Object3D();
* let ret = object.body.scale[1] == 1;
* // @expect(ret == true)
* object.body.scale = [10, 10, 10];
* ret = object.body.scale[1] == 10;
* // @expect(ret == true)
* @public
*/
get scale() {
let _private = this[__.private];
let target = [1, 1, 1];
return _private.renderableNode.getWorldScale(target);
}
set scale(value) {
let _private = this[__.private];
this.createRootNode();
_private.renderableNode.setWorldScale(value);
// Update privot
if (_private.pivotNode) {
_private.object.setPivot(_private.object.pivot)
}
}
/**
* 获取/设置变换矩阵。
* @type {Array<number>}
* @example
* let object = new THING.Object3D();
* let ret = object.body.matrix[12] == 0;
* // @expect(ret == true)
* object.body.matrix = THING.Math.mat4.fromTranslation([], [10, 10, 10]);
* ret = object.body.matrix[12] == 10;
* // @expect(ret == true)
* @public
*/
get matrix() {
let _private = this[__.private];
return _private.renderableNode.getMatrix();
}
set matrix(value) {
let _private = this[__.private];
this.createRootNode();
_private.renderableNode.setMatrix(value);
}
/**
* 获取/设置世界变换矩阵。
* @type {Array<number>}
* @example
* let object = new THING.Object3D();
* let ret = object.body.matrixWorld[12] == 0;
* // @expect(ret == true)
* object.body.matrixWorld = THING.Math.mat4.fromTranslation([], [10, 10, 10]);
* ret = object.body.matrixWorld[12] == 10;
* // @expect(ret == true)
* @public
*/
get matrixWorld() {
let _private = this[__.private];
return _private.renderableNode.getMatrixWorld();
}
set matrixWorld(value) {
let _private = this[__.private];
this.createRootNode();
_private.renderableNode.setMatrixWorld(value);
}
// #endregion
// #region BoundingBox
/**
* BoundingBox对象
* @typedef {object} BoundingBoxResult
* @property {Array<number>} center 中心点坐标
* @property {Array<number>} halfSize 包围盒三个轴向尺寸的一半
* @public
*/
/**
* 获取自身的包围盒
* @returns {BoundingBoxResult} 返回包围盒结果
* @example
* var object = new THING.Object3D();
* var boundingBox = object.body.getLocalBoundingBox();
* console.log(boundingBox);
* @public
*/
getLocalBoundingBox() {
const _private = this[__.private];
const boundingComponent = _private.object.bounding;
if (!boundingComponent) {
return {
center: [0, 0, 0],
halfSize: [Number.EPSILON, Number.EPSILON, Number.EPSILON]
};
}
const result = boundingComponent.getSelfBoundingBox();
return result;
}
// #endregion
// #region Resource
/**
* Create the root node.
* @private
*/
createRootNode() {
let _private = this[__.private];
if (!_private.rootNode) {
let node = _private.renderableNode;
if (node.isCamera || node.isLight || node.isDecal) {
_private.rootNode = node;
}
else {
_private.rootNode = this._createParentNode('root', node);
}
this._updateNode();
}
}
/**
* Clear pivot node.
* @private
*/
clearPivotNode() {
let _private = this[__.private];
let pivotNode = _private.pivotNode;
if (!pivotNode) {
return;
}
let parentNode = pivotNode.getParent();
if (parentNode) {
let children = pivotNode.getChildren().slice(0);
children.forEach(child => {
child.setPosition([0, 0, 0]);
parentNode.add(child);
});
parentNode.remove(pivotNode);
}
pivotNode.dispose();
_private.pivotNode = null;
this._updateNode();
}
/**
* Create pivot node.
* @private
*/
createPivotNode() {
let _private = this[__.private];
if (!_private.pivotNode) {
let node = _private.renderableNode;
_private.pivotNode = this._createParentNode('pivot', node, false);
this._updateNode();
}
return _private.pivotNode;
}
/**
* Get the pivot node.
* @type {object}
* @private
*/
getPivotNode() {
return this[__.private].pivotNode;
}
/**
* Get the root node.
* @type {object}
* @private
*/
getRootNode() {
return this[__.private].rootNode;
}
/**
* Get the renderable node.
* @type {object}
* @private
*/
getRenderableNode() {
return this[__.private].renderableNode;
}
/**
* Get the node.
* @type {object}
* @private
*/
getNode() {
return this[__.private].node;
}
/**
* Set node.
* @param {object} node The node.
* @private
*/
setNode(node) {
let _private = this[__.private];
// Get the renderable node
let renderableNode = _private.renderableNode;
// Get the previous node's matrix to sync
// Becareful: do not use matrix here, due to local angles would be changed by negative scale or some angels value
renderableNode.getPosition(_vec3);
renderableNode.getScale(_scale);
renderableNode.getQuaternion(_quat);
// Get the current states
let curStates = {
parentNode: renderableNode.getParent(),
name: renderableNode.getName(),
userData: renderableNode.getUserData()
};
// Get the current render node stats
if (renderableNode.isRenderableNode) {
if (renderableNode.hasStyle()) {
curStates.style = renderableNode.getStyle();
}
curStates.visible = renderableNode.getVisible();
curStates.renderOrder = renderableNode.getRenderOrder();
curStates.castShadow = renderableNode.getCastShadow();
curStates.receiveShadow = renderableNode.getReceiveShadow();
curStates.layerMask = renderableNode.getLayerMask();
}
let app = _private.object.app;
// Dispose current node
let nodePool = app.resourceManager.getNodePool();
if (nodePool) {
nodePool.free(renderableNode);
}
else {
renderableNode.dispose();
}
// Update node
renderableNode = node;
_private.renderableNode = node;
// Resume matrix
renderableNode.setPosition(_vec3);
renderableNode.setScale(_scale);
renderableNode.setQuaternion(_quat);
// Relink to parent node
if (curStates.parentNode) {
curStates.parentNode.add(renderableNode);
}
// Resume the states
renderableNode.setName(curStates.name);
renderableNode.setUserData(curStates.userData);
if (renderableNode.isRenderableNode && this.style.resource != node.getStyle()) {
if (curStates.style) {
if (_private.sharedStyle) {
renderableNode.setStyle(_private.sharedStyle.resource);
}
else {
if (this.style.isChanged) {
let cloneStyle = curStates.style.clone();
let oriStyle = renderableNode.getStyle();
this.style.initResource(oriStyle);
this.style.updateResource(cloneStyle);
}
else {
let oriStyle = renderableNode.getStyle();
this.style.initResource(oriStyle);
this.style.updateResource(oriStyle);
}
}
}
renderableNode.setVisible(curStates.visible);
if (renderableNode.getRenderOrder() != curStates.renderOrder) {
renderableNode.setRenderOrder(curStates.renderOrder);
}
if (renderableNode.getCastShadow() != curStates.castShadow) {
renderableNode.setCastShadow(curStates.castShadow);
}
if (renderableNode.getReceiveShadow() != curStates.receiveShadow) {
renderableNode.setReceiveShadow(curStates.receiveShadow);
}
if (renderableNode.getLayerMask() != curStates.layerMask) {
renderableNode.setLayerMask(curStates.layerMask);
}
}
this._updateNode();
}
/**
* Just update node.
* @param {object} node The node.
* @private
*/
updateNode(node) {
let _private = this[__.private];
_private.renderableNode = node;
this._updateNode();
}
/**
* Unload resource.
* @param {Function} onCreateBodyNode When create body node callback function.
* @private
*/
unloadResource(onCreateBodyNode) {
let _private = this[__.private];
let renderableNode = _private.renderableNode;
if (!renderableNode) {
return;
}
// Get the user data and prepare to resume
let userData = renderableNode.getUserData();
// Get some useful info and wait to resume
let parentNode = renderableNode.getParent();
let visible = renderableNode.getVisible();
let type = renderableNode.getType();
let name = renderableNode.getName();
let matrix = renderableNode.getMatrix(_mat4);
// Get style
let style;
if (renderableNode.isRenderableNode) {
style = renderableNode.getStyle();
}
// Destroy renderable node
renderableNode.dispose();
// Recreate renderable node
renderableNode = onCreateBodyNode(type);
renderableNode.setName(name);
// Resume info
parentNode.add(renderableNode);
renderableNode.setMatrix(matrix);
renderableNode.setUserData(userData);
renderableNode.setVisible(visible);
if (style) {
renderableNode.setStyle(style);
}
// Update renderable node
_private.renderableNode = renderableNode;
// Update node
this._updateNode();
}
getGeometryInfo() {
return this.getRenderableNode().getGeometryInfo();
}
// #endregion
// #region SubNodes
/**
* @callback TraverseNodesCallback
* @param {NodeObject} nodeObject 子节点对象
* @public
*/
/**
* 遍历所有子节点
* @param {TraverseNodesCallback} callback 遍历回调函数
* @example
* object.traverseNodes(node => {
* console.log(node.name);
* let pos = node.position;
* let angles = node.angles;
* let scale = node.scale;
* console.log(pos, angles, scale);
* });
*/
traverseNodes(callback) {
let _private = this[__.private];
let target = this._getSubNodes(_private.renderableNode, _private.node);
target.forEach(node => {
let nodeObject = new NodeObject({
renderableNode: _private.renderableNode,
node
});
callback(nodeObject);
});
}
/**
* 获取所有子节点, 并按节点深度排序
* @type {Array<NodeObject>}
* @public
* @example
* let nodes = object.nodes;
* nodes.forEach(node => {
* console.log(node.name);
* let pos = node.position;
* let angles = node.angles;
* let scale = node.scale;
* console.log(pos, angles, scale);
* });
*/
get nodes() {
let _private = this[__.private];
let target = this._getSubNodes(_private.renderableNode, _private.node);
let subNodes = target.sort(function (a, b) {
return b.depth - a.depth;
}).map(node => {
return new NodeObject({
renderableNode: _private.renderableNode,
node
});
});
return subNodes;
}
/**
* Get the renderable nodes sorted by node depth.
* @type {Array<NodeObject>}
* @private
*/
get renderableNodes() {
let _private = this[__.private];
let target = this._getSubNodes(_private.renderableNode, _private.node);
let subNodes = target.filter(node => {
return node.isRenderable;
}).sort(function (a, b) {
return b.depth - a.depth;
}).map(node => {
return new NodeObject({
renderableNode: _private.renderableNode,
node
});
});
return subNodes;
}
_getSubNodes(renderableNode, rootNode) {
if (!renderableNode.isRenderableNode) {
return [];
}
let subNodes = [];
let name = renderableNode.getName();
renderableNode.getSubNodes(subNodes, rootNode, true);
return subNodes.filter(subNode => {
return subNode.name !== name;
})
}
/**
* 获取子节点名称的集合,根据节点的层级深度排列
* @type {Array<string>}
* @public
*/
get nodeNames() {
let _private = this[__.private];
// Use 'null' to skip matrix calculation
let subNodes = this._getSubNodes(_private.renderableNode, null);
let names = subNodes.sort(function (a, b) {
return b.depth - a.depth;
}).map(node => {
return node.name;
});
return names;
}
/**
* 检查是否有子节点。
* @param {string} name 节点名称。
* @returns {boolean} 如果有子节点返回true,否则返回false。
* @public
* @example
* let hasSubNode = bodyObject.hasNode('subNodeName');
* if (hasSubNode) {
* console.log('存在子节点。');
* } else {
* console.log('不存在子节点。');
* }
*/
hasNode(name) {
let node = this._getNodeByName(name, null);
if (!node) {
return false;
}
return true;
}
/**
* 根据名称获取子节点结果。
* @param {string} name 节点名称。
* @returns {NodeObject} 返回一个NodeObject对象。
* @public
* @example
* let node = bodyObject.getNodeByName('subNodeName');
* if (node) {
* console.log('找到子节点。');
* } else {
* console.log('未找到子节点。');
* }
*/
getNodeByName(name) {
let _private = this[__.private];
return this._getNodeByName(name, _private.node, null,
(node) => {
return new NodeObject({
renderableNode: _private.renderableNode,
node
});
}
);
}
/**
* Promote node to object.
* @param {string} name The node name.
* @param {object} parentNode The parent node.
* @param {UStyle} nodeUStyle The sub node style.
* @returns {object}
* @private
*/
promoteNode(name, parentNode, nodeUStyle) {
let _private = this[__.private];
// Find sub node by name
let node = this._getNodeByName(name, null);
if (!node) {
return null;
}
// clear subnode materal
_private.renderableNode.clearAllSubNodeMaterials();
// clear subnode effect
_private.renderableNode.clearAllSubNodeEffects();
// Attach sub node to parent
const unode = parentNode.attachSubNode(node, nodeUStyle, (ustyle) => {
_private.object.body.style.updateResource(ustyle)
});
return unode
}
// #endregion
// #region Style
hasStyle() {
let _private = this[__.private];
return !!_private.style;
}
getStyle() {
let _private = this[__.private];
if (!_private.style) {
let bodyNode = this.getRenderableNode();
if (!bodyNode.isRenderableNode) {
return null;
}
_private.style = new Style(new StyleModifier(_private.object));
}
return _private.style;
}
setStyle(value) {
if (!value) {
return;
}
let style = this.getStyle();
if (style == value) {
return;
}
style.copy(value);
}
/**
* Get/Set style of body.
* @type {THING.Style}
* @example
* let object = new THING.Object3D();
* let style = object.body.style;
* style.color = 'red';
* style.opacity = 0.1;
* let ret = object.body.style.color[0] == 1;
* // @expect(ret == true)
* ret = object.body.style.opacity == 0.1;
* // @expect(ret == true)
*/
get style() {
return this.getStyle();
}
set style(value) {
this.setStyle(value);
}
clearAllSubNodeMaterials() {
let _private = this[__.private];
if (_private.renderableNode) {
_private.renderableNode.clearAllSubNodeMaterials();
}
}
/**
* Get/Set sharedStyle of body.
* @type {THING.SharedStyle}
* @example
* let obj1 = new THING.Box({
* position: [0, 0, 0],
* });
* let obj2 = new THING.Box({
* position: [2, 0, 0],
* });
* let sharedStyle = new THING.SharedStyle({
* color: 'red',
* opacity: 0.5,
* wireframe: true,
* })
* obj1.body.sharedStyle = sharedStyle;
* obj2.body.sharedStyle = sharedStyle;
*/
get sharedStyle() {
const _private = this[__.private];
return _private.sharedStyle
}
set sharedStyle(style) {
const _private = this[__.private];
const oldSharedStyle = this.sharedStyle;
if (style === oldSharedStyle) {
return;
}
if (oldSharedStyle && (!style || style !== oldSharedStyle)) {
oldSharedStyle.removeObject(_private.object);
oldSharedStyle.release();
}
if (style) {
style.addRef();
style.addObject(_private.object);
_private.renderableNode.setStyle(style.resource);
_private.sharedStyle = style;
}
else {
_private.sharedStyle && _private.renderableNode.setStyle(this.style.resource);
_private.sharedStyle = null;
}
}
// #endregion
// #region Attach
// A.Attach(B) Means B attch to A, B as a child Node of A
// 目前这个接口产生的对象变化不支持保存,只能在运行时用
attach(body, name) {
let _private = this[__.private];
// 创建rootNode-renderableRoot-renderableNode结构
this.createRootNode();
let node = _private.renderableNode
if (node.isRenderableNode && node.getName() != 'renderableRoot') {
_private.renderableNode = this._createParentNode('renderableRoot', node);
}
// 将body的renderableNode挂在renderableRoot下
let oriRenderableNode = body.getRenderableNode()
let oriParent = oriRenderableNode.getParent();
let oriMatrixWorld = oriRenderableNode.getMatrixWorld();
_private.renderableNode.add(oriRenderableNode);
oriRenderableNode.setMatrixWorld(oriMatrixWorld);
if (name) {
// temp: 因为setName的接口修改,此处直接修改_node.name
oriRenderableNode._node.name = name;
}
// 特殊处理
// saveToDefault:保证被attach对象的style不被覆盖
// 清空baseObject_orderID:避免鼠标点击拾取到原对象
oriRenderableNode.$traverse(item => {
item.getStyle().saveToDefault();
})
let userData = oriRenderableNode.getUserData();
if (userData && userData['baseObject_orderID']) {
delete userData['baseObject_orderID'];
}
oriRenderableNode.setUserData(userData);
// 将body的renderableNode设置为新Node
let newRenderableNode = Utils.createObject('Node', { app: this.app });
oriParent.add(newRenderableNode);
body.updateNode(newRenderableNode);
body.style.replaceResource(newRenderableNode.getStyle())
}
// #endregion
}
export {
BodyObject
}