mirror of
https://github.com/enduro2d/enduro2d.git
synced 2025-12-16 14:08:59 +07:00
calculation delta time and company
This commit is contained in:
@@ -70,6 +70,18 @@ namespace e2d
|
|||||||
bool fullscreen_{false};
|
bool fullscreen_{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class timer_parameters {
|
||||||
|
public:
|
||||||
|
timer_parameters& minimal_framerate(u32 value) noexcept;
|
||||||
|
timer_parameters& maximal_framerate(u32 value) noexcept;
|
||||||
|
|
||||||
|
u32 minimal_framerate() const noexcept;
|
||||||
|
u32 maximal_framerate() const noexcept;
|
||||||
|
private:
|
||||||
|
u32 minimal_framerate_{30u};
|
||||||
|
u32 maximal_framerate_{1000u};
|
||||||
|
};
|
||||||
|
|
||||||
class parameters {
|
class parameters {
|
||||||
public:
|
public:
|
||||||
parameters() = delete;
|
parameters() = delete;
|
||||||
@@ -79,21 +91,25 @@ namespace e2d
|
|||||||
parameters& company_name(str_view value) noexcept;
|
parameters& company_name(str_view value) noexcept;
|
||||||
parameters& debug_params(const debug_parameters& value);
|
parameters& debug_params(const debug_parameters& value);
|
||||||
parameters& window_params(const window_parameters& value);
|
parameters& window_params(const window_parameters& value);
|
||||||
|
parameters& timer_params(const timer_parameters& value);
|
||||||
|
|
||||||
str& game_name() noexcept;
|
str& game_name() noexcept;
|
||||||
str& company_name() noexcept;
|
str& company_name() noexcept;
|
||||||
debug_parameters& debug_params() noexcept;
|
debug_parameters& debug_params() noexcept;
|
||||||
window_parameters& window_params() noexcept;
|
window_parameters& window_params() noexcept;
|
||||||
|
timer_parameters& timer_params() noexcept;
|
||||||
|
|
||||||
const str& game_name() const noexcept;
|
const str& game_name() const noexcept;
|
||||||
const str& company_name() const noexcept;
|
const str& company_name() const noexcept;
|
||||||
const debug_parameters& debug_params() const noexcept;
|
const debug_parameters& debug_params() const noexcept;
|
||||||
const window_parameters& window_params() const noexcept;
|
const window_parameters& window_params() const noexcept;
|
||||||
|
const timer_parameters& timer_params() const noexcept;
|
||||||
private:
|
private:
|
||||||
str game_name_{"noname"};
|
str game_name_{"noname"};
|
||||||
str company_name_{"noname"};
|
str company_name_{"noname"};
|
||||||
debug_parameters debug_params_;
|
debug_parameters debug_params_;
|
||||||
window_parameters window_params_;
|
window_parameters window_params_;
|
||||||
|
timer_parameters timer_params_;
|
||||||
};
|
};
|
||||||
public:
|
public:
|
||||||
engine(const parameters& params);
|
engine(const parameters& params);
|
||||||
@@ -102,6 +118,13 @@ namespace e2d
|
|||||||
template < typename Application, typename... Args >
|
template < typename Application, typename... Args >
|
||||||
bool start(Args&&... args);
|
bool start(Args&&... args);
|
||||||
bool start(application_uptr app);
|
bool start(application_uptr app);
|
||||||
|
|
||||||
|
f32 time() const noexcept;
|
||||||
|
f32 delta_time() const noexcept;
|
||||||
|
|
||||||
|
u32 frame_rate() const noexcept;
|
||||||
|
u32 frame_count() const noexcept;
|
||||||
|
f32 realtime_time() const noexcept;
|
||||||
private:
|
private:
|
||||||
class internal_state;
|
class internal_state;
|
||||||
std::unique_ptr<internal_state> state_;
|
std::unique_ptr<internal_state> state_;
|
||||||
|
|||||||
@@ -8,27 +8,6 @@
|
|||||||
|
|
||||||
#include "_utils.hpp"
|
#include "_utils.hpp"
|
||||||
|
|
||||||
namespace e2d { namespace time
|
|
||||||
{
|
|
||||||
template < typename T >
|
|
||||||
const seconds<T>& second() noexcept {
|
|
||||||
static seconds<T> second = seconds<T>(T(1));
|
|
||||||
return second;
|
|
||||||
}
|
|
||||||
|
|
||||||
template < typename T >
|
|
||||||
const seconds<T>& minute() noexcept {
|
|
||||||
static seconds<T> minute = second<T>() * T(60);
|
|
||||||
return minute;
|
|
||||||
}
|
|
||||||
|
|
||||||
template < typename T >
|
|
||||||
const seconds<T>& hour() noexcept {
|
|
||||||
static seconds<T> hour = minute<T>() * T(60);
|
|
||||||
return hour;
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
|
|
||||||
namespace e2d
|
namespace e2d
|
||||||
{
|
{
|
||||||
template < typename T >
|
template < typename T >
|
||||||
@@ -143,6 +122,63 @@ namespace e2d { namespace time
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
namespace e2d { namespace time
|
||||||
|
{
|
||||||
|
template < typename T >
|
||||||
|
const seconds<T>& second() noexcept {
|
||||||
|
static seconds<T> second = seconds<T>(T(1));
|
||||||
|
return second;
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
const milliseconds<T>& second_ms() noexcept {
|
||||||
|
static milliseconds<T> second_ms = to_milliseconds(second<T>());
|
||||||
|
return second_ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
const microseconds<T>& second_us() noexcept {
|
||||||
|
static microseconds<T> second_us = to_microseconds(second<T>());
|
||||||
|
return second_us;
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
const seconds<T>& minute() noexcept {
|
||||||
|
static seconds<T> minute = second<T>() * T(60);
|
||||||
|
return minute;
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
const milliseconds<T>& minute_ms() noexcept {
|
||||||
|
static milliseconds<T> minute_ms = to_milliseconds(minute<T>());
|
||||||
|
return minute_ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
const microseconds<T>& minute_us() noexcept {
|
||||||
|
static microseconds<T> minute_us = to_microseconds(minute<T>());
|
||||||
|
return minute_us;
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
const seconds<T>& hour() noexcept {
|
||||||
|
static seconds<T> hour = minute<T>() * T(60);
|
||||||
|
return hour;
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
const milliseconds<T>& hour_ms() noexcept {
|
||||||
|
static milliseconds<T> hour_ms = to_milliseconds(hour<T>());
|
||||||
|
return hour_ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename T >
|
||||||
|
const microseconds<T>& hour_us() noexcept {
|
||||||
|
static microseconds<T> hour_us = to_microseconds(hour<T>());
|
||||||
|
return hour_us;
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
namespace e2d { namespace time
|
namespace e2d { namespace time
|
||||||
{
|
{
|
||||||
template < typename TimeTag >
|
template < typename TimeTag >
|
||||||
|
|||||||
@@ -83,6 +83,28 @@ namespace e2d
|
|||||||
return console_logging_;
|
return console_logging_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// engine::timer_parameters
|
||||||
|
//
|
||||||
|
|
||||||
|
engine::timer_parameters& engine::timer_parameters::minimal_framerate(u32 value) noexcept {
|
||||||
|
minimal_framerate_ = value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
engine::timer_parameters& engine::timer_parameters::maximal_framerate(u32 value) noexcept {
|
||||||
|
maximal_framerate_ = value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 engine::timer_parameters::minimal_framerate() const noexcept {
|
||||||
|
return minimal_framerate_;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 engine::timer_parameters::maximal_framerate() const noexcept {
|
||||||
|
return maximal_framerate_;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// engine::window_parameters
|
// engine::window_parameters
|
||||||
//
|
//
|
||||||
@@ -142,6 +164,11 @@ namespace e2d
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
engine::parameters& engine::parameters::timer_params(const timer_parameters& value) {
|
||||||
|
timer_params_ = value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
str& engine::parameters::game_name() noexcept {
|
str& engine::parameters::game_name() noexcept {
|
||||||
return game_name_;
|
return game_name_;
|
||||||
}
|
}
|
||||||
@@ -158,6 +185,10 @@ namespace e2d
|
|||||||
return window_params_;
|
return window_params_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
engine::timer_parameters& engine::parameters::timer_params() noexcept {
|
||||||
|
return timer_params_;
|
||||||
|
}
|
||||||
|
|
||||||
const str& engine::parameters::game_name() const noexcept {
|
const str& engine::parameters::game_name() const noexcept {
|
||||||
return game_name_;
|
return game_name_;
|
||||||
}
|
}
|
||||||
@@ -174,14 +205,93 @@ namespace e2d
|
|||||||
return window_params_;
|
return window_params_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const engine::timer_parameters& engine::parameters::timer_params() const noexcept {
|
||||||
|
return timer_params_;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// engine::internal_state
|
// engine
|
||||||
//
|
//
|
||||||
|
|
||||||
class engine::internal_state final : private e2d::noncopyable {
|
class engine::internal_state final : private e2d::noncopyable {
|
||||||
public:
|
public:
|
||||||
internal_state() = default;
|
internal_state(const parameters& params)
|
||||||
|
: timer_params_(params.timer_params())
|
||||||
|
{
|
||||||
|
const auto first_frame_time = math::clamp(
|
||||||
|
math::max(timer_params_.minimal_framerate(), timer_params_.maximal_framerate()),
|
||||||
|
1u,
|
||||||
|
1000u);
|
||||||
|
delta_time_us_.store(
|
||||||
|
(time::second_us<u64>() / math::numeric_cast<u64>(first_frame_time)).value);
|
||||||
|
}
|
||||||
~internal_state() noexcept = default;
|
~internal_state() noexcept = default;
|
||||||
|
public:
|
||||||
|
f32 time() const noexcept {
|
||||||
|
return time::to_seconds(
|
||||||
|
make_microseconds(time_us_.load()).cast_to<f32>()).value;
|
||||||
|
}
|
||||||
|
|
||||||
|
f32 delta_time() const noexcept {
|
||||||
|
return time::to_seconds(
|
||||||
|
make_microseconds(delta_time_us_.load()).cast_to<f32>()).value;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 frame_rate() const noexcept {
|
||||||
|
return frame_rate_.load();
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 frame_count() const noexcept {
|
||||||
|
return frame_count_.load();
|
||||||
|
}
|
||||||
|
|
||||||
|
f32 realtime_time() const noexcept {
|
||||||
|
const auto delta_us = time::now_us().cast_to<u64>() - init_time_;
|
||||||
|
return time::to_seconds(delta_us.cast_to<f32>()).value;
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
void calculate_end_frame_timers() noexcept {
|
||||||
|
const auto second_us = time::second_us<u64>();
|
||||||
|
|
||||||
|
const auto minimal_delta_time_us =
|
||||||
|
second_us / math::numeric_cast<u64>(math::clamp(
|
||||||
|
timer_params_.maximal_framerate(), 1u, 1000u));
|
||||||
|
|
||||||
|
const auto maximal_delta_time_us =
|
||||||
|
second_us / math::numeric_cast<u64>(math::clamp(
|
||||||
|
timer_params_.minimal_framerate(), 1u, 1000u));
|
||||||
|
|
||||||
|
auto now_us = time::now_us().cast_to<u64>();
|
||||||
|
while ( now_us - prev_frame_time_ < minimal_delta_time_us ) {
|
||||||
|
std::this_thread::yield();
|
||||||
|
now_us = time::now_us().cast_to<u64>();
|
||||||
|
}
|
||||||
|
|
||||||
|
delta_time_us_.store(math::minimized(
|
||||||
|
now_us - prev_frame_time_,
|
||||||
|
maximal_delta_time_us).value);
|
||||||
|
|
||||||
|
time_us_.store((now_us - init_time_).value);
|
||||||
|
prev_frame_time_ = now_us;
|
||||||
|
|
||||||
|
frame_count_.fetch_add(1);
|
||||||
|
frame_rate_counter_.fetch_add(1);
|
||||||
|
while ( now_us - prev_frame_rate_time_ >= second_us ) {
|
||||||
|
prev_frame_rate_time_ += second_us;
|
||||||
|
frame_rate_.store(frame_rate_counter_.exchange(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
timer_parameters timer_params_;
|
||||||
|
microseconds<u64> init_time_{time::now_us().cast_to<u64>()};
|
||||||
|
microseconds<u64> prev_frame_time_{time::now_us().cast_to<u64>()};
|
||||||
|
microseconds<u64> prev_frame_rate_time_{time::now_us().cast_to<u64>()};
|
||||||
|
std::atomic_uint64_t time_us_{0};
|
||||||
|
std::atomic_uint64_t delta_time_us_{0};
|
||||||
|
std::atomic_uint32_t frame_rate_{0};
|
||||||
|
std::atomic_uint32_t frame_count_{0};
|
||||||
|
std::atomic_uint32_t frame_rate_counter_{0};
|
||||||
|
u8 _pad[4] = {0};
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -189,7 +299,7 @@ namespace e2d
|
|||||||
//
|
//
|
||||||
|
|
||||||
engine::engine(const parameters& params)
|
engine::engine(const parameters& params)
|
||||||
: state_(new internal_state())
|
: state_(new internal_state(params))
|
||||||
{
|
{
|
||||||
// setup debug
|
// setup debug
|
||||||
|
|
||||||
@@ -244,20 +354,48 @@ namespace e2d
|
|||||||
engine::~engine() noexcept = default;
|
engine::~engine() noexcept = default;
|
||||||
|
|
||||||
bool engine::start(application_uptr app) {
|
bool engine::start(application_uptr app) {
|
||||||
|
E2D_ASSERT(main_thread() == std::this_thread::get_id());
|
||||||
|
|
||||||
if ( !app || !app->initialize() ) {
|
if ( !app || !app->initialize() ) {
|
||||||
the<debug>().error("ENGINE: Failed to initialize application");
|
the<debug>().error("ENGINE: Failed to initialize application");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
try {
|
|
||||||
while ( app->frame_tick() ) {
|
while ( true ) {
|
||||||
the<input>().frame_tick();
|
try {
|
||||||
window::poll_events();
|
if ( !app->frame_tick() ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
state_->calculate_end_frame_timers();
|
||||||
|
} catch ( ... ) {
|
||||||
|
app->shutdown();
|
||||||
|
throw;
|
||||||
}
|
}
|
||||||
} catch ( ... ) {
|
the<input>().frame_tick();
|
||||||
app->shutdown();
|
window::poll_events();
|
||||||
throw;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
app->shutdown();
|
app->shutdown();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
f32 engine::time() const noexcept {
|
||||||
|
return state_->time();
|
||||||
|
}
|
||||||
|
|
||||||
|
f32 engine::delta_time() const noexcept {
|
||||||
|
return state_->delta_time();
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 engine::frame_rate() const noexcept {
|
||||||
|
return state_->frame_rate();
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 engine::frame_count() const noexcept {
|
||||||
|
return state_->frame_count();
|
||||||
|
}
|
||||||
|
|
||||||
|
f32 engine::realtime_time() const noexcept {
|
||||||
|
return state_->realtime_time();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,16 @@ using namespace e2d;
|
|||||||
TEST_CASE("time") {
|
TEST_CASE("time") {
|
||||||
{
|
{
|
||||||
REQUIRE(time::second<i32>().value == 1);
|
REQUIRE(time::second<i32>().value == 1);
|
||||||
|
REQUIRE(time::second_ms<i32>().value == 1000);
|
||||||
|
REQUIRE(time::second_us<i32>().value == 1'000'000);
|
||||||
|
|
||||||
REQUIRE(time::minute<i32>().value == 60);
|
REQUIRE(time::minute<i32>().value == 60);
|
||||||
|
REQUIRE(time::minute_ms<i32>().value == 60000);
|
||||||
|
REQUIRE(time::minute_us<i32>().value == 60'000'000);
|
||||||
|
|
||||||
REQUIRE(time::hour<i32>().value == 60 * 60);
|
REQUIRE(time::hour<i32>().value == 60 * 60);
|
||||||
|
REQUIRE(time::hour_ms<i32>().value == 60 * 60 * 1000);
|
||||||
|
REQUIRE(time::hour_us<i64>().value == 60 * 60 * i64(1'000'000));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
REQUIRE(make_seconds(1).convert_to<milliseconds_tag>().value == 1000);
|
REQUIRE(make_seconds(1).convert_to<milliseconds_tag>().value == 1000);
|
||||||
|
|||||||
Reference in New Issue
Block a user