changed get_configuration to configuration; added option to return the larger ratio to box aspect; changed default window size to 16:9; changed get_window to window; added SDL_RENDERER_PRESENTVSYNC; removed clear renderer to black on emscripten builds to prevent mouse bug;

This commit is contained in:
frank 2022-06-16 16:45:41 -04:00
parent ee119ecc7e
commit 3444afc2c1
21 changed files with 163 additions and 116 deletions

9
README
View File

@ -152,8 +152,9 @@ Included libraries are included under various permissive licenses:
- superxbr.cpp is included under the permissive license at the top of lib/superxbr.cpp - superxbr.cpp is included under the permissive license at the top of lib/superxbr.cpp
############ ###########
# Business # # Contact #
############ ###########
egg@shampoo.ooo email sega@nugget.fun
twitter https://twitter.com/diskmem

View File

@ -37,7 +37,7 @@ Richard Russell -- richard at rtrussell dot co dot uk
#define M_PI 3.1415926535897932384626433832795 #define M_PI 3.1415926535897932384626433832795
#endif #endif
#include "SDL2/SDL.h" #include "SDL.h"
/* Set up for C function definitions, even when using C++ */ /* Set up for C function definitions, even when using C++ */
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -118,12 +118,12 @@ Audio::Audio(Node* parent) : Node(parent) {}
void Audio::load_sfx() void Audio::load_sfx()
{ {
load_directory(get_configuration()["audio"]["default-sfx-root"], sfx, this); load_directory(configuration()["audio"]["default-sfx-root"], sfx, this);
} }
void Audio::load_bgm() void Audio::load_bgm()
{ {
load_directory(get_configuration()["audio"]["default-bgm-root"], bgm, this); load_directory(configuration()["audio"]["default-bgm-root"], bgm, this);
} }
void Audio::update() void Audio::update()

View File

@ -85,11 +85,16 @@ void Box::size(const glm::vec2& size, bool preserve_center)
} }
} }
/* Returns width divided by height. Returns a value regardless of which side is longer, so it can return values float Box::aspect(bool larger_ratio) const
* greater or less than 0. */
float Box::aspect() const
{ {
return width() / height(); if (!larger_ratio || width() > height())
{
return width() / height();
}
else
{
return height() / width();
}
} }
/* Return the area of the box (width * height) */ /* Return the area of the box (width * height) */

View File

@ -8,8 +8,8 @@
| ~~~~~~~ BOX |/ | ~~~~~~~ BOX |/
+-------------*/ +-------------*/
#ifndef Box_h_ #ifndef SB_BOX_H_
#define Box_h_ #define SB_BOX_H_
#include <iostream> #include <iostream>
#include <algorithm> #include <algorithm>
@ -43,7 +43,11 @@ public:
void height(float); void height(float);
glm::vec2 size() const; glm::vec2 size() const;
void size(const glm::vec2&, bool = false); void size(const glm::vec2&, bool = false);
float aspect() const;
/* If the flag is not set, this will return width divided by height. Otherwise, it will check which side is longer and return the longer side
* divided by the shorter side. */
float aspect(bool = false) const;
float area() const; float area() const;
float top() const; float top() const;
float right() const; float right() const;

View File

