import type { Pose as GLPose , PoseJoint as GLPoseJoint } from '../parsers/gltf2/Pose' ; import type Armature from './Armature.js' ; import type Bone from './Bone.js' ; import { vec3 , quat } from 'gl-matrix' ; import Transform from '../maths/Transform' ; import Vec3Util from '../maths/Vec3Util' ; class Pose { arm ! : Armature ; bones ! : Bone [ ] ; offset = new Transform ( ) ; constructor ( arm ? ) { if ( arm ) { const bCnt = arm . bones . length ; this . bones = new Array ( bCnt ) ; this . arm = arm ; for ( let i = 0 ; i < bCnt ; i ++ ) { this . bones [ i ] = arm . bones [ i ] . clone ( ) ; } this . offset . copy ( this . arm . offset ) ; } } /** Get Bone by Name */ get ( bName ) { const bIdx = this . arm . names . get ( bName ) ; return ( bIdx !== undefined ) ? this . bones [ bIdx ] : null ; } clone ( ) { const bCnt = this . bones . length ; const p = new Pose ( ) ; p . arm = this . arm ; p . bones = new Array ( bCnt ) ; p . offset . copy ( this . offset ) ; for ( let i = 0 ; i < bCnt ; i ++ ) { p . bones [ i ] = this . bones [ i ] . clone ( ) ; } return p ; } setLocalPos ( bone , v ) { const bIdx = ( typeof bone === 'string' ) ? this . arm . names . get ( bone ) : bone ; if ( bIdx != undefined ) vec3 . copy ( this . bones [ bIdx ] . local . pos , v ) ; return this ; } setLocalRot ( bone , v ) { const bIdx = ( typeof bone === 'string' ) ? this . arm . names . get ( bone ) : bone ; if ( bIdx != undefined ) quat . copy ( this . bones [ bIdx ] . local . rot , v ) ; return this ; } fromGLTF2 ( glPose ) { let jnt ; let b ; for ( jnt of glPose . joints ) { b = this . bones [ jnt . index ] ; if ( jnt . rot ) quat . copy ( b . local . rot , jnt . rot as quat ) ; if ( jnt . pos ) vec3 . copy ( b . local . pos , jnt . pos as vec3 ) ; if ( jnt . scl ) vec3 . copy ( b . local . scl , jnt . scl as vec3 ) ; } return this ; } copy ( pose ) { const bLen = this . bones . length ; for ( let i = 0 ; i < bLen ; i ++ ) { this . bones [ i ] . local . copy ( pose . bones [ i ] . local ) ; this . bones [ i ] . world . copy ( pose . bones [ i ] . world ) ; } return this ; } rotLocal ( bone , deg , axis = 'x' ) { const bIdx = ( typeof bone === 'string' ) ? this . arm . names . get ( bone ) : bone ; if ( bIdx != undefined ) { const q = this . bones [ bIdx ] . local . rot ; const rad = deg * Math . PI / 180 ; switch ( axis ) { case 'y' : quat . rotateY ( q , q , rad ) ; break ; case 'z' : quat . rotateZ ( q , q , rad ) ; break ; default : quat . rotateX ( q , q , rad ) ; break ; } } else console . warn ( 'Bone not found, ' , bone ) ; return this ; } moveLocal ( bone , offset ) { const bIdx = ( typeof bone === 'string' ) ? this . arm . names . get ( bone ) : bone ; if ( bIdx != undefined ) { const v = this . bones [ bIdx ] . local . pos ; vec3 . add ( v , v , offset ) ; } else console . warn ( 'Bone not found, ' , bone ) ; return this ; } sclLocal ( bone , v ) { const bIdx = ( typeof bone === 'string' ) ? this . arm . names . get ( bone ) : bone ; if ( bIdx != undefined ) { const scl = this . bones [ bIdx ] . local . scl ; if ( v instanceof Array || v instanceof Float32Array ) vec3 . copy ( scl , v as vec3 ) ; else vec3 . set ( scl , v , v , v ) ; } else console . warn ( 'Bone not found, ' , bone ) ; return this ; } updateWorld ( useOffset = true ) { let i , b ; for ( i = 0 ; i < this . bones . length ; i ++ ) { b = this . bones [ i ] ; if ( b . pidx != - 1 ) b . world . fromMul ( this . bones [ b . pidx ] . world , b . local ) ; else if ( useOffset ) b . world . fromMul ( this . offset , b . local ) ; else b . world . copy ( b . local ) ; } return this ; } getWorldTransform ( bIdx , out ? ) { out ??= new Transform ( ) ; if ( bIdx == - 1 ) return out . copy ( this . offset ) ; let bone = this . bones [ bIdx ] ; out . copy ( bone . local ) ; while ( bone . pidx != - 1 ) { bone = this . bones [ bone . pidx ] ; out . pmul ( bone . local ) ; } out . pmul ( this . offset ) ; return out ; } getWorldRotation ( bIdx , out ? ) { out ??= quat . create ( ) ; if ( bIdx == - 1 ) { quat . copy ( out , this . offset . rot ) ; return out ; } let bone = this . bones [ bIdx ] ; quat . copy ( out , bone . local . rot ) ; while ( bone . pidx != - 1 ) { bone = this . bones [ bone . pidx ] ; quat . mul ( out , bone . local . rot , out ) ; } quat . mul ( out , this . offset . rot , out ) ; return out ; } updateBoneLengths ( defaultBoneLen = 0 ) { const bCnt = this . bones . length ; let b , p ; for ( let i = bCnt - 1 ; i >= 0 ; i -- ) { b = this . bones [ i ] ; if ( b . pidx == - 1 ) continue ; p = this . bones [ b . pidx ] ; p . len = Vec3Util . len ( p . world . pos , b . world . pos ) ; } if ( defaultBoneLen != 0 ) { for ( let i = 0 ; i < bCnt ; i ++ ) { b = this . bones [ i ] ; if ( b . len == 0 ) b . len = defaultBoneLen ; } } return this ; } } export default Pose ;