diff --git a/libopenage/curve/CMakeLists.txt b/libopenage/curve/CMakeLists.txt index 1aa1efb55b..0b800ced83 100644 --- a/libopenage/curve/CMakeLists.txt +++ b/libopenage/curve/CMakeLists.txt @@ -1,4 +1,5 @@ add_sources(libopenage + array.cpp base_curve.cpp continuous.cpp discrete.cpp diff --git a/libopenage/curve/array.cpp b/libopenage/curve/array.cpp new file mode 100644 index 0000000000..97e07033ce --- /dev/null +++ b/libopenage/curve/array.cpp @@ -0,0 +1,10 @@ +// Copyright 2024-2024 the openage authors. See copying.md for legal info. + + +#include "array.h" + +namespace openage::curve { + +// This file is intended to be empty + +} // openage::curve diff --git a/libopenage/curve/array.h b/libopenage/curve/array.h new file mode 100644 index 0000000000..18f300c2b3 --- /dev/null +++ b/libopenage/curve/array.h @@ -0,0 +1,197 @@ +// Copyright 2024-2024 the openage authors. See copying.md for legal info. + +#pragma once + +#include + +#include "curve/keyframe_container.h" +#include "event/evententity.h" + + +// remember to update docs +namespace openage { +namespace curve { + +template +class Array : event::EventEntity { +public: + Array(const std::shared_ptr &loop, + size_t id, + const std::string &idstr = "", + const EventEntity::single_change_notifier ¬ifier = nullptr) : + EventEntity(loop, notifier), _id{id}, _idstr{idstr}, loop{loop}{} + + // prevent accidental copy of queue + Array(const Array &) = delete; + + + T get(const time::time_t &t, const size_t index) const; + + + std::array get_all(const time::time_t &t) const; + + + consteval size_t size() const; + + std::pair frame(const time::time_t &t, const size_t index) const; + + + std::pair next_frame(const time::time_t &t, const size_t index) const; + + void set_insert(const time::time_t &t, const size_t index, T value); + + void set_last(const time::time_t &t, const size_t index, T value); + + void set_replace(const time::time_t &t, const size_t index, T value); + + void sync(const Array &other, const time::time_t &t); + + + /** + * Get the identifier of this curve. + * + * @return Identifier. + */ + size_t id() const override { + return this->_id; + } + + /** + * Get the human-readable identifier of this curve. + * + * @return Human-readable identifier. + */ + std::string idstr() const override { + if (this->_idstr.size() == 0) { + return std::to_string(this->id()); + } + return this->_idstr; + } + + + + class Iterator { + public: + Iterator(Array *curve, const time::time_t &time = time::TIME_MAX, size_t offset = 0) : + curve(curve), time(time), offset(offset) {}; + + const T &operator*() { + return curve->frame(this->time, this->offset).second; + } + + void operator++() { + this->offset++; + } + + bool operator!=(const Array::Iterator &rhs) const { + return this->offset != rhs.offset; + } + + + private: + size_t offset; + Array *curve; + time::time_t time; + }; + + + Iterator begin(const time::time_t &time = time::TIME_MAX); + + Iterator end(const time::time_t &time = time::TIME_MAX); + + +private: + std::array, Size> container; + + //hint for KeyframeContainer operations + mutable std::array last_element = {}; + + /** + * Identifier for the container + */ + const size_t _id; + + /** + * Human-readable identifier for the container + */ + const std::string _idstr; + + /** + * The eventloop this curve was registered to + */ + const std::shared_ptr loop; +}; + + +template +std::pair Array::frame(const time::time_t &t, const size_t index) const { + size_t frmae_index = container[index].last(t, this->last_element[index]); + this->last_element[index] = frmae_index; + return container[index].get(frmae_index).make_pair(); +} + +template +std::pair Array::next_frame(const time::time_t &t, const size_t index) const { + size_t frmae_index = container[index].last(t, this->last_element[index]); + this->last_element[index] = frmae_index; + return container[index].get(frmae_index + 1); +} + +template +T Array::get(const time::time_t &t, const size_t index) const { + return this->frame(t, index).second; +} + +template +std::array Array::get_all(const time::time_t &t) const { + return [&](std::index_sequence) { + return std::array{this->get(t, I)...}; + }(std::make_index_sequence{}); +} + +template +consteval size_t Array::size() const { + return Size; +} + + +template +void Array::set_insert(const time::time_t &t, const size_t index, T value) { + this->last_element[index] = this->container[index].insert_after(Keyframe(t, value), this->last_element[index]); +} + + +template +void Array::set_last(const time::time_t &t, const size_t index, T value) { + + size_t frame_index = this->container[index].insert_after(Keyframe(t, value), this->last_element[index]); + this->last_element[index] = frame_index; + this->container[index].erase_after(frame_index); +} + + +template +void Array::set_replace(const time::time_t &t, const size_t index, T value) { + this->container[index].insert_overwrite(Keyframe(t, value), this->last_element[index]); +} + +template +void Array::sync(const Array &other, const time::time_t &start) { + for (int i = 0; i < Size; i++) { + this->container[i].sync(other[i], start); + } +} + +template +typename Array::Iterator Array::begin(const time::time_t &time) { + return Array::Iterator(this, time); +} + + +template +typename Array::Iterator Array::end(const time::time_t &time) { + return Array::Iterator(this, time, this->container.size()); +} + +} // namespace curve +} // namespace openage diff --git a/libopenage/curve/keyframe.h b/libopenage/curve/keyframe.h index e868783cbb..a34b0c6262 100644 --- a/libopenage/curve/keyframe.h +++ b/libopenage/curve/keyframe.h @@ -54,6 +54,15 @@ class Keyframe { return this->value; } + /** + * Get the value and timestamp of the keyframe in form of std::pair + * @return keyframe pair + */ + std::pair make_pair() const + { + return {time(), val()}; + } + public: /** * Value of the keyframe. diff --git a/libopenage/curve/keyframe_container.h b/libopenage/curve/keyframe_container.h index d9bb9a0bbd..8434942058 100644 --- a/libopenage/curve/keyframe_container.h +++ b/libopenage/curve/keyframe_container.h @@ -279,8 +279,6 @@ class KeyframeContainer { * Replaces all keyframes beginning at t >= start with keyframes from \p other. * * @param other Curve that keyframes are copied from. - * @param converter Function that converts the value type of \p other to the - * value type of \p this. * @param start Start time at which keyframes are replaced (default = -INF). * Using the default value replaces ALL keyframes of \p this with * the keyframes of \p other. diff --git a/libopenage/curve/tests/curve_types.cpp b/libopenage/curve/tests/curve_types.cpp index 421d3fb4d7..43f3893a82 100644 --- a/libopenage/curve/tests/curve_types.cpp +++ b/libopenage/curve/tests/curve_types.cpp @@ -5,6 +5,7 @@ #include #include +#include "curve/array.h" #include "curve/continuous.h" #include "curve/discrete.h" #include "curve/discrete_mod.h" @@ -232,7 +233,7 @@ void curve_types() { TESTEQUALS(c.get(8), 4); } - //Check the discrete type + // Check the discrete type { auto f = std::make_shared(); Discrete c(f, 0); @@ -257,7 +258,7 @@ void curve_types() { TESTEQUALS(complex.get(10), "Test 10"); } - //Check the discrete mod type + // Check the discrete mod type { auto f = std::make_shared(); DiscreteMod c(f, 0); @@ -290,7 +291,7 @@ void curve_types() { TESTEQUALS(c.get_mod(15, 0), 0); } - //check set_last + // check set_last { auto f = std::make_shared(); Discrete c(f, 0); @@ -386,6 +387,18 @@ void curve_types() { TESTEQUALS(c.get(1), 0); TESTEQUALS(c.get(5), 0); } + + { // array + auto f = std::make_shared(); + + Array a(f,0); + a.set_insert(time::time_t(1), 0, 0); + a.set_insert(time::time_t(1), 1, 1); + const auto res = a.get_all(1); + TESTEQUALS(res[0], 0); + TESTEQUALS(res[1], 1); + //TODO + } } } // namespace openage::curve::tests