@ -48,7 +48,7 @@ void Configuration::set_defaults()
{"ignore-repeat-keypress", true} {"ignore-repeat-keypress", true}
}; };
sys_config["display"] = { sys_config["display"] = {
{"dimensions", {640, 480}}, {"dimensions", {960, 540}},
{"framerate", 60}, {"framerate", 60},
{"title", "[SPACE BOX]"}, {"title", "[SPACE BOX]"},
{"debug", false}, {"debug", false},

View File

@ -20,7 +20,7 @@ sb::Display::Display(Node* parent) : Node(parent)
glm::ivec2 sb::Display::window_size() const glm::ivec2 sb::Display::window_size() const
{ {
glm::ivec2 size; glm::ivec2 size;
SDL_GetWindowSize(const_cast<SDL_Window*>(get_window()), &size.x, &size.y); SDL_GetWindowSize(const_cast<SDL_Window*>(window()), &size.x, &size.y);
return size; return size;
} }
@ -159,15 +159,14 @@ void sb::Display::respond(SDL_Event& event)
* function to toggle the fullscreen state */ * function to toggle the fullscreen state */
void sb::Display::toggle_fullscreen() const void sb::Display::toggle_fullscreen() const
{ {
SDL_Window* window = const_cast<SDL_Window*>(get_window()); if (SDL_GetWindowFlags(const_cast<SDL_Window*>(window())) & SDL_WINDOW_FULLSCREEN)
if (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN)
{ {
sb::Log::log("fullscreen requested"); sb::Log::log("fullscreen requested");
SDL_SetWindowFullscreen(window, 0); SDL_SetWindowFullscreen(const_cast<SDL_Window*>(window()), 0);
} }
else else
{ {
sb::Log::log("exit fullscreen requested"); sb::Log::log("exit fullscreen requested");
SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN); SDL_SetWindowFullscreen(const_cast<SDL_Window*>(window()), SDL_WINDOW_FULLSCREEN);
} }
} }

View File

@ -29,13 +29,6 @@
#ifndef SB_GLOBJECT_H_ #ifndef SB_GLOBJECT_H_
#define SB_GLOBJECT_H_ #define SB_GLOBJECT_H_
/* include Open GL */
#if defined(__EMSCRIPTEN__)
#include <GL/glew.h>
#else
#include "glew/glew.h"
#endif
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <memory> #include <memory>

View File

@ -5,7 +5,7 @@ Game::Game()
/* Set the appropriate priority level for the default log category so either info level messages /* Set the appropriate priority level for the default log category so either info level messages
* and higher are enabled or debug level messages are enabled, depending on the global configuration */ * and higher are enabled or debug level messages are enabled, depending on the global configuration */
SDL_LogPriority default_log_category_priority; SDL_LogPriority default_log_category_priority;
if (get_configuration()["log"]["debug-to-file"] || get_configuration()["log"]["debug-to-stdout"]) if (configuration()["log"]["debug-to-file"] || configuration()["log"]["debug-to-stdout"])
{ {
default_log_category_priority = SDL_LOG_PRIORITY_DEBUG; default_log_category_priority = SDL_LOG_PRIORITY_DEBUG;
} }
@ -18,13 +18,13 @@ Game::Game()
SDL_LogSetOutputFunction(&Game::sdl_log_override, this); SDL_LogSetOutputFunction(&Game::sdl_log_override, this);
/* pretty print config to debug log */ /* pretty print config to debug log */
std::ostringstream log_message; std::ostringstream log_message;
log_message << std::setw(4) << get_configuration() << std::endl; log_message << std::setw(4) << configuration() << std::endl;
sb::Log::log(log_message, sb::Log::DEBUG); sb::Log::log(log_message, sb::Log::DEBUG);
/* tell SDL which render driver you will be requesting when calling SDL_CreateRenderer */ /* tell SDL which render driver you will be requesting when calling SDL_CreateRenderer */
SDL_SetHint(SDL_HINT_RENDER_DRIVER, get_configuration()["display"]["render driver"].get<std::string>().c_str()); SDL_SetHint(SDL_HINT_RENDER_DRIVER, configuration()["display"]["render driver"].get<std::string>().c_str());
/* initialize the buffer of frame lengths which will be used to calculate FPS */ /* initialize the buffer of frame lengths which will be used to calculate FPS */
frame_length_history.reserve(5000); frame_length_history.reserve(5000);
set_framerate(get_configuration()["display"]["framerate"]); set_framerate(configuration()["display"]["framerate"]);
delegate.subscribe(&Game::handle_quit_event, this, SDL_QUIT); delegate.subscribe(&Game::handle_quit_event, this, SDL_QUIT);
/* Needed for displaying fullscreen correctly on Linux (?) Also might need SDL_VIDEO_CENTERED (?) */ /* Needed for displaying fullscreen correctly on Linux (?) Also might need SDL_VIDEO_CENTERED (?) */
std::string fullscreen_env_assigment = "SDL_VIDEO_X11_LEGACY_FULLSCREEN=0"; std::string fullscreen_env_assigment = "SDL_VIDEO_X11_LEGACY_FULLSCREEN=0";
@ -49,20 +49,20 @@ Game::Game()
log_message = std::ostringstream(); log_message = std::ostringstream();
log_message << "GLEW " << glewGetString(GLEW_VERSION); log_message << "GLEW " << glewGetString(GLEW_VERSION);
sb::Log::log(log_message.str()); sb::Log::log(log_message.str());
glm::ivec2 window_size = get_configuration()["display"]["dimensions"].get<glm::ivec2>(); glm::ivec2 window_size = configuration()["display"]["dimensions"].get<glm::ivec2>();
/* Create a window with dimensions set in the config, centered, and flagged to be usable in OpenGL context */ /* Create a window with dimensions set in the config, centered, and flagged to be usable in OpenGL context */
window = SDL_CreateWindow( _window = SDL_CreateWindow(
get_configuration()["display"]["title"].get_ref<const std::string&>().c_str(), SDL_WINDOWPOS_CENTERED, configuration()["display"]["title"].get_ref<const std::string&>().c_str(), SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, window_size.x, window_size.y, SDL_WINDOW_OPENGL); SDL_WINDOWPOS_CENTERED, window_size.x, window_size.y, SDL_WINDOW_OPENGL);
if (window == nullptr) if (_window == nullptr)
{ {
sb::Log::sdl_error("Could not create window"); sb::Log::sdl_error("Could not create window");
flag_to_end(); flag_to_end();
} }
/* Create an SDL renderer for clearing the screen to black and for logging renderer properties. Destroy renderer /* Create an SDL renderer for clearing the screen to black and for logging renderer properties. Destroy renderer when finished.
* when finished. * Skip this in emscripten because it causes a mouse event bug. */
*/ #ifndef __EMSCRIPTEN__
if ((renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_TARGETTEXTURE | SDL_RENDERER_ACCELERATED)) == nullptr) if ((renderer = SDL_CreateRenderer(_window, -1, SDL_RENDERER_TARGETTEXTURE | SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC)) == nullptr)
{ {
sb::Log::sdl_error("Could not create renderer"); sb::Log::sdl_error("Could not create renderer");
flag_to_end(); flag_to_end();
@ -83,7 +83,8 @@ Game::Game()
SDL_RenderFlush(renderer); SDL_RenderFlush(renderer);
SDL_DestroyRenderer(renderer); SDL_DestroyRenderer(renderer);
} }
SDL_ShowCursor(get_configuration()["display"]["show-cursor"]); #endif
SDL_ShowCursor(configuration()["display"]["show-cursor"]);
if (TTF_Init() < 0) if (TTF_Init() < 0)
{ {
sb::Log::sdl_error("Could not initialize SDL ttf"); sb::Log::sdl_error("Could not initialize SDL ttf");
@ -101,7 +102,7 @@ Game::Game()
if (Mix_Init(MIX_INIT_OGG) == 0) if (Mix_Init(MIX_INIT_OGG) == 0)
{ {
sb::Log::sdl_error("Could not initialize SDL mixer"); sb::Log::sdl_error("Could not initialize SDL mixer");
flag_to_end(); // flag_to_end();
} }
else else
{ {
@ -147,7 +148,7 @@ void Game::load_sdl_context()
SDL_GetRenderDriverInfo(ii, &renderer_info); SDL_GetRenderDriverInfo(ii, &renderer_info);
log_renderer_info(renderer_info); log_renderer_info(renderer_info);
} }
if ((renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_TARGETTEXTURE | SDL_RENDERER_ACCELERATED)) == nullptr) if ((renderer = SDL_CreateRenderer(_window, -1, SDL_RENDERER_TARGETTEXTURE | SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC)) == nullptr)
{ {
sb::Log::sdl_error("Could not create renderer"); sb::Log::sdl_error("Could not create renderer");
flag_to_end(); flag_to_end();
@ -170,14 +171,16 @@ void Game::load_gl_context()
SDL_DestroyRenderer(renderer); SDL_DestroyRenderer(renderer);
renderer = nullptr; renderer = nullptr;
} }
#ifndef __EMSCRIPTEN__
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
#endif
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
if ((glcontext = SDL_GL_CreateContext(window)) == nullptr) if ((glcontext = SDL_GL_CreateContext(_window)) == nullptr)
{ {
sb::Log::sdl_error("Could not get GL context"); sb::Log::sdl_error("Could not get GL context");
flag_to_end(); flag_to_end();
@ -213,14 +216,14 @@ void Game::sdl_log_override(void* userdata, int category, SDL_LogPriority priori
Game* game = static_cast<Game*>(userdata); Game* game = static_cast<Game*>(userdata);
std::ostream& out = (priority > SDL_LOG_PRIORITY_WARN) ? std::cerr : std::cout; std::ostream& out = (priority > SDL_LOG_PRIORITY_WARN) ? std::cerr : std::cout;
/* print to stdout/stderr if priority is higher than debug or debug statements are enabled */ /* print to stdout/stderr if priority is higher than debug or debug statements are enabled */
if (priority > SDL_LOG_PRIORITY_DEBUG || game->get_configuration()["log"]["debug-to-stdout"]) if (priority > SDL_LOG_PRIORITY_DEBUG || game->configuration()["log"]["debug-to-stdout"])
{ {
out << message << std::endl; out << message << std::endl;
} }
/* handle writing to log file */ /* handle writing to log file */
if (game->get_configuration()["log"]["enabled"]) if (game->configuration()["log"]["enabled"])
{ {
fs::path path = game->get_configuration()["log"]["output-directory"]; fs::path path = game->configuration()["log"]["output-directory"];
if (!fs::exists(path)) if (!fs::exists(path))
{ {
fs::create_directories(path); fs::create_directories(path);
@ -230,16 +233,16 @@ void Game::sdl_log_override(void* userdata, int category, SDL_LogPriority priori
std::stringstream stamped_message; std::stringstream stamped_message;
stamped_message << std::put_time(std::localtime(&now), "%F %T ") << message; stamped_message << std::put_time(std::localtime(&now), "%F %T ") << message;
/* if debug is enabled, append message to debug log file */ /* if debug is enabled, append message to debug log file */
if (game->get_configuration()["log"]["debug-to-file"]) if (game->configuration()["log"]["debug-to-file"])
{ {
fs::path debug_path = path / game->get_configuration()["log"]["debug-file-name"]; fs::path debug_path = path / game->configuration()["log"]["debug-file-name"];
std::ofstream debug_stream(debug_path, std::ios_base::app); std::ofstream debug_stream(debug_path, std::ios_base::app);
debug_stream << stamped_message.str() << std::endl; debug_stream << stamped_message.str() << std::endl;
} }
/* only append messages to the info log that are higher than debug priority */ /* only append messages to the info log that are higher than debug priority */
if (priority > SDL_LOG_PRIORITY_DEBUG) if (priority > SDL_LOG_PRIORITY_DEBUG)
{ {
fs::path info_path = path / game->get_configuration()["log"]["info-file-name"]; fs::path info_path = path / game->configuration()["log"]["info-file-name"];
std::ofstream info_stream(info_path, std::ios_base::app); std::ofstream info_stream(info_path, std::ios_base::app);
info_stream << stamped_message.str() << std::endl; info_stream << stamped_message.str() << std::endl;
} }
@ -483,14 +486,24 @@ std::string Game::get_pixel_format_string(Uint32 format)
return pixel_format; return pixel_format;
} }
const SDL_Window* Game::get_window() const const nlohmann::json& Game::configuration() const
{ {
return window; return _configuration.config;
} }
SDL_Window* Game::get_window() nlohmann::json& Game::configuration()
{ {
return window; return _configuration.config;
}
const SDL_Window* Game::window() const
{
return _window;
}
SDL_Window* Game::window()
{
return _window;
} }
const SDL_Renderer* Game::get_renderer() const const SDL_Renderer* Game::get_renderer() const
@ -525,6 +538,7 @@ glm::vec2 Game::weight(glm::vec2 motion)
return {weight(motion.x), weight(motion.y)}; return {weight(motion.x), weight(motion.y)};
} }
void Game::run() void Game::run()
{ {
SDL_FlushEvents(SDL_FIRSTEVENT, SDL_LASTEVENT); SDL_FlushEvents(SDL_FIRSTEVENT, SDL_LASTEVENT);
@ -562,7 +576,7 @@ void Game::frame(float ticks)
input.unsuppress_animation.update(); input.unsuppress_animation.update();
update(); update();
framerate_indicator.update(); framerate_indicator.update();
configuration.update(); _configuration.update();
if (!is_gl_context) if (!is_gl_context)
{ {
SDL_SetRenderTarget(renderer, nullptr); SDL_SetRenderTarget(renderer, nullptr);
@ -639,9 +653,9 @@ void Game::quit()
{ {
SDL_DestroyRenderer(renderer); SDL_DestroyRenderer(renderer);
} }
if (window != nullptr) if (_window != nullptr)
{ {
SDL_DestroyWindow(window); SDL_DestroyWindow(_window);
} }
if (TTF_WasInit()) if (TTF_WasInit())
{ {

View File

@ -1,5 +1,4 @@
#ifndef Game_h_ #pragma once
#define Game_h_
#include <stdlib.h> #include <stdlib.h>
#include <vector> #include <vector>
@ -55,6 +54,8 @@ private:
int ticks; int ticks;
float frame_length = 1000.0 / 60.0; float frame_length = 1000.0 / 60.0;
Configuration _configuration {this};
SDL_Window* _window;
static void sdl_log_override(void*, int, SDL_LogPriority, const char*); static void sdl_log_override(void*, int, SDL_LogPriority, const char*);
@ -72,13 +73,11 @@ public:
Game(Game&&) = delete; Game(Game&&) = delete;
Game& operator=(Game&&) = delete; Game& operator=(Game&&) = delete;
SDL_Window* window;
SDL_Renderer* renderer = nullptr; SDL_Renderer* renderer = nullptr;
SDL_GLContext glcontext = nullptr; SDL_GLContext glcontext = nullptr;
int frame_count_this_second = 0, last_frame_length; int frame_count_this_second = 0, last_frame_length;
float frame_time_overflow = 0, last_frame_timestamp, last_frame_count_timestamp; float frame_time_overflow = 0, last_frame_timestamp, last_frame_count_timestamp;
bool done = false, show_framerate = true, is_gl_context = true; bool done = false, show_framerate = true, is_gl_context = true;
Configuration configuration {this};
Delegate delegate {this}; Delegate delegate {this};
sb::Display display {this}; sb::Display display {this};
Recorder recorder {this}; Recorder recorder {this};
@ -99,8 +98,10 @@ public:
void log_display_mode(); void log_display_mode();
void log_surface_format(SDL_Surface*, std::string = "surface"); void log_surface_format(SDL_Surface*, std::string = "surface");
std::string get_pixel_format_string(Uint32); std::string get_pixel_format_string(Uint32);
const SDL_Window* get_window() const; const nlohmann::json& configuration() const;
SDL_Window* get_window(); nlohmann::json& configuration();
const SDL_Window* window() const;
SDL_Window* window();
const SDL_Renderer* get_renderer() const; const SDL_Renderer* get_renderer() const;
SDL_Renderer* get_renderer(); SDL_Renderer* get_renderer();
const Input& get_input() const; const Input& get_input() const;
@ -133,5 +134,3 @@ public:
void loop(void*); void loop(void*);
#endif #endif
#endif

View File

@ -30,7 +30,7 @@ void Input::print_key_combination(const KeyCombination &combination) const
void Input::load_key_map() void Input::load_key_map()
{ {
nlohmann::json &config = get_configuration(); nlohmann::json &config = configuration();
for (auto& entry : config.at("keys").items()) for (auto& entry : config.at("keys").items())
{ {
bool ctrl = false, alt = false, shift = false; bool ctrl = false, alt = false, shift = false;
@ -90,10 +90,10 @@ void Input::respond(SDL_Event &event)
SDL_Keycode sym = event.key.keysym.sym; SDL_Keycode sym = event.key.keysym.sym;
bool found_command = false, cancel = event.type != SDL_KEYDOWN, ctrl = mod & KMOD_CTRL, bool found_command = false, cancel = event.type != SDL_KEYDOWN, ctrl = mod & KMOD_CTRL,
shift = mod & KMOD_SHIFT, alt = mod & KMOD_ALT, shift = mod & KMOD_SHIFT, alt = mod & KMOD_ALT,
suppress_any_key = get_configuration()["input"]["suppress-any-key-on-mods"] && (ctrl || alt); suppress_any_key = configuration()["input"]["suppress-any-key-on-mods"] && (ctrl || alt);
const std::vector<std::string>& system_any_key_ignore = get_configuration()["input"]["system-any-key-ignore-commands"]; const std::vector<std::string>& system_any_key_ignore = configuration()["input"]["system-any-key-ignore-commands"];
const std::vector<std::string>& any_key_ignore = get_configuration()["input"]["any-key-ignore-commands"]; const std::vector<std::string>& any_key_ignore = configuration()["input"]["any-key-ignore-commands"];
bool ignore_repeat = get_configuration()["input"]["ignore-repeat-keypress"]; bool ignore_repeat = configuration()["input"]["ignore-repeat-keypress"];
if (event.key.repeat == 0 || !ignore_repeat) if (event.key.repeat == 0 || !ignore_repeat)
{ {
for (KeyCombination& combination : key_map) for (KeyCombination& combination : key_map)

View File

@ -89,14 +89,14 @@ void sb::Log::sdl_error(const std::string& original_message)
// Game* game = static_cast<Game*>(userdata); // Game* game = static_cast<Game*>(userdata);
// std::ostream& out = (priority > SDL_LOG_PRIORITY_WARN) ? std::cerr : std::cout; // std::ostream& out = (priority > SDL_LOG_PRIORITY_WARN) ? std::cerr : std::cout;
// /* print to stdout/stderr if priority is higher than debug or debug statements are enabled */ // /* print to stdout/stderr if priority is higher than debug or debug statements are enabled */
// if (priority > SDL_LOG_PRIORITY_DEBUG /* || game->get_configuration()["log"]["debug-to-stdout"] */) // if (priority > SDL_LOG_PRIORITY_DEBUG /* || game->configuration()["log"]["debug-to-stdout"] */)
// { // {
// out << message << std::endl; // out << message << std::endl;
// } // }
// /* handle writing to log file */ // /* handle writing to log file */
// if (game->get_configuration()["log"]["enabled"]) // if (game->configuration()["log"]["enabled"])
// { // {
// fs::path path = game->get_configuration()["log"]["output-directory"]; // fs::path path = game->configuration()["log"]["output-directory"];
// if (!fs::exists(path)) // if (!fs::exists(path))
// { // {
// fs::create_directories(path); // fs::create_directories(path);
@ -106,16 +106,16 @@ void sb::Log::sdl_error(const std::string& original_message)
// std::stringstream stamped_message; // std::stringstream stamped_message;
// stamped_message << std::put_time(std::localtime(&now), "%F %T ") << message; // stamped_message << std::put_time(std::localtime(&now), "%F %T ") << message;
// /* if debug is enabled, append message to debug log file */ // /* if debug is enabled, append message to debug log file */
// if (game->get_configuration()["log"]["debug-to-file"]) // if (game->configuration()["log"]["debug-to-file"])
// { // {
// fs::path debug_path = path / game->get_configuration()["log"]["debug-file-name"]; // fs::path debug_path = path / game->configuration()["log"]["debug-file-name"];
// std::ofstream debug_stream(debug_path, std::ios_base::app); // std::ofstream debug_stream(debug_path, std::ios_base::app);
// debug_stream << stamped_message.str() << std::endl; // debug_stream << stamped_message.str() << std::endl;
// } // }
// /* only append messages to the info log that are higher than debug priority */ // /* only append messages to the info log that are higher than debug priority */
// if (priority > SDL_LOG_PRIORITY_DEBUG) // if (priority > SDL_LOG_PRIORITY_DEBUG)
// { // {
// fs::path info_path = path / game->get_configuration()["log"]["info-file-name"]; // fs::path info_path = path / game->configuration()["log"]["info-file-name"];
// std::ofstream info_stream(info_path, std::ios_base::app); // std::ofstream info_stream(info_path, std::ios_base::app);
// info_stream << stamped_message.str() << std::endl; // info_stream << stamped_message.str() << std::endl;
// } // }

View File

@ -44,14 +44,14 @@ bool Node::is_active() const
return active; return active;
} }
const nlohmann::json& Node::get_configuration() const const nlohmann::json& Node::configuration() const
{ {
return get_root()->configuration.config; return get_root()->configuration();
} }
nlohmann::json& Node::get_configuration() nlohmann::json& Node::configuration()
{ {
return get_root()->configuration.config; return get_root()->configuration();
} }
Delegate& Node::get_delegate() Delegate& Node::get_delegate()
@ -74,14 +74,14 @@ SDL_Renderer* Node::get_renderer()
return get_root()->get_renderer(); return get_root()->get_renderer();
} }
const SDL_Window* Node::get_window() const const SDL_Window* Node::window() const
{ {
return get_root()->get_window(); return get_root()->window();
} }
SDL_Window* Node::get_window() SDL_Window* Node::window()
{ {
return get_root()->get_window(); return get_root()->window();
} }
const Input& Node::get_input() const const Input& Node::get_input() const
@ -126,7 +126,7 @@ void Node::suppress_input_temporarily(int length)
suppress_input(); suppress_input();
if (length == 0) if (length == 0)
{ {
length = get_configuration()["input"]["default-unsuppress-delay"]; length = configuration()["input"]["default-unsuppress-delay"];
} }
get_root()->get_input().unsuppress_animation.play_once(length); get_root()->get_input().unsuppress_animation.play_once(length);
} }

View File

@ -44,14 +44,14 @@ public:
void set_canvas(SDL_Texture*); void set_canvas(SDL_Texture*);
SDL_Texture* get_canvas(); SDL_Texture* get_canvas();
bool is_active() const; bool is_active() const;
const nlohmann::json& get_configuration() const; const nlohmann::json& configuration() const;
nlohmann::json& get_configuration(); nlohmann::json& configuration();
Delegate& get_delegate(); Delegate& get_delegate();
const sb::Display& get_display() const; const sb::Display& get_display() const;
const SDL_Renderer* get_renderer() const; const SDL_Renderer* get_renderer() const;
SDL_Renderer* get_renderer(); SDL_Renderer* get_renderer();
const SDL_Window* get_window() const; const SDL_Window* window() const;
SDL_Window* get_window(); SDL_Window* window();
const Input& get_input() const; const Input& get_input() const;
Input& get_input(); Input& get_input();
Audio& get_audio(); Audio& get_audio();

View File

@ -11,7 +11,7 @@ Recorder::Recorder(Node* parent) : Node(parent)
get_delegate().subscribe(&Recorder::respond, this); get_delegate().subscribe(&Recorder::respond, this);
animation.play(); animation.play();
Mix_SetPostMix(Recorder::process_audio, this); Mix_SetPostMix(Recorder::process_audio, this);
if (!get_configuration()["recording"]["enabled"]) if (!configuration()["recording"]["enabled"])
{ {
deactivate(); deactivate();
} }
@ -21,7 +21,7 @@ Recorder::Recorder(Node* parent) : Node(parent)
* been configured by the user. */ * been configured by the user. */
float Recorder::frame_length() float Recorder::frame_length()
{ {
return get_configuration()["recording"].value("video-frame-length", get_root()->get_frame_length()); return configuration()["recording"].value("video-frame-length", get_root()->get_frame_length());
} }
/* Handle commands for screenshot, record video and save video */ /* Handle commands for screenshot, record video and save video */
@ -64,7 +64,7 @@ void Recorder::respond(SDL_Event& event)
* screenshots found in the output directory. */ * screenshots found in the output directory. */
void Recorder::capture_screen() void Recorder::capture_screen()
{ {
nlohmann::json config = get_configuration(); nlohmann::json config = configuration();
SDL_Surface* surface = get_display().screen_surface(); SDL_Surface* surface = get_display().screen_surface();
fs::path directory = config["recording"]["screenshot-directory"]; fs::path directory = config["recording"]["screenshot-directory"];
fs::create_directories(directory); fs::create_directories(directory);
@ -86,7 +86,7 @@ void Recorder::grab_stash()
{ {
if (!is_recording and !writing_recording) if (!is_recording and !writing_recording)
{ {
int length = get_configuration()["recording"]["max-stash-length"]; int length = configuration()["recording"]["max-stash-length"];
std::ostringstream message; std::ostringstream message;
message << "stashing most recent " << length / 1000.0f << " seconds of video"; message << "stashing most recent " << length / 1000.0f << " seconds of video";
sb::Log::log(message); sb::Log::log(message);
@ -115,7 +115,7 @@ void Recorder::write_most_recent_frames()
most_recent_stash.audio_buffer_lengths.erase(most_recent_stash.audio_buffer_lengths.begin()); most_recent_stash.audio_buffer_lengths.erase(most_recent_stash.audio_buffer_lengths.begin());
} }
audio_file.close(); audio_file.close();
if (get_configuration()["recording"]["write-mp4"]) if (configuration()["recording"]["write-mp4"])
{ {
write_mp4(); write_mp4();
} }
@ -155,7 +155,7 @@ void Recorder::add_frame()
int bytes = sb::Display::bpp / 8 * size.x * size.y; int bytes = sb::Display::bpp / 8 * size.x * size.y;
unsigned char* pixels = new unsigned char[bytes]; unsigned char* pixels = new unsigned char[bytes];
get_display().screen_pixels(pixels, size.x, size.y); get_display().screen_pixels(pixels, size.x, size.y);
int max_length = get_configuration()["recording"]["max-stash-length"]; int max_length = configuration()["recording"]["max-stash-length"];
float length = frame_length() * current_stash.pixel_buffers.size(); float length = frame_length() * current_stash.pixel_buffers.size();
if (length > max_length) if (length > max_length)
{ {
@ -233,7 +233,7 @@ int Recorder::get_memory_size()
void Recorder::make_directory() void Recorder::make_directory()
{ {
nlohmann::json config = get_configuration(); nlohmann::json config = configuration();
fs::path root = config["recording"]["video-directory"]; fs::path root = config["recording"]["video-directory"];
fs::create_directories(root); fs::create_directories(root);
fs::path directory = sb::get_next_file_name(root, 5, "video-"); fs::path directory = sb::get_next_file_name(root, 5, "video-");
@ -246,7 +246,7 @@ void Recorder::write_stash_frames(Stash* stash)
SDL_Log("Writing stash offset %i to %s...", stash->frame_offset, current_video_directory.c_str()); SDL_Log("Writing stash offset %i to %s...", stash->frame_offset, current_video_directory.c_str());
SDL_Surface* frame; SDL_Surface* frame;
GifWriter gif_writer; GifWriter gif_writer;
int gif_frame_length = get_configuration()["recording"]["gif-frame-length"]; int gif_frame_length = configuration()["recording"]["gif-frame-length"];
fs::path gif_path = sb::get_next_file_name( fs::path gif_path = sb::get_next_file_name(
current_video_directory, 3, "gif-", ".gif"); current_video_directory, 3, "gif-", ".gif");
float elapsed = 0, last_gif_write = 0, gif_write_overflow = 0; float elapsed = 0, last_gif_write = 0, gif_write_overflow = 0;
@ -289,7 +289,7 @@ void Recorder::keep_stash()
{ {
in_game_stashes.push_back(current_stash); in_game_stashes.push_back(current_stash);
current_stash = Stash(); current_stash = Stash();
auto max_stashes = get_configuration()["recording"]["max-in-game-stashes"]; auto max_stashes = configuration()["recording"]["max-in-game-stashes"];
if (in_game_stashes.size() > max_stashes) if (in_game_stashes.size() > max_stashes)
{ {
Stash& stash = in_game_stashes.front(); Stash& stash = in_game_stashes.front();
@ -331,7 +331,7 @@ void Recorder::finish_writing_video()
} }
} }
video_stashes.clear(); video_stashes.clear();
if (get_configuration()["recording"]["write-mp4"]) if (configuration()["recording"]["write-mp4"])
{ {
write_mp4(); write_mp4();
} }
@ -345,7 +345,7 @@ void Recorder::write_mp4()
{ {
glm::ivec2 size = get_display().window_size(); glm::ivec2 size = get_display().window_size();
std::ostringstream mp4_command; std::ostringstream mp4_command;
std::string pixel_format = get_configuration()["recording"]["mp4-pixel-format"].get<std::string>(); std::string pixel_format = configuration()["recording"]["mp4-pixel-format"].get<std::string>();
fs::path images_match = current_video_directory / "%05d.png"; fs::path images_match = current_video_directory / "%05d.png";
mp4_command << "ffmpeg -f s16le -ac 2 -ar 22050 -i " << current_audio_path.string() << mp4_command << "ffmpeg -f s16le -ac 2 -ar 22050 -i " << current_audio_path.string() <<
" -f image2 -framerate " << (1000 / frame_length()) << " -f image2 -framerate " << (1000 / frame_length()) <<
@ -364,7 +364,7 @@ void Recorder::write_audio(Uint8* stream, int len)
void Recorder::update() void Recorder::update()
{ {
if (is_recording and get_memory_size() > get_configuration()["recording"]["max-video-memory"]) if (is_recording and get_memory_size() > configuration()["recording"]["max-video-memory"])
{ {
end_recording(); end_recording();
} }
@ -377,7 +377,7 @@ void Recorder::process_audio(void* context, Uint8* stream, int len)
Recorder* recorder = static_cast<Recorder*>(context); Recorder* recorder = static_cast<Recorder*>(context);
if (recorder->is_active()) if (recorder->is_active())
{ {
int max_length = recorder->get_configuration()["recording"]["max-stash-length"]; int max_length = recorder->configuration()["recording"]["max-stash-length"];
float length = recorder->frame_length() * recorder->current_stash.pixel_buffers.size(); float length = recorder->frame_length() * recorder->current_stash.pixel_buffers.size();
if (length > max_length) if (length > max_length)
{ {

View File

@ -4,7 +4,7 @@
Sprite::Sprite() : Sprite(nullptr) {} Sprite::Sprite() : Sprite(nullptr) {}
Sprite::Sprite(Node* parent) : Sprite::Sprite(Node* parent) :
Node(parent), current_frameset_name(get_configuration()["animation"]["all-frames-frameset-name"]) Node(parent), current_frameset_name(configuration()["animation"]["all-frames-frameset-name"])
{ {
add_frameset(current_frameset_name); add_frameset(current_frameset_name);
frame_animation.play(); frame_animation.play();
@ -118,7 +118,7 @@ const std::vector<SDL_Texture*>& Sprite::get_frames() const
Sprite::Frameset& Sprite::get_all_frames_frameset() Sprite::Frameset& Sprite::get_all_frames_frameset()
{ {
return framesets[get_configuration()["animation"]["all-frames-frameset-name"]]; return framesets[configuration()["animation"]["all-frames-frameset-name"]];
} }
Sprite::Frameset& Sprite::add_frameset(std::string name) Sprite::Frameset& Sprite::add_frameset(std::string name)

View File

@ -22,13 +22,6 @@
#ifndef SB_TEXTURE_H_ #ifndef SB_TEXTURE_H_
#define SB_TEXTURE_H_ #define SB_TEXTURE_H_
/* include Open GL */
#if defined(__EMSCRIPTEN__)
#include <GL/glew.h>
#else
#include "glew/glew.h"
#endif
#include <sstream> #include <sstream>
#include <stdexcept> #include <stdexcept>
#include "glm/vec2.hpp" #include "glm/vec2.hpp"

View File

@ -19,7 +19,7 @@
a time to fill the buffer. a time to fill the buffer.
This class doesn't support updating the attribute values once they've been added. To do that, This class doesn't support updating the attribute values once they've been added. To do that,
either reallocate the entire buffer and readd the attribute values or keep track of the offset either reallocate the entire buffer and re-add the attribute values or keep track of the offset
returned by the add function and use glBufferSubData independently. returned by the add function and use glBufferSubData independently.
*/ */

11
src/math.cpp Normal file
View File

@ -0,0 +1,11 @@
#include "math.hpp"
glm::vec2 sb::velocity_to_delta(float angle, float magnitude)
{
return {glm::sin(angle) * magnitude, -glm::cos(angle) * magnitude};
}
glm::vec2 sb::velocity_to_delta(glm::vec2 velocity)
{
return velocity_to_delta(velocity.x, velocity.y);
}

31
src/math.hpp Normal file
View File

@ -0,0 +1,31 @@
/* /\ +--------------------------------------------------------------+
____/ \____ /| - zlib/MIT/Unlicenced game framework licensed to freely use, |
\ / / | copy, modify and sell without restriction |
+--\ ^__^ /--+ | |
| ~/ \~ | | - originally created at [http://nugget.fun] |
| ~~~~~~~~~~~~ | +--------------------------------------------------------------+
| SPACE ~~~~~ | /
| ~~~~~~~ BOX |/
+--------------+
[math.hpp]
For math helper functions that require only GLM primitives.
*/
#pragma once
/* GLM */
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/glm.hpp>
#include <glm/gtx/compatibility.hpp>
namespace sb
{
/* Convert a vector described by the given angle and magnitude to an X and Y offset vector. */
glm::vec2 velocity_to_delta(float, float);
/* Convert a vector containing angle and magnitude to an X and Y offset vector. */
glm::vec2 velocity_to_delta(glm::vec2);
}

View File

@ -15,12 +15,9 @@
*/ */
#ifndef SB_UTILITY_H_ #pragma once
#define SB_UTILITY_H_
namespace sb namespace sb
{ {
int mod(int a, int b); int mod(int, int);
} }
#endif