diff --git a/include/app/app.h b/include/app/app.h index 69180f0..e9947d3 100644 --- a/include/app/app.h +++ b/include/app/app.h @@ -252,26 +252,35 @@ struct App { current_scene_id = scene_pool.acquire(loading_scene); } - void loop() { - const uint64_t TARGET_NS = 1e9 / 60; + void set_fps(float fps) { + this->fps = fps; + target_frame_time = 1e9 / fps; + } - uint64_t time_a = window.get_time(); - uint64_t time_b = window.get_time(); + uint64_t get_fps() const { + 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) { - time_a = window.get_time(); - uint64_t frame_time = time_a - time_b; + frame_start = window.get_time(); + uint64_t frame_time = frame_start - frame_end; - if (frame_time <= TARGET_NS) { + if (frame_time <= target_frame_time) { struct timespec req; req.tv_sec = 0; - req.tv_nsec = TARGET_NS - frame_time; + req.tv_nsec = target_frame_time - frame_time; 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]; @@ -329,6 +338,10 @@ struct App { window.clear(); } } + +private: + uint64_t fps = 60; + uint64_t target_frame_time = 1e9 / fps; }; } // namespace app diff --git a/include/binding/definitions.h b/include/binding/definitions.h index a78ce1e..b0e9fa9 100644 --- a/include/binding/definitions.h +++ b/include/binding/definitions.h @@ -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) { mrb_int width, height; + mrb_value options_hash; 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); + 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(); } @@ -1750,9 +1768,11 @@ inline void setup() { ADD_METHOD(Scene, "elements", scene_elements, MRB_ARGS_NONE()); 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, "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, "language=", app_language_set, MRB_ARGS_REQ(1)); ADD_MODULE_METHOD(App, "language", app_language_get, MRB_ARGS_NONE()); diff --git a/include/window/window.h b/include/window/window.h index 2b1889c..f64c9da 100644 --- a/include/window/window.h +++ b/include/window/window.h @@ -341,8 +341,7 @@ public: // Time - 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 + uint64_t get_time(); // returns the time in nanoseconds since the window was created private: // internal data and functions diff --git a/samples/button.rb b/samples/button.rb index cba77a6..213aa2e 100644 --- a/samples/button.rb +++ b/samples/button.rb @@ -1,4 +1,4 @@ -App.run 720, 480, "Button Test" +App.run 720, 480, "Button Test", fps: 24 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 -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 @@ -49,7 +49,7 @@ main_scene.on_update do |delta_time| 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)}" @@ -72,6 +72,10 @@ main_scene.delete(text) App.start main_scene +time = Time.now - start + 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" \ No newline at end of file diff --git a/src/window/window.cc b/src/window/window.cc index 2360077..0897921 100644 --- a/src/window/window.cc +++ b/src/window/window.cc @@ -472,17 +472,6 @@ uint64_t Window::get_time() { 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() { float scale_factor_x = real_size.x / virtual_size.x; float scale_factor_y = real_size.y / virtual_size.y;