@name anim_lib_test3
@inputs 
@outputs Test
@persist Animations:table [Runtime Deltatime Curtime Lasttime] MyAnim:table
@trigger none


if (first()) {
    

    #-------------------------------------------------------------
    #-- Updating/Delta

    function void update(UpdateRate) {
        interval(UpdateRate)
        
        Curtime   = curtime()
        Deltatime = min(Curtime - Lasttime, UpdateRate/1000)
        Lasttime  = Curtime
        Runtime  += Deltatime
    }
    

    #-------------------------------------------------------------
    #-- New Animation
    
    function table newAnimation(Name:string, Duration) {
        local MyAnim = table(
            "setKeyFrames"     = table(),
            "setAnimDuration"  = Duration,
            "varAnimProgress"  = 0,
            "varAnimFraction"  = 0
        )    
        
        Animations[Name, table] = MyAnim
        
        return MyAnim
    }
    

    #-------------------------------------------------------------
    #-- Add new task to keyframe
        
    function table newFrameTask(HoloIndex, Parent:entity, Angle:angle) {
        local MyKeyFrame = table(
            "self"   = HoloIndex,
            "parent" = Parent,
            "angle"  = quat(Angle)
        )
        
        return MyKeyFrame
    }


    #-------------------------------------------------------------
    #-- Update frame count/duration
        
    function void table:preprocessKeyFrames() {
        This["setFrameCount", number]    = This["setKeyFrames", table]:count() - 1
        This["setFrameDuration", number] = This["setAnimDuration", number]/This["setFrameCount", number]
    }
    
    
    #-------------------------------------------------------------
    #-- Add a new keyframe to animation

    function void table:insertKeyFrame(KeyIndex, KeyFrame:table) {
        This["setKeyFrames", table][KeyIndex, table] = KeyFrame
        This:preprocessKeyFrames() 
    }
    
    
    #-------------------------------------------------------------
    #-- Blend keyframes
    
    function void table:mixKeyFrames(NextFrame, Mix) {
        local Next = This["setKeyFrames", table][NextFrame, table]
        local Prev = This["setKeyFrames", table][NextFrame - 1, table]
     
        for (I = 1, Next:count()) {
            local NData = Next[I, table]
            local PData = Prev[I, table]
    
            holoAng(NData["self", number], NData["parent", entity]:toWorld(slerp(PData["angle", quaternion], NData["angle", quaternion], Mix):toAngle()))
        }
    }
    
    #-------------------------------------------------------------
    #-- Play animation
    
    function number table:playAnimation() {
        if (This["varAnimFraction", number] != 1) {
            This["varAnimProgress", number] = min(This["varAnimProgress", number] + Deltatime, This["setAnimDuration", number])
            This["varAnimFraction", number] = This["varAnimProgress", number]/This["setAnimDuration", number]
        
            local Fraction  = This["varAnimProgress", number]/This["setFrameDuration", number]
            local NextFrame = min(floor(Fraction) + 1, This["setFrameCount", number])
            
            This:mixKeyFrames(NextFrame, 1 - (NextFrame - Fraction))
        
            return This["varAnimFraction", number]
        }
        
        return 1
    }




    #-------------------------------------------------------------
    #-- Example

    holoCreate(1)
    holoCreate(2)
    
    holoParent(1, entity())
    holoParent(2, holoEntity(1))
    
    holoPos(2, holoEntity(1):toWorld(vec(0, 0, 50)))
    
    MyAnim = newAnimation("test", 5)
    
    MyAnim:insertKeyFrame(0, table(
        newFrameTask(1, entity(), ang(0, 0, 0)),
        newFrameTask(2, holoEntity(1), ang(0, 0, 0))
    ))
    
    MyAnim:insertKeyFrame(1, table(
        newFrameTask(1, entity(), ang(0, 90, 0)),
        newFrameTask(2, holoEntity(1), ang(0, 0, 0))
    ))
    
    MyAnim:insertKeyFrame(2, table(
        newFrameTask(1, entity(), ang(90, 90, 0)),
        newFrameTask(2, holoEntity(1), ang(0, 0, 0))
    ))

    MyAnim:insertKeyFrame(3, table(
        newFrameTask(1, entity(), ang(90, 90, 0)),
        newFrameTask(2, holoEntity(1), ang(90, 0, 0))
    ))
    
    MyAnim:insertKeyFrame(4, table(
        newFrameTask(1, entity(), ang(0, 0, 90)),
        newFrameTask(2, holoEntity(1), ang(90, 0, 0))
    ))    
}

update(90)

if (Runtime > 1) { MyAnim:playAnimation() }

