Skip to content

Commit

Permalink
Merge pull request #1635 from heinezen/feature/keyframe_vector
Browse files Browse the repository at this point in the history
Port curve container types to `std::vector`
  • Loading branch information
TheJJ authored May 8, 2024
2 parents b7ec91b + d2349d5 commit 73c8dfd
Show file tree
Hide file tree
Showing 10 changed files with 381 additions and 314 deletions.
27 changes: 14 additions & 13 deletions libopenage/curve/base_curve.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

#include <cstddef>
#include <functional>
#include <iterator>
#include <memory>
#include <sstream>
#include <string>
Expand Down Expand Up @@ -40,7 +39,7 @@ class BaseCurve : public event::EventEntity {
_id{id},
_idstr{idstr},
loop{loop},
last_element{this->container.begin()} {}
last_element{this->container.size()} {}

virtual ~BaseCurve() = default;

Expand Down Expand Up @@ -193,9 +192,9 @@ class BaseCurve : public event::EventEntity {
const std::shared_ptr<event::EventLoop> loop;

/**
* Cache the iterator for quickly finding the last accessed element (usually the end)
* Cache the index of the last accessed element (usually the end).
*/
mutable typename KeyframeContainer<T>::iterator last_element;
mutable typename KeyframeContainer<T>::elem_ptr last_element;
};


Expand All @@ -204,7 +203,7 @@ void BaseCurve<T>::set_last(const time::time_t &at, const T &value) {
auto hint = this->container.last(at, this->last_element);

// erase max one same-time value
if (hint->time == at) {
if (this->container.get(hint).time() == at) {
hint--;
}

Expand All @@ -221,7 +220,7 @@ template <typename T>
void BaseCurve<T>::set_insert(const time::time_t &at, const T &value) {
auto hint = this->container.insert_after(at, value, this->last_element);
// check if this is now the final keyframe
if (hint->time > this->last_element->time) {
if (this->container.get(hint).time() > this->container.get(this->last_element).time()) {
this->last_element = hint;
}
this->changes(at);
Expand All @@ -244,24 +243,26 @@ void BaseCurve<T>::erase(const time::time_t &at) {

template <typename T>
std::pair<time::time_t, const T> BaseCurve<T>::frame(const time::time_t &time) const {
auto e = this->container.last(time, this->container.end());
return std::make_pair(e->time, e->value);
auto e = this->container.last(time, this->container.size());
auto elem = this->container.get(e);
return std::make_pair(elem.time(), elem.val());
}


template <typename T>
std::pair<time::time_t, const T> BaseCurve<T>::next_frame(const time::time_t &time) const {
auto e = this->container.last(time, this->container.end());
auto e = this->container.last(time, this->container.size());
e++;
return std::make_pair(e->time, e->value);
auto elem = this->container.get(e);
return std::make_pair(elem.time(), elem.val());
}

template <typename T>
std::string BaseCurve<T>::str() const {
std::stringstream ss;
ss << "Curve[" << this->idstr() << "]{" << std::endl;
for (const auto &keyframe : this->container) {
ss << " " << keyframe.time << ": " << keyframe.value << "," << std::endl;
ss << " " << keyframe.time() << ": " << keyframe.val() << "," << std::endl;
}
ss << "}";

Expand All @@ -272,10 +273,10 @@ template <typename T>
void BaseCurve<T>::check_integrity() const {
time::time_t last_time = time::TIME_MIN;
for (const auto &keyframe : this->container) {
if (keyframe.time < last_time) {
if (keyframe.time() < last_time) {
throw Error{MSG(err) << "curve is broken after t=" << last_time << ": " << this->str()};
}
last_time = keyframe.time;
last_time = keyframe.time();
}
}

Expand Down
4 changes: 2 additions & 2 deletions libopenage/curve/continuous.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2017-2023 the openage authors. See copying.md for legal info.
// Copyright 2017-2024 the openage authors. See copying.md for legal info.

#pragma once

Expand Down Expand Up @@ -48,7 +48,7 @@ void Continuous<T>::set_last(const time::time_t &at, const T &value) {
auto hint = this->container.last(at, this->last_element);

// erase all same-time entries
while (hint->time == at) {
while (this->container.get(hint).time() == at) {
hint--;
}

Expand Down
13 changes: 8 additions & 5 deletions libopenage/curve/discrete.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2017-2023 the openage authors. See copying.md for legal info.
// Copyright 2017-2024 the openage authors. See copying.md for legal info.

#pragma once

Expand Down Expand Up @@ -55,7 +55,7 @@ template <typename T>
T Discrete<T>::get(const time::time_t &time) const {
auto e = this->container.last(time, this->last_element);
this->last_element = e; // TODO if Caching?
return e->value;
return this->container.get(e).val();
}


Expand All @@ -78,7 +78,9 @@ template <typename T>
std::pair<time::time_t, T> Discrete<T>::get_time(const time::time_t &time) const {
auto e = this->container.last(time, this->last_element);
this->last_element = e;
return std::make_pair(e->time, e->value);

auto elem = this->container.get(e);
return std::make_pair(elem.time, elem.value);
}


Expand All @@ -89,12 +91,13 @@ std::optional<std::pair<time::time_t, T>> Discrete<T>::get_previous(const time::

// if we're not at the container head
// go back one entry.
if (e == std::begin(this->container)) {
if (e == 0) {
return {};
}

e--;
return std::make_pair(e->time, e->value);
auto elem = this->container.get(e);
return std::make_pair(elem.time(), elem.val());
}

} // namespace openage::curve
2 changes: 1 addition & 1 deletion libopenage/curve/discrete_mod.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ void DiscreteMod<T>::erase(const time::time_t &at) {
BaseCurve<T>::erase(at);

if (this->time_length == at) {
this->time_length = this->last_element->time;
this->time_length = this->container.get(this->container.size() - 1).time();
}
}

Expand Down
19 changes: 10 additions & 9 deletions libopenage/curve/interpolated.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,29 +40,29 @@ class Interpolated : public BaseCurve<T> {

template <typename T>
T Interpolated<T>::get(const time::time_t &time) const {
const auto &e = this->container.last(time, this->last_element);
const auto e = this->container.last(time, this->last_element);
this->last_element = e;

auto nxt = e;
++nxt;

time::time_t interval = 0;

auto offset = time - e->time;
auto offset = time - this->container.get(e).time();

if (nxt != this->container.end()) {
interval = nxt->time - e->time;
if (nxt != this->container.size()) {
interval = this->container.get(nxt).time() - this->container.get(e).time();
}

// here, offset > interval will never hold.
// otherwise the underlying storage is broken.

// If the next element is at the same time, just return the value of this one.
if (nxt == this->container.end() // use the last curve value
|| offset == 0 // values equal -> don't need to interpolate
|| interval == 0) { // values at the same time -> division-by-zero-error
if (nxt == this->container.size() // use the last curve value
|| offset == 0 // values equal -> don't need to interpolate
|| interval == 0) { // values at the same time -> division-by-zero-error

return e->value;
return this->container.get(e).val();
}
else {
// Interpolation between time(now) and time(next) that has elapsed
Expand All @@ -72,7 +72,8 @@ T Interpolated<T>::get(const time::time_t &time) const {
// TODO: nxt->value - e->value will produce wrong results if
// the nxt->value < e->value and curve element type is unsigned
// Example: nxt = 2, e = 4; type = uint8_t ==> 2 - 4 = 254
return e->value + (nxt->value - e->value) * elapsed_frac;
auto diff_value = (this->container.get(nxt).val() - this->container.get(e).val()) * elapsed_frac;
return this->container.get(e).val() + diff_value;
}
}

Expand Down
37 changes: 33 additions & 4 deletions libopenage/curve/keyframe.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,46 @@ class Keyframe {
* New, default-constructed element at the given time
*/
Keyframe(const time::time_t &time) :
time{time} {}
timestamp{time} {}

/**
* New element fron time and value
*/
Keyframe(const time::time_t &time, const T &value) :
time{time},
value{value} {}
value{value},
timestamp{time} {}

const time::time_t time = time::TIME_MIN;
/**
* Get the time of this keyframe.
*
* @return Keyframe time.
*/
const time::time_t &time() const {
return this->timestamp;
}

/**
* Get the value of this keyframe.
*
* @return Keyframe value.
*/
const T &val() const {
return this->value;
}

public:
/**
* Value of the keyframe.
*
* Can be modified by the curve if necessary.
*/
T value = T{};

private:
/**
* Time of the keyframe.
*/
time::time_t timestamp = time::TIME_MIN;
};

} // namespace openage::curve
Loading

0 comments on commit 73c8dfd

Please sign in to comment.