Skip to content

Commit

Permalink
[SVG] Fixed issues with the synchronisation of animation timers.
Browse files Browse the repository at this point in the history
  • Loading branch information
paul-manias committed Apr 23, 2024
1 parent 890e546 commit 7c775d7
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 59 deletions.
48 changes: 47 additions & 1 deletion src/svg/animation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,50 @@
// https://www.w3.org/TR/2001/REC-smil-animation-20010904

//********************************************************************************************************************
// Set common animation properties

void anim_base::activate(extSVG *SVG)
{
// Reset all the variables that control time management and the animation will start from scratch.
begin_offset = (double(PreciseTime()) / 1000000.0) - SVG->AnimEpoch;
repeat_index = 0;
start_time = SVG->AnimEpoch + begin_offset;
end_time = 0;

// Test: w3-animate-elem-21-t.svg

for (auto &other : start_on_begin) {
other->activate(SVG);
other->start_time = start_time; // Ensure that times match exactly
}
}

//********************************************************************************************************************

void anim_base::stop(extSVG *SVG, double Time)
{
if (!begin_series.empty()) {
// Check if there's a serialised begin offset following the one that's completed.
LONG i;
for (i=0; i < std::ssize(begin_series)-1; i++) {
if (begin_offset IS begin_series[i]) {
begin_offset = begin_series[i+1];
start_time = 0;
return;
}
}
}

end_time = Time;
seek = 1.0; // Necessary in case the seek range calculation has overflowed

// Start animations that are to be triggered from our ending.
for (auto &other : start_on_end) {
other->activate(SVG);
other->start_time = Time;
}
}

//********************************************************************************************************************

