4
Copyright (c) 2010 Carnegie Mellon University
6
Permission is hereby granted, free of charge, to any person obtaining a copy
7
of this software and associated documentation files (the "Software"), to deal
8
in the Software without restriction, including without limitation the rights
9
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
copies of the Software, and to permit persons to whom the Software is
11
furnished to do so, subject to the following conditions:
13
The above copyright notice and this permission notice shall be included in
14
all copies or substantial portions of the Software.
16
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
-- Animation System. Big Lua wrapper around Pose and MultiPose to play animations
29
lastTime = Timer.getTime()
30
ProfileTimerAnimationUpdate = ProfileTimer.new("Timer::runFrame::Animation Update")
33
returnChannel = SceneObject:playAnimation(animation,{speed (optional), channel (optional), uniqueChannel(optional), start (optional), stop (optional), time (optional), loop (optional), callback (optional), prePad (optional), postPad (optional), fadeInTime (optional), fadeOutTime (optional), weight (optional) } (optional) )
35
- animation: (Animation) The animation to play
36
- speed: (number) Playback speed relative to the animation's recorded speed. 1 is 100% speed, 2 is 200%, .5 is 50%
37
- channel: (number/string) Playback channel. Animations in different channels may be played simultaneously, animation blending will average between them if they touch the same bones.
38
- uniqueChannel: (boolean) if set to true it will create a random channel and not set channel to 1. (Overridden if channel is set)
39
- start: (number) Start time, in seconds.
40
- stop: (number) Stop time, in seconds.
41
- time: (number) Initialization time, in seconds. If the animation is looping, the first cycle will start at this time. Otherwise, this option will override 'start'.
42
- loop: (boolean) if true, animation will loop once it reaches the end. If false, animation will play once.
43
- callback: (function ()) Function to be called when the animation completes a cycle.
44
- callTime: (number) The amount of time before the end of the animation that the callback is called (default 0)
45
- prePad: (number) Seconds to stay on the first frame of the animation before starting to play (default 0)
46
- postPad: (number) Seconds to stay on the last frame of the animation after playing the full animation (default 0) (has no effect when loop = true)
47
- fadeInTime: (number) Seconds including prePad to fade the weight from 0 to the set weight. (default 0)
48
- fadeOutTime: (number) Seconds before the end, including postPad, to start fading from the set weight to 0 (default 0)
49
- fadeAll: (boolean) if set to true fades all other animations out and then back in again (default 0)
50
- weight: (number 0.0-1.0) The weight as compared to other animations currently playing on different channels. (default 1)
52
Plays an animation on the object. Several parameters can be
53
specified to control the animation. Normally, the animation will play
54
until it completes. The loop argument may be specified to continue
55
playback. The speed argument can be used to adjust the speed of the
56
animation. A speed of 1 is the default speed of the animation, 2 is
57
twice as fast, .5 is half as fast. If a negative speed is specified,
58
the animation will play in reverse (and either stop or loop when it
59
reaches the 'start' time).
61
Animation blending allows multiple animations to be played simultaniously
62
and the engine averages between the two of them based on their given weights.
63
This allows one animation to be faded out while another is faded in and a semless
64
transition to be seen between them.
66
This function always returns the channel that this animation is set to
70
function SceneObject:playAnimation(whichAnimation,extraArgs)
73
--Animations are stored in a linked list of tables.
74
--This is no longer needed and if anyone wants to change it to a table that's fine
75
--This was implimented back when it was needed that animations be in order for blending
76
--but that only lasted a couple of days, but by then it was written and worked.
78
--Check if Animation is a String or an animation, and if string, make it an animation
79
if type(whichAnimation) == type("") then
80
whichAnimation = Animation.load(whichAnimation)
83
if type(whichAnimation) ~= "Animation" then
84
error("SceneObject:playAnimation must be passed an animation or the filename of an animation.")
89
--local animations = animationTable[self]
90
--if animations == nil then animations = {} animations["__n__"] = 0 end
91
--local firstAnim = false
92
--if animations["__n__"] == 0 then firstAnim = true end
95
if extraArgs==nil then
100
--[[if extraArgs.uniqueChannel and not extraArgs.channel then
102
while animations[channel] do
103
channel = channel + 1 XXXXXX REPLACE THIS!!!!!!!!!!!!!!!!!!! XXXXX
105
extraArgs.channel = channel
108
if extraArgs.uniqueChannel and not extraArgs.channel then
109
extraArgs.channel = {}
114
if extraArgs.channel=="__n__" then
115
error("nope, you can't make a channel '__n__'. We use that.")
119
if extraArgs.channel==nil then
123
if extraArgs.speed==nil then
126
if extraArgs.start==nil then
127
extraArgs.start=whichAnimation:getStartTime()
130
if extraArgs.stop==nil then
131
extraArgs.stop=whichAnimation:getEndTime()
133
if extraArgs.loop==nil then
136
if extraArgs.weight == nil then
138
elseif extraArgs.weight > 1 then
140
elseif extraArgs.weight < 0 then
143
if extraArgs.prePad == nil then
146
if extraArgs.postPad == nil then
147
extraArgs.postPad = 0
149
if extraArgs.fadeInTime == nil then
150
extraArgs.fadeInTime = 0
152
if extraArgs.fadeOutTime == nil then
153
extraArgs.fadeOutTime = 0
155
if (extraArgs.fadeInTime + extraArgs.fadeOutTime) > (extraArgs.stop - extraArgs.start) + extraArgs.prePad + extraArgs.postPad then
156
error("fadeInTime and fadeOutTime are too long, cannot fade more animation than there is.")
158
if extraArgs.callTime == nil then
159
extraArgs.callTime = extraArgs.stop
163
if (extraArgs.speed > 0 and extraArgs.start > extraArgs.stop) or
164
(extraArgs.speed < 0 and extraArgs.start < extraArgs.stop)
166
local swap=extraArgs.start
167
extraArgs.start=extraArgs.stop
172
if extraArgs.time==nil then
173
extraArgs.time=extraArgs.start
176
if extraArgs.fadeAll == nil then
177
extraArgs.fadeAll = false
180
if type(extraArgs.callTime) ~= "number" then error("callTime must be a number") end
181
if (type(extraArgs.callback) ~= "function" and type(extraArgs.callback) ~= "nil" and type(extraArgs.callback) ~= "no value") then error("callback must be a function") end
182
if type(extraArgs.speed) ~= "number" then error("speed must be a number") end
183
if type(extraArgs.time) ~= "number" then error("time must be a number") end
184
if type(extraArgs.start) ~= "number" then error("start must be a number") end
185
if type(extraArgs.stop) ~= "number" then error("stop must be a number") end
186
if type(extraArgs.prePad) ~= "number" then error("prePad must be a number") end
187
if type(extraArgs.postPad) ~= "number" then error("postPad must be a number") end
188
if type(extraArgs.fadeInTime) ~= "number" then error("fadeInTime must be a number") end
189
if type(extraArgs.fadeOutTime) ~= "number" then error("fadeOutTime must be a number") end
190
if type(extraArgs.loop) ~= "boolean" then error("loop must be a boolean") end
191
if type(extraArgs.weight) ~= "number" then error("weight must be a number") end
192
if type(extraArgs.fadeAll) ~= "boolean" then error("fadeAll must be a boolean") end
194
if extraArgs.time < extraArgs.start or extraArgs.time > extraArgs.stop then
195
extraArgs.time = extraArgs.start
199
--if not animations[extraArgs.channel] then animations["__n__"] = animations["__n__"] + 1 end
200
local fadeInAnimation = false
201
local fadeOutTime = 0
202
if extraArgs.fadeOutTime > extraArgs.postPad then
203
fadeInAnimation = true
204
fadeOutTime = extraArgs.stop + extraArgs.postPad - extraArgs.fadeOutTime
206
fadeOutTime = extraArgs.postPad - extraArgs.fadeOutTime
209
local runBackwards = false
211
local absoluteSpeed = extraArgs.speed
212
if absoluteSpeed < 0 then
214
absoluteSpeed = -absoluteSpeed
217
local tempAnimTable = {
218
runBackwards = runBackwards,
219
anim = whichAnimation,
221
prePadTotal = extraArgs.prePad,
223
postPadTotal = extraArgs.postPad,
224
fadeInAnimation = fadeInAnimation,
225
fadeOutTime = fadeOutTime,
226
time = extraArgs.time,
227
fadeAll = extraArgs.fadeAll,
228
speed = absoluteSpeed,
229
rangeStart = extraArgs.start,
230
rangeEnd = extraArgs.stop,
231
loop = extraArgs.loop,
232
callback = extraArgs.callback,
233
callTime = extraArgs.callTime,
234
weight = extraArgs.weight,
235
originalArgs = extraArgs
238
if extraArgs.fadeInTime > 0 then
240
tempAnimTable.fade = {
242
goalWeight = extraArgs.weight,
243
totalTime = (extraArgs.fadeInTime / math.abs(extraArgs.speed)),
249
--Doing it with a linked list for easy removal addition and manipulation.
252
--Finding the Object in the linked list
253
local thisObject = animationTable
254
local lastObject = {}
255
lastObject.next = animationTable
260
--print(1,"checking if object ", thisObject.object, " matches myself: ", self)
261
if thisObject.object == self then break end
262
lastObject = thisObject
263
thisObject = thisObject.next
266
if thisObject == nil then
267
--print(1,"Nothing Matched, creating a new object at the end.")
268
lastObject.next = {next = nil,object=self,channelList=nil, lastRunTime = Timer.getTime()}
270
thisObject=lastObject.next
272
--print(1, "Setting ", thisObject.object, " s lastRunTime to ", thisObject.lastRunTime)
275
--print(1,"I am ", thisObject.object)
277
if animationTable == nil then
278
--print(1,"This was the first animation")
279
animationTable = thisObject
284
--Fade All XXX THIS IS KINDA A HACK
285
if extraArgs.fadeAll then
286
local thisChannel = thisObject.channelList
288
--print(1, "Fading out channel ", thisChannel.channel ," because of fadeAll")
289
local list = thisChannel.infoTable
290
if not list.originalWeight then list.originalWeight = list.weight end
292
startWeight = list.weight,
294
totalTime = (extraArgs.fadeInTime / absoluteSpeed),
297
thisChannel = thisChannel.next
301
--Finding a Channel on this object:
304
local thisChannel = thisObject.channelList
305
local lastChannel = {}
306
lastChannel.next = thisObject.channelList
309
--print(1,"checking if channel ", thisChannel.channel, " matches myself: ", extraArgs.channel)
310
if thisChannel.channel == extraArgs.channel then break end
311
lastChannel = thisChannel
312
thisChannel = thisChannel.next
314
if lastChannel.next == nil then
315
--print(1,"Nothing Matched, creating a new channel at the end.")
316
lastChannel.next = {next=nil,channel=extraArgs.channel}
317
thisChannel = lastChannel.next
319
if thisObject.channelList == nil then
320
--print(1,"This was the first Channel on this object")
321
thisObject.channelList = thisChannel
325
--print(1,"My Channel is: \"", thisChannel.channel, "\"")
328
thisChannel.infoTable = tempAnimTable
329
thisObject.dirty = true
330
syncObjectAnimations(thisObject)
333
return extraArgs.channel
336
--[[if (extraArgs.fadeAll) then
337
for channel,animTable in pairs(animations) do
339
if (channel ~= extraArgs.channel) and (channel ~= "__n__") and (animTable.originalWeight == nil) then
340
animTable.originalWeight = animTable.weightEnd
341
animTable.timeToFade = extraArgs.fadeInTime
342
animTable.fadeTime = 0
343
animTable.weightStart = animTable.weight
344
animTable.weightEnd = 0
353
sandboxScope(SceneObject,"playAnimation","USER")
355
--------------------------------------------------------------------------
357
--This function takes the linked list table, not an object.
358
function syncObjectAnimations(thisObject)
359
--print(2,"Calculating animations on object: ", thisObject.object)
361
if not thisObject.dirty then
362
--print(2,"The animation has already been run this frame, returning")
365
local deltaTime = Timer.getTime() - thisObject.lastRunTime
367
local thisChannel = thisObject.channelList
368
local lastChannel = nil
370
--print(2,"Calculating Channel: ", thisChannel.channel)
371
local channel = thisChannel.channel
372
local animTable = thisChannel.infoTable
373
local deltaT = deltaTime * animTable.speed
374
local deadAnim = false
376
--Fading system runs regardless and independantly
377
if animTable.fade then
378
local fadeTable = animTable.fade
379
fadeTable.now = fadeTable.now + deltaTime
380
--print(2,"Fading from ", animTable.fade.startWeight, " to ", animTable.fade.goalWeight, " current at ", animTable.weight)
381
if fadeTable.now >= fadeTable.totalTime or fadeTable.totalTime <= 0 then
382
animTable.weight = fadeTable.goalWeight
385
animTable.weight = ((fadeTable.now) * (fadeTable.goalWeight - fadeTable.startWeight)) / fadeTable.totalTime + fadeTable.startWeight
393
if ((animTable.fadeInAnimation and animTable.time > animTable.fadeOutTime) or (animTable.postPadTime > animTable.fadeOutTime)) and not animTable.finalFadeout and not animTable.loop then
394
--print(1,"we're fading out now")
396
--print(animTable.loop)
398
startWeight = animTable.weight,
400
totalTime = (animTable.originalArgs.fadeOutTime),
404
if animTable.fadeAll then
405
local fadeChannels = thisObject.channelList
406
while fadeChannels do
407
if fadeChannels.channel ~= channel then
408
--print(1, "Fading in channel ", fadeChannels.channel ," because of fadeAll")
409
local list = fadeChannels.infoTable
410
if list.originalWeight then
413
startWeight = list.weight,
414
goalWeight = list.originalWeight,
416
totalTime = (animTable.originalArgs.fadeOutTime)
418
list.originalWeight = nil
421
fadeChannels = fadeChannels.next
424
animTable.finalFadeout = true
426
--print("OH GOD HI AGAIN")
428
--The Meat and/or Potatoes
430
if animTable.prePadTime < animTable.prePadTotal then
432
animTable.prePadTime = animTable.prePadTime + deltaTime
434
elseif (animTable.time < animTable.rangeEnd and not animTable.runBackwards ) or (animTable.time > animTable.rangeEnd and animTable.runBackwards )then
435
--we're playing the animation
436
--print("Animation on Channel ", channel, " is playing")
437
local timePassed = nil
438
if animTable.runBackwards then
439
animTable.time = animTable.time - deltaT
440
timePassed = function (a,b) return a < b end
442
animTable.time = animTable.time + deltaT
443
timePassed = function (a,b) return a > b end
448
if animTable.callback and not animTable.callbackCalled and timePassed(animTable.time,animTable.callTime) then
450
if type(animTable.callback) == "function" then
451
--print(1,"running callback")
453
if not thisObject.dirty then
454
--print(1,"The callback has changed this animations status to clean.")
458
animTable.callbackCalled = true
461
--print("Animation on Channel ", channel, " is still playing")
462
if timePassed(animTable.time, animTable.rangeEnd) then
463
if animTable.loop then
464
if animTable.callback and not animTable.callbackCalled then
465
if type(animTable.callback) == "function" then
466
--print(1,"running callback")
468
animTable.callbackCalled = true
469
if not thisObject.dirty then
470
--print(1,"The callback has changed this animations status to clean.")
475
animTable.callbackCalled = false
476
animTable.time = animTable.rangeStart
478
animTable.time = animTable.rangeEnd
483
--print("Animation on Channel ", channel, " is still alive playing")
484
elseif animTable.postPadTime < animTable.postPadTotal then
485
--we're on the postPad
486
if animTable.callback and not animTable.callbackCalled and ((animTable.time + animTable.postPadTime) > animTable.callTime) then
487
if type(animTable.callback) == "function" then
488
--print(1,"running callback")
490
if not thisObject.dirty then
491
--print(1,"The callback has changed this animations status to clean.")
495
animTable.callbackCalled = true
497
animTable.postPadTime = animTable.postPadTime + deltaTime
500
--if none of those things are true, this animation is finished.
502
--Call the callback if it hasn't been called yet, I'm sure they'd want us to.
503
if animTable.callback and not animTable.callbackCalled then
504
if type(animTable.callback) == "function" then
505
--print(1,"running callback")
507
animTable.callbackCalled = true
508
if not thisObject.dirty then
509
--print(1,"The callback has changed this animations status to clean.")
514
--We're completely done with this channel
515
if lastChannel == nil then
516
thisObject.channelList = thisChannel.next
518
lastChannel.next = thisChannel.next
524
poseList[channel] = {anim = animTable.anim, time = animTable.time, weight = animTable.weight}
526
lastChannel = thisChannel
529
thisChannel = thisChannel.next
532
local weightList = {}
533
local animationList = {}
535
local numAnimations = 0
536
for k,v in pairs(poseList) do
537
numAnimations = numAnimations + 1
538
weightList[numAnimations] = v.weight
539
animationList[numAnimations] = v.anim
540
timeList[numAnimations] = v.time
542
thisObject.object:multiPose(numAnimations,animationList,timeList,weightList)
547
--------------------------------------------------------------------------
550
function timeRemaining(thisTable)
551
local totalTime = thisTable.prePad + thisTable.postPad + ((thisTable.stop - thisTable.start) / thisTable.speed)
552
if thisTable.status=="pausedBegin" then
553
return (thisTable.prePad - thisTable.pauseTime) + thisTable.postPad + ((thisTable.stop - thisTable.start) / thisTable.speed)
554
elseif thisTable.status=="playing" then
555
return ((thisTable.stop - thisTable.time) / thisTable.speed) + thisTable.postPad
557
return (thisTable.postPad - thisTable.pauseTime)
562
function doAnimation()
567
--------------------------------------------------------------------------
570
table = SceneObject:getAnimationInfo(channel)
571
channel - defaults to 1
574
- speed: (number) Playback speed relative to the animation's recorded speed. 1 is 100% speed, 2 is 200%, .5 is 50%
575
- start: (number) Start time, in seconds.
576
- stop: (number) Stop time, in seconds.
577
- time: (number) Initialization time, in seconds. If the animation is looping, the first cycle will start at this time. Otherwise, this option will override 'start'.
578
- loop: (boolean) if true, animation will loop once it reaches the end. If false, animation will play once.
579
- callback: (function ()) Function to be called when the animation completes a cycle.
580
- callTime: (number) The amount of time before the end of the animation that the callback is called (default 0)
581
- prePad: (number) Seconds to stay on the first frame of the animation before starting to play (default 0)
582
- postPad: (number) Seconds to stay on the last frame of the animation after playing the full animation (default 0) (has no effect when loop = true)
583
- fadeInTime: (number) Seconds including prePad to fade the weight from 0 to the set weight. (default 0)
584
- fadeOutTime: (number) Seconds before the end, including postPad, to start fading from the set weight to 0 (default 0)
585
- weight: (number 0.0-1.0) The weight as compared to other animations currently playing on different channels. (default 1)
587
Returns data about the animation on a given channel
590
function SceneObject:getAnimationInfo(channel)
591
if animationTable[self] ~= nil then
592
if animationTable[self][channel] then
594
returnTable.speed = animationTable[self][channel].speed
595
returnTable.start = animationTable[self][channel].start
596
returnTable.stop = animationTable[self][channel].stop
597
returnTable.time = animationTable[self][channel].time
598
returnTable.loop = animationTable[self][channel].loop
599
returnTable.callback = animationTable[self][channel].callback
600
returnTable.callTime = animationTable[self][channel].callTime
601
returnTable.prePad = animationTable[self][channel].prePad
602
returnTable.postPad = animationTable[self][channel].postPad
603
returnTable.fadeInTime = animationTable[self][channel].fadeInTime
604
returnTable.fadeOutTime = animationTable[self][channel].fadeOutTime
605
returnTable.weight = animationTable[self][channel].weight
611
sandboxScope(SceneObject,"getAnimationInfo","USER")
616
--------------------------------------------------------------------------
619
SceneObject:stopAnimation(channel (optional))
621
- channel: (number) The channel to stop
623
Stops the currently playing animation. A channel may be
624
specified. If a channel is not specified, channel 1 is stopped.
627
function SceneObject:stopAnimation(channel)
628
--print(1, "calling stop animation on channel ", channel, " on object ", self)
632
local thisObject = animationTable
634
if thisObject.object == self then break end
635
lastObject = thisObject
636
thisObject = thisObject.next
639
if not thisObject then warning("This object has no animations playing on it.") return end
640
local thisChannel = thisObject.channelList
641
local lastChannel = nil
643
if thisChannel.channel == channel then
645
if lastChannel == nil then
646
thisObject.channelList = thisChannel.next
648
lastChannel.next = thisChannel.next
652
lastChannel = thisChannel
653
thisChannel = thisChannel.next
655
if thisChannel == nil then warning("no channel: ", channel, " is playing on this object.") end
659
sandboxScope(SceneObject,"stopAnimation","USER")
661
--------------------------------------------------------------------------
663
--------------------------------------------------------------------------
666
SceneObject:setAnimationLoop(flag,channel)
668
- loop: (boolean) If true, animation should loop when it reaches the end
669
- channel: (number, optional) The channel to loop. If uspecified, channel 1 is set to loop.
671
Sets the animation to loop when it reaches the end of its timeline.
674
function SceneObject:setAnimationLoop(loop,channel)
675
--print(1, "calling loop animation on channel ", channel, " setting it to ", loop, " on object ", self)
680
local thisObject = animationTable
682
if thisObject.object == self then break end
683
lastObject = thisObject
684
thisObject = thisObject.next
687
if not thisObject then warning("This object has no animations playing on it.") return end
688
local thisChannel = thisObject.channelList
689
local lastChannel = nil
691
if thisChannel.channel == channel then
692
thisChannel.infoTable.loop = loop
695
lastChannel = thisChannel
696
thisChannel = thisChannel.next
698
if thisChannel == nil then warning("no channel: ", channel, " is playing on this object.") end
700
sandboxScope(SceneObject,"setAnimationLoop","USER")
703
--------------------------------------------------------------------------
706
speed = SceneObject:getAnimationSpeed(channel)
708
- speed: (boolean) If true, animation should loop when it reaches the end
709
- channel: (number, optional) The channel to loop. If uspecified, channel 1 is set to loop.
711
Sets the animation to loop when it reaches the end of its timeline.
714
function SceneObject:getAnimationSpeed(channel)
716
--print(1, "getting animation speed on channel ", channel, " on object ", self)
720
local thisObject = animationTable
722
if thisObject.object == self then break end
723
lastObject = thisObject
724
thisObject = thisObject.next
727
if not thisObject then warning("This object has no animations playing on it.") return end
728
local thisChannel = thisObject.channelList
729
local lastChannel = nil
731
if thisChannel.channel == channel then
732
if thisChannel.infoTable.runBackwards then
733
return -thisChannel.infoTable.speed
735
return thisChannel.infoTable.speed
738
lastChannel = thisChannel
739
thisChannel = thisChannel.next
741
if thisChannel == nil then warning("no channel: ", channel, " is playing on this object.") end
744
sandboxScope(SceneObject,"getAnimationSpeed","USER")
747
--------------------------------------------------------------------------
750
SceneObject:setAnimationSpeed(speed,channel)
752
- speed: (number) The rate to play the animation.
753
- channel: (number, optional) The channel to loop. If uspecified, channel 1's speed is set.
755
Sets the play rate of the animation. 1 is the original rate; 2 is
756
twice as fast, 0.5 is half as fast.
759
function SceneObject:setAnimationSpeed(newSpeed,channel)
761
--print(1, "setting animation speed to ", newSpeed, " on channel ", channel, " on object ", self)
762
-- set the speed of the animation
766
local thisObject = animationTable
768
if thisObject.object == self then break end
769
lastObject = thisObject
770
thisObject = thisObject.next
773
if not thisObject then error("This object has no animations playing on it.") return end
774
local thisChannel = thisObject.channelList
775
local lastChannel = nil
777
if thisChannel.channel == channel then
778
animTable = thisChannel.infoTable
781
animTable.runBackwards = true
784
animTable.runBackwards = false
786
animTable.speed = newSpeed
789
lastChannel = thisChannel
790
thisChannel = thisChannel.next
792
if thisChannel == nil then error("no channel: ", channel, " is playing on this object.") end
796
sandboxScope(SceneObject,"setAnimationSpeed","USER")
798
--------------------------------------------------------------------------
801
loop = SceneObject:getAnimationLoop(channel)
803
- loop: (boolean) If true, animation should loop when it reaches the end
804
- channel: (number, optional) The channel to loop. If uspecified, channel 1 is set to loop.
806
Sets the animation to loop when it reaches the end of its timeline.
809
function SceneObject:getAnimationLoop(channel)
811
--print(1, "getting animation loop on channel ", channel, " on object ", self)
815
local thisObject = animationTable
817
if thisObject.object == self then break end
818
lastObject = thisObject
819
thisObject = thisObject.next
822
if not thisObject then warning("This object has no animations playing on it.") return end
823
local thisChannel = thisObject.channelList
824
local lastChannel = nil
826
if thisChannel.channel == channel then
827
return thisChannel.infoTable.loop
830
lastChannel = thisChannel
831
thisChannel = thisChannel.next
833
if thisChannel == nil then warning("no channel: ", channel, " is playing on this object.") end
837
sandboxScope(SceneObject,"getAnimationLoop","USER")
841
--------------------------------------------------------------------------
843
--------------------------------------------------------------------------
845
channels = SceneObject:getAllAnimations()
847
channels - table of all channels of animations currently playing in any way
849
Returns a list of all animations playing in a table. Usefull for looping through.
852
function SceneObject:getAllAnimations()
854
--print(1, "getting animation list on object ", self)
855
local animations = {}
858
local thisObject = animationTable
860
if thisObject.object == self then break end
861
lastObject = thisObject
862
thisObject = thisObject.next
865
if not thisObject then warning("This object has no animations playing on it.") return end
866
local thisChannel = thisObject.channelList
868
animations[i] = thisChannel.channel
870
thisChannel = thisChannel.next
875
sandboxScope(SceneObject,"getAllAnimations","USER")
877
----------------------------------------------------------------------------------
880
--------------------------------------------------------------------------
883
playing = SceneObject:isAnimationPlaying(channel)
885
- playing: (boolean) If true, the animation is currently playing.
886
- channel: (number, optional) The channel to check. If uspecified, channel 1 is checked.
888
Checks whether an animation is playing on the specified channel.
892
function SceneObject:isAnimationPlaying(channel)
894
--print(1, "Checking if animation is playing on channel ", channel, " on object ", self)
898
local thisObject = animationTable
900
if thisObject.object == self then break end
901
lastObject = thisObject
902
thisObject = thisObject.next
905
if not thisObject then return false end
906
local thisChannel = thisObject.channelList
907
local lastChannel = nil
909
if thisChannel.channel == channel then
913
lastChannel = thisChannel
914
thisChannel = thisChannel.next
920
sandboxScope(SceneObject,"isAnimationPlaying","USER")
923
--------------------------------------------------------------------------
926
SceneObject:animationFade(endWeight,time,channel)
928
endWeight - The weight to fade to
929
time - how much time in seconds to fade to
930
channel - What channel the animation is playing on (default 1)
932
Fades the weights of an animation up and down. Default weight
933
is 1, a weight of 0 results in no animation movement. Weights
934
are all compared to other animations currently playing.
938
function SceneObject:animationFade(endWeight,time,channel,callback)
939
--print(1, "called animationFade to ", endWeight, " in ", time, " seconds on channel ", channel, " on object ", self)
941
if type(endWeight) ~= "number" then error("The Weight must be a number") end
942
if type(time) ~= "number" then error("The time to fade must be a number") end
946
local thisObject = animationTable
948
if thisObject.object == self then break end
949
lastObject = thisObject
950
thisObject = thisObject.next
953
if not thisObject then warning("This object has no animations playing on it.") return end
954
local thisChannel = thisObject.channelList
955
local lastChannel = nil
957
if thisChannel.channel == channel then
958
thisChannel.infoTable.fade = {
959
startWeight = thisChannel.infoTable.weight,
960
goalWeight = endWeight,
966
lastChannel = thisChannel
967
thisChannel = thisChannel.next
969
if thisChannel == nil then warning("no channel: ".. tostring(channel) .. " is playing on this object.") end
974
sandboxScope(SceneObject,"animationFade","USER")
977
--------------------------------------------------------------------------
978
--Main animation looping functions
979
function animationLoop()
980
local start = ProfileTimer.queryPerformanceCounter()
981
--print(2,"looping through every object and every animation and doing it.")
986
--print("Syncing animations for this frame.")]]
987
local thisObject = animationTable
988
local lastObject = nil
991
--print("Doing animations on object: ", thisObject.object)
992
if SceneManager.isDeletedObject(thisObject.object) or thisObject.channelList == nil then
993
--This Object has been deleted or has noo channels on it.
994
if lastObject == nil then
995
animationTable = thisObject.next
997
lastObject.next = thisObject.next
1000
--We're not yet finished with this object
1001
lastObject = thisObject
1002
syncObjectAnimations(thisObject)
1004
thisObject = thisObject.next
1007
ProfileTimerAnimationUpdate:addFromStart(start)
1009
--------------------------------------------------------------------------
1011
SceneObject:setAllAnimDirty()
1013
This function sets all the dirty flags on all the animations so they will be calculated next frame.
1015
function SceneObject.setAllAnimDirty(now)
1016
local thisObject = animationTable
1019
thisObject.dirty = true
1020
thisObject.lastRunTime = now
1021
--print(2, "Setting ", thisObject.object, " s lastRunTime to ", thisObject.lastRunTime)
1022
thisObject = thisObject.next
1026
sandboxScope(SceneObject,"setAllAnimDirty","KERNEL")
1030
--------------------------------------------------------------------------
1032
SceneObject:syncAnimations()
1034
This function is a state changing function that calls into the lua layer and forcefully makes sure that the bones
1035
in this scene object are updated
1037
function SceneObject:syncAnimations()
1038
--print(2,"running Animation Sync")
1039
local thisObject = animationTable
1042
if thisObject.object == self then
1043
syncObjectAnimations(thisObject)
1045
thisObject = thisObject.next
1049
sandboxScope(SceneObject,"syncAnimations","USER")
1052
--------------------------------------------------------------------------
1055
table = SceneObject:getAnimationInfo(channel)
1056
channel - defaults to 1
1059
- speed: (number) Playback speed relative to the animation's recorded speed. 1 is 100% speed, 2 is 200%, .5 is 50%
1060
- start: (number) Start time, in seconds.
1061
- stop: (number) Stop time, in seconds.
1062
- time: (number) Initialization time, in seconds. If the animation is looping, the first cycle will start at this time. Otherwise, this option will override 'start'.
1063
- loop: (boolean) if true, animation will loop once it reaches the end. If false, animation will play once.
1064
- callback: (function ()) Function to be called when the animation completes a cycle.
1065
- callTime: (number) The amount of time before the end of the animation that the callback is called (default 0)
1066
- prePad: (number) Seconds to stay on the first frame of the animation before starting to play (default 0)
1067
- postPad: (number) Seconds to stay on the last frame of the animation after playing the full animation (default 0) (has no effect when loop = true)
1068
- fadeInTime: (number) Seconds including prePad to fade the weight from 0 to the set weight. (default 0)
1069
- fadeOutTime: (number) Seconds before the end, including postPad, to start fading from the set weight to 0 (default 0)
1070
- weight: (number 0.0-1.0) The weight as compared to other animations currently playing on different channels. (default 1)
1072
Returns data about the animation on a given channel
1075
function SceneObject:getAnimationInfo(channel)
1076
--print(1, "getting animation info on channel " , channel)
1077
if channel==nil then
1080
local thisObject = animationTable
1082
if thisObject.object == self then break end
1083
lastObject = thisObject
1084
thisObject = thisObject.next
1087
if not thisObject then warning("This object has no animations playing on it.") return end
1088
local thisChannel = thisObject.channelList
1089
local lastChannel = nil
1090
while thisChannel do
1092
if thisChannel.channel == channel then
1095
if thisChannel.infoTable.runBackwards then
1096
returnTable.speed = -thisChannel.infoTable.speed
1098
returnTable.speed = thisChannel.infoTable.speed
1100
returnTable.start = thisChannel.infoTable.rangeStart
1101
returnTable.stop = thisChannel.infoTable.rangeEnd
1102
returnTable.time = thisChannel.infoTable.time
1103
returnTable.loop = thisChannel.infoTable.loop
1104
returnTable.callback = thisChannel.infoTable.callback
1105
returnTable.callTime = thisChannel.infoTable.originalArgs.callTime
1106
returnTable.prePad = thisChannel.infoTable.originalArgs.prePad
1107
returnTable.postPad = thisChannel.infoTable.originalArgs.postPad
1108
returnTable.fadeInTime = thisChannel.infoTable.originalArgs.fadeInTime
1109
returnTable.fadeOutTime = thisChannel.infoTable.originalArgs.fadeOutTime
1110
returnTable.weight = thisChannel.infoTable.weight
1114
lastChannel = thisChannel
1115
thisChannel = thisChannel.next
1117
if thisChannel == nil then error("no channel: ", channel, " is playing on this object.") end
1121
sandboxScope(SceneObject,"getAnimationInfo","USER")
1123
Timer.every(animationLoop,0,"__animationLoop")