How to program a timeline?

BlitzMax Forums/BlitzMax Programming/How to program a timeline?

ImaginaryHuman(Posted 2012) [#1]
I'm trying to create a timeline. Basically it's sort of a way to store and track sequences of animated objects over time, sort of like a timeline in video editing software except each block of video is made up of keyframes and periods of tweening. Eventually the structure needs to store all objects and their keyframes and tweening for random-access playback.

I'm not quite sure what the best way would be to structure the data to be efficient. I want to be able to jump to any moment in time instantly and pull up all the objects whose animations span that moment and display the appropriate tweened state. I was thinking about splitting time into small chunks and then adding a pointer to every object that spans that chunk .. but that seems like over the course of time there could be thousands of repeated references to the same objects. Is there a better way?

Last edited 2012


Armitage 1982(Posted 2012) [#2]
Maybe you could have a look at the last iteration of CEgui, they are using tweening and keyframes for the animation system and since the whole project is open source with visual editor.

Is your project in fixed rate logic ? Because it's always possible to store position, angle and transformation for each frame within your object for a direct access. I would go that way.


jkrankie(Posted 2012) [#3]
I'd be tempted to create an keyframe object holding the position/rotation whatever and a timestamp and put it in a set. That would keep the number of keyframes to a minimum, and whatever interpolation code you're using could fill in the blanks between timestamps.

Cheers
Charlie


ImaginaryHuman(Posted 2012) [#4]
Yes I understand how to do the keyframes and tweening, that's not a problem. I'm just not sure how to efficiently reference objects in a random-access manner over a long period of time. What if say there is a particle system with 10,000 objects between 17 minutes and 19 minutes on the timeline, does every frame of those 2 minutes have references to all 10,000 objects? That'd be too much.


Kryzon(Posted 2012) [#5]
Anytime you create a keyframe for a controller, you update the controller's active time range.

More on controller theory:

• Every animatable property has a controller. This controller is an object that holds keyframes and is responsible for returning you a tweened value based on these keyframes. It's also the interface you use to add\delete\modify keyframes for a given property.
• There are two kinds of controllers: Linear and Bezier.
• Say your actor is animated on its X, Y and alpha properties. Say you want a linear movement for your actor, you'd use Linear controllers for the X and Y properties. For the alpha you'd want a smooth variation, with some cool curves - you'd use a Bezier controller and make use of tangent controls.
If your actor has a 'visible' property (in reality a boolean property, 'on' or 'off'), you would use a Linear controller with keyframe values that are always 'zero' or '1' so it's animatable and works for this kind of on\off property.
• The keyframe objects stored in a controller hold a value and a time position at the scene's current frame range (the total amount of frames for the scene\animation). Same as Jrankie said.

So a single actor may have tons of child controllers. X, Y, Width, Height, Angle, R, G, B, Alpha, Visible etc. That's 11 controllers right there for a single actor in a 2D game.

Now on to your question about retrieving animated actors\controllers at a given time range.
You need to internally keep track of the time range that the extreme keyframes of a controller occupy. Every controller is gonna have starting and ending keyframes, they're the first and last items of the controller's keyframe TList (if your Tlist is sorted by time, that is).
So this "active time range" for a controller is a pair of values, a "startTime" and "endTime", taken from the 'time' value of the first and last keyframes of a given controller.
Very easy range to determine.

Everytime you create, delete or modify a keyframe for a controller, check to see if this operation will extend or diminish the time range on which this controller has variation.
Updating the controller's active time range every time a keyframe operation is performed is key to being able to select active controllers at a certain time\range: when you need to filter a given time range, go through all controllers in the scene and check their active time ranges - if they happen to intersect with the time range in question with at least one frame then they're the ones you need to collect.

Here's how the timeline\curve graph for a controller with a single frame looks like:

Inactive. The values this controller returns are always the same.

If you add a second or more keyframes and these keyframes have differing values (so the controller is animated, the values it returns will vary along with time), you have an active range for as long as there's variation of value:

If you happen to query the time range that goes beyond that second keyframe, this controller will be reported as inactive.

You can also use this same logic for actors - an actor has an active time range, which represents the range of time any of its properties is active as well. An actor's active time range is the sum of all its child controllers active ranges.
Everytime a controller does a keyframe operation, update not only the controller's active time range but the actor's too. If you're deleting or changing the time of a keyframe from a controller and no other controller from this actor has a keyframe at that position, then the actor's active time range will be shortened.
This way you can have the options to filter not only active controllers but also any active actor (actors that have 'at least' one animated controller\property at a given time\range).

EDIT: I don't think I used the word 'active' appropriately in this context. If the controller has variation at some point in the scene then it should always be considered active.
Something more appropriate would be 'work', or even 'transformation'...
Anway, I hope you can find a better way to name this stuff!

Last edited 2012


ImaginaryHuman(Posted 2012) [#6]
Hey, thanks for all the input, Kyrzon, that's awesome. Thanks for clarifying things.

Based on what you've said I'm starting to think about maybe a bounding volume hierarchy? i.e. have a bounding volume around a group of objects (an `effect` or whatever), and that `box` obviously has a start and end point across time. So instead of having to check every sub-object that might be involved I can just check the larger bounding column or timespan for the group, then IF the group should show in the current frame I should go further into the hierarchy to find subgroups or individual objects. I think that way it will keep checks to a minimum?


AdamRedwoods(Posted 2012) [#7]
minib3d stores bone animation as keyframes and when the 'playhead' is at a certain time it finds the prior keyframe to that time depending on if the playhead is moving forwards or backwards, and interpolates from that keyframe.

each dimension gets it's own value in that keyframe, in 3D programs they're usually referred to as channels. for example, each channel represents x,y,z position and pitch,heading,bank rotation and x,y,z scale.

each keyframe may hold interpolation information as well, and is based on preference: linear, spline, cubic, hermite, or an alternative as tension, bias, continuity.


ImaginaryHuman(Posted 2012) [#8]
Ok cool. You said "it finds the prior keyframe". ... but how? How are all these keyframes stored in such a way that you can just find which ones need to be looked at quickly? Surely you don't search the entire linked list/array of keyframes every time.


AdamRedwoods(Posted 2012) [#9]
from minib3d:



I wouldn't say this is the best way to do this, but it works.

It basically looks up a keyframe at key[frame], and then checks to see if that if the flag value we're looking for. it progresses until we find a match. keys are stored from the B3D file load.

flags = tells us if a keyframe holds a position, rotation or scale value


If you're uneasy about array size for say 1000 objects in a 10000 frame animation, then you'd need to compress this a bit. one way would be to hold a keyframe-time only list (links to values) and utilize a binary search ( http://www.fredosaurus.com/notes-cpp/algorithms/searching/binarysearch.html ).

Last edited 2012


ImaginaryHuman(Posted 2012) [#10]
Ahh yeah a binary search could be useful. Thanks