diff options
51 files changed, 348 insertions, 311 deletions
diff --git a/src/crepe/Asset.cpp b/src/crepe/Asset.cpp index 8a2a11c..9c41ecb 100644 --- a/src/crepe/Asset.cpp +++ b/src/crepe/Asset.cpp @@ -3,14 +3,14 @@ #include "Asset.h" using namespace crepe; +using namespace std; -Asset::Asset(const std::string & src) { - // FIXME: restore this - // this->src = std::filesystem::canonical(src); - this->src = src; +// FIXME: restore this +// src(std::filesystem::canonical(src)) +Asset::Asset(const std::string & src) : src(src) { this->file = std::ifstream(this->src, std::ios::in | std::ios::binary); } -const std::istream & Asset::read() { return this->file; } +istream & Asset::get_stream() { return this->file; } -const char * Asset::canonical() { return this->src.c_str(); } +const string & Asset::get_canonical() const { return this->src; } diff --git a/src/crepe/Asset.h b/src/crepe/Asset.h index 0cb5834..cb413f4 100644 --- a/src/crepe/Asset.h +++ b/src/crepe/Asset.h @@ -20,13 +20,21 @@ public: Asset(const std::string & src); public: - //! Get an input stream to the contents of this resource - const std::istream & read(); - //! Get the canonical path to this resource - const char * canonical(); + /** + * \brief Get an input stream to the contents of this asset + * \return Input stream with file contents + */ + std::istream & get_stream(); + /** + * \brief Get the canonical path to this asset + * \return Canonical path to this asset + */ + const std::string & get_canonical() const; private: - std::string src; + //! Canonical path to asset + const std::string src; + //! File handle (stream) std::ifstream file; }; diff --git a/src/crepe/CMakeLists.txt b/src/crepe/CMakeLists.txt index fc95bd3..52a781e 100644 --- a/src/crepe/CMakeLists.txt +++ b/src/crepe/CMakeLists.txt @@ -16,6 +16,7 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES ValueBroker.h ValueBroker.hpp Exception.h + Exception.hpp ) add_subdirectory(api) diff --git a/src/crepe/ComponentManager.cpp b/src/crepe/ComponentManager.cpp index 8f8437b..c6b658c 100644 --- a/src/crepe/ComponentManager.cpp +++ b/src/crepe/ComponentManager.cpp @@ -1,5 +1,5 @@ #include "api/GameObject.h" -#include "util/log.h" +#include "util/Log.h" #include "ComponentManager.h" diff --git a/src/crepe/Exception.cpp b/src/crepe/Exception.cpp index dab8f2e..5a24e7e 100644 --- a/src/crepe/Exception.cpp +++ b/src/crepe/Exception.cpp @@ -1,16 +1,8 @@ -#include <cstdarg> - #include "Exception.h" -#include "util/fmt.h" -using namespace std; using namespace crepe; +using namespace std; -const char * Exception::what() { return error.c_str(); } +const char * Exception::what() const noexcept { return error.c_str(); } -Exception::Exception(const char * fmt, ...) { - va_list args; - va_start(args, fmt); - this->error = va_stringf(args, fmt); - va_end(args); -} +Exception::Exception(const string & msg) { this->error = msg; } diff --git a/src/crepe/Exception.h b/src/crepe/Exception.h index 6473043..580fc16 100644 --- a/src/crepe/Exception.h +++ b/src/crepe/Exception.h @@ -1,22 +1,31 @@ #pragma once #include <exception> +#include <format> #include <string> namespace crepe { -//! Exception class with printf-style constructor +//! Exception class class Exception : public std::exception { public: - //! printf - Exception(const char * fmt, ...); + //! Exception with plain message + Exception(const std::string & msg); + + //! Exception with \c std::format message + template <class... Args> + Exception(std::format_string<Args...> fmt, Args &&... args); + //! Get formatted error message - const char * what(); + const char * what() const noexcept; protected: Exception() = default; + //! Formatted error message std::string error; }; } // namespace crepe + +#include "Exception.hpp" diff --git a/src/crepe/Exception.hpp b/src/crepe/Exception.hpp new file mode 100644 index 0000000..7c462a3 --- /dev/null +++ b/src/crepe/Exception.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include "Exception.h" + +namespace crepe { + +template <class... Args> +Exception::Exception(std::format_string<Args...> fmt, Args &&... args) { + this->error = std::format(fmt, std::forward<Args>(args)...); +} + +} // namespace crepe diff --git a/src/crepe/api/Animator.cpp b/src/crepe/api/Animator.cpp index fcc07ef..54b2ec3 100644 --- a/src/crepe/api/Animator.cpp +++ b/src/crepe/api/Animator.cpp @@ -1,7 +1,7 @@ #include <cstdint> -#include "util/log.h" +#include "util/Log.h" #include "Animator.h" #include "Component.h" diff --git a/src/crepe/api/AssetManager.cpp b/src/crepe/api/AssetManager.cpp index b891760..3925758 100644 --- a/src/crepe/api/AssetManager.cpp +++ b/src/crepe/api/AssetManager.cpp @@ -1,4 +1,4 @@ -#include "util/log.h" +#include "util/Log.h" #include "AssetManager.h" diff --git a/src/crepe/api/AudioSource.cpp b/src/crepe/api/AudioSource.cpp deleted file mode 100644 index 63fd0d7..0000000 --- a/src/crepe/api/AudioSource.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include <memory> - -#include "../facade/Sound.h" - -#include "AudioSource.h" - -using namespace crepe; - -AudioSource::AudioSource(std::unique_ptr<Asset> audio_clip) { - this->sound = std::make_unique<crepe::Sound>(std::move(audio_clip)); -} - -void AudioSource::play() { return this->play(false); } - -void AudioSource::play(bool looping) { - this->sound->set_looping(looping); - this->sound->play(); -} - -void AudioSource::stop() { - this->sound->pause(); - this->sound->rewind(); -} diff --git a/src/crepe/api/AudioSource.h b/src/crepe/api/AudioSource.h deleted file mode 100644 index 1e24ae8..0000000 --- a/src/crepe/api/AudioSource.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include <memory> - -#include "../Asset.h" -#include "../Component.h" - -namespace crepe { - -class Sound; - -//! Audio source component -class AudioSource : public Component { -public: - AudioSource(std::unique_ptr<Asset> audio_clip); - virtual ~AudioSource() = default; - -public: - //! Start or resume this audio source - void play(); - void play(bool looping); - //! Stop this audio source - void stop(); - -public: - //! Sample file location - std::unique_ptr<Asset> audio_clip; - //! TODO: ????? - bool play_on_awake; - //! Repeat the current audio clip during playback - bool loop; - //! Normalized volume (0.0 - 1.0) - float volume; - -private: - std::unique_ptr<Sound> sound; -}; - -} // namespace crepe diff --git a/src/crepe/api/BehaviorScript.h b/src/crepe/api/BehaviorScript.h index a49fc96..2982358 100644 --- a/src/crepe/api/BehaviorScript.h +++ b/src/crepe/api/BehaviorScript.h @@ -11,6 +11,13 @@ class ScriptSystem; class ComponentManager; class Script; +/** + * \brief Script component + * + * This class acts as a (component) wrapper around an instance of (a class + * derivatived from) \c Script. \c BehaviorScript is the only ECS component + * that stores member function implementations as data. + */ class BehaviorScript : public Component { protected: BehaviorScript(game_object_id_t id, ComponentManager & component_manager); @@ -18,7 +25,7 @@ protected: friend class ComponentManager; public: - virtual ~BehaviorScript() = default; + ~BehaviorScript() = default; public: /** @@ -36,7 +43,9 @@ protected: friend class ScriptSystem; //! Flag to indicate if script->init() has been called already bool initialized = false; + //! Script instance std::unique_ptr<Script> script = nullptr; + //! Reference to component manager ComponentManager & component_manager; private: diff --git a/src/crepe/api/BehaviorScript.hpp b/src/crepe/api/BehaviorScript.hpp index 2bed1b7..eec26da 100644 --- a/src/crepe/api/BehaviorScript.hpp +++ b/src/crepe/api/BehaviorScript.hpp @@ -2,7 +2,7 @@ #include <type_traits> -#include "../util/log.h" +#include "../util/Log.h" #include "BehaviorScript.h" #include "Script.h" diff --git a/src/crepe/api/Camera.cpp b/src/crepe/api/Camera.cpp index 232c922..5835bdd 100644 --- a/src/crepe/api/Camera.cpp +++ b/src/crepe/api/Camera.cpp @@ -1,4 +1,4 @@ -#include "util/log.h" +#include "util/Log.h" #include "Camera.h" #include "Color.h" diff --git a/src/crepe/api/Config.h b/src/crepe/api/Config.h index 8c9e643..e3f86bf 100644 --- a/src/crepe/api/Config.h +++ b/src/crepe/api/Config.h @@ -1,6 +1,6 @@ #pragma once -#include "../util/log.h" +#include "../util/Log.h" namespace crepe { @@ -26,10 +26,10 @@ public: /** * \brief Log level * - * Only messages with equal or higher priority than this value will be + * Only messages with equal or higher severity than this value will be * logged. */ - LogLevel level = LogLevel::INFO; + Log::Level level = Log::Level::INFO; /** * \brief Colored log output * diff --git a/src/crepe/api/LoopTimer.cpp b/src/crepe/api/LoopTimer.cpp index 8f09e41..b3aec22 100644 --- a/src/crepe/api/LoopTimer.cpp +++ b/src/crepe/api/LoopTimer.cpp @@ -1,7 +1,7 @@ #include <chrono> #include "../facade/SDLContext.h" -#include "../util/log.h" +#include "../util/Log.h" #include "LoopTimer.h" diff --git a/src/crepe/api/SaveManager.cpp b/src/crepe/api/SaveManager.cpp index 43276c5..2974b91 100644 --- a/src/crepe/api/SaveManager.cpp +++ b/src/crepe/api/SaveManager.cpp @@ -1,5 +1,5 @@ #include "../facade/DB.h" -#include "../util/log.h" +#include "../util/Log.h" #include "Config.h" #include "SaveManager.h" diff --git a/src/crepe/api/Script.h b/src/crepe/api/Script.h index 051ea00..68a46d7 100644 --- a/src/crepe/api/Script.h +++ b/src/crepe/api/Script.h @@ -3,20 +3,36 @@ #include <vector> namespace crepe { -class ScriptSystem; -} - -namespace crepe { +class ScriptSystem; class BehaviorScript; class ComponentManager; +/** + * \brief Script interface + * + * This class is used as a base class for user-defined scripts that can be + * added to game objects using the \c BehaviorScript component. + */ class Script { //! ScriptSystem calls \c update() friend class crepe::ScriptSystem; protected: + /** + * \brief Script initialization function + * + * This function is called during the ScriptSystem::update() routine *before* + * Script::update() if it (a) has not yet been called and (b) the \c + * BehaviorScript component holding this script instance is active. + */ virtual void init() {} + /** + * \brief Script update function + * + * This function is called during the ScriptSystem::update() routine if the + * \c BehaviorScript component holding this script instance is active. + */ virtual void update() {} // NOTE: additional *events* (like unity's OnDisable and OnEnable) should be // implemented as member methods in derivative user script classes and @@ -24,13 +40,28 @@ protected: // added event. protected: - //! Retrieve component from component manager (utility) + /** + * \brief Get single component of type \c T on this game object (utility) + * + * \tparam T Type of component + * + * \returns Reference to component + * + * \throws nullptr if this game object does not have a component matching + * type \c T + */ template <typename T> - T & get_component(); + T & get_component() const; - //! Retrieve components from component manager (utility) + /** + * \brief Get all components of type \c T on this game object (utility) + * + * \tparam T Type of component + * + * \returns List of component references + */ template <typename T> - std::vector<std::reference_wrapper<T>> get_components(); + std::vector<std::reference_wrapper<T>> get_components() const; protected: // NOTE: Script must have a constructor without arguments so the game diff --git a/src/crepe/api/Script.hpp b/src/crepe/api/Script.hpp index ee8c380..aceb38b 100644 --- a/src/crepe/api/Script.hpp +++ b/src/crepe/api/Script.hpp @@ -1,6 +1,7 @@ #pragma once #include "../ComponentManager.h" +#include "../Exception.h" #include "BehaviorScript.h" #include "Script.h" @@ -8,16 +9,18 @@ namespace crepe { template <typename T> -T & Script::get_component() { +T & Script::get_component() const { std::vector<std::reference_wrapper<T>> all_components = this->get_components<T>(); - if (all_components.size() < 1) throw nullptr; // TODO + if (all_components.size() < 1) + throw Exception("Script: no component found with type = {}", + typeid(T).name()); return all_components.back().get(); } template <typename T> -std::vector<std::reference_wrapper<T>> Script::get_components() { +std::vector<std::reference_wrapper<T>> Script::get_components() const { auto & parent = *this->parent_ref; auto & mgr = *this->component_manager_ref; diff --git a/src/crepe/api/Sprite.cpp b/src/crepe/api/Sprite.cpp index 6f0433f..ac0079e 100644 --- a/src/crepe/api/Sprite.cpp +++ b/src/crepe/api/Sprite.cpp @@ -1,6 +1,6 @@ #include <memory> -#include "../util/log.h" +#include "../util/Log.h" #include "facade/SDLContext.h" #include "Component.h" diff --git a/src/crepe/api/Texture.cpp b/src/crepe/api/Texture.cpp index 5ebd23d..de0d0ea 100644 --- a/src/crepe/api/Texture.cpp +++ b/src/crepe/api/Texture.cpp @@ -1,7 +1,7 @@ #include <SDL2/SDL_render.h> #include "../facade/SDLContext.h" -#include "../util/log.h" +#include "../util/Log.h" #include "Asset.h" #include "Texture.h" @@ -26,7 +26,7 @@ Texture::~Texture() { void Texture::load(unique_ptr<Asset> res) { SDLContext & ctx = SDLContext::get_instance(); - this->texture = std::move(ctx.texture_from_path(res->canonical())); + this->texture = std::move(ctx.texture_from_path(res->get_canonical())); } int Texture::get_width() const { diff --git a/src/crepe/api/Transform.cpp b/src/crepe/api/Transform.cpp index e401120..e9108c4 100644 --- a/src/crepe/api/Transform.cpp +++ b/src/crepe/api/Transform.cpp @@ -1,4 +1,4 @@ -#include "util/log.h" +#include "../util/Log.h" #include "Transform.h" diff --git a/src/crepe/facade/DB.cpp b/src/crepe/facade/DB.cpp index 0a2f455..80047a6 100644 --- a/src/crepe/facade/DB.cpp +++ b/src/crepe/facade/DB.cpp @@ -1,7 +1,7 @@ #include <cstring> #include "Exception.h" -#include "util/log.h" +#include "util/Log.h" #include "DB.h" @@ -15,19 +15,18 @@ DB::DB(const string & path) { // init database struct libdb::DB * db; if ((ret = libdb::db_create(&db, NULL, 0)) != 0) - throw Exception("db_create: %s", libdb::db_strerror(ret)); + throw Exception("db_create: {}", libdb::db_strerror(ret)); this->db = {db, [](libdb::DB * db) { db->close(db, 0); }}; // load or create database file - if ((ret = this->db->open(this->db.get(), NULL, path.c_str(), NULL, - libdb::DB_BTREE, DB_CREATE, 0)) - != 0) - throw Exception("db->open: %s", libdb::db_strerror(ret)); + ret = this->db->open(this->db.get(), NULL, path.c_str(), NULL, + libdb::DB_BTREE, DB_CREATE, 0); + if (ret != 0) throw Exception("db->open: {}", libdb::db_strerror(ret)); // create cursor libdb::DBC * cursor; - if ((ret = this->db->cursor(this->db.get(), NULL, &cursor, 0)) != 0) - throw Exception("db->cursor: %s", libdb::db_strerror(ret)); + ret = this->db->cursor(this->db.get(), NULL, &cursor, 0); + if (ret != 0) throw Exception("db->cursor: {}", libdb::db_strerror(ret)); this->cursor = {cursor, [](libdb::DBC * cursor) { cursor->close(cursor); }}; } @@ -45,7 +44,7 @@ string DB::get(const string & key) { memset(&db_val, 0, sizeof(libdb::DBT)); int ret = this->cursor->get(this->cursor.get(), &db_key, &db_val, DB_FIRST); - if (ret != 0) throw Exception("cursor->get: %s", libdb::db_strerror(ret)); + if (ret != 0) throw Exception("cursor->get: {}", libdb::db_strerror(ret)); return {static_cast<char *>(db_val.data), db_val.size}; } @@ -53,7 +52,7 @@ void DB::set(const string & key, const string & value) { libdb::DBT db_key = this->to_thing(key); libdb::DBT db_val = this->to_thing(value); int ret = this->db->put(this->db.get(), NULL, &db_key, &db_val, 0); - if (ret != 0) throw Exception("cursor->get: %s", libdb::db_strerror(ret)); + if (ret != 0) throw Exception("cursor->get: {}", libdb::db_strerror(ret)); } bool DB::has(const std::string & key) noexcept { diff --git a/src/crepe/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp index 236bf8c..a68d940 100644 --- a/src/crepe/facade/SDLContext.cpp +++ b/src/crepe/facade/SDLContext.cpp @@ -15,7 +15,7 @@ #include "../api/Sprite.h" #include "../api/Texture.h" #include "../api/Transform.h" -#include "../util/log.h" +#include "../util/Log.h" #include "Exception.h" #include "SDLContext.h" @@ -171,7 +171,7 @@ SDLContext::texture_from_path(const std::string & path) { this->game_renderer.get(), img_surface.get()); if (tmp_texture == nullptr) { - throw Exception("Texture cannot be load from %s", path.c_str()); + throw Exception("Texture cannot be load from {}", path); } std::unique_ptr<SDL_Texture, std::function<void(SDL_Texture *)>> diff --git a/src/crepe/facade/Sound.cpp b/src/crepe/facade/Sound.cpp index 648ec81..a65b052 100644 --- a/src/crepe/facade/Sound.cpp +++ b/src/crepe/facade/Sound.cpp @@ -1,22 +1,23 @@ -#include "../util/log.h" +#include "../util/Log.h" #include "Sound.h" #include "SoundContext.h" using namespace crepe; +using namespace std; -Sound::Sound(std::unique_ptr<Asset> res) { +Sound::Sound(unique_ptr<Asset> res) { dbg_trace(); this->load(std::move(res)); } Sound::Sound(const char * src) { dbg_trace(); - this->load(std::make_unique<Asset>(src)); + this->load(make_unique<Asset>(src)); } -void Sound::load(std::unique_ptr<Asset> res) { - this->sample.load(res->canonical()); +void Sound::load(unique_ptr<Asset> res) { + this->sample.load(res->get_canonical().c_str()); } void Sound::play() { diff --git a/src/crepe/facade/Sound.h b/src/crepe/facade/Sound.h index 183bd7c..402482f 100644 --- a/src/crepe/facade/Sound.h +++ b/src/crepe/facade/Sound.h @@ -8,6 +8,12 @@ namespace crepe { +/** + * \brief Sound resource facade + * + * This class is a wrapper around a \c SoLoud::Wav instance, which holds a + * single sample. It is part of the sound facade. + */ class Sound { public: /** diff --git a/src/crepe/facade/SoundContext.cpp b/src/crepe/facade/SoundContext.cpp index 5e5a3a9..deb2b62 100644 --- a/src/crepe/facade/SoundContext.cpp +++ b/src/crepe/facade/SoundContext.cpp @@ -1,4 +1,4 @@ -#include "../util/log.h" +#include "../util/Log.h" #include "SoundContext.h" diff --git a/src/crepe/facade/SoundContext.h b/src/crepe/facade/SoundContext.h index d3123d2..d703c16 100644 --- a/src/crepe/facade/SoundContext.h +++ b/src/crepe/facade/SoundContext.h @@ -6,19 +6,24 @@ namespace crepe { +/** + * \brief Sound engine facade + * + * This class is a wrapper around a \c SoLoud::Soloud instance, which provides + * the methods for playing \c Sound instances. It is part of the sound facade. + */ class SoundContext { private: + // singleton SoundContext(); virtual ~SoundContext(); - - // singleton - static SoundContext & get_instance(); SoundContext(const SoundContext &) = delete; SoundContext(SoundContext &&) = delete; SoundContext & operator=(const SoundContext &) = delete; SoundContext & operator=(SoundContext &&) = delete; private: + static SoundContext & get_instance(); SoLoud::Soloud engine; friend class Sound; }; diff --git a/src/crepe/system/RenderSystem.cpp b/src/crepe/system/RenderSystem.cpp index 3e6360c..0d37808 100644 --- a/src/crepe/system/RenderSystem.cpp +++ b/src/crepe/system/RenderSystem.cpp @@ -5,7 +5,7 @@ #include "../api/Sprite.h" #include "../api/Transform.h" #include "../facade/SDLContext.h" -#include "../util/log.h" +#include "../util/Log.h" #include "RenderSystem.h" diff --git a/src/crepe/system/ScriptSystem.cpp b/src/crepe/system/ScriptSystem.cpp index 644e96e..7b22533 100644 --- a/src/crepe/system/ScriptSystem.cpp +++ b/src/crepe/system/ScriptSystem.cpp @@ -5,7 +5,6 @@ #include "../ComponentManager.h" #include "../api/BehaviorScript.h" #include "../api/Script.h" -#include "../util/log.h" #include "ScriptSystem.h" @@ -28,7 +27,7 @@ void ScriptSystem::update() { } } -forward_list<reference_wrapper<Script>> ScriptSystem::get_scripts() { +forward_list<reference_wrapper<Script>> ScriptSystem::get_scripts() const { forward_list<reference_wrapper<Script>> scripts = {}; ComponentManager & mgr = this->component_manager; vector<reference_wrapper<BehaviorScript>> behavior_scripts @@ -44,3 +43,4 @@ forward_list<reference_wrapper<Script>> ScriptSystem::get_scripts() { return scripts; } + diff --git a/src/crepe/system/ScriptSystem.h b/src/crepe/system/ScriptSystem.h index b0b4185..deb89cb 100644 --- a/src/crepe/system/ScriptSystem.h +++ b/src/crepe/system/ScriptSystem.h @@ -8,13 +8,32 @@ namespace crepe { class Script; +/** + * \brief Script system + * + * The script system is responsible for all \c BehaviorScript components, and + * calls the methods on classes derived from \c Script. + */ class ScriptSystem : public System { public: using System::System; + /** + * \brief Call Script::update() on all active \c BehaviorScript instances + * + * This routine updates all scripts sequentially using the Script::update() + * method. It also calls Script::init() if this has not been done before on + * the \c BehaviorScript instance. + */ void update() override; private: - std::forward_list<std::reference_wrapper<Script>> get_scripts(); + /** + * \brief Aggregate all active \c BehaviorScript components and return a list + * of references to their \c Script instances (utility) + * + * \returns List of active \c Script instances + */ + std::forward_list<std::reference_wrapper<Script>> get_scripts() const; }; } // namespace crepe diff --git a/src/crepe/system/System.cpp b/src/crepe/system/System.cpp index 201b9ad..937a423 100644 --- a/src/crepe/system/System.cpp +++ b/src/crepe/system/System.cpp @@ -1,4 +1,4 @@ -#include "../util/log.h" +#include "../util/Log.h" #include "System.h" diff --git a/src/crepe/system/System.h b/src/crepe/system/System.h index 7970e72..28ea20e 100644 --- a/src/crepe/system/System.h +++ b/src/crepe/system/System.h @@ -4,8 +4,18 @@ namespace crepe { class ComponentManager; +/** + * \brief Base ECS system class + * + * This class is used as the base for all system classes. Classes derived from + * System must implement the System::update() method and copy Script::Script + * with the `using`-syntax. + */ class System { public: + /** + * \brief Process all components this system is responsible for. + */ virtual void update() = 0; public: diff --git a/src/crepe/util/CMakeLists.txt b/src/crepe/util/CMakeLists.txt index 0fa4343..4be738a 100644 --- a/src/crepe/util/CMakeLists.txt +++ b/src/crepe/util/CMakeLists.txt @@ -1,13 +1,12 @@ target_sources(crepe PUBLIC LogColor.cpp - log.cpp - fmt.cpp + Log.cpp ) target_sources(crepe PUBLIC FILE_SET HEADERS FILES LogColor.h - log.h - fmt.h + Log.h + Log.hpp Proxy.h Proxy.hpp ) diff --git a/src/crepe/util/log.cpp b/src/crepe/util/Log.cpp index 4a8f8e8..e583734 100644 --- a/src/crepe/util/log.cpp +++ b/src/crepe/util/Log.cpp @@ -4,50 +4,35 @@ #include <string> #include "../api/Config.h" -#include "fmt.h" -#include "log.h" +#include "Log.h" using namespace crepe; using namespace std; -string log_prefix(LogLevel level) { +string Log::prefix(const Level & level) { switch (level) { - case LogLevel::TRACE: + case Level::TRACE: return LogColor().fg_white().str("[TRACE]") + " "; - case LogLevel::DEBUG: + case Level::DEBUG: return LogColor().fg_magenta().str("[DEBUG]") + " "; - case LogLevel::INFO: + case Level::INFO: return LogColor().fg_blue().str("[INFO]") + " "; - case LogLevel::WARNING: + case Level::WARNING: return LogColor().fg_yellow().str("[WARN]") + " "; - case LogLevel::ERROR: + case Level::ERROR: return LogColor().fg_red().str("[ERROR]") + " "; } return ""; } -static void log(LogLevel level, const string msg) { +void Log::log(const Level & level, const string & msg) { auto & cfg = Config::get_instance(); if (level < cfg.log.level) return; - string out = log_prefix(level) + msg; + string out = Log::prefix(level) + msg; if (!out.ends_with("\n")) out += "\n"; // TODO: also log to file or smth fwrite(out.c_str(), 1, out.size(), stdout); fflush(stdout); } - -void crepe::logf(const char * fmt, ...) { - va_list args; - va_start(args, fmt); - log(LogLevel::DEBUG, va_stringf(args, fmt)); - va_end(args); -} - -void crepe::logf(LogLevel level, const char * fmt, ...) { - va_list args; - va_start(args, fmt); - log(level, va_stringf(args, fmt)); - va_end(args); -} diff --git a/src/crepe/util/Log.h b/src/crepe/util/Log.h new file mode 100644 index 0000000..01452b2 --- /dev/null +++ b/src/crepe/util/Log.h @@ -0,0 +1,85 @@ +#pragma once + +#include <format> + +// allow user to disable debug macros +#ifndef CREPE_DISABLE_MACROS + +#include "LogColor.h" + +// utility macros +#define _crepe_logf_here(level, fmt, ...) \ + crepe::Log::logf( \ + level, "{}" fmt, \ + crepe::LogColor().fg_white(false).str(std::format( \ + "{} ({}:{})", __PRETTY_FUNCTION__, __FILE_NAME__, __LINE__)), \ + __VA_ARGS__) + +// very illegal global function-style macros +// NOLINTBEGIN +#define dbg_logf(fmt, ...) \ + _crepe_logf_here(crepe::Log::Level::DEBUG, ": " fmt, __VA_ARGS__) +#define dbg_log(str) _crepe_logf_here(crepe::Log::Level::DEBUG, ": {}", str) +#define dbg_trace() _crepe_logf_here(crepe::Log::Level::TRACE, "", "") +// NOLINTEND + +#endif + +namespace crepe { + +/** + * \brief Logging utility + * + * This class is used to output log messages to the console and/or log files. + */ +class Log { +public: + //! Log message severity + enum Level { + TRACE, //< Include (internal) function calls + DEBUG, //< Include dbg_logf output + INFO, //< General-purpose messages + WARNING, //< Non-fatal errors + ERROR, //< Fatal errors + }; + + /** + * \brief Log a formatted message + * + * \param level Message severity + * \param msg Formatted message + */ + static void log(const Level & level, const std::string & msg); + + /** + * \brief Format a message and log it + * + * \param level Message severity + * \param fmt Message format + * \param args Format arguments + */ + template <class... Args> + static void logf(const Level & level, std::format_string<Args...> fmt, + Args &&... args); + + /** + * \brief Format a message and log it (with default severity \c INFO) + * + * \param fmt Message format + * \param args Format arguments + */ + template <class... Args> + static void logf(std::format_string<Args...> fmt, Args &&... args); + +private: + /** + * \brief Output a message prefix depending on the log level + * + * \param level Message severity + */ + static std::string prefix(const Level & level); +}; + +} // namespace crepe + +#include "Log.hpp" diff --git a/src/crepe/util/Log.hpp b/src/crepe/util/Log.hpp new file mode 100644 index 0000000..651f076 --- /dev/null +++ b/src/crepe/util/Log.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include "Log.h" + +namespace crepe { + +template <class... Args> +void Log::logf(std::format_string<Args...> fmt, Args &&... args) { + Log::logf(Level::INFO, fmt, std::forward<Args>(args)...); +} + +template <class... Args> +void Log::logf(const Level & level, std::format_string<Args...> fmt, + Args &&... args) { + Log::log(level, std::format(fmt, std::forward<Args>(args)...)); +} + +} // namespace crepe diff --git a/src/crepe/util/LogColor.cpp b/src/crepe/util/LogColor.cpp index b5fe3ea..ae44d72 100644 --- a/src/crepe/util/LogColor.cpp +++ b/src/crepe/util/LogColor.cpp @@ -3,14 +3,12 @@ #include "../api/Config.h" #include "LogColor.h" -#include "fmt.h" - using namespace crepe; using namespace std; static constexpr const char * RESET_CODE = "\e[0m"; -const string LogColor::str(const string & content) { +const string LogColor::str(const string & content) const { auto & cfg = Config::get_instance(); string out = content; if (cfg.log.color) out = this->code + out; @@ -19,21 +17,8 @@ const string LogColor::str(const string & content) { return out; } -const char * LogColor::c_str(const char * content) { - this->final = this->str(content == NULL ? "" : content); - return this->final.c_str(); -} - -const char * LogColor::fmt(const char * fmt, ...) { - va_list args; - va_start(args, fmt); - string content = va_stringf(args, fmt); - va_end(args); - return this->c_str(content.c_str()); -} - LogColor & LogColor::add_code(unsigned int code) { - this->code += stringf("\e[%dm", code); + this->code += format("\e[{}m", code); return *this; } diff --git a/src/crepe/util/LogColor.h b/src/crepe/util/LogColor.h index c1170cb..4b65127 100644 --- a/src/crepe/util/LogColor.h +++ b/src/crepe/util/LogColor.h @@ -4,20 +4,19 @@ namespace crepe { +/** + * \brief Utility class for coloring text using ANSI escape codes + * + * \note Most methods in this class return a reference to \c this, which may be + * used to chain multiple display attributes. + */ class LogColor { public: - LogColor() = default; + //! Get color code as stl string (or color content string) + const std::string str(const std::string & content = "") const; public: - //! get color code as c-style string (or color content string) - const char * c_str(const char * content = NULL); - //! color printf-style format string - const char * fmt(const char * fmt, ...); - //! get color code as stl string (or color content string) - const std::string str(const std::string & content = ""); - -public: - //! reset color to default foreground and background color + //! Reset color to default foreground and background color LogColor & reset(); public: @@ -41,11 +40,19 @@ public: LogColor & bg_white(bool bright = false); private: + /** + * \brief Append SGR escape sequence to \c this->code + * + * \param code SGR attribute number + * + * See <https://en.wikipedia.org/wiki/ANSI_escape_code> for magic number + * reference. + */ LogColor & add_code(unsigned int code); private: + //! Color escape sequence std::string code = ""; - std::string final = ""; }; } // namespace crepe diff --git a/src/crepe/util/fmt.cpp b/src/crepe/util/fmt.cpp deleted file mode 100644 index 4b50da8..0000000 --- a/src/crepe/util/fmt.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include <cstdarg> -#include <cstdio> -#include <string> - -#include "fmt.h" - -using namespace std; - -string crepe::va_stringf(va_list args, const char * fmt) { - string out; - - va_list args_copy; - va_copy(args_copy, args); - size_t length = vsnprintf(NULL, 0, fmt, args_copy); - // resize to include terminating null byte - out.resize(length + 1); - va_end(args_copy); - - // vsnprintf adds terminating null byte - vsnprintf(out.data(), out.size(), fmt, args); - // resize to actual length - out.resize(length); - - va_end(args); - - return out; -} - -string crepe::stringf(const char * fmt, ...) { - va_list args; - va_start(args, fmt); - string out = va_stringf(args, fmt); - va_end(args); - return out; -} diff --git a/src/crepe/util/fmt.h b/src/crepe/util/fmt.h deleted file mode 100644 index e319e6e..0000000 --- a/src/crepe/util/fmt.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include <string> - -namespace crepe { - -std::string va_stringf(va_list args, const char * fmt); -std::string stringf(const char * fmt, ...); - -} // namespace crepe diff --git a/src/crepe/util/log.h b/src/crepe/util/log.h deleted file mode 100644 index 5a1cf00..0000000 --- a/src/crepe/util/log.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -// allow user to disable debug macros -#ifndef CREPE_DISABLE_MACROS - -#include "LogColor.h" - -// utility macros -#define _crepe_logf_here(level, format, ...) \ - crepe::logf( \ - level, "%s" format, \ - crepe::LogColor().fg_white(false).fmt( \ - "%s (%s:%d)", __PRETTY_FUNCTION__, __FILE_NAME__, __LINE__), \ - __VA_ARGS__) - -// very illegal global function-style macros -// NOLINTBEGIN -#define dbg_logf(fmt, ...) \ - _crepe_logf_here(crepe::LogLevel::DEBUG, ": " fmt, __VA_ARGS__) -#define dbg_log(str) _crepe_logf_here(crepe::LogLevel::DEBUG, "%s: " str, "") -#define dbg_trace() _crepe_logf_here(crepe::LogLevel::TRACE, "%s", "") -// NOLINTEND - -#endif - -namespace crepe { - -enum LogLevel { - TRACE, - DEBUG, - INFO, - WARNING, - ERROR, -}; - -void logf(const char * fmt, ...); -void logf(enum LogLevel level, const char * fmt, ...); - -} // namespace crepe diff --git a/src/example/audio_internal.cpp b/src/example/audio_internal.cpp index 1ea839d..ff55a59 100644 --- a/src/example/audio_internal.cpp +++ b/src/example/audio_internal.cpp @@ -5,7 +5,7 @@ #include <crepe/api/Config.h> #include <crepe/facade/Sound.h> -#include <crepe/util/log.h> +#include <crepe/util/Log.h> #include <thread> @@ -18,7 +18,7 @@ using std::make_unique; int _ = []() { // Show dbg_trace() output auto & cfg = Config::get_instance(); - cfg.log.level = LogLevel::TRACE; + cfg.log.level = Log::Level::TRACE; return 0; // satisfy compiler }(); diff --git a/src/example/components_internal.cpp b/src/example/components_internal.cpp index dd4c7df..7a8a08a 100644 --- a/src/example/components_internal.cpp +++ b/src/example/components_internal.cpp @@ -13,7 +13,7 @@ #include <crepe/api/Rigidbody.h> #include <crepe/api/Sprite.h> -#include <crepe/util/log.h> +#include <crepe/util/Log.h> using namespace crepe; using namespace std; diff --git a/src/example/db.cpp b/src/example/db.cpp index 8c06a84..ee4e8fc 100644 --- a/src/example/db.cpp +++ b/src/example/db.cpp @@ -1,6 +1,6 @@ #include <crepe/api/Config.h> #include <crepe/facade/DB.h> -#include <crepe/util/log.h> +#include <crepe/util/Log.h> using namespace crepe; using namespace std; @@ -8,7 +8,7 @@ using namespace std; // run before main static auto _ = []() { auto & cfg = Config::get_instance(); - cfg.log.level = LogLevel::TRACE; + cfg.log.level = Log::Level::TRACE; return 0; }(); @@ -20,11 +20,11 @@ int main() { const char * test_key = "test-key"; string test_data = "Hello world!"; - dbg_logf("DB has key = %d", db.has(test_key)); + dbg_logf("DB has key = {}", db.has(test_key)); db.set(test_key, test_data); - dbg_logf("key = \"%s\"", db.get(test_key).c_str()); + dbg_logf("key = \"{}\"", db.get(test_key)); return 0; } diff --git a/src/example/log.cpp b/src/example/log.cpp index db8aa48..5baa021 100644 --- a/src/example/log.cpp +++ b/src/example/log.cpp @@ -4,7 +4,7 @@ */ #include <crepe/api/Config.h> -#include <crepe/util/log.h> +#include <crepe/util/Log.h> using namespace crepe; @@ -12,17 +12,17 @@ using namespace crepe; int _ = []() { // make sure all log messages get printed auto & cfg = Config::get_instance(); - cfg.log.level = LogLevel::TRACE; + cfg.log.level = Log::Level::TRACE; return 0; // satisfy compiler }(); int main() { dbg_trace(); - dbg_logf("test printf parameters: %d", 3); - logf(LogLevel::INFO, "info message"); - logf(LogLevel::WARNING, "warning"); - logf(LogLevel::ERROR, "error"); + dbg_log("debug message"); + Log::logf("info message with variable: {}", 3); + Log::logf(Log::Level::WARNING, "warning"); + Log::logf(Log::Level::ERROR, "error"); return 0; } diff --git a/src/example/proxy.cpp b/src/example/proxy.cpp index 0afff41..69451f8 100644 --- a/src/example/proxy.cpp +++ b/src/example/proxy.cpp @@ -5,8 +5,8 @@ #include <crepe/ValueBroker.h> #include <crepe/api/Config.h> +#include <crepe/util/Log.h> #include <crepe/util/Proxy.h> -#include <crepe/util/log.h> using namespace std; using namespace crepe; @@ -17,18 +17,17 @@ void test_ro_val(int val) {} int main() { auto & cfg = Config::get_instance(); - cfg.log.level = LogLevel::DEBUG; + cfg.log.level = Log::Level::DEBUG; int real_value = 0; ValueBroker<int> broker{ [&real_value](const int & target) { - dbg_logf("set %s to %s", to_string(real_value).c_str(), - to_string(target).c_str()); + dbg_logf("set {} to {}", real_value, target); real_value = target; }, [&real_value]() -> const int & { - dbg_logf("get %s", to_string(real_value).c_str()); + dbg_logf("get {}", real_value); return real_value; }, }; diff --git a/src/example/rendering.cpp b/src/example/rendering.cpp index 95d5dac..74c00e2 100644 --- a/src/example/rendering.cpp +++ b/src/example/rendering.cpp @@ -2,7 +2,7 @@ #include <crepe/ComponentManager.h> #include <crepe/api/GameObject.h> #include <crepe/system/RenderSystem.h> -#include <crepe/util/log.h> +#include <crepe/util/Log.h> #include <crepe/api/AssetManager.h> #include <crepe/api/Color.h> diff --git a/src/example/savemgr.cpp b/src/example/savemgr.cpp index 436fb5a..65c4a34 100644 --- a/src/example/savemgr.cpp +++ b/src/example/savemgr.cpp @@ -6,8 +6,8 @@ #include <cassert> #include <crepe/api/Config.h> #include <crepe/api/SaveManager.h> +#include <crepe/util/Log.h> #include <crepe/util/Proxy.h> -#include <crepe/util/log.h> using namespace crepe; @@ -15,7 +15,7 @@ using namespace crepe; int _ = []() { // make sure all log messages get printed auto & cfg = Config::get_instance(); - cfg.log.level = LogLevel::TRACE; + cfg.log.level = Log::Level::TRACE; return 0; // satisfy compiler }(); @@ -25,19 +25,19 @@ int main() { SaveManager & mgr = SaveManager::get_instance(); - dbg_logf("has key = %s", mgr.has(key) ? "true" : "false"); + dbg_logf("has key = {}", mgr.has(key)); ValueBroker<int> prop = mgr.get<int>(key, 0); Proxy<int> val = mgr.get<int>(key, 0); - dbg_logf("val = %d", mgr.get<int>(key).get()); + dbg_logf("val = {}", mgr.get<int>(key).get()); prop.set(1); - dbg_logf("val = %d", mgr.get<int>(key).get()); + dbg_logf("val = {}", mgr.get<int>(key).get()); val = 2; - dbg_logf("val = %d", mgr.get<int>(key).get()); + dbg_logf("val = {}", mgr.get<int>(key).get()); mgr.set<int>(key, 3); - dbg_logf("val = %d", mgr.get<int>(key).get()); + dbg_logf("val = {}", mgr.get<int>(key).get()); - dbg_logf("has key = %s", mgr.has(key) ? "true" : "false"); + dbg_logf("has key = {}", mgr.has(key)); assert(true == mgr.has(key)); return 0; diff --git a/src/example/script.cpp b/src/example/script.cpp index 69d1ce1..c82764c 100644 --- a/src/example/script.cpp +++ b/src/example/script.cpp @@ -5,7 +5,7 @@ #include <crepe/ComponentManager.h> #include <crepe/system/ScriptSystem.h> -#include <crepe/util/log.h> +#include <crepe/util/Log.h> #include <crepe/api/BehaviorScript.h> #include <crepe/api/Config.h> @@ -20,7 +20,7 @@ using namespace std; int _ = []() { // Show dbg_trace() output auto & cfg = Config::get_instance(); - cfg.log.level = LogLevel::TRACE; + cfg.log.level = Log::Level::TRACE; return 0; // satisfy compiler }(); @@ -30,7 +30,7 @@ class MyScript : public Script { void update() { // Retrieve component from the same GameObject this script is on Transform & test = get_component<Transform>(); - dbg_logf("Transform(%.2f, %.2f)", test.position.x, test.position.y); + dbg_logf("Transform({:.2f}, {:.2f})", test.position.x, test.position.y); } }; diff --git a/src/test/main.cpp b/src/test/main.cpp index a54d239..241015d 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -9,7 +9,7 @@ int main(int argc, char ** argv) { InitGoogleTest(&argc, argv); auto & cfg = Config::get_instance(); - cfg.log.level = LogLevel::ERROR; + cfg.log.level = Log::Level::ERROR; return RUN_ALL_TESTS(); } |