Home Reference Source Repository

js/base/Model.js

'use strict'

import Bone from './Bone'
import Matrix from './Matrix'
import Vector3 from './Vector3'
import RenderGroup from './RenderGroup'

import ObjectAssign from '../etc/ObjectAssign'

/**
 * Model class
 * @access public
 */
export default class Model {
  /**
   * constructor
   * @access public
   * @param {Model} model -
   * @constructor
   */
  constructor(model) {
    this.renderer = null
    this.hashName = ''
    this.loaded = false
    this.onload = null

    // Skin
    this.skinArray = []
    this.dynamicSkinArray = []
    this.dynamicSkinOffset = 0

    // Index
    this.indexArray = []

    // Material
    this.materialArray = []
    // TODO: texture
    // this.toonFileName = []
  
    // Bone
    this.boneArray = []
    this.boneHash = new Map()
    this.rootBone = null

    // IK
    this.ikArray = []

    // RigidBody
    this.rigidBodyArray = []

    // Constraint
    this.constraintArray = []

    // RenderGroup
    this.renderGroupArray = []

    // VertexBuffer
    this.vertexBuffer = null

    if(model instanceof Model){
      model.copy(this)
      return
    }

    // FIXME: 処理が煩雑
    this.rootBone = new Bone()
    this.rootBone.bonePosition = new Vector3(0, 0, 0)
    this.rootBone.localMatrix = new Matrix()
    this.rootBone.initBoneData()
  }

  destroy() {
  }

  /**
   * copy given model data to this model
   * @access public
   * @param {Model} model - source model
   * @returns {void}
   */
  copy(model) {
    this.renderer          = model.renderer
    this.hashName          = model.hashName
    this.skinArray         = model.skinArray
    this.dynamicSkinArray  = model.dynamicSkinArray
    this.dynamicSkinOffset = model.dynamicSkinOffset
    this.indexArray        = model.indexArray
    this.materialArray     = model.materialArray
    this.boneArray         = model.boneArray
    this.boneHash          = model.boneHash
    this.rootBone          = model.rootBone
    this.ikArray           = model.ikArray
    this.rigidBodyArray    = model.rigidBodyArray
    this.constraintArray   = model.constraintArray
    this.renderGroupArray  = model.renderGroupArray
    this.vertexBuffer      = model.vertexBuffer
  }


  cloneForLoading() {
    //const newModel = Object.assign(new this.constructor(), this)
    const newModel = ObjectAssign(new this.constructor(), this)

    return newModel
  }

  clone() {
    const newModel = this.cloneForLoading()

    if(!this.loaded){
      return newModel
    }

    const obj = this

    // clone dynamicSkinArray
    newModel.dynamicSkinArray = []
    // newModel.skinArray = this.skinArray.clone()
    newModel.skinArray = this.skinArray.concat()
    this.dynamicSkinArray.forEach( (skin) => {
      const index = obj.skinArray.indexOf(skin)
      if(index >= 0){
        newModel.skinArray[index] = skin
      }
      newModel.dynamicSkinArray.push(skin)
    })

    // clone Bone
    newModel.boneArray = []
    newModel.boneHash = new Map()

    const oldRootBone = this.rootBone
    const oldBoneHash = this.boneHash

    newModel.rootBone = 
       this.cloneBoneRecursive(this.rootBone, this.boneArray,     this.boneHash,
                                              newModel.boneArray, newModel.boneHash)

    // clone renderGroup
    newModel.renderGroupArray = []
    this.renderGroupArray.forEach( (group) => {
      newModel.renderGroupArray.push(obj.cloneRenderGroup(group, newModel.boneArray))
    })
    
    // clone IK
    newModel.ikArray = []
    this.ikArray.forEach( (ik) => {
      const newIK = ik.clone()
      newIK.targetBone = newModel.boneHash.get(ik.targetBone.name)
      newIK.effectBone = newModel.boneHash.get(ik.effectBone.name)

      newIK.boneList = []
      ik.boneList.forEach( (ikBone) => {
        newIK.boneList.push(newModel.boneHash.get(ikBone.name))
      })
      newModel.ikArray.push(newIK)
    })

    return newModel
  }

  cloneBoneRecursive(bone, oldArray, oldHash, newArray, newHash) {
    const newBone = bone.clone()

    const index = oldArray.indexOf(bone)
    if(index >= 0){
      newArray[index] = newBone
    }

    oldHash.forEach( (value, key) => {
      if(value === bone){
        newHash.set(key, newBone)
      }
    })

    const obj = this
    newBone.childBoneArray = []
    bone.childBoneArray.forEach( (cb) => {
      const newChildBone = obj.cloneBoneRecursive(cb, oldArray, oldHash, newArray, newHash)

      newBone.childBoneArray.push(newChildBone)
      newChildBone.parentBone = newBone
    })

    return newBone
  }

  cloneRenderGroup(oldGroup, newBoneArray) {
    //const newGroup = Object.assign(new RenderGroup(), oldGroup)
    const newGroup = ObjectAssign(new RenderGroup(), oldGroup)

    const oldBoneArray = this.boneArray
    newGroup.boneArray = []
    oldGroup.boneArray.forEach( (bone) => {
      const index = oldBoneArray.indexOf(bone)
      if(index >= 0){
        newGroup.boneArray.push(newBoneArray[index])
      }else{
        // error
        newGroup.boneArray.push(null)
      }
    })

    return newGroup
  }

  getSkinArray() {
    return this.skinArray
  }

  getDynamicSkinArray() {
    return this.dynamicSkinArray
  }

}