From 0ccc00f201b0138fecb2a761fcc10384a9a70a24 Mon Sep 17 00:00:00 2001 From: Frank DeMarco Date: Sun, 19 Jul 2020 15:43:47 -0400 Subject: [PATCH] - framerate indicator sprite added to Game class - functions to build vectors from an integer range (from https://stackoverflow.com/a/30312659/1256386) - fullscreen toggle added to Display class --- BPmono.ttf | Bin 0 -> 23568 bytes src/Box.cpp | 10 ++++++ src/Box.hpp | 2 ++ src/Configuration.cpp | 4 +-- src/Display.cpp | 27 ++++++++++++++- src/Display.hpp | 2 ++ src/Game.cpp | 74 ++++++++++++++++++++++++++++++++++++------ src/Game.hpp | 28 ++++++++-------- src/Input.hpp | 1 - src/Node.cpp | 2 -- src/Node.hpp | 5 ++- src/Recorder.cpp | 1 - src/Recorder.hpp | 7 ++-- src/Sprite.cpp | 13 +++++--- src/Sprite.hpp | 7 ++-- src/extension.hpp | 33 +++++++++++++++++++ 16 files changed, 176 insertions(+), 40 deletions(-) create mode 100755 BPmono.ttf diff --git a/BPmono.ttf b/BPmono.ttf new file mode 100755 index 0000000000000000000000000000000000000000..e6bb690fb41e8d87b52c0a20efcb885f5c4263a8 GIT binary patch literal 23568 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 KVZ%Q%_J0AD?#)sF literal 0 HcmV?d00001 diff --git a/src/Box.cpp b/src/Box.cpp index 5e9ba12..1a7323b 100644 --- a/src/Box.cpp +++ b/src/Box.cpp @@ -107,6 +107,11 @@ glm::vec2 Box::get_north() const return glm::vec2(get_x() + get_w() / 2, get_y()); } +glm::vec2 Box::get_ne() const +{ + return glm::vec2(get_right(), get_y()); +} + glm::vec2 Box::get_east() const { return glm::vec2(get_right(), get_y() + get_h() / 2); @@ -138,6 +143,11 @@ void Box::set_north(const glm::vec2& n) move(n - get_north()); } +void Box::set_ne(const glm::vec2& ne) +{ + move(ne - get_ne()); +} + void Box::set_east(const glm::vec2& e) { move(e - get_east()); diff --git a/src/Box.hpp b/src/Box.hpp index 330ed56..86ed636 100644 --- a/src/Box.hpp +++ b/src/Box.hpp @@ -34,12 +34,14 @@ struct Box void set_left(float); glm::vec2 get_nw() const; glm::vec2 get_north() const; + glm::vec2 get_ne() const; glm::vec2 get_east() const; glm::vec2 get_south() const; glm::vec2 get_west() const; glm::vec2 get_center() const; void set_nw(const glm::vec2&); void set_north(const glm::vec2&); + void set_ne(const glm::vec2&); void set_east(const glm::vec2&); void set_south(const glm::vec2&); void set_west(const glm::vec2&); diff --git a/src/Configuration.cpp b/src/Configuration.cpp index 7eb58e4..bbab862 100644 --- a/src/Configuration.cpp +++ b/src/Configuration.cpp @@ -23,7 +23,7 @@ void Configuration::set_defaults() {"left", "left"}, {"pause", "enter"}, {"fullscreen", {"ALT", "enter"}}, - {"show-fps", {"CTRL", "f"}} + {"toggle-framerate", {"CTRL", "f"}} }; sys_config["path"] = { {"screenshots", "."}, @@ -31,7 +31,7 @@ void Configuration::set_defaults() }; sys_config["display"] = { {"dimensions", {640, 480}}, - {"fps", 60}, + {"framerate", 60}, {"title", "sfw"} }; sys_config["recording"] = { diff --git a/src/Display.cpp b/src/Display.cpp index 7e013a0..3d0aba6 100644 --- a/src/Display.cpp +++ b/src/Display.cpp @@ -1,7 +1,10 @@ #include "Display.hpp" #include "Game.hpp" -Display::Display(Node* parent) : Node(parent) {} +Display::Display(Node* parent) : Node(parent) +{ + get_delegate().subscribe(&Display::respond, this); +} glm::ivec2 Display::get_window_size() { @@ -88,3 +91,25 @@ SDL_Surface* Display::get_screen_surface_from_pixels( } return surface; } + +void Display::respond(SDL_Event& event) +{ + if (get_delegate().compare(event, "fullscreen")) + { + toggle_fullscreen(); + } +} + +void Display::toggle_fullscreen() +{ + if (SDL_GetWindowFlags(get_root()->get_window()) & SDL_WINDOW_FULLSCREEN) + { + SDL_Log("fullscreen requested"); + SDL_SetWindowFullscreen(get_root()->window, 0); + } + else + { + SDL_Log("exit fullscreen requested"); + SDL_SetWindowFullscreen(get_root()->get_window(), SDL_WINDOW_FULLSCREEN); + } +} diff --git a/src/Display.hpp b/src/Display.hpp index ade58f9..ed97251 100644 --- a/src/Display.hpp +++ b/src/Display.hpp @@ -28,6 +28,8 @@ struct Display : Node void get_screen_pixels(unsigned char*, int, int, int = 0, int = 0); SDL_Surface* get_screen_surface(); SDL_Surface* get_screen_surface_from_pixels(unsigned char*, bool); + void respond(SDL_Event&); + void toggle_fullscreen(); }; diff --git a/src/Game.cpp b/src/Game.cpp index deb4efd..b3a091d 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -1,16 +1,53 @@ #include "Game.hpp" -// FPSIndicator::FPSIndicator(Node* parent) : Node(parent) {} +FramerateIndicator::FramerateIndicator(Node* parent) : Sprite(parent) +{ + get_delegate().subscribe(&FramerateIndicator::respond, this); + hide(); +} -// FPSIndicator::update() -// { - -// } +void FramerateIndicator::respond(SDL_Event& event) +{ + if (get_delegate().compare(event, "toggle-framerate")) + { + toggle_hidden(); + } +} + +SDL_Surface* FramerateIndicator::get_surface() +{ + std::string padded = sfw::pad(get_root()->frame_count_this_second, 2); + SDL_Surface* shaded = TTF_RenderText_Shaded( + get_root()->bp_mono_font, padded.c_str(), {0, 0, 0}, {255, 255, 255}); + // SDL_Surface* converted = SDL_ConvertSurfaceFormat( + // shaded, SDL_PIXELFORMAT_ARGB8888, 0); + // SDL_Surface* flipped = zoomSurface(converted, 1, -1, SMOOTHING_OFF); + // SDL_FreeSurface(shaded); + // SDL_FreeSurface(converted); + if (!shaded) + { + get_root()->print_sdl_error("Could not create text"); + } + return shaded; +} + +void FramerateIndicator::refresh() +{ + if (!is_hidden() && get_root()->bp_mono_font != NULL) + { + unload(); + SDL_Surface* surface = get_surface(); + SDL_Texture* texture = SDL_CreateTextureFromSurface(get_root()->get_renderer(), surface); + add_frame(texture); + SDL_FreeSurface(surface); + box.set_ne(get_display().get_window_box().get_ne()); + } +} Game::Game() { frame_length_history.reserve(5000); - set_framerate(get_configuration()["display"]["fps"]); + set_framerate(get_configuration()["display"]["framerate"]); delegate.subscribe(&Game::handle_quit_event, this, SDL_QUIT); SDL_Log("GLEW %s", glewGetString(GLEW_VERSION)); putenv("SDL_VIDEO_X11_LEGACY_FULLSCREEN=0"); @@ -58,6 +95,10 @@ Game::Game() SDL_Log("initialized SDL ttf %d.%d.%d", SDL_TTF_MAJOR_VERSION, SDL_TTF_MINOR_VERSION, SDL_TTF_PATCHLEVEL); } + if ((bp_mono_font = TTF_OpenFont("BPmono.ttf", 14)) == NULL) + { + print_error("Could not load BPmono.ttf"); + } #if !defined(__EMSCRIPTEN__) if (Mix_Init(MIX_INIT_FLAC) == 0) { @@ -452,11 +493,23 @@ void Game::frame(float ticks) recorder.update(); delegate.dispatch(); update(); + framerate_indicator.update(); + if (!is_gl_context) + { + SDL_RenderPresent(renderer); + } if (frame_time_overflow > frame_length) { // SDL_Log("%i frame(s) dropped", ((int) (frame_time_overflow / frame_length))); frame_time_overflow = 0; } + frame_count_this_second++; + if (ticks - last_frame_count_timestamp >= 1000) + { + framerate_indicator.refresh(); + last_frame_count_timestamp = ticks; + frame_count_this_second = 0; + } } // std::cout << std::endl; } @@ -485,13 +538,13 @@ glm::vec2 Game::weight(glm::vec2 motion) return glm::vec2(weight(motion.x), weight(motion.y)); } -void Game::set_framerate(int fps) +void Game::set_framerate(int f) { - if (fps < 1) + if (f < 1) { - fps = 1; + f = 1; } - framerate = fps; + framerate = f; frame_length = 1000.0 / framerate; } @@ -519,6 +572,7 @@ void Game::quit() } if (TTF_WasInit()) { + TTF_CloseFont(bp_mono_font); TTF_Quit(); } Mix_CloseAudio(); diff --git a/src/Game.hpp b/src/Game.hpp index 537c2b4..7749be7 100644 --- a/src/Game.hpp +++ b/src/Game.hpp @@ -27,19 +27,19 @@ #endif #include "Node.hpp" -#include "Configuration.hpp" -#include "Delegate.hpp" -#include "Display.hpp" -#include "Recorder.hpp" #include "Input.hpp" -// #include "Sprite.hpp" +#include "Recorder.hpp" +#include "Sprite.hpp" -// struct FPSIndicator : Sprite -// { +struct FramerateIndicator : Sprite +{ -// FPSIndicator(Node*); + FramerateIndicator(Node*); + void respond(SDL_Event&); + SDL_Surface* get_surface(); + void refresh(); -// }; +}; struct Game : Node { @@ -54,9 +54,9 @@ struct Game : Node SDL_GLContext glcontext = NULL; // 768, 432 // 864, 486 - int framerate, ticks, last_frame_length; - float frame_length = 1000.0 / 60.0, frame_time_overflow = 0, - last_frame_timestamp, emscripten_previous_time; + int frame_count_this_second = 0, framerate, ticks, last_frame_length; + float frame_length = 1000.0 / 60.0, frame_time_overflow = 0, last_frame_timestamp, + last_frame_count_timestamp, emscripten_previous_time; bool done = false, show_framerate = true, is_gl_context = true; Configuration configuration = Configuration(this); Delegate delegate = Delegate(this); @@ -64,6 +64,8 @@ struct Game : Node Recorder recorder = Recorder(this); Input input = Input(this); std::vector frame_length_history; + TTF_Font* bp_mono_font = NULL; + FramerateIndicator framerate_indicator = FramerateIndicator(this); Game(); ~Game(); @@ -103,6 +105,4 @@ void loop(void*); #endif -#include "Sprite.hpp" - #endif diff --git a/src/Input.hpp b/src/Input.hpp index df3c5d0..04e75d2 100644 --- a/src/Input.hpp +++ b/src/Input.hpp @@ -9,7 +9,6 @@ #include "SDL.h" #include "Node.hpp" -#include "Delegate.hpp" struct KeyCombination { diff --git a/src/Node.cpp b/src/Node.cpp index 76f6011..a1fe1fe 100644 --- a/src/Node.cpp +++ b/src/Node.cpp @@ -1,7 +1,5 @@ #include "Node.hpp" #include "Game.hpp" -// #include "Display.hpp" -// #include "Delegate.hpp" Node::Node() : Node(NULL) {} diff --git a/src/Node.hpp b/src/Node.hpp index 51c526d..0edab5f 100644 --- a/src/Node.hpp +++ b/src/Node.hpp @@ -11,7 +11,6 @@ struct Game; struct Delegate; struct Display; -struct TimeFilter; struct Node { @@ -35,4 +34,8 @@ struct Node }; +#include "Configuration.hpp" +#include "Delegate.hpp" +#include "Display.hpp" + #endif diff --git a/src/Recorder.cpp b/src/Recorder.cpp index 6b42572..c1c0d2e 100644 --- a/src/Recorder.cpp +++ b/src/Recorder.cpp @@ -1,4 +1,3 @@ -#include "Game.hpp" #include "Recorder.hpp" #include "gif-h/gif.h" diff --git a/src/Recorder.hpp b/src/Recorder.hpp index 4b214e0..b288bfe 100644 --- a/src/Recorder.hpp +++ b/src/Recorder.hpp @@ -6,8 +6,10 @@ #include #include #include +#include #include "SDL.h" +#include "SDL_mixer.h" #define GLM_ENABLE_EXPERIMENTAL #include "glm/ext.hpp" @@ -15,9 +17,8 @@ #include "json/json.hpp" #include "filesystem.hpp" +#include "Node.hpp" #include "Animation.hpp" -#include "Delegate.hpp" -#include "Display.hpp" #include "extension.hpp" struct Stash @@ -67,4 +68,6 @@ struct Recorder : Node void process_audio(void*, Uint8*, int); +#include "Game.hpp" + #endif diff --git a/src/Sprite.cpp b/src/Sprite.cpp index b8b5ef1..8fd914a 100644 --- a/src/Sprite.cpp +++ b/src/Sprite.cpp @@ -136,17 +136,22 @@ void Sprite::advance_frame() void Sprite::hide() { - is_hidden = true; + hidden = true; } void Sprite::unhide() { - is_hidden = false; + hidden = false; } void Sprite::toggle_hidden() { - is_hidden = !is_hidden; + hidden = !hidden; +} + +bool Sprite::is_hidden() const +{ + return hidden; } void Sprite::set_step(glm::vec2 s) @@ -227,7 +232,7 @@ void Sprite::update() move(step); frame_animation.update(); blink_animation.update(); - if (is_loaded() && !is_hidden && get_current_frameset().get_frame_count()) + if (is_loaded() && !is_hidden() && get_current_frameset().get_frame_count()) { int index = get_current_frameset().get_current_frame_index(); SDL_Texture* texture = frames[index]; diff --git a/src/Sprite.hpp b/src/Sprite.hpp index 74797b2..2258f0a 100644 --- a/src/Sprite.hpp +++ b/src/Sprite.hpp @@ -11,11 +11,11 @@ #include #include "Node.hpp" -#include "Game.hpp" #include "Box.hpp" #include "Animation.hpp" #include "extension.hpp" +struct Game; struct Frameset; struct Sprite : Node @@ -26,7 +26,7 @@ struct Sprite : Node Box box; Animation frame_animation = Animation(&Sprite::advance_frame, this); Animation blink_animation = Animation(&Sprite::toggle_hidden, this, 500); - bool is_hidden = false; + bool hidden = false; glm::vec2 step = {0, 0}; Uint8 alpha_mod = 255; std::map framesets; @@ -51,6 +51,7 @@ struct Sprite : Node void hide(); void unhide(); void toggle_hidden(); + bool is_hidden() const; void set_step(glm::vec2); float get_w() const; float get_h() const; @@ -101,4 +102,6 @@ struct Frameset }; +#include "Game.hpp" + #endif diff --git a/src/extension.hpp b/src/extension.hpp index e9138a5..1e6ee57 100644 --- a/src/extension.hpp +++ b/src/extension.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #define GLM_ENABLE_EXPERIMENTAL #include "glm/trigonometric.hpp" @@ -39,6 +40,38 @@ namespace sfw padded << end; return padded.str(); } + + // from https://stackoverflow.com/a/30312659/1256386 + template + std::vector range(IntType start, IntType stop, IntType step) + { + if (step == IntType(0)) + { + throw std::invalid_argument("step for range must be non-zero"); + } + std::vector result; + IntType i = start; + while ((step > 0) ? (i < stop) : (i > stop)) + { + result.push_back(i); + i += step; + } + return result; + } + + // from https://stackoverflow.com/a/30312659/1256386 + template + std::vector range(IntType start, IntType stop) + { + return range(start, stop, IntType(1)); + } + + // from https://stackoverflow.com/a/30312659/1256386 + template + std::vector range(IntType stop) + { + return range(IntType(0), stop, IntType(1)); + } } std::ostream& operator<<(std::ostream&, const glm::vec2&);