diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2024-02-29 21:29:56 +0100 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2024-03-01 06:06:53 +0100 |
commit | 486e591169af724107ffaf6f24cd1e81b24529a9 (patch) | |
tree | 012ec6c07c474d4695eb5c22b47dd35cfce2767c /src | |
parent | 5afe42d6a81eeb81db08d4bd2107ac4c71f6671e (diff) |
time wip
It works now, but some functionality is lost in main/draw.cpp
Diffstat (limited to 'src')
-rw-r--r-- | src/anim.hpp | 2 | ||||
-rw-r--r-- | src/critter.cpp | 62 | ||||
-rw-r--r-- | src/critter.hpp | 8 | ||||
-rw-r--r-- | src/light.cpp | 3 | ||||
-rw-r--r-- | src/light.hpp | 2 | ||||
-rw-r--r-- | src/object.cpp | 36 | ||||
-rw-r--r-- | src/object.hpp | 6 | ||||
-rw-r--r-- | src/scenery.cpp | 16 | ||||
-rw-r--r-- | src/scenery.hpp | 6 | ||||
-rw-r--r-- | src/timer-fwd.hpp | 27 | ||||
-rw-r--r-- | src/timer.cpp | 76 | ||||
-rw-r--r-- | src/timer.hpp | 13 |
12 files changed, 198 insertions, 59 deletions
diff --git a/src/anim.hpp b/src/anim.hpp index 3c25f51c..e22d1e6b 100644 --- a/src/anim.hpp +++ b/src/anim.hpp @@ -57,7 +57,7 @@ struct anim_def final Array<anim_group> groups{}; Vector2ui pixel_size{}; anim_scale scale = anim_scale::ratio{1}; - size_t nframes = 0, fps = 0, action_frame = 0, action_frame2 = 0; + uint32_t nframes = 0, fps = 0, action_frame = 0, action_frame2 = 0; }; } // namespace floormat diff --git a/src/critter.cpp b/src/critter.cpp index 1a4f77a1..fb3d7e52 100644 --- a/src/critter.cpp +++ b/src/critter.cpp @@ -4,13 +4,13 @@ #include "loader/loader.hpp" #include "src/world.hpp" #include "src/object.hpp" +#include "src/timer.hpp" #include "shaders/shader.hpp" #include "compat/exception.hpp" #include <cmath> #include <utility> #include <algorithm> #include <mg/Functions.h> -#include <mg/Timeline.h> namespace floormat { @@ -110,17 +110,6 @@ bool critter_proto::operator==(const object_proto& e0) const return name == s0.name && playable == s0.playable; } -int critter::allocate_frame_time(float dt) -{ - auto d = (double)delta / 65535. + (double)dt; - d = std::min(1., d); - auto ret = (int)(d / frame_time); - d -= ret; - d = Math::clamp(d, 0., 1.); - delta = (uint16_t)(d * 65535); - return ret; -} - void critter::set_keys(bool L, bool R, bool U, bool D) { b_L = L; @@ -140,10 +129,30 @@ Vector2 critter::ordinal_offset(Vector2b offset) const return Vector2(offset); } -void critter::update(size_t i, float dt) +void critter::update(size_t i, Ns dt) { if (playable) { +#if 0 + static auto TL = Time::now(); + static Ns TIME{0}; + static unsigned FRAMES; + + if (++FRAMES == 0) + TL = Time::now(); + else + TIME += dt; + + if (++FRAMES > 240) + { + auto t = TL.update(); + Debug{} << "player time" << Time::to_milliseconds(TIME) << Time::to_milliseconds(t); + Debug{} << Time::to_milliseconds(TIME) / Time::to_milliseconds(t); + TIME = Ns{0}; + FRAMES = 0; + } +#endif + const auto new_r = arrows_to_dir(b_L, b_R, b_U, b_D); if (new_r == rotation_COUNT) { @@ -157,21 +166,21 @@ void critter::update(size_t i, float dt) update_nonplayable(i, dt); } -void critter::update_nonplayable(size_t i, float dt) +void critter::update_nonplayable(size_t i, Ns dt) { (void)i; (void)dt; (void)playable; } -void critter::update_movement(size_t i, float dt, rotation new_r) +void critter::update_movement(size_t i, Ns dt, rotation new_r) { fm_assert(new_r < rotation_COUNT); fm_assert(is_dynamic()); - int nframes = allocate_frame_time(dt * speed); + auto nframes = allocate_frame_time(dt * speed); if (nframes == 0) { static unsigned foo; - Debug{} << ++foo << "stopped"; + //Debug{} << ++foo << "stopped"; return; } @@ -184,24 +193,7 @@ void critter::update_movement(size_t i, float dt, rotation new_r) c->ensure_passability(); - static Timeline TL{}; - static double TIME; - static unsigned FRAMES; - - if (++FRAMES == 0) - TL.start(); - else - TIME += (double)dt; - - if (++FRAMES > 30) - { - Debug{} << "player time" << TIME; - TL.stop(); - TIME = 0; - FRAMES = 0; - } - - for (int k = 0; k < nframes; k++) + for (auto k = 0u; k < nframes; k++) { for (unsigned j = 0; j < nvecs; j++) { diff --git a/src/critter.hpp b/src/critter.hpp index a6e9e4cc..01159710 100644 --- a/src/critter.hpp +++ b/src/critter.hpp @@ -26,9 +26,9 @@ struct critter final : object object_type type() const noexcept override; explicit operator critter_proto() const; - void update(size_t i, float dt) override; - void update_movement(size_t i, float dt, rotation r); - void update_nonplayable(size_t i, float dt); + void update(size_t i, Ns dt) override; + void update_movement(size_t i, Ns dt, rotation r); + void update_nonplayable(size_t i, Ns dt); void set_keys(bool L, bool R, bool U, bool D); Vector2 ordinal_offset(Vector2b offset) const override; float depth_offset() const override; @@ -40,8 +40,6 @@ struct critter final : object bool playable : 1 = false; private: - int allocate_frame_time(float dt); - friend class world; critter(object_id id, class chunk& c, const critter_proto& proto); }; diff --git a/src/light.cpp b/src/light.cpp index 3de02885..ead434a2 100644 --- a/src/light.cpp +++ b/src/light.cpp @@ -1,4 +1,5 @@ #include "light.hpp" +#include "timer.hpp" #include "tile-constants.hpp" #include "shaders/shader.hpp" #include "loader/loader.hpp" @@ -52,7 +53,7 @@ light::operator light_proto() const } object_type light::type() const noexcept { return object_type::light; } -void light::update(size_t, float) {} +void light::update(size_t, Ns) {} bool light::is_dynamic() const { return true; } bool light::is_virtual() const { return true; } diff --git a/src/light.hpp b/src/light.hpp index 92da2a19..91709b1b 100644 --- a/src/light.hpp +++ b/src/light.hpp @@ -33,7 +33,7 @@ struct light final : object Vector2 ordinal_offset(Vector2b offset) const override; float depth_offset() const override; object_type type() const noexcept override; - void update(size_t i, float dt) override; + void update(size_t i, Ns dt) override; bool is_dynamic() const override; bool is_virtual() const override; diff --git a/src/object.cpp b/src/object.cpp index 550f8a6b..9aca4705 100644 --- a/src/object.cpp +++ b/src/object.cpp @@ -4,8 +4,9 @@ #include "rotation.inl" #include "anim-atlas.hpp" #include "src/RTree-search.hpp" +#include "src/timer.hpp" +#include "compat/debug.hpp" #include "compat/exception.hpp" -#include "shaders/shader.hpp" #include <cmath> #include <algorithm> #include <Corrade/Containers/GrowableArray.h> @@ -268,6 +269,39 @@ void object::move_to(Magnum::Vector2i delta) move_to(i, delta, r); } +uint32_t object::allocate_frame_time(Ns dt, uint16_t& accum, uint32_t hz) +{ + fm_assert(hz > 0); + fm_assert(dt >= Ns{0}); + constexpr auto ns_in_sec = Ns::Type{Ns(1e9)}; + //const auto count = Ns::Type{ns_in_sec / hz} + accum}; + const auto nsecs = Ns::Type{dt} + accum * ns_in_sec / Ns::Type{65535}; + const auto frame_duration = ns_in_sec / hz; + const auto frames = (uint32_t)(nsecs / frame_duration); + const auto rem = nsecs % frame_duration; + const auto new_accum_ = rem * Ns::Type{65535} / ns_in_sec; + const auto new_accum = (uint16_t)Math::clamp(new_accum_, Ns::Type{0}, Ns::Type{65535}); + [[maybe_unused]] const auto old_accum = accum; + accum = new_accum; +#if 0 + DBG_nospace << "alloc-frame-time: " + << "dt:" << fraction(Time::to_milliseconds(dt)) << "ms" + << ", secs:" << fraction(Time::to_milliseconds(Ns{nsecs}), 1) << " ms" + << ", frames:" << frames + << ", acc:" << new_accum_ + << ", rem:" << rem; +#endif + return frames; +} + +uint32_t object::allocate_frame_time(Ns dt) +{ + fm_assert(atlas); + auto hz = atlas->info().fps; + fm_assert(hz > 0); + return allocate_frame_time(dt, delta, hz); +} + void object::set_bbox_(Vector2b offset_, Vector2b bb_offset_, Vector2ub bb_size_, pass_mode pass_) { const_cast<Vector2b&>(offset) = offset_; diff --git a/src/object.hpp b/src/object.hpp index 2d33885d..e462c8db 100644 --- a/src/object.hpp +++ b/src/object.hpp @@ -6,6 +6,7 @@ #include "src/object-type.hpp" #include "src/object-id.hpp" #include "src/point.hpp" +#include "src/timer-fwd.hpp" #include <memory> namespace floormat { @@ -68,7 +69,7 @@ struct object virtual object_type type() const noexcept = 0; virtual bool can_activate(size_t i) const; virtual bool activate(size_t i); - virtual void update(size_t i, float dt) = 0; + virtual void update(size_t i, Ns dt) = 0; virtual void rotate(size_t i, rotation r); virtual bool can_rotate(global_coords coord, rotation new_r, rotation old_r, Vector2b offset, Vector2b bbox_offset, Vector2ub bbox_size); virtual bool can_move_to(Vector2i delta, global_coords coord, Vector2b offset, Vector2b bbox_offset, Vector2ub bbox_aize); @@ -84,6 +85,9 @@ struct object void move_to(size_t& i, Vector2i delta, rotation new_r); void move_to(Vector2i delta); + static uint32_t allocate_frame_time(Ns dt, uint16_t& accum, uint32_t hz); + uint32_t allocate_frame_time(Ns dt); + protected: object(object_id id, class chunk& c, const object_proto& proto); void set_bbox_(Vector2b offset, Vector2b bbox_offset, Vector2ub bbox_size, pass_mode pass); diff --git a/src/scenery.cpp b/src/scenery.cpp index ed5b643f..b5fd3b59 100644 --- a/src/scenery.cpp +++ b/src/scenery.cpp @@ -7,6 +7,7 @@ #include "shaders/shader.hpp" #include "src/rotation.inl" #include "compat/exception.hpp" +#include "src/timer.hpp" #include <algorithm> namespace floormat { @@ -50,7 +51,7 @@ scenery_proto::operator bool() const { return atlas != nullptr; } bool generic_scenery_proto::operator==(const generic_scenery_proto& p) const = default; enum scenery_type generic_scenery_proto::scenery_type() const { return scenery_type::generic; } -void generic_scenery::update(scenery&, size_t, float) {} +void generic_scenery::update(scenery&, size_t, Ns) {} Vector2 generic_scenery::ordinal_offset(const scenery&, Vector2b offset) const { return Vector2(offset); } bool generic_scenery::can_activate(const scenery&, size_t) const { return interactive; } bool generic_scenery::activate(floormat::scenery&, size_t) { return false; } @@ -80,23 +81,16 @@ door_scenery::door_scenery(object_id, class chunk&, const door_scenery_proto& p) closing{p.closing}, active{p.active}, interactive{p.interactive} {} -void door_scenery::update(scenery& s, size_t, float dt) +void door_scenery::update(scenery& s, size_t, Ns dt) { if (!s.atlas || !active) return; fm_assert(s.atlas); auto& anim = *s.atlas; - const auto hz = uint8_t(s.atlas->info().fps); const auto nframes = (int)anim.info().nframes; fm_debug_assert(anim.info().fps > 0 && anim.info().fps <= 0xff); - - auto delta_ = int(s.delta) + int(65535u * dt); - delta_ = std::min(65535, delta_); - const auto frame_time = int(1.f/hz * 65535); - const auto n = (uint8_t)std::clamp(delta_ / frame_time, 0, 255); - s.delta = (uint16_t)std::clamp(delta_ - frame_time*n, 0, 65535); - fm_debug_assert(s.delta >= 0); + const auto n = (int)s.allocate_frame_time(dt); if (n == 0) return; const int8_t dir = closing ? 1 : -1; @@ -154,7 +148,7 @@ bool scenery::can_activate(size_t i) const ); } -void scenery::update(size_t i, float dt) +void scenery::update(size_t i, Ns dt) { return std::visit( [&]<typename T>(T& sc) { sc.update(*this, i, dt); }, diff --git a/src/scenery.hpp b/src/scenery.hpp index 8b003e73..25d40889 100644 --- a/src/scenery.hpp +++ b/src/scenery.hpp @@ -63,7 +63,7 @@ struct generic_scenery unsigned char active : 1 = false; unsigned char interactive : 1 = false; - void update(scenery& sc, size_t i, float dt); + void update(scenery& sc, size_t i, Ns dt); Vector2 ordinal_offset(const scenery& sc, Vector2b offset) const; bool can_activate(const scenery& sc, size_t i) const; bool activate(scenery& sc, size_t i); @@ -80,7 +80,7 @@ struct door_scenery unsigned char active : 1 = false; unsigned char interactive : 1 = false; - void update(scenery& sc, size_t i, float dt); + void update(scenery& sc, size_t i, Ns dt); Vector2 ordinal_offset(const scenery& sc, Vector2b offset) const; bool can_activate(const scenery& sc, size_t i) const; bool activate(scenery& sc, size_t i); @@ -97,7 +97,7 @@ struct scenery final : object { scenery_variants subtype; - void update(size_t i, float dt) override; + void update(size_t i, Ns dt) override; Vector2 ordinal_offset(Vector2b offset) const override; float depth_offset() const override; bool can_activate(size_t i) const override; diff --git a/src/timer-fwd.hpp b/src/timer-fwd.hpp new file mode 100644 index 00000000..5e11ce7b --- /dev/null +++ b/src/timer-fwd.hpp @@ -0,0 +1,27 @@ +#pragma once +#include <compare> + +namespace Magnum::Math { template<class T> class Nanoseconds; } + +namespace floormat { + +using Ns = Math::Nanoseconds<int64_t>; + +struct Time final +{ + static Time now() noexcept; + bool operator==(const Time&) const noexcept; + std::strong_ordering operator<=>(const Time&) const noexcept; + friend Ns operator-(const Time& a, const Time& b) noexcept; + [[nodiscard]] Ns update(const Time& ts = now()) & noexcept; + + static float to_seconds(const Ns& ts) noexcept; + static float to_milliseconds(const Ns& ts) noexcept; + + uint64_t stamp = init(); + +private: + static uint64_t init() noexcept; +}; + +} // namespace floormat diff --git a/src/timer.cpp b/src/timer.cpp new file mode 100644 index 00000000..0b87ac06 --- /dev/null +++ b/src/timer.cpp @@ -0,0 +1,76 @@ +#include "timer.hpp" +#include "compat/assert.hpp" +#include <ctime> +#include <cstdio> +#include <chrono> +#include <mg/Time.h> + +namespace floormat { + +using std::chrono::duration_cast; +using std::chrono::duration; + +using Clock = std::chrono::high_resolution_clock; +using SystemClock = std::chrono::system_clock; +using Nsecs = duration<uint64_t, std::nano>; +using Millis = duration<unsigned, std::milli>; + +namespace { + +template<typename T> struct array_size_; +template<typename T, size_t N> struct array_size_<T(&)[N]> : std::integral_constant<size_t, N> {}; +template<typename T, size_t N> struct array_size_<std::array<T, N>> : std::integral_constant<size_t, N> {}; +template<typename T> constexpr inline auto array_size = array_size_<T>::value; + +uint64_t get_time() noexcept { return duration_cast<Nsecs>(Clock::now().time_since_epoch()).count(); } + +const uint64_t Epoch = get_time(); + +} // namespace + +Time Time::now() noexcept +{ + auto val = get_time(); + auto ret = val - Epoch; + return {ret}; +} + +Ns operator-(const Time& a, const Time& b) noexcept +{ + fm_assert(a.stamp >= b.stamp); + auto ret = a.stamp - b.stamp; + fm_assert(ret < uint64_t{1} << 63); + return Ns{ int64_t(ret) }; +} + +Ns Time::update(const Time& ts) & noexcept +{ + auto ret = ts - *this; + stamp = ts.stamp; + return ret; +} + +uint64_t Time::init() noexcept { return get_time(); } +bool Time::operator==(const Time&) const noexcept = default; +std::strong_ordering Time::operator<=>(const Time&) const noexcept = default; + +float Time::to_seconds(const Ns& ts) noexcept { return float(Ns::Type{ts} * 1e-9L); } +float Time::to_milliseconds(const Ns& ts) noexcept { return float(Ns::Type{ts} * 1e-6L); } + +const char* format_datetime_to_string(char (&buf)[fm_DATETIME_BUF_SIZE]) +{ + constexpr const char* fmt = "%a, %d %b %Y %H:%M:%S."; + constexpr size_t fmtsize = std::size("Thu 01 Mon 197000 00:00:00."); + static_assert(array_size<decltype(buf)> - fmtsize == 4); + const auto t = SystemClock::now(); + const auto ms = duration_cast<Millis>(t.time_since_epoch()) % 1000; + const auto time = SystemClock::to_time_t(t); + const auto* tm = std::localtime(&time); + auto len = std::strftime(buf, std::size(buf), fmt, tm); + fm_assert(len > 0 && len <= fmtsize); + auto len2 = std::sprintf(buf + len, "%03u", unsigned{ms.count()}); + fm_assert(len2 > 0 && len + (size_t)len2 < std::size(buf)); + return buf; +} + +} // namespace floormat diff --git a/src/timer.hpp b/src/timer.hpp new file mode 100644 index 00000000..24554363 --- /dev/null +++ b/src/timer.hpp @@ -0,0 +1,13 @@ +#pragma once +#include "timer-fwd.hpp" +#include <mg/Time.h> + +namespace floormat { + +long double operator/(Ns a, Ns b) noexcept; +using namespace Magnum::Math::Literals::TimeLiterals; + +constexpr inline size_t fm_DATETIME_BUF_SIZE = 32; +const char* format_datetime_to_string(char(&buf)[fm_DATETIME_BUF_SIZE]); + +} // namespace floormat |