141 lines
4.2 KiB
C
141 lines
4.2 KiB
C
/**
|
|
* Copyright (c) 2021 Dominic Masters
|
|
*
|
|
* This software is released under the MIT License.
|
|
* https://opensource.org/licenses/MIT
|
|
*/
|
|
|
|
#include "timeline.h"
|
|
|
|
void _timelineActionDeltaUpdateStart(
|
|
timeline_t *timeline, timelineaction_t *action, uint8_t i
|
|
) {
|
|
if(action->data == NULL) return;
|
|
*((float *)action->data) = timeline->initials[i];
|
|
}
|
|
|
|
void _timelineActionDeltaUpdateDuration(
|
|
timeline_t *timeline, timelineaction_t *action, uint8_t i
|
|
) {
|
|
float n;
|
|
if(action->data == NULL) return;
|
|
n = timeline->easings[i](
|
|
timelineActionGetTimeRaw(timeline, action)
|
|
);
|
|
*((float *)action->data) = timeline->initials[i] + (timeline->deltas[i] * n);
|
|
}
|
|
|
|
void _timelineActionDeltaUpdateEnd(
|
|
timeline_t *timeline, timelineaction_t *action, uint8_t i
|
|
) {
|
|
if(action->data == NULL) return;
|
|
*((float *)action->data) = timeline->initials[i] + timeline->deltas[i];
|
|
}
|
|
|
|
|
|
void timelineInit(timeline_t *timeline) {
|
|
timeline->current = 0;
|
|
timeline->diff = 0;
|
|
timeline->previous = 0;
|
|
timeline->user = 0;
|
|
timeline->actionCount = 0;
|
|
}
|
|
|
|
void timelineUpdate(timeline_t *timeline, float delta) {
|
|
uint8_t i;
|
|
timelineaction_t *action;
|
|
float full;
|
|
|
|
timeline->diff = delta;
|
|
timeline->previous = timeline->current;
|
|
timeline->current = timeline->current + delta;
|
|
|
|
// Find all actions that would have started or ended in this timespan.
|
|
for(i = 0; i < timeline->actionCount; i++) {
|
|
action = timeline->actions +i;
|
|
|
|
// Has the action started yet?
|
|
if(action->start > timeline->current) continue;
|
|
|
|
// Did we start this frame?
|
|
if(action->start > timeline->previous && action->onStart != NULL) {
|
|
action->onStart(timeline, action, i);
|
|
}
|
|
|
|
// Durations of 0 only fire starts, never ends or durations.
|
|
if(action->duration == 0) continue;
|
|
|
|
// Is the end still in the future? Durations in negatives go forever
|
|
full = action->start+action->duration;
|
|
if(action->duration < 0 || full > timeline->current) {
|
|
if(action->onDuration != NULL) action->onDuration(timeline, action, i);
|
|
} else if(full > timeline->previous) {// Did we end this frame?
|
|
if(action->onEnd != NULL) action->onEnd(timeline, action, i);
|
|
if(action->loop) action->start = timeline->current;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool timelineIsFinished(timeline_t *timeline) {
|
|
uint8_t i;
|
|
timelineaction_t *action;
|
|
|
|
for(i = 0; i < timeline->actionCount; i++) {
|
|
action = timeline->actions +i;
|
|
if(action->start > timeline->current) return false;
|
|
if(action->duration < 0) return false;
|
|
if(action->duration == 0) continue;
|
|
if(action->start+action->duration > timeline->current) return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
timelineaction_t * timelineAddAction(timeline_t *timeline, float start,
|
|
float duration
|
|
) {
|
|
timelineaction_t *action = timeline->actions + (timeline->actionCount++);
|
|
action->loop = false;
|
|
action->start = start, action->duration = duration;
|
|
action->onStart = action->onEnd = action->onDuration = NULL;
|
|
return action;
|
|
}
|
|
|
|
timelineaction_t * timelineAddDeltaAction(timeline_t *timeline,
|
|
float start, float duration, float initial, float delta,
|
|
easefunction_t *easing, float *destination
|
|
) {
|
|
timelineaction_t *action;
|
|
timeline->initials[timeline->actionCount] = initial;
|
|
timeline->deltas[timeline->actionCount] = delta;
|
|
timeline->easings[timeline->actionCount] = (
|
|
easing == NULL ? &easeLinear : easing
|
|
);
|
|
action = timelineAddAction(timeline, start, duration);
|
|
action->data = destination;
|
|
action->onStart = &_timelineActionDeltaUpdateStart;
|
|
action->onDuration = &_timelineActionDeltaUpdateDuration;
|
|
action->onEnd = &_timelineActionDeltaUpdateEnd;
|
|
return action;
|
|
}
|
|
|
|
timelineaction_t * timelineAddDeltaActionTo(timeline_t *timeline,
|
|
float start, float duration, float initial, float end,
|
|
easefunction_t *easing, float *destination
|
|
) {
|
|
return timelineAddDeltaAction(
|
|
timeline, start, duration, initial, end-initial, easing, destination
|
|
);
|
|
}
|
|
|
|
float timelineActionGetTimeRaw(timeline_t *timeline, timelineaction_t *action) {
|
|
return (timeline->current - action->start) / action->duration;
|
|
}
|
|
|
|
float timelineActionGetTime(timeline_t *tl, timelineaction_t *at) {
|
|
return mathClamp(timelineActionGetTimeRaw(tl, at), 0, 1);
|
|
}
|
|
|
|
void timelineClear(timeline_t *timeline) {
|
|
timeline->actionCount = 0;
|
|
} |