Improve loop with fps control
This commit is contained in:
+23
-10
@@ -252,26 +252,35 @@ struct App {
|
|||||||
current_scene_id = scene_pool.acquire(loading_scene);
|
current_scene_id = scene_pool.acquire(loading_scene);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void set_fps(float fps) {
|
||||||
const uint64_t TARGET_NS = 1e9 / 60;
|
this->fps = fps;
|
||||||
|
target_frame_time = 1e9 / fps;
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t time_a = window.get_time();
|
uint64_t get_fps() const {
|
||||||
uint64_t time_b = window.get_time();
|
return fps;
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
uint64_t frame_start = window.get_time();
|
||||||
|
uint64_t frame_end = window.get_time();
|
||||||
|
uint64_t previous_frame_end = 0;
|
||||||
|
|
||||||
while (running) {
|
while (running) {
|
||||||
time_a = window.get_time();
|
frame_start = window.get_time();
|
||||||
uint64_t frame_time = time_a - time_b;
|
uint64_t frame_time = frame_start - frame_end;
|
||||||
|
|
||||||
if (frame_time <= TARGET_NS) {
|
if (frame_time <= target_frame_time) {
|
||||||
struct timespec req;
|
struct timespec req;
|
||||||
req.tv_sec = 0;
|
req.tv_sec = 0;
|
||||||
req.tv_nsec = TARGET_NS - frame_time;
|
req.tv_nsec = target_frame_time - frame_time;
|
||||||
nanosleep(&req, nullptr);
|
nanosleep(&req, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
time_b = window.get_time();
|
previous_frame_end = frame_end;
|
||||||
|
frame_end = window.get_time();
|
||||||
|
|
||||||
uint64_t dt = window.delta_time();
|
float dt = frame_end - previous_frame_end;
|
||||||
|
|
||||||
Scene *scene = scene_pool[current_scene_id];
|
Scene *scene = scene_pool[current_scene_id];
|
||||||
|
|
||||||
@@ -329,6 +338,10 @@ struct App {
|
|||||||
window.clear();
|
window.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint64_t fps = 60;
|
||||||
|
uint64_t target_frame_time = 1e9 / fps;
|
||||||
};
|
};
|
||||||
} // namespace app
|
} // namespace app
|
||||||
|
|
||||||
|
|||||||
@@ -1487,11 +1487,29 @@ static mrb_value scene_hash(mrb_state *mrb, mrb_value self) {
|
|||||||
|
|
||||||
static mrb_value app_run(mrb_state *mrb, mrb_value) {
|
static mrb_value app_run(mrb_state *mrb, mrb_value) {
|
||||||
mrb_int width, height;
|
mrb_int width, height;
|
||||||
|
mrb_value options_hash;
|
||||||
char *title = nullptr;
|
char *title = nullptr;
|
||||||
mrb_get_args(mrb, "iiz", &width, &height, &title);
|
mrb_get_args(mrb, "iiz|H", &width, &height, &title, &options_hash);
|
||||||
|
|
||||||
app_ = new app::App({(float)width, (float)height}, title);
|
app_ = new app::App({(float)width, (float)height}, title);
|
||||||
|
|
||||||
|
float fps = 60;
|
||||||
|
if (!mrb_nil_p(options_hash))
|
||||||
|
HASH_FLOAT(options_hash, fps, fps);
|
||||||
|
|
||||||
|
app_->set_fps(fps);
|
||||||
|
|
||||||
|
return mrb_nil_value();
|
||||||
|
}
|
||||||
|
|
||||||
|
static mrb_value app_fps_get(mrb_state *mrb, mrb_value) {
|
||||||
|
return mrb_float_value(mrb, app_->get_fps());
|
||||||
|
}
|
||||||
|
|
||||||
|
static mrb_value app_fps_set(mrb_state *mrb, mrb_value) {
|
||||||
|
mrb_float fps;
|
||||||
|
mrb_get_args(mrb, "f", &fps);
|
||||||
|
app_->set_fps(fps);
|
||||||
return mrb_nil_value();
|
return mrb_nil_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1750,9 +1768,11 @@ inline void setup() {
|
|||||||
ADD_METHOD(Scene, "elements", scene_elements, MRB_ARGS_NONE());
|
ADD_METHOD(Scene, "elements", scene_elements, MRB_ARGS_NONE());
|
||||||
|
|
||||||
DEF_MODULE(App);
|
DEF_MODULE(App);
|
||||||
ADD_MODULE_METHOD(App, "run", app_run, MRB_ARGS_REQ(3));
|
ADD_MODULE_METHOD(App, "run", app_run, MRB_ARGS_REQ(3) | MRB_ARGS_OPT(1));
|
||||||
ADD_MODULE_METHOD(App, "start", app_start, MRB_ARGS_REQ(1));
|
ADD_MODULE_METHOD(App, "start", app_start, MRB_ARGS_REQ(1));
|
||||||
ADD_MODULE_METHOD(App, "switch_to", app_switch_to, MRB_ARGS_REQ(1));
|
ADD_MODULE_METHOD(App, "switch_to", app_switch_to, MRB_ARGS_REQ(1));
|
||||||
|
ADD_MODULE_METHOD(App, "fps=", app_fps_set, MRB_ARGS_REQ(1));
|
||||||
|
ADD_MODULE_METHOD(App, "fps", app_fps_get, MRB_ARGS_NONE());
|
||||||
ADD_MODULE_METHOD(App, "localize", app_localize, MRB_ARGS_REQ(3));
|
ADD_MODULE_METHOD(App, "localize", app_localize, MRB_ARGS_REQ(3));
|
||||||
ADD_MODULE_METHOD(App, "language=", app_language_set, MRB_ARGS_REQ(1));
|
ADD_MODULE_METHOD(App, "language=", app_language_set, MRB_ARGS_REQ(1));
|
||||||
ADD_MODULE_METHOD(App, "language", app_language_get, MRB_ARGS_NONE());
|
ADD_MODULE_METHOD(App, "language", app_language_get, MRB_ARGS_NONE());
|
||||||
|
|||||||
@@ -342,7 +342,6 @@ public:
|
|||||||
// Time
|
// Time
|
||||||
|
|
||||||
uint64_t get_time(); // returns the time in nanoseconds since the window was created
|
uint64_t get_time(); // returns the time in nanoseconds since the window was created
|
||||||
uint64_t delta_time(); // returns the time in nanoseconds since the last render call
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// internal data and functions
|
// internal data and functions
|
||||||
|
|||||||
+8
-4
@@ -1,4 +1,4 @@
|
|||||||
App.run 720, 480, "Button Test"
|
App.run 720, 480, "Button Test", fps: 24
|
||||||
|
|
||||||
main_scene = Scene.new
|
main_scene = Scene.new
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@ App.localize(:en, :btn_text, "Click %{name}!")
|
|||||||
|
|
||||||
text = ElementText.new :btn_text, default_font, 0xFFFF00, {name: "Me"}, position: {x: 50, y: 50}, z: 1, click_through: true, alpha: 1
|
text = ElementText.new :btn_text, default_font, 0xFFFF00, {name: "Me"}, position: {x: 50, y: 50}, z: 1, click_through: true, alpha: 1
|
||||||
|
|
||||||
rect = ElementRect.new 100, 25, 0xFF0000, position: {x: 50, y: 50}, z: 0, rotation: 60, pivot: {x: 0.5, y: 0.5}, scale: { x: 1, y: 1 }, alpha: 0.4
|
rect = ElementRect.new 100, 25, 0xFF0000, position: {x: 50, y: 50}, z: 0, rotation: 60, scale: { x: 1, y: 1 }, alpha: 0.4
|
||||||
|
|
||||||
image_element = ElementImage.new bg_animation, position: {x: 0, y: 0}, z: -1, click_through: true, alpha: 1
|
image_element = ElementImage.new bg_animation, position: {x: 0, y: 0}, z: -1, click_through: true, alpha: 1
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ main_scene.on_update do |delta_time|
|
|||||||
|
|
||||||
pp App.text_input if App.text_input != ""
|
pp App.text_input if App.text_input != ""
|
||||||
|
|
||||||
next unless App.down?(:press)
|
next unless App.pressed?(:press)
|
||||||
|
|
||||||
pp "#{App.pressed?(:press)}, #{App.down?(:press)}, #{App.released?(:press)}"
|
pp "#{App.pressed?(:press)}, #{App.down?(:press)}, #{App.released?(:press)}"
|
||||||
|
|
||||||
@@ -72,6 +72,10 @@ main_scene.delete(text)
|
|||||||
|
|
||||||
App.start main_scene
|
App.start main_scene
|
||||||
|
|
||||||
|
time = Time.now - start
|
||||||
|
|
||||||
p "Average delta time: #{c_ / c_c}s"
|
p "Average delta time: #{c_ / c_c}s"
|
||||||
p "Time since start (real): #{Time.now - start}s"
|
p "Average FPS (real): #{c_c / time}s"
|
||||||
|
p "Average FPS (from dt): #{c_c / c_}"
|
||||||
|
p "Time since start (real): #{time}s"
|
||||||
p "Time since start (from dt): #{c_}s"
|
p "Time since start (from dt): #{c_}s"
|
||||||
@@ -472,17 +472,6 @@ uint64_t Window::get_time() {
|
|||||||
return SDL_GetTicksNS();
|
return SDL_GetTicksNS();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t Window::delta_time() {
|
|
||||||
static uint64_t last_time = 0;
|
|
||||||
static bool first_call = 1;
|
|
||||||
uint64_t current_time = SDL_GetTicksNS();
|
|
||||||
uint64_t delta = current_time - last_time;
|
|
||||||
last_time = current_time;
|
|
||||||
if (first_call)
|
|
||||||
return (first_call = 0);
|
|
||||||
return delta;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Window::compute_transform() {
|
void Window::compute_transform() {
|
||||||
float scale_factor_x = real_size.x / virtual_size.x;
|
float scale_factor_x = real_size.x / virtual_size.x;
|
||||||
float scale_factor_y = real_size.y / virtual_size.y;
|
float scale_factor_y = real_size.y / virtual_size.y;
|
||||||
|
|||||||
Reference in New Issue
Block a user