From 3ba3be449618ef2a7a5a46cef61492d57d04ed82 Mon Sep 17 00:00:00 2001 From: frank Date: Tue, 23 May 2023 15:28:53 -0400 Subject: [PATCH] - add Switch and time_it classes - finish adding #pragma once to headers - move configuration initialization into Game class - print debug to stdout by default - explicitly pass file to refresh to config auto refresh - add delegate to sb namespace and deprecate get_delegate() in favor of delegate() - set custom log function before loading config - raise exception when no model textures are available --- src/Animation.hpp | 15 +++-- src/Attributes.hpp | 5 +- src/Audio.hpp | 15 +++-- src/Carousel.hpp | 5 +- src/Color.hpp | 5 +- src/Configuration.cpp | 35 +++++++---- src/Configuration.hpp | 18 +++--- src/Connection.hpp | 23 ++++--- src/Delegate.cpp | 20 ++++--- src/Delegate.hpp | 114 +++++++++++++++++------------------ src/Display.hpp | 23 ++++--- src/GLObject.hpp | 6 +- src/Game.cpp | 44 ++++++++------ src/Game.hpp | 5 +- src/Input.cpp | 20 +++---- src/Input.hpp | 23 ++++--- src/Model.cpp | 15 ++++- src/Model.hpp | 12 ++-- src/Node.cpp | 33 +++++------ src/Node.hpp | 42 ++++++++----- src/Pixels.hpp | 15 +++-- src/Recorder.hpp | 15 +++-- src/Segment.hpp | 16 +++-- src/Sprite.hpp | 5 +- src/Switch.hpp | 135 ++++++++++++++++++++++++++++++++++++++++++ src/Texture.hpp | 5 +- src/Timer.hpp | 15 +++-- src/VBO.hpp | 5 +- src/filesystem.hpp | 2 + src/time_it.hpp | 93 +++++++++++++++++++++++++++++ 30 files changed, 546 insertions(+), 238 deletions(-) create mode 100644 src/Switch.hpp create mode 100644 src/time_it.hpp diff --git a/src/Animation.hpp b/src/Animation.hpp index d55d7a8..3cd617c 100644 --- a/src/Animation.hpp +++ b/src/Animation.hpp @@ -1,5 +1,14 @@ -#ifndef Animation_h_ -#define Animation_h_ + /* +------------------------------------------------------+ + ____/ \____ /| - Open source game framework licensed to freely use, | + \ / / | copy, modify and sell without restriction | ++--\ ^__^ /--+ | | +| ~/ \~ | | - created for | +| ~~~~~~~~~~~~ | +------------------------------------------------------+ +| SPACE ~~~~~ | / +| ~~~~~~~ BOX |/ ++-------------*/ + +#pragma once #include #include @@ -58,5 +67,3 @@ public: }; #include "Node.hpp" - -#endif diff --git a/src/Attributes.hpp b/src/Attributes.hpp index b9e4d37..aee20cb 100644 --- a/src/Attributes.hpp +++ b/src/Attributes.hpp @@ -84,8 +84,7 @@ * { 5.5 6.6 7.7 8.8 } */ -#ifndef SB_ATTRIBUTES_H_ -#define SB_ATTRIBUTES_H_ +#pragma once /* include Open GL */ #if defined(__EMSCRIPTEN__) @@ -289,5 +288,3 @@ namespace sb }; } - -#endif diff --git a/src/Audio.hpp b/src/Audio.hpp index abfed69..7409525 100644 --- a/src/Audio.hpp +++ b/src/Audio.hpp @@ -1,5 +1,14 @@ -#ifndef Audio_h_ -#define Audio_h_ + /* +------------------------------------------------------+ + ____/ \____ /| - Open source game framework licensed to freely use, | + \ / / | copy, modify and sell without restriction | ++--\ ^__^ /--+ | | +| ~/ \~ | | - created for | +| ~~~~~~~~~~~~ | +------------------------------------------------------+ +| SPACE ~~~~~ | / +| ~~~~~~~ BOX |/ ++-------------*/ + +#pragma once #include #include @@ -89,5 +98,3 @@ struct Audio : Node #include "Box.hpp" #include "Configuration.hpp" #include "Display.hpp" - -#endif diff --git a/src/Carousel.hpp b/src/Carousel.hpp index da89a27..522368c 100644 --- a/src/Carousel.hpp +++ b/src/Carousel.hpp @@ -8,8 +8,7 @@ | ~~~~~~~ BOX |/ +-------------*/ -#ifndef CAROUSEL_H_ -#define CAROUSEL_H_ +#pragma once #include #include @@ -86,5 +85,3 @@ namespace sb }; } - -#endif diff --git a/src/Color.hpp b/src/Color.hpp index 861721b..5e0a1bb 100644 --- a/src/Color.hpp +++ b/src/Color.hpp @@ -1,5 +1,4 @@ -#ifndef Color_h_ -#define Color_h_ +#pragma once #include #include @@ -50,5 +49,3 @@ namespace std { std::ostream& operator<<(std::ostream&, const Color&); } - -#endif diff --git a/src/Configuration.cpp b/src/Configuration.cpp index 371b76d..32d516d 100644 --- a/src/Configuration.cpp +++ b/src/Configuration.cpp @@ -13,12 +13,6 @@ Configuration::Configuration(Node* parent) : Node(parent) { set_defaults(); - merge(USER_CONFIG_PATH); -#ifdef __ANDROID__ - merge(ANDROID_CONFIG_PATH); -#endif - auto_refresher.set_frame_length(config["configuration"]["auto-refresh-interval"].get()); - auto_refresh(config["configuration"]["auto-refresh"]); } void Configuration::set_defaults() @@ -93,7 +87,7 @@ void Configuration::set_defaults() }; config["log"] = { {"enabled", false}, - {"debug-to-stdout", false}, + {"debug-to-stdout", true}, {"debug-to-file", false}, {"output-directory", "."}, {"info-file-name", "space_box_log.txt"}, @@ -123,6 +117,7 @@ const nlohmann::json& Configuration::operator()() const void Configuration::merge(const nlohmann::json& incoming) { + sb::Log::log("Merging into configuration", sb::Log::DEBUG); if (!incoming.empty()) { /* loop over first level key/value pairs */ @@ -186,19 +181,35 @@ void Configuration::merge(const char* path) merge(fs::path(path)); } -void Configuration::auto_refresh(bool on) +void Configuration::enable_auto_refresh(const fs::path& file_to_refresh, float interval) { - on ? auto_refresher.play() : auto_refresher.pause(); +#ifndef __ANDROID__ + /* Warn user if the file does not exist */ + if (!fs::exists(file_to_refresh)) + { + std::ostringstream message; + message << "File to auto-refresh does not exist: " << file_to_refresh; + sb::Log::log(file_to_refresh, sb::Log::WARN); + } +#endif + this->file_to_refresh = file_to_refresh; + auto_refresher.set_frame_length(interval); + auto_refresher.play(); +} + +void Configuration::disable_auto_refresh() +{ + auto_refresher.pause(); } void Configuration::refresh() { - if (fs::exists(USER_CONFIG_PATH) && fs::last_write_time(USER_CONFIG_PATH) > config_file_modification_time) + if (fs::exists(file_to_refresh) && fs::last_write_time(file_to_refresh) > config_file_modification_time) { std::ostringstream message; - message << "config file modified, reloading " << USER_CONFIG_PATH; + message << "config file modified, reloading " << file_to_refresh; sb::Log::log(message, sb::Log::DEBUG); - merge(USER_CONFIG_PATH); + merge(file_to_refresh); } } diff --git a/src/Configuration.hpp b/src/Configuration.hpp index ff853a8..db17654 100644 --- a/src/Configuration.hpp +++ b/src/Configuration.hpp @@ -25,12 +25,10 @@ class Configuration : public Node private: - inline static const std::string USER_CONFIG_PATH = "config.json"; - inline static const std::string ANDROID_CONFIG_PATH = "config_android.json"; - Animation auto_refresher = Animation(&Configuration::refresh, this); fs::file_time_type config_file_modification_time; nlohmann::json config; + fs::path file_to_refresh; /*! * Fill the config JSON with default values set by the framework. @@ -103,12 +101,18 @@ public: void merge(const char* path); /*! - * Set auto refresh to on or off. Auto refresh watches the file at Configuration::user_path (set in the contructor) for changes - * and loads them automatically at the interval set at Configuration::config["configuration"]["auto-refresh-interval"]. + * Enable auto refresh. Auto refresh watches the file at the given path for changes and loads them automatically every interval given + * in milliseconds. * - * @param bool true to refresh automatically, false to turn off automatic refresh + * @param file_to_refresh path to a configuration JSON + * @param interval amount of milliseconds between each refresh */ - void auto_refresh(bool); + void enable_auto_refresh(const fs::path& file_to_refresh, float interval); + + /*! + * Disable auto refresh. The file previously set with Configuration::enable_auto_refresh will no longer be watched for changes. + */ + void disable_auto_refresh(); /*! * Check if the user config file was modified and merge if so. diff --git a/src/Connection.hpp b/src/Connection.hpp index a67f01b..fe94418 100644 --- a/src/Connection.hpp +++ b/src/Connection.hpp @@ -8,12 +8,14 @@ * | ~~~~~~~ BOX |/ * +--------------+ * - * Connection - * ========== + * Connection objects contain a binary state of either on (connected) or off (not connected). When their state + * is changed, an optional user supplied function corresponding to the state change is run automatically. * - * A connection is an object containing a binary state of either on (connected) or off (not connected) - * and user supplied functions that run automatically on each state change. The functions each have the - * same return type, number of arguments, and argument types determined by the template arguments. + * The functions each have the same return type, number of arguments, and argument types determined by the + * template arguments. + * + * By default, the state must change in order for a callback to be triggered. To allow repeat calls to + * trigger a callback, the * * Original test code: * @@ -34,6 +36,8 @@ * std::cout << result << std::endl; */ +#pragma once + #include namespace sb @@ -58,9 +62,14 @@ namespace sb public: - /* Without any arguments, the connection object will be in the disconnected state with empty functions. Otherwise, + /*! + * Without any arguments, the connection object will be in the disconnected state with empty functions. Otherwise, * the supplied functions will be added to the connection object. The first function argument will be run on a - * connection, and the second function argument will be run on a disconnection. */ + * connection, and the second function argument will be run on a disconnection. + * + * @param on_connect_callback function to run on connection + * @param on_disconnect_callback function to run on disconnection + */ Connection(callback on_connect_callback = callback(), callback on_disconnect_callback = callback()) { if (on_connect_callback) diff --git a/src/Delegate.cpp b/src/Delegate.cpp index 980c258..869640d 100644 --- a/src/Delegate.cpp +++ b/src/Delegate.cpp @@ -1,15 +1,17 @@ -/* /\ +--------------------------------------------------------------+ - ____/ \____ /| - zlib/MIT/Unlicenced game framework licensed to freely use, | - \ / / | copy, modify and sell without restriction | - +--\ ^__^ /--+ | | - | ~/ \~ | | - originally created at [http://nugget.fun] | - | ~~~~~~~~~~~~ | +--------------------------------------------------------------+ - | SPACE ~~~~~ | / - | ~~~~~~~ BOX |/ - +-------------*/ + /* +------------------------------------------------------+ + ____/ \____ /| - Open source game framework licensed to freely use, | + \ / / | copy, modify and sell without restriction | ++--\ ^__^ /--+ | | +| ~/ \~ | | - created for | +| ~~~~~~~~~~~~ | +------------------------------------------------------+ +| SPACE ~~~~~ | / +| ~~~~~~~ BOX |/ ++-------------*/ #include "Delegate.hpp" +using namespace sb; + Delegate::Delegate(Node* parent) : Node(parent) {} void Delegate::add_subscriber(Subscriber s, std::uint32_t type) diff --git a/src/Delegate.hpp b/src/Delegate.hpp index 8e2e0d3..db938fb 100644 --- a/src/Delegate.hpp +++ b/src/Delegate.hpp @@ -1,15 +1,14 @@ -/* /\ +--------------------------------------------------------------+ - ____/ \____ /| - zlib/MIT/Unlicenced game framework licensed to freely use, | - \ / / | copy, modify and sell without restriction | - +--\ ^__^ /--+ | | - | ~/ \~ | | - originally created at [http://nugget.fun] | - | ~~~~~~~~~~~~ | +--------------------------------------------------------------+ - | SPACE ~~~~~ | / - | ~~~~~~~ BOX |/ - +-------------*/ + /* +------------------------------------------------------+ + ____/ \____ /| - Open source game framework licensed to freely use, | + \ / / | copy, modify and sell without restriction | ++--\ ^__^ /--+ | | +| ~/ \~ | | - created for | +| ~~~~~~~~~~~~ | +------------------------------------------------------+ +| SPACE ~~~~~ | / +| ~~~~~~~ BOX |/ ++-------------*/ -#ifndef SB_DELEGATE_H_ -#define SB_DELEGATE_H_ +#pragma once #include #include @@ -20,63 +19,64 @@ #include "SDL.h" #include "Node.hpp" -struct Subscriber +namespace sb { - std::function f; - Node* o; -}; - -class Delegate : public Node -{ - -private: - - std::map> subscribers; - bool cancelling_propagation = false; - -public: - - inline static std::uint32_t command_event_type = SDL_RegisterEvents(1); - - Delegate(Node*); - void add_subscriber(Subscriber, std::uint32_t); - void dispatch(); - static bool compare(SDL_Event&, const std::vector&, bool = false, bool = false); - static bool compare(SDL_Event&, const std::string& = "", bool = false, bool = false); - static bool compare_cancel(SDL_Event&, const std::string& = ""); - static bool compare_neutral(SDL_Event&, const std::string& = ""); - void cancel_propagation(); - static const std::string& get_event_command(SDL_Event&); - static bool get_event_cancel_state(SDL_Event&); - - template - void subscribe(void(T::*f)(SDL_Event&), T* o, std::uint32_t type = command_event_type) + struct Subscriber { - add_subscriber({std::bind(f, o, std::placeholders::_1), static_cast(o)}, type); - } + std::function f; + Node* o; + }; - template - void unsubscribe(T* p) + class Delegate : public Node { - for (auto t = subscribers.begin(); t != subscribers.end(); t++) + + private: + + std::map> subscribers; + bool cancelling_propagation = false; + + public: + + inline static std::uint32_t command_event_type = SDL_RegisterEvents(1); + + Delegate(Node*); + void add_subscriber(Subscriber, std::uint32_t); + void dispatch(); + static bool compare(SDL_Event&, const std::vector&, bool = false, bool = false); + static bool compare(SDL_Event&, const std::string& = "", bool = false, bool = false); + static bool compare_cancel(SDL_Event&, const std::string& = ""); + static bool compare_neutral(SDL_Event&, const std::string& = ""); + void cancel_propagation(); + static const std::string& get_event_command(SDL_Event&); + static bool get_event_cancel_state(SDL_Event&); + + template + void subscribe(void(T::*f)(SDL_Event&), T* o, std::uint32_t type = command_event_type) { - for (auto s = t->second.begin(); s != t->second.end();) + add_subscriber({std::bind(f, o, std::placeholders::_1), static_cast(o)}, type); + } + + template + void unsubscribe(T* p) + { + for (auto t = subscribers.begin(); t != subscribers.end(); t++) { - if (p == s->o) + for (auto s = t->second.begin(); s != t->second.end();) { - s = t->second.erase(s); - } - else - { - s++; + if (p == s->o) + { + s = t->second.erase(s); + } + else + { + s++; + } } } } - } -}; + }; +} #include "Input.hpp" #include "Game.hpp" - -#endif diff --git a/src/Display.hpp b/src/Display.hpp index 2df856c..50a095e 100644 --- a/src/Display.hpp +++ b/src/Display.hpp @@ -1,15 +1,14 @@ -/* /\ +--------------------------------------------------------------+ - ____/ \____ /| - zlib/MIT/Unlicenced game framework licensed to freely use, | - \ / / | copy, and modify without restriction | - +--\ ^__^ /--+ | | - | ~/ \~ | | - originally created at [http://nugget.fun] | - | ~~~~~~~~~~~~ | +--------------------------------------------------------------+ - | SPACE ~~~~~ | / - | ~~~~~~~ BOX |/ - +-------------*/ + /* +------------------------------------------------------+ + ____/ \____ /| - Open source game framework licensed to freely use, | + \ / / | copy, modify and sell without restriction | ++--\ ^__^ /--+ | | +| ~/ \~ | | - created for | +| ~~~~~~~~~~~~ | +------------------------------------------------------+ +| SPACE ~~~~~ | / +| ~~~~~~~ BOX |/ ++-------------*/ -#ifndef SB_DISPLAY_H_ -#define SB_DISPLAY_H_ +#pragma once #include #include "glm/vec2.hpp" @@ -47,5 +46,3 @@ namespace sb } #include "Game.hpp" - -#endif diff --git a/src/GLObject.hpp b/src/GLObject.hpp index 4ba5582..274706d 100644 --- a/src/GLObject.hpp +++ b/src/GLObject.hpp @@ -26,13 +26,13 @@ */ -#ifndef SB_GLOBJECT_H_ -#define SB_GLOBJECT_H_ +#pragma once #include #include #include #include +#include /* include Open GL */ #if defined(__EMSCRIPTEN__) @@ -122,5 +122,3 @@ namespace sb void buffer_deleter(GLuint*); } - -#endif diff --git a/src/Game.cpp b/src/Game.cpp index b7a77b1..d844b88 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -12,21 +12,27 @@ Game::Game() { - /* 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 */ - SDL_LogPriority default_log_category_priority; - if (configuration()["log"]["debug-to-file"] || configuration()["log"]["debug-to-stdout"]) - { - default_log_category_priority = SDL_LOG_PRIORITY_DEBUG; - } - else - { - default_log_category_priority = SDL_LOG_PRIORITY_INFO; - } - SDL_LogSetPriority(sb::Log::DEFAULT_CATEGORY, default_log_category_priority); - - /* Set custom log function that prints to stdout/stderr and to file if enabled */ + /* Set custom log function that prints to stdout/stderr and to file if enabled. Temporarily set to DEBUG priority before loading + * user setting. */ SDL_LogSetOutputFunction(&Game::sdl_log_override, this); + SDL_LogSetPriority(sb::Log::DEFAULT_CATEGORY, SDL_LOG_PRIORITY_DEBUG); + + /* Merge user configuration into the existing configuration and turn on auto refresh if it is enabled by the configuration. */ + _configuration.merge(USER_CONFIG_PATH); +#ifdef __ANDROID__ + _configuration.merge(ANDROID_CONFIG_PATH); +#endif + if (configuration()["configuration"]["auto-refresh"]) + { + _configuration.enable_auto_refresh(USER_CONFIG_PATH, configuration()["configuration"]["auto-refresh-interval"].get()); + } + + /* Set the appropriate priority level for the default log category, changing it to INFO if the user does not want debug statements, + * or leaving it at DEBUG otherwise. */ + if (!configuration()["log"]["debug-to-file"] && !configuration()["log"]["debug-to-stdout"]) + { + SDL_LogSetPriority(sb::Log::DEFAULT_CATEGORY, SDL_LOG_PRIORITY_INFO); + } /* Log the current working directory as seen by std::filesystem */ std::ostringstream log_message; @@ -56,7 +62,7 @@ Game::Game() set_framerate(configuration()["display"]["framerate"]); /* Subscribe to SDL's quit event */ - 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 (?) */ std::string fullscreen_env_assigment = "SDL_VIDEO_X11_LEGACY_FULLSCREEN=0"; @@ -538,7 +544,7 @@ void Game::frame(float ticks) if (last_frame_length < 1000) { recorder.update(); - delegate.dispatch(); + _delegate.dispatch(); audio.update(); input.unsuppress_animation.update(); update(); @@ -636,18 +642,18 @@ void Game::quit() Game::~Game() { - get_delegate().unsubscribe(this); + _delegate.unsubscribe(this); } FramerateIndicator::FramerateIndicator(Node* parent) : Sprite(parent) { - get_delegate().subscribe(&FramerateIndicator::respond, this); + delegate().subscribe(&FramerateIndicator::respond, this); hide(); } void FramerateIndicator::respond(SDL_Event& event) { - if (get_delegate().compare(event, "toggle-framerate")) + if (delegate().compare(event, "toggle-framerate")) { toggle_hidden(); } diff --git a/src/Game.hpp b/src/Game.hpp index 53ebc6e..09bc534 100644 --- a/src/Game.hpp +++ b/src/Game.hpp @@ -73,6 +73,9 @@ private: float frame_length = 1000.0 / 60.0; SDL_Window* _window; + inline static const std::string USER_CONFIG_PATH = "config.json"; + inline static const std::string ANDROID_CONFIG_PATH = "config_android.json"; + /*! * Overrides SDL's default log function to log a message to stdout/stderr and, if log is enabled in the * global configuration, to a file. Debug level statements may be suppressed, printed to stdout, or printed to @@ -108,7 +111,7 @@ public: float frame_time_overflow = 0, last_frame_timestamp, last_frame_count_timestamp; bool done = false, show_framerate = true, is_gl_context = true; Configuration _configuration {this}; - Delegate delegate {this}; + sb::Delegate _delegate {this}; sb::Display display {this}; Recorder recorder {this}; Input input {this}; diff --git a/src/Input.cpp b/src/Input.cpp index ba6d509..ab306a1 100644 --- a/src/Input.cpp +++ b/src/Input.cpp @@ -1,12 +1,12 @@ -/* /\ +--------------------------------------------------------------+ - ____/ \____ /| - zlib/MIT/Unlicenced game framework licensed to freely use, | - \ / / | copy, modify and sell without restriction | - +--\ ^__^ /--+ | | - | ~/ \~ | | - originally created at [http://nugget.fun] | - | ~~~~~~~~~~~~ | +--------------------------------------------------------------+ - | SPACE ~~~~~ | / - | ~~~~~~~ BOX |/ - +-------------*/ + /* +------------------------------------------------------+ + ____/ \____ /| - Open source game framework licensed to freely use, | + \ / / | copy, modify and sell without restriction | ++--\ ^__^ /--+ | | +| ~/ \~ | | - created for | +| ~~~~~~~~~~~~ | +------------------------------------------------------+ +| SPACE ~~~~~ | / +| ~~~~~~~ BOX |/ ++-------------*/ #include "Input.hpp" @@ -121,7 +121,7 @@ void Input::post_command(std::string& name, const bool& cancel) { SDL_Event relay; bool* cancel_pointer = new bool(cancel); - relay.type = Delegate::command_event_type; + relay.type = sb::Delegate::command_event_type; relay.user.data1 = &name; relay.user.data2 = cancel_pointer; SDL_PushEvent(&relay); diff --git a/src/Input.hpp b/src/Input.hpp index 1828636..23db7a8 100644 --- a/src/Input.hpp +++ b/src/Input.hpp @@ -1,15 +1,14 @@ -/* /\ +--------------------------------------------------------------+ - ____/ \____ /| - zlib/MIT/Unlicenced game framework licensed to freely use, | - \ / / | copy, modify and sell without restriction | - +--\ ^__^ /--+ | | - | ~/ \~ | | - originally created at [http://nugget.fun] | - | ~~~~~~~~~~~~ | +--------------------------------------------------------------+ - | SPACE ~~~~~ | / - | ~~~~~~~ BOX |/ - +-------------*/ + /* +------------------------------------------------------+ + ____/ \____ /| - Open source game framework licensed to freely use, | + \ / / | copy, modify and sell without restriction | ++--\ ^__^ /--+ | | +| ~/ \~ | | - created for | +| ~~~~~~~~~~~~ | +------------------------------------------------------+ +| SPACE ~~~~~ | / +| ~~~~~~~ BOX |/ ++-------------*/ -#ifndef SB_INPUT_H_ -#define SB_INPUT_H_ +#pragma once #include #include @@ -79,5 +78,3 @@ public: #include "extension.hpp" #include "Configuration.hpp" #include "Delegate.hpp" - -#endif diff --git a/src/Model.cpp b/src/Model.cpp index 9caba1f..31c5741 100644 --- a/src/Model.cpp +++ b/src/Model.cpp @@ -115,7 +115,20 @@ std::map& sb::Model::textures() * anything else a Texture object can be used for with direct calls to GL functions. */ sb::Texture& sb::Model::texture(const std::string& name) { - return textures().at(name); + if (textures().empty()) + { + throw std::out_of_range("There are no textures attached to this model."); + } + else if (textures().find(name) == textures().end()) + { + std::ostringstream message; + message << "No texture named " << name << " found attached to this model."; + throw std::out_of_range(message.str()); + } + else + { + return textures().at(name); + } } /* Get the default texture. The default texture must have previously been set with the default key as diff --git a/src/Model.hpp b/src/Model.hpp index 7d6581d..7f3e7f9 100644 --- a/src/Model.hpp +++ b/src/Model.hpp @@ -8,8 +8,7 @@ | ~~~~~~~ BOX |/ +-------------*/ -#ifndef MODEL_H_ -#define MODEL_H_ +#pragma once /* GL functions */ #if defined(__EMSCRIPTEN__) @@ -26,6 +25,7 @@ #include #include #include +#include #include "glm/glm.hpp" #include "Attributes.hpp" #include "Texture.hpp" @@ -82,8 +82,12 @@ namespace sb {0.0f, 1.0f}, {1.0f, 1.0f}, {0.0f, 0.0f}, {1.0f, 1.0f}, {1.0f, 0.0f}, {0.0f, 0.0f} }); + inline const static std::shared_ptr color = std::make_shared(sb::Attributes{ + {1.0f, 1.0f, 0.0f}, {1.0f, 1.0f, 0.0f}, {0.8f, 0.0f, 0.3f}, + {1.0f, 1.0f, 0.0f}, {0.8f, 0.0f, 0.3f}, {0.8f, 0.0f, 0.3f} + }); - Plane() : Model(std::map>({{"position", position}, {"uv", uv}})) {} + Plane() : Model(std::map>({{"position", position}, {"uv", uv}, {"color", color}})) {} }; @@ -109,5 +113,3 @@ namespace sb }; } - -#endif diff --git a/src/Node.cpp b/src/Node.cpp index 520d72d..5bd4010 100644 --- a/src/Node.cpp +++ b/src/Node.cpp @@ -1,20 +1,14 @@ -/* /\ +--------------------------------------------------------------+ - ____/ \____ /| - zlib/MIT/Unlicenced game framework licensed to freely use, | - \ / / | copy, and modify without restriction | - +--\ ^__^ /--+ | | - | ~/ \~ | | - originally created at [http://nugget.fun] | - | ~~~~~~~~~~~~ | +--------------------------------------------------------------+ - | SPACE ~~~~~ | / - | ~~~~~~~ BOX |/ - +-------------*/ + /* +------------------------------------------------------+ + ____/ \____ /| - Open source game framework licensed to freely use, | + \ / / | copy, modify and sell without restriction | ++--\ ^__^ /--+ | | +| ~/ \~ | | - created for | +| ~~~~~~~~~~~~ | +------------------------------------------------------+ +| SPACE ~~~~~ | / +| ~~~~~~~ BOX |/ ++-------------*/ -#include "Configuration.hpp" -#include "Delegate.hpp" -#include "Display.hpp" -#include "Input.hpp" -#include "Box.hpp" #include "Game.hpp" -#include "Audio.hpp" #include "Node.hpp" Node::Node() : Node(nullptr) {} @@ -54,9 +48,14 @@ Configuration& Node::configuration() return get_root()->configuration(); } -Delegate& Node::get_delegate() +sb::Delegate& Node::delegate() { - return get_root()->delegate; + return get_root()->_delegate; +} + +sb::Delegate& Node::get_delegate() +{ + return delegate(); } const sb::Display& Node::get_display() const diff --git a/src/Node.hpp b/src/Node.hpp index e967cc6..8975174 100644 --- a/src/Node.hpp +++ b/src/Node.hpp @@ -1,15 +1,14 @@ -/* /\ +--------------------------------------------------------------+ - ____/ \____ /| - zlib/MIT/Unlicenced game framework licensed to freely use, | - \ / / | copy, and modify without restriction | - +--\ ^__^ /--+ | | - | ~/ \~ | | - originally created at [http://nugget.fun] | - | ~~~~~~~~~~~~ | +--------------------------------------------------------------+ - | SPACE ~~~~~ | / - | ~~~~~~~ BOX |/ - +-------------*/ + /* +------------------------------------------------------+ + ____/ \____ /| - Open source game framework licensed to freely use, | + \ / / | copy, modify and sell without restriction | ++--\ ^__^ /--+ | | +| ~/ \~ | | - created for | +| ~~~~~~~~~~~~ | +------------------------------------------------------+ +| SPACE ~~~~~ | / +| ~~~~~~~ BOX |/ ++-------------*/ -#ifndef SB_NODE_H_ -#define SB_NODE_H_ +#pragma once #include #include @@ -20,7 +19,12 @@ #include "filesystem.hpp" class Game; -class Delegate; + +namespace sb +{ + class Delegate; +} + class Input; class Box; class Configuration; @@ -47,7 +51,17 @@ public: bool is_active() const; const Configuration& configuration() const; Configuration& configuration(); - Delegate& get_delegate(); + + /*! + * @return the Delegate object + */ + sb::Delegate& delegate(); + + /*! + * @deprecated use Node::delegate + */ + sb::Delegate& get_delegate(); + const sb::Display& get_display() const; const SDL_Renderer* get_renderer() const; SDL_Renderer* get_renderer(); @@ -85,5 +99,3 @@ private: bool active = true; }; - -#endif diff --git a/src/Pixels.hpp b/src/Pixels.hpp index 0deaee3..16a43bd 100644 --- a/src/Pixels.hpp +++ b/src/Pixels.hpp @@ -1,5 +1,14 @@ -#ifndef Pixels_h_ -#define Pixels_h_ + /* +------------------------------------------------------+ + ____/ \____ /| - Open source game framework licensed to freely use, | + \ / / | copy, modify and sell without restriction | ++--\ ^__^ /--+ | | +| ~/ \~ | | - created for | +| ~~~~~~~~~~~~ | +------------------------------------------------------+ +| SPACE ~~~~~ | / +| ~~~~~~~ BOX |/ ++-------------*/ + +#pragma once #include "SDL.h" #include "Box.hpp" @@ -49,5 +58,3 @@ struct Pixels } }; - -#endif diff --git a/src/Recorder.hpp b/src/Recorder.hpp index 5741d62..b42a63f 100644 --- a/src/Recorder.hpp +++ b/src/Recorder.hpp @@ -1,5 +1,14 @@ -#ifndef Recorder_h_ -#define Recorder_h_ + /* +------------------------------------------------------+ + ____/ \____ /| - Open source game framework licensed to freely use, | + \ / / | copy, modify and sell without restriction | ++--\ ^__^ /--+ | | +| ~/ \~ | | - created for | +| ~~~~~~~~~~~~ | +------------------------------------------------------+ +| SPACE ~~~~~ | / +| ~~~~~~~ BOX |/ ++-------------*/ + +#pragma once #define GLM_ENABLE_EXPERIMENTAL @@ -70,5 +79,3 @@ public: virtual std::string class_name() const { return "Recorder"; } }; - -#endif diff --git a/src/Segment.hpp b/src/Segment.hpp index d8093bb..7bfc51e 100644 --- a/src/Segment.hpp +++ b/src/Segment.hpp @@ -1,9 +1,19 @@ -#ifndef Segment_h_ -#define Segment_h_ + /* +------------------------------------------------------+ + ____/ \____ /| - Open source game framework licensed to freely use, | + \ / / | copy, modify and sell without restriction | ++--\ ^__^ /--+ | | +| ~/ \~ | | - created for | +| ~~~~~~~~~~~~ | +------------------------------------------------------+ +| SPACE ~~~~~ | / +| ~~~~~~~ BOX |/ ++-------------*/ + +#pragma once #include #include #include +#include #include "glm/vec2.hpp" @@ -66,5 +76,3 @@ namespace std { std::ostream& operator<<(std::ostream&, const Segment&); } - -#endif diff --git a/src/Sprite.hpp b/src/Sprite.hpp index 29e00ad..b761d3f 100644 --- a/src/Sprite.hpp +++ b/src/Sprite.hpp @@ -1,5 +1,4 @@ -#ifndef Sprite_h_ -#define Sprite_h_ +#pragma once #include #include @@ -212,5 +211,3 @@ public: #include "Pixels.hpp" #include "extension.hpp" - -#endif diff --git a/src/Switch.hpp b/src/Switch.hpp new file mode 100644 index 0000000..234c938 --- /dev/null +++ b/src/Switch.hpp @@ -0,0 +1,135 @@ + /* +------------------------------------------------------+ + ____/ \____ /| - Open source game framework licensed to freely use, | + \ / / | copy, modify and sell without restriction | ++--\ ^__^ /--+ | | +| ~/ \~ | | - created for | +| ~~~~~~~~~~~~ | +------------------------------------------------------+ +| SPACE ~~~~~ | / +| ~~~~~~~ BOX |/ ++--------------+ + +A switch object contains a state of either on or off which can be read by reading the switch in a bool context. A +switch can be flipped to change the state. If a reaction function has been set, it will run every time the switch +is flipped. The function must accept a bool as its first argument which will provide the state of the switch. It can +also accept an arbitrary number of arguments after that and can return a value. + +This example will flip the switch three times and print the state each time. + + sb::Switch<> sw1; + sw1.on_state_change([](bool state) { + std::cout << "Door is " << (state ? "OPEN" : "CLOSED") << std::endl; + }); + sw1.flip(); + sw1.flip(); + sw1.flip(); + +The expected output is + + Door is OPEN + Door is CLOSED + Door is OPEN + +This example ignores the switch state and adds an arbitrary amount to a running tally each flip. + + sb::Switch sw2; + sw2.on_state_change([](bool state, int tally, int add) -> int { + tally += add; + std::cout << "Adding " << add << " to tally: " << tally << std::endl; + return tally; + }); + int tally = 0; + tally = sw2.flip(tally, 1); + tally = sw2.flip(tally, 5); + tally = sw2.flip(tally, 99); + +The expected output is + + Adding 1 to tally: 1 + Adding 5 to tally: 6 + Adding 99 to tally: 105 + +Although the state can just be ignored, it can also be forced to remain in one state. This example uses the +`&` operator to allow access to the switch itself so it can be turned off automatically after every flip. + + sb::Switch sw3; + sw3.on_state_change([&](bool state, const std::string& visitor) { + if (state) + { + std::cout << "Come in " << visitor << ", my door is always " << (state ? "OPEN" : "CLOSED") << std::endl; + sw3.flip(""); + } + }); + sw3.flip("Mario"); + sw3.flip("Luigi"); + sw3.flip("Toad"); + +The expected output is + + Come in Mario, my door is always OPEN + Come in Luigi, my door is always OPEN + Come in Toad, my door is always OPEN +*/ + +#pragma once + +#include + +namespace sb +{ + template + class Switch + { + + private: + + using Reaction = std::function; + inline static const bool STATE_OFF = false; + inline static const bool STATE_ON = true; + + bool state = STATE_OFF; + Reaction reaction; + + public: + + /*! + * The switch object will initialized to the off state. A reaction function can be specified, otherwise it will have an + * empty reaction function. + * + * @param callback function to run on state change + */ + Switch(Reaction reaction = Reaction()) : reaction(reaction) {} + + return_type flip(arguments... args) + { + state = !state; + return reaction(state, args...); + } + + /*! + * Assign the reaction function. + * + * @param reaction function to be called when the state is changed + */ + void on_state_change(Reaction reaction) + { + this->reaction = reaction; + } + + /*! + * @return true if state is Switch::STATE_ON, false otherwise + */ + bool on() + { + return state; + } + + /*! + * @return when called as a boolean, return state + */ + operator bool() + { + return on(); + } + + }; +} diff --git a/src/Texture.hpp b/src/Texture.hpp index d30286a..b8fdca4 100644 --- a/src/Texture.hpp +++ b/src/Texture.hpp @@ -20,8 +20,7 @@ * functions. */ -#ifndef SB_TEXTURE_H_ -#define SB_TEXTURE_H_ +#pragma once #include #include @@ -144,5 +143,3 @@ namespace sb void texture_deleter(GLuint*); } - -#endif diff --git a/src/Timer.hpp b/src/Timer.hpp index 77e00c0..7688699 100644 --- a/src/Timer.hpp +++ b/src/Timer.hpp @@ -1,5 +1,14 @@ -#ifndef Timer_h_ -#define Timer_h_ + /* +------------------------------------------------------+ + ____/ \____ /| - Open source game framework licensed to freely use, | + \ / / | copy, modify and sell without restriction | ++--\ ^__^ /--+ | | +| ~/ \~ | | - created for | +| ~~~~~~~~~~~~ | +------------------------------------------------------+ +| SPACE ~~~~~ | / +| ~~~~~~~ BOX |/ ++-------------*/ + +#pragma once #include "SDL.h" @@ -33,5 +42,3 @@ public: void update(); }; - -#endif diff --git a/src/VBO.hpp b/src/VBO.hpp index 3c60cb9..c1cfccd 100644 --- a/src/VBO.hpp +++ b/src/VBO.hpp @@ -24,8 +24,7 @@ */ -#ifndef SB_VBO_H_ -#define SB_VBO_H_ +#pragma once #include #include @@ -58,5 +57,3 @@ namespace sb }; } - -#endif diff --git a/src/filesystem.hpp b/src/filesystem.hpp index 529f640..9bcf0c6 100644 --- a/src/filesystem.hpp +++ b/src/filesystem.hpp @@ -1,3 +1,5 @@ +#pragma once + /* MinGW filesystem library is in another location */ #if defined(__MINGW32__) #include diff --git a/src/time_it.hpp b/src/time_it.hpp new file mode 100644 index 0000000..c43137e --- /dev/null +++ b/src/time_it.hpp @@ -0,0 +1,93 @@ +/* /\ +------------------------------------------------------+ + * ____/ \____ /| - Open source game framework licensed to freely use, | + * \ / / | copy, modify and sell without restriction | + * +--\ ^__^ /--+ | | + * | ~/ \~ | | - created for | + * | ~~~~~~~~~~~~ | +------------------------------------------------------+ + * | SPACE ~~~~~ | / + * | ~~~~~~~ BOX |/ + * +--------------+ + * + * time_it + * ======= + * + * This class is used for printing the running time of a function or lambda. It can be + * inserted inline into existing code by wrapping the block to time in a lambda. It can also be + * given a function and optionally the function's arguments and will return a value of the type specified. + * + * The following code + * + * ~~~{.cpp} + * std::string fake(std::string x, std::string y) + * { + * return x + y; + * } + * + * // Needs SPACEBOX initialization for log call + * int ii = 0; + * time_it()([&] { while (ii++ < 1000); }); + * ii = 0; + * int revolving = time_it("for revolving")([&](int x) -> int { while (ii++ < 10000); return x; }, 1); + * ii = 0; + * std::cout << "Revolving is " << revolving << std::endl; + * std::string addition = time_it("for combination")(fake, "Hello, ", "World!"); + * std::cout << "Combination is " << addition << std::endl; + * time_it("for many combinations")([&] { while (ii++ < 100000) { fake("a", "b"); } }); + * ~~~ + * + * gives the expected output + * + * Elapsed time: 2.588e-06s + * Elapsed time for revolving: 2.1547e-05s + * Revolving is 1 + * Elapsed time for combination: 7.27e-07s + * Combination is Hello, World! + * Elapsed time for many combinations: 0.0107351s + */ + +#pragma once + +#include +#include +#include +#include +#include + +template +class time_it +{ + +private: + + std::string info = ""; + +public: + + time_it(std::string info = "") : info(info) {}; + + return_type operator()(const std::function&& block, arguments... args) + { + std::cout << "{Elapsed time"; + if (!info.empty()) + { + std::cout << " " << info; + } + std::cout << ": "; + auto start = std::chrono::steady_clock::now(); + std::chrono::duration elapsed; + if constexpr (std::is_same_v) + { + block(args...); + elapsed = std::chrono::steady_clock::now() - start; + std::cout << elapsed.count() << "s}" << std::endl; + } + else + { + return_type result = block(args...); + elapsed = std::chrono::steady_clock::now() - start; + std::cout << elapsed.count() << "s}" << std::endl; + return result; + } + } + +};