Source: core/Skeleton.js

import Class from './Class';
import math from '../math/math';


/**
 * 骨架
 * @class
 */
const Skeleton = Class.create(/** @lends Skeleton.prototype */ {
    /**
     * @default true
     * @type {Boolean}
     */
    isSkeleton: true,

    /**
     * @default Skeleton
     * @type {String}
     */
    className: 'Skeleton',

    /**
     * 用户数据
     * @default null
     * @type {any}
     */
    userData: null,

    /**
     * @constructs
     * @param {Object} [params] 创建对象的属性参数。可包含此类的所有属性。
     */
    constructor(params) {
        /**
         * id
         * @default math.generateUUID('Skeleton')
         * @type {String}
         */
        this.id = math.generateUUID(this.className);

        /**
         * @default []
         * @type {Node[]}
         */
        this.jointNodeList = [];
        /**
         * @default []
         * @type {string[]}
         */
        this.jointNames = [];
        /**
         * @default []
         * @type {Matrix4[]}
         */
        this.inverseBindMatrices = [];
        Object.assign(this, params);
    },

    /**
     * 关节数量
     * @readOnly
     * @type {Number}
     */
    jointCount: {
        get() {
            return this.jointNodeList.length;
        }
    },

    /**
     * @private
     * @type {Node}
     */
    _rootNode: null,
    /**
     * 设置根节点
     * @type {Node}
     */
    rootNode: {
        get() {
            return this._rootNode;
        },
        set(rootNode) {
            this._rootNode = rootNode;
            if (rootNode) {
                this._initJointNodeList();
            }
        }
    },

    /**
     * @private
     */
    _initJointNodeList() {
        const map = {};
        this.rootNode.traverse((node) => {
            map[node.jointName] = node;
        });

        this.jointNodeList = this.jointNames.map((name) => {
            return map[name];
        });
    },

    /**
     * 用新骨骼的 node name 重设 jointNames
     * @param  {Skeleton} skeleton 新骨架
     */
    resetJointNamesByNodeName(skeleton) {
        const jointNames = this.jointNames;
        this.jointNodeList.forEach((jointNode, index) => {
            const mainJointNode = skeleton.rootNode.getChildByName(jointNode.name);
            if (mainJointNode) {
                jointNames[index] = mainJointNode.jointName;
            }
        });
    },

    /**
     * clone
     * @param {Node} [rootNode]
     * @return {Skeleton}
     */
    clone(rootNode) {
        const skeleton = new Skeleton();
        skeleton.copy(this, rootNode);
        return skeleton;
    },

    /**
     * copy
     * @param  {Skeleton} skeleton
     * @param {Node} [rootNode]
     * @return {Skeleton} this
     */
    copy(skeleton, rootNode) {
        this.inverseBindMatrices = skeleton.inverseBindMatrices;
        this.jointNames = skeleton.jointNames.slice();
        if (rootNode === undefined) {
            rootNode = skeleton.rootNode;
        }
        this.rootNode = rootNode;
        return this;
    }
});

export default Skeleton;