- 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
This commit is contained in:
Frank DeMarco 2020-07-19 15:43:47 -04:00
parent 1df303fe17
commit 0ccc00f201
16 changed files with 176 additions and 40 deletions

BIN
BPmono.ttf Executable file

Binary file not shown.

View File

@ -107,6 +107,11 @@ glm::vec2 Box::get_north() const
return glm::vec2(get_x() + get_w() / 2, get_y()); 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 glm::vec2 Box::get_east() const
{ {
return glm::vec2(get_right(), get_y() + get_h() / 2); 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()); move(n - get_north());
} }
void Box::set_ne(const glm::vec2& ne)
{
move(ne - get_ne());
}
void Box::set_east(const glm::vec2& e) void Box::set_east(const glm::vec2& e)
{ {
move(e - get_east()); move(e - get_east());

View File

@ -34,12 +34,14 @@ struct Box
void set_left(float); void set_left(float);
glm::vec2 get_nw() const; glm::vec2 get_nw() const;
glm::vec2 get_north() const; glm::vec2 get_north() const;
glm::vec2 get_ne() const;
glm::vec2 get_east() const; glm::vec2 get_east() const;
glm::vec2 get_south() const; glm::vec2 get_south() const;
glm::vec2 get_west() const; glm::vec2 get_west() const;
glm::vec2 get_center() const; glm::vec2 get_center() const;
void set_nw(const glm::vec2&); void set_nw(const glm::vec2&);
void set_north(const glm::vec2&); void set_north(const glm::vec2&);
void set_ne(const glm::vec2&);
void set_east(const glm::vec2&); void set_east(const glm::vec2&);
void set_south(const glm::vec2&); void set_south(const glm::vec2&);
void set_west(const glm::vec2&); void set_west(const glm::vec2&);

View File

@ -23,7 +23,7 @@ void Configuration::set_defaults()
{"left", "left"}, {"left", "left"},
{"pause", "enter"}, {"pause", "enter"},
{"fullscreen", {"ALT", "enter"}}, {"fullscreen", {"ALT", "enter"}},
{"show-fps", {"CTRL", "f"}} {"toggle-framerate", {"CTRL", "f"}}
}; };
sys_config["path"] = { sys_config["path"] = {
{"screenshots", "."}, {"screenshots", "."},
@ -31,7 +31,7 @@ void Configuration::set_defaults()
}; };
sys_config["display"] = { sys_config["display"] = {
{"dimensions", {640, 480}}, {"dimensions", {640, 480}},
{"fps", 60}, {"framerate", 60},
{"title", "sfw"} {"title", "sfw"}
}; };
sys_config["recording"] = { sys_config["recording"] = {

View File

@ -1,7 +1,10 @@
#include "Display.hpp" #include "Display.hpp"
#include "Game.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() glm::ivec2 Display::get_window_size()
{ {
@ -88,3 +91,25 @@ SDL_Surface* Display::get_screen_surface_from_pixels(
} }
return surface; 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);
}
}

View File

@ -28,6 +28,8 @@ struct Display : Node
void get_screen_pixels(unsigned char*, int, int, int = 0, int = 0); void get_screen_pixels(unsigned char*, int, int, int = 0, int = 0);
SDL_Surface* get_screen_surface(); SDL_Surface* get_screen_surface();
SDL_Surface* get_screen_surface_from_pixels(unsigned char*, bool); SDL_Surface* get_screen_surface_from_pixels(unsigned char*, bool);
void respond(SDL_Event&);
void toggle_fullscreen();
}; };

View File

