import { vec3 , quat } from 'gl-matrix' ; import { lerp , hermite , bezier } from '../../../common/math' ; import { Animation , UintAnimation , FloatAnimation , Vector3Animation , InterpolationType } from '../../../parsers/mdlx/animations' ; import MdxModel from './model' ; /**
 * Animated data for a specific sequence.
 */ class SdSequence { sd : Sd ; start : number ; end : number ; frames : number [ ] = [ ] ; values : ( Uint32Array | Float32Array ) [ ] = [ ] ; inTans : ( Uint32Array | Float32Array ) [ ] = [ ] ; outTans : ( Uint32Array | Float32Array ) [ ] = [ ] ; constant = false ; constructor ( sd , start , end , animation , isGlobal ) { this . sd = sd ; this . start = start ; this . end = end ; const interpolationType = sd . interpolationType ; const frames = animation . frames ; const values = animation . values ; const inTans = animation . inTans ; const outTans = animation . outTans ; const defval = sd . defval ; if ( isGlobal && frames [ 0 ] > end ) { this . frames [ 0 ] = frames [ 0 ] ; this . values [ 0 ] = values [ 0 ] ; } for ( let i = 0 , l = frames . length ; i < l ; i ++ ) { const frame = frames [ i ] ; if ( frame >= start && frame <= end ) { this . frames . push ( frame ) ; this . values . push ( values [ i ] ) ; if ( interpolationType > 1 ) { this . inTans . push ( inTans [ i ] ) ; this . outTans . push ( outTans [ i ] ) ; } } } const tracksCount = this . frames . length ; if ( tracksCount === 0 ) { this . constant = true ; this . frames [ 0 ] = start ; this . values [ 0 ] = defval ; } else if ( tracksCount === 1 ) { this . constant = true ; } else { const firstValue = this . values [ 0 ] ; this . constant = this . values . every ( ( value ) => firstValue . every ( ( element , index ) => element === value [ index ] ) ) ; } } getValue ( out , frame ) { const frames = this . frames ; const length = frames . length ; if ( this . constant || frame < this . start ) { this . sd . copy ( out , this . values [ 0 ] ) ; return - 1 ; } else { let startFrameIndex = - 1 ; let endFrameIndex = - 1 ; const lengthLessOne = length - 1 ; if ( ( frame < this . frames [ 0 ] ) || ( frame >= this . frames [ lengthLessOne ] ) ) { startFrameIndex = lengthLessOne ; endFrameIndex = 0 ; } else { for ( let i = 1 ; i < length ; i ++ ) { if ( this . frames [ i ] > frame ) { startFrameIndex = i - 1 ; endFrameIndex = i ; break ; } } } let startFrame = this . frames [ startFrameIndex ] ; const endFrame = this . frames [ endFrameIndex ] ; let timeBetweenFrames = endFrame - startFrame ; if ( timeBetweenFrames < 0 ) { timeBetweenFrames += ( this . end - this . start ) ; if ( frame < startFrame ) { startFrame = endFrame ; } } const t = ( ( timeBetweenFrames ) == 0 ? 0 : ( ( frame - startFrame ) / timeBetweenFrames ) ) ; this . sd . interpolate ( out , this . values , this . inTans , this . outTans , startFrameIndex , endFrameIndex , t ) ; return startFrameIndex ; } } } const forcedInterpMap = { KLAV : InterpolationType . DontInterp , KATV : InterpolationType . DontInterp , KPEV : InterpolationType . DontInterp , KP2V : InterpolationType . DontInterp , KRVS : InterpolationType . DontInterp , } ; const floatDefval = new Float32Array ( 1 ) ; const uintDefval = new Uint32Array ( 1 ) ; const visibilityDefval = new Float32Array ( [ 1 ] ) ; const translationDefval = vec3 . create ( ) ; const rotationDefval = quat . create ( ) ; const scaleDefval = vec3 . fromValues ( 1 , 1 , 1 ) ; const alphaDefval = visibilityDefval ; const colorDefval = translationDefval ; const defVals = { KMTF : floatDefval , KMTA : alphaDefval , KTAT : translationDefval , KTAR : rotationDefval , KTAS : scaleDefval , KGAO : alphaDefval , KGAC : colorDefval , KLAS : floatDefval , KLAE : floatDefval , KLAC : colorDefval , KLAI : floatDefval , KLBI : floatDefval , KLBC : colorDefval , KLAV : visibilityDefval , KATV : visibilityDefval , KPEE : floatDefval , KPEG : floatDefval , KPLN : floatDefval , KPLT : floatDefval , KPEL : floatDefval , KPES : floatDefval , KPEV : visibilityDefval , KP2S : floatDefval , KP2R : floatDefval , KP2L : floatDefval , KP2G : floatDefval , KP2E : floatDefval , KP2N : floatDefval , KP2W : floatDefval , KP2V : visibilityDefval , KRHA : floatDefval , KRHB : floatDefval , KRAL : new Float32Array ( [ 0 ] ) , KRCO : colorDefval , KRTX : floatDefval , KRVS : visibilityDefval , KCTR : translationDefval , KTTR : translationDefval , KCRL : uintDefval , KGTR : translationDefval , KGRT : rotationDefval , KGSC : scaleDefval , } ; /**
 * Animated data.
 */ export abstract class Sd { defval : Float32Array | Uint32Array ; model : MdxModel ; name : string ; globalSequence : SdSequence | null = null ; sequences : SdSequence [ ] = [ ] ; interpolationType : InterpolationType ; abstract copy ( out , value ) ; abstract interpolate ( out , values , inTans , outTans , start , end , t ) ; constructor ( model , animation ) { const globalSequences = model . globalSequences ; const globalSequenceId = animation . globalSequenceId ; const forcedInterp = forcedInterpMap [ animation . name ] ; this . model = model ; this . name = animation . name ; this . defval = defVals [ animation . name ] ; this . interpolationType = forcedInterp !== undefined ? forcedInterp : animation . interpolationType ; if ( globalSequenceId !== - 1 && globalSequences ) { this . globalSequence = new SdSequence ( this , 0 , globalSequences [ globalSequenceId ] , animation , true ) ; } else { for ( const sequence of model . sequences ) { const interval = sequence . interval ; this . sequences . push ( new SdSequence ( this , interval [ 0 ] , interval [ 1 ] , animation , false ) ) ; } } } getValue ( out , sequence , frame , counter ) { if ( this . globalSequence ) { return this . globalSequence . getValue ( out , counter % this . globalSequence . end ) ; } return this . sequences [ sequence ] . getValue ( out , frame ) ; } isVariant ( sequence ) { if ( this . globalSequence ) { return ! this . globalSequence . constant ; } else { return ! this . sequences [ sequence ] . constant ; } } } /**
 * A scalar animation.
 */ export class ScalarSd extends Sd { copy < T extends Uint32Array | Float32Array > ( out , value ) { out [ 0 ] = value [ 0 ] ; } interpolate < T extends Uint32Array | Float32Array > ( out , values , inTans , outTans , start , end , t ) { const interpolationType = this . interpolationType ; const startValue = values [ start ] [ 0 ] ; if ( interpolationType === InterpolationType . DontInterp ) { out [ 0 ] = startValue ; } else if ( interpolationType === InterpolationType . Linear ) { out [ 0 ] = lerp ( startValue , values [ end ] [ 0 ] , t ) ; } else if ( interpolationType === InterpolationType . Hermite ) { out [ 0 ] = hermite ( startValue , outTans [ start ] [ 0 ] , inTans [ end ] [ 0 ] , values [ end ] [ 0 ] , t ) ; } else if ( interpolationType === InterpolationType . Bezier ) { out [ 0 ] = bezier ( startValue , outTans [ start ] [ 0 ] , inTans [ end ] [ 0 ] , values [ end ] [ 0 ] , t ) ; } } } /**
 * A vector animation.
 */ export class VectorSd extends Sd { copy ( out , value ) { vec3 . copy ( out , value ) ; } interpolate ( out , values , inTans , outTans , start , end , t ) { const interpolationType = this . interpolationType ; if ( interpolationType === InterpolationType . DontInterp ) { vec3 . copy ( out , values [ start ] ) ; } else if ( interpolationType === InterpolationType . Linear ) { vec3 . lerp ( out , values [ start ] , values [ end ] , t ) ; } else if ( interpolationType === InterpolationType . Hermite ) { vec3 . hermite ( out , values [ start ] , outTans [ start ] , inTans [ end ] , values [ end ] , t ) ; } else if ( interpolationType === InterpolationType . Bezier ) { vec3 . bezier ( out , values [ start ] , outTans [ start ] , inTans [ end ] , values [ end ] , t ) ; } } } /**
 * A quaternion animation.
 */ export class QuatSd extends Sd { copy ( out , value ) { quat . copy ( out , value ) ; } interpolate ( out , values , inTans , outTans , start , end , t ) { const interpolationType = this . interpolationType ; if ( interpolationType === InterpolationType . DontInterp ) { quat . copy ( out , values [ start ] ) ; } else if ( interpolationType === InterpolationType . Linear ) { quat . slerp ( out , values [ start ] , values [ end ] , t ) ; } else if ( interpolationType === InterpolationType . Hermite || interpolationType === InterpolationType . Bezier ) { quat . sqlerp ( out , values [ start ] , outTans [ start ] , inTans [ end ] , values [ end ] , t ) ; } } } export function createTypedSd ( model , animation ) { if ( animation instanceof UintAnimation || animation instanceof FloatAnimation ) { return new ScalarSd ( model , animation ) ; } else if ( animation instanceof Vector3Animation ) { return new VectorSd ( model , animation ) ; } else { return new QuatSd ( model , animation ) ; } }