static ERR parse_spline(APTR Path, LONG Index, LONG Command, double X, double Y, anim_base::SPLINE_POINTS &Meta)
{
Expand All @@ -17,6 +60,9 @@ static ERR parse_spline(APTR Path, LONG Index, LONG Command, double X, double Y,
return ERR::Okay;
}

//********************************************************************************************************************
// Set common animation properties

static ERR set_anim_property(extSVG *Self, anim_base &Anim, XMLTag &Tag, ULONG Hash, const std::string_view Value)
{
switch (Hash) {
Expand Down
36 changes: 3 additions & 33 deletions src/svg/animation.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ class anim_base {
double min_duration = 0; // The minimum value of the active duration. If zero, the active duration is not constrained.
double max_duration = 0; // The maximum value of the active duration.
double duration = 0; // Measured in seconds, anything < 0 means infinite.
double first_time = 0; // Time-stamp of the first iteration
double start_time = 0; // This is time-stamped once the animation has started (the first begin event is hit)
double end_time = 0; // This is time-stamped once the animation has finished all of its cycles (including repetitions)
double end = 0;
Expand All @@ -145,40 +144,11 @@ class anim_base {
double get_numeric_value(objVector &, FIELD);
std::string get_string();
FRGB get_colour_value(objVector &, FIELD);
bool started(double);
bool started(extSVG *, double);
bool next_frame(double);
void set_orig_value();

void activate(void) {
// Reset all the variables that control time management and the animation will start from scratch.
begin_offset = 0;
repeat_index = 0;
start_time = 0;
end_time = 0;
}

void stop(double Time) {
if (!begin_series.empty()) {
// Check if there's a serialised begin offset following the one that's completed.
LONG i;
for (i=0; i < std::ssize(begin_series)-1; i++) {
if (begin_offset IS begin_series[i]) {
begin_offset = begin_series[i+1];
start_time = 0;
return;
}
}
}

end_time = Time;
seek = 1.0; // Necessary in case the seek range calculation has overflowed

// Start animations that are to be triggered from our ending.
for (auto &other : start_on_end) {
other->activate();
other->start_time = Time;
}
}
void activate(extSVG *);
void stop(extSVG *, double);

virtual void perform(class extSVG &) = 0;

Expand Down
45 changes: 23 additions & 22 deletions src/svg/animation_timing.cpp
Original file line number Diff line number Diff line change
@@ -1,27 +1,26 @@

//********************************************************************************************************************
// Return true if the animation has started
// Return true if the animation has started. For absolute consistency, animations start 'at the time they should have
// started', which we can strictly calculate from begin and duration timing values.

bool anim_base::started(double CurrentTime)
bool anim_base::started(extSVG *SVG, double CurrentTime)
{
if (not first_time) first_time = CurrentTime;

if (end_time) return false;
if (start_time) return true;
if (repeat_index > 0) return true;

if (begin_offset) {
// Check if one of the animation's begin triggers has been tripped.
const double elapsed = CurrentTime - start_time;
if (elapsed < begin_offset) return false;
}
// Check if the begin trigger has been tripped. If begin_offset is 0 then we start immediately.

if (CurrentTime < SVG->AnimEpoch + begin_offset) return false;
start_time = SVG->AnimEpoch + begin_offset;

// Start/Reset linked animations that are to start when we do

// Start/Reset linked animations
for (auto &other : start_on_begin) {
other->activate();
other->start_time = CurrentTime;
other->activate(SVG);
other->start_time = start_time; // Ensure that times match exactly
}

start_time = CurrentTime;
return true;
}

Expand Down Expand Up @@ -71,17 +70,19 @@ static ERR animation_timer(extSVG *SVG, LARGE TimeElapsed, LARGE CurrentTime)
matrix.second.transforms.clear();
}

for (auto &record : SVG->Animations) {
std::visit([SVG](auto &&anim) {
double current_time = double(PreciseTime()) / 1000000.0;
if (!SVG->AnimEpoch) {
SVG->AnimEpoch = double(CurrentTime) / 1000000.0;
}

if (not anim.started(current_time)) return;
double current_time = double(CurrentTime) / 1000000.0;

if (anim.next_frame(current_time)) {
anim.perform(*SVG);
anim.stop(current_time);
}
else anim.perform(*SVG);
for (auto &record : SVG->Animations) {
std::visit([ SVG, current_time ](auto &&anim) {
if (not anim.started(SVG, current_time)) return;

bool stop = anim.next_frame(current_time);
anim.perform(*SVG);
if (stop) anim.stop(SVG, current_time);
}, record);
}

Expand Down
4 changes: 2 additions & 2 deletions src/svg/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2371,8 +2371,8 @@ static ERR link_event(objVector *Vector, const InputEvent *Events, svgLink *Link
// The link activates a document node, like an animation.
if (find_href_tag(Self, Link->ref)) {
for (auto &record : Self->Animations) {
std::visit([ Link ](auto &&anim) {
if (anim.id IS Link->ref.substr(1)) anim.activate();
std::visit([ Link, Self ](auto &&anim) {
if (anim.id IS Link->ref.substr(1)) anim.activate(Self);
}, record);
}
}
Expand Down
6 changes: 5 additions & 1 deletion src/svg/svg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ Relevant SVG reference manuals:
#include <parasol/modules/display.h>
#include <parasol/strings.hpp>
#include "svg_def.c"
#include "animation.h"
#include <katana.h>
#include <math.h>

Expand Down Expand Up @@ -71,6 +70,10 @@ struct svgAnimState {

#include <parasol/modules/svg.h>

class extSVG;

#include "animation.h"

//********************************************************************************************************************

class extSVG : public objSVG {
Expand All @@ -79,6 +82,7 @@ class extSVG : public objSVG {
std::unordered_map<std::string, XMLTag> IDs;
std::unordered_map<std::string, objFilterEffect *> Effects; // All effects, registered by their SVG identifier.
DOUBLE SVGVersion;
DOUBLE AnimEpoch; // Epoch time for the animations.
objXML *XML;
objVectorScene *Scene;
STRING Folder;
Expand Down

0 comments on commit 7c775d7

Please sign in to comment.