@ -1,16 +1,53 @@
#include "Game.hpp" #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() Game::Game()
{ {
frame_length_history.reserve(5000); 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); delegate.subscribe(&Game::handle_quit_event, this, SDL_QUIT);
SDL_Log("GLEW %s", glewGetString(GLEW_VERSION)); SDL_Log("GLEW %s", glewGetString(GLEW_VERSION));
putenv("SDL_VIDEO_X11_LEGACY_FULLSCREEN=0"); 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_Log("initialized SDL ttf %d.%d.%d", SDL_TTF_MAJOR_VERSION,
SDL_TTF_MINOR_VERSION, SDL_TTF_PATCHLEVEL); 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 !defined(__EMSCRIPTEN__)
if (Mix_Init(MIX_INIT_FLAC) == 0) if (Mix_Init(MIX_INIT_FLAC) == 0)
{ {
@ -452,11 +493,23 @@ void Game::frame(float ticks)
recorder.update(); recorder.update();
delegate.dispatch(); delegate.dispatch();
update(); update();
framerate_indicator.update();
if (!is_gl_context)
{
SDL_RenderPresent(renderer);
}
if (frame_time_overflow > frame_length) if (frame_time_overflow > frame_length)
{ {
// SDL_Log("%i frame(s) dropped", ((int) (frame_time_overflow / frame_length))); // SDL_Log("%i frame(s) dropped", ((int) (frame_time_overflow / frame_length)));
frame_time_overflow = 0; 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; // std::cout << std::endl;
} }
@ -485,13 +538,13 @@ glm::vec2 Game::weight(glm::vec2 motion)
return glm::vec2(weight(motion.x), weight(motion.y)); 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; frame_length = 1000.0 / framerate;
} }
@ -519,6 +572,7 @@ void Game::quit()
} }
if (TTF_WasInit()) if (TTF_WasInit())
{ {
TTF_CloseFont(bp_mono_font);
TTF_Quit(); TTF_Quit();
} }
Mix_CloseAudio(); Mix_CloseAudio();

View File

