summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2024-02-29 21:29:56 +0100
committerStanislaw Halik <sthalik@misaki.pl>2024-03-01 06:06:53 +0100
commit486e591169af724107ffaf6f24cd1e81b24529a9 (patch)
tree012ec6c07c474d4695eb5c22b47dd35cfce2767c /src
parent5afe42d6a81eeb81db08d4bd2107ac4c71f6671e (diff)
time wip
It works now, but some functionality is lost in main/draw.cpp
Diffstat (limited to 'src')
-rw-r--r--src/anim.hpp2
-rw-r--r--src/critter.cpp62
-rw-r--r--src/critter.hpp8
-rw-r--r--src/light.cpp3
-rw-r--r--src/light.hpp2
-rw-r--r--src/object.cpp36
-rw-r--r--src/object.hpp6
-rw-r--r--src/scenery.cpp16
-rw-r--r--src/scenery.hpp6
-rw-r--r--src/timer-fwd.hpp27
-rw-r--r--src/timer.cpp76
-rw-r--r--src/timer.hpp13
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