@ -27,19 +27,19 @@
#endif #endif
#include "Node.hpp" #include "Node.hpp"
#include "Configuration.hpp"
#include "Delegate.hpp"
#include "Display.hpp"
#include "Recorder.hpp"
#include "Input.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 struct Game : Node
{ {
@ -54,9 +54,9 @@ struct Game : Node
SDL_GLContext glcontext = NULL; SDL_GLContext glcontext = NULL;
// 768, 432 // 768, 432
// 864, 486 // 864, 486
int framerate, ticks, last_frame_length; int frame_count_this_second = 0, framerate, ticks, last_frame_length;
float frame_length = 1000.0 / 60.0, frame_time_overflow = 0, float frame_length = 1000.0 / 60.0, frame_time_overflow = 0, last_frame_timestamp,
last_frame_timestamp, emscripten_previous_time; last_frame_count_timestamp, emscripten_previous_time;
bool done = false, show_framerate = true, is_gl_context = true; bool done = false, show_framerate = true, is_gl_context = true;
Configuration configuration = Configuration(this); Configuration configuration = Configuration(this);
Delegate delegate = Delegate(this); Delegate delegate = Delegate(this);
@ -64,6 +64,8 @@ struct Game : Node
Recorder recorder = Recorder(this); Recorder recorder = Recorder(this);
Input input = Input(this); Input input = Input(this);
std::vector<float> frame_length_history; std::vector<float> frame_length_history;
TTF_Font* bp_mono_font = NULL;
FramerateIndicator framerate_indicator = FramerateIndicator(this);
Game(); Game();
~Game(); ~Game();
@ -103,6 +105,4 @@ void loop(void*);
#endif #endif
#include "Sprite.hpp"
#endif #endif

View File

@ -9,7 +9,6 @@
#include "SDL.h" #include "SDL.h"
#include "Node.hpp" #include "Node.hpp"
#include "Delegate.hpp"
struct KeyCombination struct KeyCombination
{ {

View File

@ -1,7 +1,5 @@
#include "Node.hpp" #include "Node.hpp"
#include "Game.hpp" #include "Game.hpp"
// #include "Display.hpp"
// #include "Delegate.hpp"
Node::Node() : Node(NULL) {} Node::Node() : Node(NULL) {}

View File

@ -11,7 +11,6 @@
struct Game; struct Game;
struct Delegate; struct Delegate;
struct Display; struct Display;
struct TimeFilter;
struct Node struct Node
{ {
@ -35,4 +34,8 @@ struct Node
}; };
#include "Configuration.hpp"
#include "Delegate.hpp"
#include "Display.hpp"
#endif #endif

View File

@ -1,4 +1,3 @@
#include "Game.hpp"
#include "Recorder.hpp" #include "Recorder.hpp"
#include "gif-h/gif.h" #include "gif-h/gif.h"

View File

@ -6,8 +6,10 @@
#include <thread> #include <thread>
#include <functional> #include <functional>
#include <cstdlib> #include <cstdlib>
#include <fstream>
#include "SDL.h" #include "SDL.h"
#include "SDL_mixer.h"
#define GLM_ENABLE_EXPERIMENTAL #define GLM_ENABLE_EXPERIMENTAL
#include "glm/ext.hpp" #include "glm/ext.hpp"
@ -15,9 +17,8 @@
#include "json/json.hpp" #include "json/json.hpp"
#include "filesystem.hpp" #include "filesystem.hpp"
#include "Node.hpp"
#include "Animation.hpp" #include "Animation.hpp"
#include "Delegate.hpp"
#include "Display.hpp"
#include "extension.hpp" #include "extension.hpp"
struct Stash struct Stash
@ -67,4 +68,6 @@ struct Recorder : Node
void process_audio(void*, Uint8*, int); void process_audio(void*, Uint8*, int);
#include "Game.hpp"
#endif #endif

View File

@ -136,17 +136,22 @@ void Sprite::advance_frame()
void Sprite::hide() void Sprite::hide()
{ {
is_hidden = true; hidden = true;
} }
void Sprite::unhide() void Sprite::unhide()
{ {
is_hidden = false; hidden = false;
} }
void Sprite::toggle_hidden() void Sprite::toggle_hidden()
{ {
is_hidden = !is_hidden; hidden = !hidden;
}
bool Sprite::is_hidden() const
{
return hidden;
} }
void Sprite::set_step(glm::vec2 s) void Sprite::set_step(glm::vec2 s)
@ -227,7 +232,7 @@ void Sprite::update()
move(step); move(step);
frame_animation.update(); frame_animation.update();
blink_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(); int index = get_current_frameset().get_current_frame_index();
SDL_Texture* texture = frames[index]; SDL_Texture* texture = frames[index];

View File

@ -11,11 +11,11 @@
#include <SDL_image.h> #include <SDL_image.h>
#include "Node.hpp" #include "Node.hpp"
#include "Game.hpp"
#include "Box.hpp" #include "Box.hpp"
#include "Animation.hpp" #include "Animation.hpp"
#include "extension.hpp" #include "extension.hpp"
struct Game;
struct Frameset; struct Frameset;
struct Sprite : Node struct Sprite : Node
@ -26,7 +26,7 @@ struct Sprite : Node
Box box; Box box;
Animation frame_animation = Animation(&Sprite::advance_frame, this); Animation frame_animation = Animation(&Sprite::advance_frame, this);
Animation blink_animation = Animation(&Sprite::toggle_hidden, this, 500); Animation blink_animation = Animation(&Sprite::toggle_hidden, this, 500);
bool is_hidden = false; bool hidden = false;
glm::vec2 step = {0, 0}; glm::vec2 step = {0, 0};
Uint8 alpha_mod = 255; Uint8 alpha_mod = 255;
std::map<std::string, Frameset> framesets; std::map<std::string, Frameset> framesets;
@ -51,6 +51,7 @@ struct Sprite : Node
void hide(); void hide();
void unhide(); void unhide();
void toggle_hidden(); void toggle_hidden();
bool is_hidden() const;
void set_step(glm::vec2); void set_step(glm::vec2);
float get_w() const; float get_w() const;
float get_h() const; float get_h() const;
@ -101,4 +102,6 @@ struct Frameset
}; };
#include "Game.hpp"
#endif #endif

View File

@ -7,6 +7,7 @@
#include <sstream> #include <sstream>
#include <algorithm> #include <algorithm>
#include <iomanip> #include <iomanip>
#include <stdexcept>
#define GLM_ENABLE_EXPERIMENTAL #define GLM_ENABLE_EXPERIMENTAL
#include "glm/trigonometric.hpp" #include "glm/trigonometric.hpp"
@ -39,6 +40,38 @@ namespace sfw
padded << end; padded << end;
return padded.str(); return padded.str();
} }
// from https://stackoverflow.com/a/30312659/1256386
template <typename IntType>
std::vector<IntType> range(IntType start, IntType stop, IntType step)
{
if (step == IntType(0))
{
throw std::invalid_argument("step for range must be non-zero");
}
std::vector<IntType> 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 <typename IntType>
std::vector<IntType> range(IntType start, IntType stop)
{
return range(start, stop, IntType(1));
}
// from https://stackoverflow.com/a/30312659/1256386
template <typename IntType>
std::vector<IntType> range(IntType stop)
{
return range(IntType(0), stop, IntType(1));
}
} }
std::ostream& operator<<(std::ostream&, const glm::vec2&); std::ostream& operator<<(std::ostream&, const glm::vec2&);