aboutsummaryrefslogtreecommitdiff
path: root/src/crepe
diff options
context:
space:
mode:
authorWBoerenkamps <wrj.boerenkamps@student.avans.nl>2024-11-18 15:34:22 +0100
committerWBoerenkamps <wrj.boerenkamps@student.avans.nl>2024-11-18 15:34:22 +0100
commitb92da3c729c8fc7c002cb3acbb75c56cb63bd89e (patch)
tree454b64d31b7e0c9151da88a0d49ee782565f49e9 /src/crepe
parent8b449e764b5c91cd3cb0c4fa404a290ab295a7ef (diff)
parent121b64b1cb6cfead5814070c8b0185d3d7308095 (diff)
Merge branch 'master' of https://github.com/lonkaars/crepe into wouter/events
Diffstat (limited to 'src/crepe')
-rw-r--r--src/crepe/Asset.cpp12
-rw-r--r--src/crepe/Asset.h18
-rw-r--r--src/crepe/CMakeLists.txt2
-rw-r--r--src/crepe/Component.cpp1
-rw-r--r--src/crepe/Component.h20
-rw-r--r--src/crepe/ComponentManager.cpp22
-rw-r--r--src/crepe/ComponentManager.h52
-rw-r--r--src/crepe/ComponentManager.hpp1
-rw-r--r--src/crepe/Exception.cpp16
-rw-r--r--src/crepe/Exception.h22
-rw-r--r--src/crepe/api/Animator.cpp6
-rw-r--r--src/crepe/api/Animator.h3
-rw-r--r--src/crepe/api/AssetManager.cpp2
-rw-r--r--src/crepe/api/AudioSource.cpp23
-rw-r--r--src/crepe/api/AudioSource.h39
-rw-r--r--src/crepe/api/BehaviorScript.cpp15
-rw-r--r--src/crepe/api/BehaviorScript.h52
-rw-r--r--src/crepe/api/BehaviorScript.hpp7
-rw-r--r--src/crepe/api/CMakeLists.txt1
-rw-r--r--src/crepe/api/Camera.cpp9
-rw-r--r--src/crepe/api/Camera.h4
-rw-r--r--src/crepe/api/Config.h21
-rw-r--r--src/crepe/api/GameObject.cpp12
-rw-r--r--src/crepe/api/GameObject.h18
-rw-r--r--src/crepe/api/GameObject.hpp2
-rw-r--r--src/crepe/api/LoopManager.cpp20
-rw-r--r--src/crepe/api/LoopManager.h42
-rw-r--r--src/crepe/api/LoopManager.hpp40
-rw-r--r--src/crepe/api/LoopTimer.cpp2
-rw-r--r--src/crepe/api/LoopTimer.h1
-rw-r--r--src/crepe/api/Rigidbody.cpp4
-rw-r--r--src/crepe/api/Rigidbody.h4
-rw-r--r--src/crepe/api/SaveManager.cpp2
-rw-r--r--src/crepe/api/Scene.cpp4
-rw-r--r--src/crepe/api/Scene.h15
-rw-r--r--src/crepe/api/SceneManager.cpp7
-rw-r--r--src/crepe/api/SceneManager.h13
-rw-r--r--src/crepe/api/SceneManager.hpp8
-rw-r--r--src/crepe/api/Script.cpp3
-rw-r--r--src/crepe/api/Script.h75
-rw-r--r--src/crepe/api/Script.hpp16
-rw-r--r--src/crepe/api/Sprite.cpp2
-rw-r--r--src/crepe/api/Sprite.h1
-rw-r--r--src/crepe/api/Texture.cpp4
-rw-r--r--src/crepe/api/Transform.cpp2
-rw-r--r--src/crepe/api/Transform.h23
-rw-r--r--src/crepe/api/Vector2.cpp16
-rw-r--r--src/crepe/api/Vector2.h15
-rw-r--r--src/crepe/facade/DB.cpp29
-rw-r--r--src/crepe/facade/DB.h7
-rw-r--r--src/crepe/facade/SDLContext.cpp7
-rw-r--r--src/crepe/facade/Sound.cpp9
-rw-r--r--src/crepe/facade/Sound.h6
-rw-r--r--src/crepe/facade/SoundContext.cpp2
-rw-r--r--src/crepe/facade/SoundContext.h11
-rw-r--r--src/crepe/system/AnimatorSystem.cpp12
-rw-r--r--src/crepe/system/AnimatorSystem.h17
-rw-r--r--src/crepe/system/CMakeLists.txt1
-rw-r--r--src/crepe/system/CollisionSystem.cpp2
-rw-r--r--src/crepe/system/CollisionSystem.h8
-rw-r--r--src/crepe/system/ParticleSystem.cpp2
-rw-r--r--src/crepe/system/ParticleSystem.h4
-rw-r--r--src/crepe/system/PhysicsSystem.cpp2
-rw-r--r--src/crepe/system/PhysicsSystem.h2
-rw-r--r--src/crepe/system/RenderSystem.cpp16
-rw-r--r--src/crepe/system/RenderSystem.h13
-rw-r--r--src/crepe/system/ScriptSystem.cpp22
-rw-r--r--src/crepe/system/ScriptSystem.h25
-rw-r--r--src/crepe/system/System.cpp7
-rw-r--r--src/crepe/system/System.h17
-rw-r--r--src/crepe/util/CMakeLists.txt7
-rw-r--r--src/crepe/util/Log.cpp37
-rw-r--r--src/crepe/util/Log.h84
-rw-r--r--src/crepe/util/Log.hpp17
-rw-r--r--src/crepe/util/LogColor.cpp20
-rw-r--r--src/crepe/util/LogColor.h51
-rw-r--r--src/crepe/util/fmt.cpp35
-rw-r--r--src/crepe/util/fmt.h10
-rw-r--r--src/crepe/util/log.cpp53
-rw-r--r--src/crepe/util/log.h37
80 files changed, 712 insertions, 559 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 ef20647..9051c5e 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..3b05742 100644
--- a/src/crepe/CMakeLists.txt
+++ b/src/crepe/CMakeLists.txt
@@ -4,7 +4,6 @@ target_sources(crepe PUBLIC
ComponentManager.cpp
Component.cpp
Collider.cpp
- Exception.cpp
)
target_sources(crepe PUBLIC FILE_SET HEADERS FILES
@@ -15,7 +14,6 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES
Collider.h
ValueBroker.h
ValueBroker.hpp
- Exception.h
)
add_subdirectory(api)
diff --git a/src/crepe/Component.cpp b/src/crepe/Component.cpp
index 73c2d07..acfd35c 100644
--- a/src/crepe/Component.cpp
+++ b/src/crepe/Component.cpp
@@ -1,5 +1,4 @@
#include "Component.h"
-#include "types.h"
using namespace crepe;
diff --git a/src/crepe/Component.h b/src/crepe/Component.h
index 59570bc..5279fb3 100644
--- a/src/crepe/Component.h
+++ b/src/crepe/Component.h
@@ -2,8 +2,6 @@
#include "types.h"
-#include <cstdint>
-
namespace crepe {
class ComponentManager;
@@ -15,16 +13,24 @@ class ComponentManager;
* components.
*/
class Component {
+public:
+ //! Whether the component is active
+ bool active = true;
+ //! The id of the GameObject this component belongs to
+ const game_object_id_t game_object_id;
+
protected:
- //! Only the ComponentManager can create components
- friend class crepe::ComponentManager;
/**
* \param id The id of the GameObject this component belongs to
*/
Component(game_object_id_t id);
+ //! Only the ComponentManager can create components
+ friend class ComponentManager;
public:
virtual ~Component() = default;
+
+public:
/**
* \brief Get the maximum number of instances for this component
*
@@ -34,12 +40,6 @@ public:
* \return The maximum number of instances for this component
*/
virtual int get_instances_max() const { return -1; }
-
-public:
- //! The id of the GameObject this component belongs to
- const game_object_id_t game_object_id;
- //! Whether the component is active
- bool active = true;
};
} // namespace crepe
diff --git a/src/crepe/ComponentManager.cpp b/src/crepe/ComponentManager.cpp
index 85149c8..e310577 100644
--- a/src/crepe/ComponentManager.cpp
+++ b/src/crepe/ComponentManager.cpp
@@ -1,13 +1,13 @@
-#include "util/log.h"
+#include "api/GameObject.h"
+#include "util/Log.h"
#include "ComponentManager.h"
using namespace crepe;
+using namespace std;
-ComponentManager & ComponentManager::get_instance() {
- static ComponentManager instance;
- return instance;
-}
+ComponentManager::ComponentManager() { dbg_trace(); }
+ComponentManager::~ComponentManager() { dbg_trace(); }
void ComponentManager::delete_all_components_of_id(game_object_id_t id) {
// Loop through all the types (in the unordered_map<>)
@@ -21,10 +21,14 @@ void ComponentManager::delete_all_components_of_id(game_object_id_t id) {
}
void ComponentManager::delete_all_components() {
- // Clear the whole unordered_map<>
this->components.clear();
+ this->next_id = 0;
}
-ComponentManager::ComponentManager() { dbg_trace(); }
-
-ComponentManager::~ComponentManager() { dbg_trace(); }
+GameObject ComponentManager::new_object(const string & name, const string & tag,
+ const Vector2 & position, double rotation,
+ double scale) {
+ GameObject object{*this, this->next_id, name, tag, position, rotation, scale};
+ this->next_id++;
+ return object;
+}
diff --git a/src/crepe/ComponentManager.h b/src/crepe/ComponentManager.h
index 9a2aa1d..2107453 100644
--- a/src/crepe/ComponentManager.h
+++ b/src/crepe/ComponentManager.h
@@ -1,34 +1,58 @@
#pragma once
-#include <cstdint>
#include <memory>
#include <typeindex>
#include <unordered_map>
#include <vector>
+#include "api/Vector2.h"
+
#include "Component.h"
namespace crepe {
+class GameObject;
+
/**
* \brief Manages all components
*
* This class manages all components. It provides methods to add, delete and get components.
*/
class ComponentManager {
+ // TODO: This relation should be removed! I (loek) believe that the scene manager should
+ // create/destroy components because the GameObject's are stored in concrete Scene classes,
+ // which will in turn call GameObject's destructor, which will in turn call
+ // ComponentManager::delete_components_by_id or something. This is a pretty major change, so
+ // here is a comment and temporary fix instead :tada:
+ friend class SceneManager;
+
public:
+ ComponentManager(); // dbg_trace
+ ~ComponentManager(); // dbg_trace
+
/**
- * \brief Get the instance of the ComponentManager
- *
- * \return The instance of the ComponentManager
+ * \brief Create a new game object using the component manager
+ *
+ * \param name Metadata::name (required)
+ * \param tag Metadata::tag (optional, empty by default)
+ * \param position Transform::position (optional, origin by default)
+ * \param rotation Transform::rotation (optional, 0 by default)
+ * \param scale Transform::scale (optional, 1 by default)
+ *
+ * \returns GameObject interface
+ *
+ * \note This method automatically assigns a new entity ID
*/
- static ComponentManager & get_instance();
- ComponentManager(const ComponentManager &) = delete;
- ComponentManager(ComponentManager &&) = delete;
- ComponentManager & operator=(const ComponentManager &) = delete;
- ComponentManager & operator=(ComponentManager &&) = delete;
- ~ComponentManager();
+ GameObject new_object(const std::string & name, const std::string & tag = "",
+ const Vector2 & position = {0, 0}, double rotation = 0,
+ double scale = 1);
+protected:
+ /**
+ * GameObject is used as an interface to add/remove components, and the game programmer is
+ * supposed to use it instead of interfacing with the component manager directly.
+ */
+ friend class GameObject;
/**
* \brief Add a component to the ComponentManager
*
@@ -76,6 +100,8 @@ public:
* This method deletes all components.
*/
void delete_all_components();
+
+public:
/**
* \brief Get all components of a specific type and id
*
@@ -99,9 +125,6 @@ public:
std::vector<std::reference_wrapper<T>> get_components_by_type() const;
private:
- ComponentManager();
-
-private:
/**
* \brief The components
*
@@ -114,6 +137,9 @@ private:
*/
std::unordered_map<std::type_index, std::vector<std::vector<std::unique_ptr<Component>>>>
components;
+
+ //! ID of next GameObject allocated by \c ComponentManager::new_object
+ game_object_id_t next_id = 0;
};
} // namespace crepe
diff --git a/src/crepe/ComponentManager.hpp b/src/crepe/ComponentManager.hpp
index c537b03..be99cac 100644
--- a/src/crepe/ComponentManager.hpp
+++ b/src/crepe/ComponentManager.hpp
@@ -40,7 +40,6 @@ T & ComponentManager::add_component(game_object_id_t id, Args &&... args) {
// Check if the vector size is not greater than get_instances_max
int max_instances = instance->get_instances_max();
if (max_instances != -1 && components[type][id].size() >= max_instances) {
- // TODO: Exception
throw std::runtime_error(
"Exceeded maximum number of instances for this component type");
}
diff --git a/src/crepe/Exception.cpp b/src/crepe/Exception.cpp
deleted file mode 100644
index dab8f2e..0000000
--- a/src/crepe/Exception.cpp
+++ /dev/null
@@ -1,16 +0,0 @@
-#include <cstdarg>
-
-#include "Exception.h"
-#include "util/fmt.h"
-
-using namespace std;
-using namespace crepe;
-
-const char * Exception::what() { 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);
-}
diff --git a/src/crepe/Exception.h b/src/crepe/Exception.h
deleted file mode 100644
index 6473043..0000000
--- a/src/crepe/Exception.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#pragma once
-
-#include <exception>
-#include <string>
-
-namespace crepe {
-
-//! Exception class with printf-style constructor
-class Exception : public std::exception {
-public:
- //! printf
- Exception(const char * fmt, ...);
- //! Get formatted error message
- const char * what();
-
-protected:
- Exception() = default;
- //! Formatted error message
- std::string error;
-};
-
-} // namespace crepe
diff --git a/src/crepe/api/Animator.cpp b/src/crepe/api/Animator.cpp
index 58fee2a..464b0fd 100644
--- a/src/crepe/api/Animator.cpp
+++ b/src/crepe/api/Animator.cpp
@@ -1,7 +1,5 @@
-#include <cstdint>
-
-#include "util/log.h"
+#include "util/Log.h"
#include "Animator.h"
#include "Component.h"
@@ -9,7 +7,7 @@
using namespace crepe;
-Animator::Animator(uint32_t id, Sprite & ss, int row, int col, int col_animator)
+Animator::Animator(game_object_id_t id, Sprite & ss, int row, int col, int col_animator)
: Component(id),
spritesheet(ss),
row(row),
diff --git a/src/crepe/api/Animator.h b/src/crepe/api/Animator.h
index b5bb4c9..53f4b91 100644
--- a/src/crepe/api/Animator.h
+++ b/src/crepe/api/Animator.h
@@ -1,11 +1,10 @@
#pragma once
-#include <cstdint>
-
#include "Component.h"
#include "Sprite.h"
namespace crepe {
+
class AnimatorSystem;
class SDLContext;
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.cpp b/src/crepe/api/BehaviorScript.cpp
index e69de29..7bbace0 100644
--- a/src/crepe/api/BehaviorScript.cpp
+++ b/src/crepe/api/BehaviorScript.cpp
@@ -0,0 +1,15 @@
+#include "BehaviorScript.h"
+#include "Component.h"
+#include "GameObject.h"
+
+using namespace crepe;
+
+BehaviorScript::BehaviorScript(game_object_id_t id, ComponentManager & mgr)
+ : Component(id),
+ component_manager(mgr) {}
+
+template <>
+BehaviorScript & GameObject::add_component<BehaviorScript>() {
+ ComponentManager & mgr = this->component_manager;
+ return mgr.add_component<BehaviorScript>(this->id, mgr);
+}
diff --git a/src/crepe/api/BehaviorScript.h b/src/crepe/api/BehaviorScript.h
index 6b1fec7..9d85d4c 100644
--- a/src/crepe/api/BehaviorScript.h
+++ b/src/crepe/api/BehaviorScript.h
@@ -4,29 +4,69 @@
#include "../Component.h"
+#include "GameObject.h"
+
namespace crepe {
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:
- friend class crepe::ComponentManager;
- using Component::Component;
-
-public:
- virtual ~BehaviorScript() = default;
+ /**
+ * \param id Parent \c GameObject id
+ * \param component_manager Reference to component manager (passed through to \c Script
+ * instance)
+ *
+ * \note Calls to this constructor (should) always pass through \c GameObject::add_component,
+ * which has an exception for this specific component type. This was done so the user does
+ * not have to pass references used within \c Script to each \c BehaviorScript instance.
+ */
+ BehaviorScript(game_object_id_t id, ComponentManager & component_manager);
+ //! Only ComponentManager is allowed to instantiate BehaviorScript
+ friend class ComponentManager;
public:
+ /**
+ * \brief Set the concrete script of this component
+ *
+ * \tparam T Concrete script type (derived from \c crepe::Script)
+ *
+ * \returns Reference to BehaviorScript component (`*this`)
+ */
template <class T>
BehaviorScript & set_script();
protected:
- friend class crepe::ScriptSystem;
+ //! Script instance
std::unique_ptr<Script> script = nullptr;
+ //! ScriptSystem needs direct access to the script instance
+ friend class ScriptSystem;
+
+protected:
+ //! Reference to component manager (passed to Script)
+ ComponentManager & component_manager;
};
+/**
+ * \brief Add a BehaviorScript component to this game object
+ *
+ * The \c BehaviorScript class is the only exception to the ECS harmony, and requires a
+ * reference to the component manager passed to its constructor in order to function normally.
+ * This is because the \c BehaviorScript (and \c Script) classes are the only component-related
+ * classes that store implemented member functions as data.
+ */
+template <>
+BehaviorScript & GameObject::add_component<BehaviorScript>();
+
} // namespace crepe
#include "BehaviorScript.hpp"
diff --git a/src/crepe/api/BehaviorScript.hpp b/src/crepe/api/BehaviorScript.hpp
index 4751607..d80321d 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"
@@ -11,10 +11,11 @@ namespace crepe {
template <class T>
BehaviorScript & BehaviorScript::set_script() {
- static_assert(std::is_base_of<Script, T>::value);
dbg_trace();
+ static_assert(std::is_base_of<Script, T>::value);
Script * s = new T();
- s->parent = this;
+ s->game_object_id = this->game_object_id;
+ s->component_manager_ref = &this->component_manager;
this->script = std::unique_ptr<Script>(s);
return *this;
}
diff --git a/src/crepe/api/CMakeLists.txt b/src/crepe/api/CMakeLists.txt
index edf4250..a185ca6 100644
--- a/src/crepe/api/CMakeLists.txt
+++ b/src/crepe/api/CMakeLists.txt
@@ -1,7 +1,6 @@
target_sources(crepe PUBLIC
# AudioSource.cpp
BehaviorScript.cpp
- Script.cpp
GameObject.cpp
Rigidbody.cpp
ParticleEmitter.cpp
diff --git a/src/crepe/api/Camera.cpp b/src/crepe/api/Camera.cpp
index d5df196..5835bdd 100644
--- a/src/crepe/api/Camera.cpp
+++ b/src/crepe/api/Camera.cpp
@@ -1,7 +1,4 @@
-
-#include <cstdint>
-
-#include "util/log.h"
+#include "util/Log.h"
#include "Camera.h"
#include "Color.h"
@@ -9,7 +6,9 @@
using namespace crepe;
-Camera::Camera(uint32_t id, const Color & bg_color) : Component(id), bg_color(bg_color) {
+Camera::Camera(game_object_id_t id, const Color & bg_color)
+ : Component(id),
+ bg_color(bg_color) {
dbg_trace();
}
diff --git a/src/crepe/api/Camera.h b/src/crepe/api/Camera.h
index c7f9af5..e0cda34 100644
--- a/src/crepe/api/Camera.h
+++ b/src/crepe/api/Camera.h
@@ -1,7 +1,5 @@
#pragma once
-#include <cstdint>
-
#include "Color.h"
#include "Component.h"
@@ -22,7 +20,7 @@ public:
* \param id Unique identifier for the camera component.
* \param bg_color Background color for the camera view.
*/
- Camera(uint32_t id, const Color & bg_color);
+ Camera(game_object_id_t id, const Color & bg_color);
~Camera(); // dbg_trace only
public:
diff --git a/src/crepe/api/Config.h b/src/crepe/api/Config.h
index 1cee668..3ab877a 100644
--- a/src/crepe/api/Config.h
+++ b/src/crepe/api/Config.h
@@ -1,19 +1,24 @@
#pragma once
-#include "../util/log.h"
+#include "../util/Log.h"
namespace crepe {
+/**
+ * \brief Global configuration interface
+ *
+ * This class stores engine default settings. Properties on this class are only supposed to be
+ * modified *before* execution is handed over from the game programmer to the engine (i.e. the
+ * main loop is started).
+ */
class Config {
-private:
- Config() = default;
-
-public:
- ~Config() = default;
-
public:
//! Retrieve handle to global Config instance
static Config & get_instance();
+
+private:
+ Config() = default;
+
// singleton
Config(const Config &) = delete;
Config(Config &&) = delete;
@@ -28,7 +33,7 @@ public:
*
* Only messages with equal or higher priority 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/GameObject.cpp b/src/crepe/api/GameObject.cpp
index d470295..287e81d 100644
--- a/src/crepe/api/GameObject.cpp
+++ b/src/crepe/api/GameObject.cpp
@@ -1,22 +1,26 @@
#include "api/Transform.h"
+#include "BehaviorScript.h"
#include "GameObject.h"
#include "Metadata.h"
using namespace crepe;
using namespace std;
-GameObject::GameObject(game_object_id_t id, const std::string & name, const std::string & tag,
+GameObject::GameObject(ComponentManager & component_manager, game_object_id_t id,
+ const std::string & name, const std::string & tag,
const Vector2 & position, double rotation, double scale)
- : id(id) {
+ : id(id),
+ component_manager(component_manager) {
+
// Add Transform and Metadata components
- ComponentManager & mgr = ComponentManager::get_instance();
+ ComponentManager & mgr = this->component_manager;
mgr.add_component<Transform>(this->id, position, rotation, scale);
mgr.add_component<Metadata>(this->id, name, tag);
}
void GameObject::set_parent(const GameObject & parent) {
- ComponentManager & mgr = ComponentManager::get_instance();
+ ComponentManager & mgr = this->component_manager;
// Set parent on own Metadata component
vector<reference_wrapper<Metadata>> this_metadata
diff --git a/src/crepe/api/GameObject.h b/src/crepe/api/GameObject.h
index 75c164b..34ef8bb 100644
--- a/src/crepe/api/GameObject.h
+++ b/src/crepe/api/GameObject.h
@@ -2,11 +2,12 @@
#include <string>
+#include "Vector2.h"
#include "types.h"
namespace crepe {
-class Vector2;
+class ComponentManager;
/**
* \brief Represents a GameObject
@@ -15,11 +16,12 @@ class Vector2;
* the game programmer. The actual implementation is done in the ComponentManager.
*/
class GameObject {
-public:
+private:
/**
* This constructor creates a new GameObject. It creates a new Transform and Metadata
* component and adds them to the ComponentManager.
*
+ * \param component_manager Reference to component_manager
* \param id The id of the GameObject
* \param name The name of the GameObject
* \param tag The tag of the GameObject
@@ -27,8 +29,13 @@ public:
* \param rotation The rotation of the GameObject
* \param scale The scale of the GameObject
*/
- GameObject(game_object_id_t id, const std::string & name, const std::string & tag,
- const Vector2 & position, double rotation, double scale);
+ GameObject(ComponentManager & component_manager, game_object_id_t id,
+ const std::string & name, const std::string & tag, const Vector2 & position,
+ double rotation, double scale);
+ //! ComponentManager instances GameObject
+ friend class ComponentManager;
+
+public:
/**
* \brief Set the parent of this GameObject
*
@@ -56,6 +63,9 @@ public:
public:
//! The id of the GameObject
const game_object_id_t id;
+
+protected:
+ ComponentManager & component_manager;
};
} // namespace crepe
diff --git a/src/crepe/api/GameObject.hpp b/src/crepe/api/GameObject.hpp
index bfba7fe..17b17d7 100644
--- a/src/crepe/api/GameObject.hpp
+++ b/src/crepe/api/GameObject.hpp
@@ -8,7 +8,7 @@ namespace crepe {
template <typename T, typename... Args>
T & GameObject::add_component(Args &&... args) {
- ComponentManager & mgr = ComponentManager::get_instance();
+ ComponentManager & mgr = this->component_manager;
return mgr.add_component<T>(this->id, std::forward<Args>(args)...);
}
diff --git a/src/crepe/api/LoopManager.cpp b/src/crepe/api/LoopManager.cpp
index 2e9823f..a64366f 100644
--- a/src/crepe/api/LoopManager.cpp
+++ b/src/crepe/api/LoopManager.cpp
@@ -1,5 +1,9 @@
-
#include "../facade/SDLContext.h"
+
+#include "../system/AnimatorSystem.h"
+#include "../system/CollisionSystem.h"
+#include "../system/ParticleSystem.h"
+#include "../system/PhysicsSystem.h"
#include "../system/RenderSystem.h"
#include "../system/ScriptSystem.h"
@@ -7,11 +11,21 @@
#include "LoopTimer.h"
using namespace crepe;
+using namespace std;
+
+LoopManager::LoopManager() {
+ this->load_system<AnimatorSystem>();
+ this->load_system<CollisionSystem>();
+ this->load_system<ParticleSystem>();
+ this->load_system<PhysicsSystem>();
+ this->load_system<RenderSystem>();
+ this->load_system<ScriptSystem>();
+}
-LoopManager::LoopManager() {}
void LoopManager::process_input() {
SDLContext::get_instance().handle_events(this->game_running);
}
+
void LoopManager::start() {
this->setup();
this->loop();
@@ -48,7 +62,7 @@ void LoopManager::setup() {
void LoopManager::render() {
if (this->game_running) {
- RenderSystem::get_instance().update();
+ this->get_system<RenderSystem>().update();
}
}
diff --git a/src/crepe/api/LoopManager.h b/src/crepe/api/LoopManager.h
index 2f03193..f6904be 100644
--- a/src/crepe/api/LoopManager.h
+++ b/src/crepe/api/LoopManager.h
@@ -2,15 +2,9 @@
#include <memory>
-class RenderSystem;
-class SDLContext;
-class LoopTimer;
-class ScriptSystem;
-class SoundSystem;
-class ParticleSystem;
-class PhysicsSystem;
-class AnimatorSystem;
-class CollisionSystem;
+#include "../ComponentManager.h"
+#include "../system/System.h"
+
namespace crepe {
class LoopManager {
@@ -73,7 +67,35 @@ private:
void render();
bool game_running = false;
- //#TODO add system instances
+
+private:
+ //! Component manager instance
+ ComponentManager component_manager{};
+
+private:
+ /**
+ * \brief Collection of System instances
+ *
+ * This map holds System instances indexed by the system's class typeid. It is filled in the
+ * constructor of \c LoopManager using LoopManager::load_system.
+ */
+ std::unordered_map<std::type_index, std::unique_ptr<System>> systems;
+ /**
+ * \brief Initialize a system
+ * \tparam T System type (must be derivative of \c System)
+ */
+ template <class T>
+ void load_system();
+ /**
+ * \brief Retrieve a reference to ECS system
+ * \tparam T System type
+ * \returns Reference to system instance
+ * \throws std::runtime_error if the System is not initialized
+ */
+ template <class T>
+ T & get_system();
};
} // namespace crepe
+
+#include "LoopManager.hpp"
diff --git a/src/crepe/api/LoopManager.hpp b/src/crepe/api/LoopManager.hpp
new file mode 100644
index 0000000..0b14fdb
--- /dev/null
+++ b/src/crepe/api/LoopManager.hpp
@@ -0,0 +1,40 @@
+#pragma once
+
+#include <cassert>
+#include <format>
+#include <memory>
+
+#include "../system/System.h"
+
+#include "LoopManager.h"
+
+namespace crepe {
+
+template <class T>
+T & LoopManager::get_system() {
+ using namespace std;
+ static_assert(is_base_of<System, T>::value,
+ "get_system must recieve a derivative class of System");
+
+ const type_info & type = typeid(T);
+ if (!this->systems.contains(type))
+ throw runtime_error(format("LoopManager: {} is not initialized", type.name()));
+
+ System * system = this->systems.at(type).get();
+ T * concrete_system = dynamic_cast<T *>(system);
+ assert(concrete_system != nullptr);
+
+ return *concrete_system;
+}
+
+template <class T>
+void LoopManager::load_system() {
+ using namespace std;
+ static_assert(is_base_of<System, T>::value,
+ "load_system must recieve a derivative class of System");
+
+ System * system = new T(this->component_manager);
+ this->systems[typeid(T)] = unique_ptr<System>(system);
+}
+
+} // namespace crepe
diff --git a/src/crepe/api/LoopTimer.cpp b/src/crepe/api/LoopTimer.cpp
index 417da47..a9800b7 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/LoopTimer.h b/src/crepe/api/LoopTimer.h
index c3c5631..f277d7b 100644
--- a/src/crepe/api/LoopTimer.h
+++ b/src/crepe/api/LoopTimer.h
@@ -1,7 +1,6 @@
#pragma once
#include <chrono>
-#include <cstdint>
namespace crepe {
diff --git a/src/crepe/api/Rigidbody.cpp b/src/crepe/api/Rigidbody.cpp
index 3bf1c5b..6b87695 100644
--- a/src/crepe/api/Rigidbody.cpp
+++ b/src/crepe/api/Rigidbody.cpp
@@ -2,8 +2,8 @@
using namespace crepe;
-crepe::Rigidbody::Rigidbody(uint32_t game_object_id, const Data & data)
- : Component(game_object_id),
+crepe::Rigidbody::Rigidbody(game_object_id_t id, const Data & data)
+ : Component(id),
data(data) {}
void crepe::Rigidbody::add_force_linear(const Vector2 & force) {
diff --git a/src/crepe/api/Rigidbody.h b/src/crepe/api/Rigidbody.h
index c74fea8..3e5c7a3 100644
--- a/src/crepe/api/Rigidbody.h
+++ b/src/crepe/api/Rigidbody.h
@@ -1,7 +1,5 @@
#pragma once
-#include <cstdint>
-
#include "../Component.h"
#include "Vector2.h"
@@ -82,7 +80,7 @@ public:
* \param game_object_id id of the gameobject the rigibody is added to.
* \param data struct to configure the rigidbody.
*/
- Rigidbody(uint32_t game_object_id, const Data & data);
+ Rigidbody(game_object_id_t id, const Data & data);
//! struct to hold data of rigidbody
Data data;
diff --git a/src/crepe/api/SaveManager.cpp b/src/crepe/api/SaveManager.cpp
index a71ad83..c5f43ea 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/Scene.cpp b/src/crepe/api/Scene.cpp
index 933edf4..88aa82d 100644
--- a/src/crepe/api/Scene.cpp
+++ b/src/crepe/api/Scene.cpp
@@ -2,4 +2,6 @@
using namespace crepe;
-Scene::Scene(const std::string & name) : name(name) {}
+Scene::Scene(ComponentManager & mgr, const std::string & name)
+ : component_manager(mgr),
+ name(name) {}
diff --git a/src/crepe/api/Scene.h b/src/crepe/api/Scene.h
index f8bcc3d..0e516b6 100644
--- a/src/crepe/api/Scene.h
+++ b/src/crepe/api/Scene.h
@@ -4,14 +4,23 @@
namespace crepe {
+class SceneManager;
+class ComponentManager;
+
class Scene {
+protected:
+ Scene(ComponentManager & mgr, const std::string & name);
+ friend class SceneManager;
+
public:
- Scene(const std::string & name);
virtual ~Scene() = default;
- virtual void load_scene() = 0;
public:
- std::string name;
+ virtual void load_scene() = 0;
+ const std::string name;
+
+protected:
+ ComponentManager & component_manager;
};
} // namespace crepe
diff --git a/src/crepe/api/SceneManager.cpp b/src/crepe/api/SceneManager.cpp
index c0f8b23..7fb5cb0 100644
--- a/src/crepe/api/SceneManager.cpp
+++ b/src/crepe/api/SceneManager.cpp
@@ -8,10 +8,7 @@
using namespace crepe;
using namespace std;
-SceneManager & SceneManager::get_instance() {
- static SceneManager instance;
- return instance;
-}
+SceneManager::SceneManager(ComponentManager & mgr) : component_manager(mgr) {}
void SceneManager::set_next_scene(const string & name) { next_scene = name; }
@@ -29,7 +26,7 @@ void SceneManager::load_next_scene() {
unique_ptr<Scene> & scene = *it;
// Delete all components of the current scene
- ComponentManager & mgr = ComponentManager::get_instance();
+ ComponentManager & mgr = this->component_manager;
mgr.delete_all_components();
// Load the new scene
diff --git a/src/crepe/api/SceneManager.h b/src/crepe/api/SceneManager.h
index 1e0e670..e854794 100644
--- a/src/crepe/api/SceneManager.h
+++ b/src/crepe/api/SceneManager.h
@@ -8,14 +8,11 @@
namespace crepe {
+class ComponentManager;
+
class SceneManager {
public:
- // Singleton
- static SceneManager & get_instance();
- SceneManager(const SceneManager &) = delete;
- SceneManager(SceneManager &&) = delete;
- SceneManager & operator=(const SceneManager &) = delete;
- SceneManager & operator=(SceneManager &&) = delete;
+ SceneManager(ComponentManager & mgr);
public:
/**
@@ -38,11 +35,9 @@ public:
void load_next_scene();
private:
- SceneManager() = default;
-
-private:
std::vector<std::unique_ptr<Scene>> scenes;
std::string next_scene;
+ ComponentManager & component_manager;
};
} // namespace crepe
diff --git a/src/crepe/api/SceneManager.hpp b/src/crepe/api/SceneManager.hpp
index 61c33bf..714f690 100644
--- a/src/crepe/api/SceneManager.hpp
+++ b/src/crepe/api/SceneManager.hpp
@@ -1,12 +1,16 @@
+#pragma once
+
#include "SceneManager.h"
namespace crepe {
template <typename T>
void SceneManager::add_scene(const std::string & name) {
- static_assert(std::is_base_of<Scene, T>::value, "T must be derived from Scene");
+ using namespace std;
+ static_assert(is_base_of<Scene, T>::value, "T must be derived from Scene");
- scenes.emplace_back(make_unique<T>(name));
+ Scene * scene = new T(this->component_manager, name);
+ this->scenes.emplace_back(unique_ptr<Scene>(scene));
// The first scene added, is the one that will be loaded at the beginning
if (next_scene.empty()) {
diff --git a/src/crepe/api/Script.cpp b/src/crepe/api/Script.cpp
deleted file mode 100644
index 390cec7..0000000
--- a/src/crepe/api/Script.cpp
+++ /dev/null
@@ -1,3 +0,0 @@
-#include "Script.h"
-
-using namespace crepe;
diff --git a/src/crepe/api/Script.h b/src/crepe/api/Script.h
index bf43a49..2b70379 100644
--- a/src/crepe/api/Script.h
+++ b/src/crepe/api/Script.h
@@ -2,34 +2,85 @@
#include <vector>
-namespace crepe {
-class ScriptSystem;
-}
+#include "../types.h"
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.
+ *
+ * \note Additional *events* (like Unity's OnDisable and OnEnable) should be implemented as
+ * member or lambda methods in derivative user script classes and registered in \c init().
+ */
class Script {
- 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 registered in init(), otherwise this
- // class will balloon in size with each added event.
+ //! ScriptSystem calls \c init() and \c update()
+ friend class crepe::ScriptSystem;
protected:
+ /**
+ * \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;
+ // TODO: make get_component calls for component types that can have more than 1 instance
+ // cause compile-time errors
+ /**
+ * \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 programmer doesn't need
+ // to manually add `using Script::Script` to their concrete script class.
+ Script() = default;
+ //! Only \c BehaviorScript instantiates Script
+ friend class BehaviorScript;
+
+private:
+ // These references are set by BehaviorScript immediately after calling the constructor of
+ // Script.
+ game_object_id_t game_object_id = -1;
+ ComponentManager * component_manager_ref = nullptr;
+ // TODO: use OptionalRef instead of pointer
private:
- friend class crepe::BehaviorScript;
- BehaviorScript * parent = nullptr;
+ //! Flag to indicate if \c init() has been called already
+ bool initialized = false;
};
} // namespace crepe
diff --git a/src/crepe/api/Script.hpp b/src/crepe/api/Script.hpp
index ce39331..a064a90 100644
--- a/src/crepe/api/Script.hpp
+++ b/src/crepe/api/Script.hpp
@@ -8,17 +8,21 @@
namespace crepe {
template <typename T>
-T & Script::get_component() {
- std::vector<std::reference_wrapper<T>> all_components = this->get_components<T>();
- if (all_components.size() < 1) throw nullptr; // TODO
+T & Script::get_component() const {
+ using namespace std;
+ vector<reference_wrapper<T>> all_components = this->get_components<T>();
+ if (all_components.size() < 1)
+ throw runtime_error(
+ format("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() {
- ComponentManager & mgr = ComponentManager::get_instance();
- return mgr.get_components_by_id<T>(this->parent->game_object_id);
+std::vector<std::reference_wrapper<T>> Script::get_components() const {
+ auto & mgr = *this->component_manager_ref;
+
+ return mgr.get_components_by_id<T>(this->game_object_id);
}
} // namespace crepe
diff --git a/src/crepe/api/Sprite.cpp b/src/crepe/api/Sprite.cpp
index c4cd29e..bd2d5cf 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/Sprite.h b/src/crepe/api/Sprite.h
index 50ea88e..0192793 100644
--- a/src/crepe/api/Sprite.h
+++ b/src/crepe/api/Sprite.h
@@ -1,6 +1,5 @@
#pragma once
-#include <cstdint>
#include <memory>
#include "Color.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 8eeec41..cd944bd 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/api/Transform.h b/src/crepe/api/Transform.h
index 51b0daa..18aa293 100644
--- a/src/crepe/api/Transform.h
+++ b/src/crepe/api/Transform.h
@@ -14,6 +14,14 @@ namespace crepe {
*/
class Transform : public Component {
public:
+ //! Translation (shift)
+ Vector2 position = {0, 0};
+ //! Rotation, in degrees
+ double rotation = 0;
+ //! Multiplication factor
+ double scale = 0;
+
+protected:
/**
* \param id The id of the GameObject this component belongs to
* \param point The position of the GameObject
@@ -22,19 +30,12 @@ public:
*/
Transform(game_object_id_t id, const Vector2 & point, double rotation, double scale);
/**
- * \brief Get the maximum number of instances for this component
- *
- * \return The maximum number of instances for this component
+ * There is always exactly one transform component per entity
+ * \return 1
*/
virtual int get_instances_max() const { return 1; }
-
-public:
- //! Translation (shift)
- Vector2 position;
- //! Rotation, in degrees
- double rotation;
- //! Multiplication factor
- double scale;
+ //! ComponentManager instantiates all components
+ friend class ComponentManager;
};
} // namespace crepe
diff --git a/src/crepe/api/Vector2.cpp b/src/crepe/api/Vector2.cpp
index 437d1d8..30b968e 100644
--- a/src/crepe/api/Vector2.cpp
+++ b/src/crepe/api/Vector2.cpp
@@ -1,47 +1,33 @@
#include "Vector2.h"
-namespace crepe {
+using namespace crepe;
-// Constructor with initial values
-Vector2::Vector2(double x, double y) : x(x), y(y) {}
-
-// Subtracts another vector from this vector and returns the result.
Vector2 Vector2::operator-(const Vector2 & other) const { return {x - other.x, y - other.y}; }
-// Adds another vector to this vector and returns the result.
Vector2 Vector2::operator+(const Vector2 & other) const { return {x + other.x, y + other.y}; }
-// Multiplies this vector by a scalar and returns the result.
Vector2 Vector2::operator*(double scalar) const { return {x * scalar, y * scalar}; }
-// Multiplies this vector by another vector element-wise and updates this vector.
Vector2 & Vector2::operator*=(const Vector2 & other) {
x *= other.x;
y *= other.y;
return *this;
}
-// Adds another vector to this vector and updates this vector.
Vector2 & Vector2::operator+=(const Vector2 & other) {
x += other.x;
y += other.y;
return *this;
}
-// Adds a scalar value to both components of this vector and updates this vector.
Vector2 & Vector2::operator+=(double other) {
x += other;
y += other;
return *this;
}
-// Returns the negation of this vector.
Vector2 Vector2::operator-() const { return {-x, -y}; }
-// Checks if this vector is equal to another vector.
bool Vector2::operator==(const Vector2 & other) const { return x == other.x && y == other.y; }
-// Checks if this vector is not equal to another vector.
bool Vector2::operator!=(const Vector2 & other) const { return !(*this == other); }
-
-} // namespace crepe
diff --git a/src/crepe/api/Vector2.h b/src/crepe/api/Vector2.h
index 5a57484..2fb6136 100644
--- a/src/crepe/api/Vector2.h
+++ b/src/crepe/api/Vector2.h
@@ -2,19 +2,12 @@
namespace crepe {
-//! Vector2 class
-class Vector2 {
-public:
+//! 2D vector
+struct Vector2 {
//! X component of the vector
- double x;
+ double x = 0;
//! Y component of the vector
- double y;
-
- //! Default constructor
- Vector2() = default;
-
- //! Constructor with initial values
- Vector2(double x, double y);
+ double y = 0;
//! Subtracts another vector from this vector and returns the result.
Vector2 operator-(const Vector2 & other) const;
diff --git a/src/crepe/facade/DB.cpp b/src/crepe/facade/DB.cpp
index bf877b5..d5d19dc 100644
--- a/src/crepe/facade/DB.cpp
+++ b/src/crepe/facade/DB.cpp
@@ -1,7 +1,6 @@
#include <cstring>
-#include "Exception.h"
-#include "util/log.h"
+#include "util/Log.h"
#include "DB.h"
@@ -15,19 +14,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 runtime_error(format("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 runtime_error(format("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 runtime_error(format("db->cursor: {}", libdb::db_strerror(ret)));
this->cursor = {cursor, [](libdb::DBC * cursor) { cursor->close(cursor); }};
}
@@ -45,21 +43,24 @@ 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));
- return {static_cast<char *>(db_val.data), db_val.size};
+ if (ret == 0) return {static_cast<char *>(db_val.data), db_val.size};
+
+ string err = format("cursor->get: {}", libdb::db_strerror(ret));
+ if (ret == DB_NOTFOUND) throw out_of_range(err);
+ else throw runtime_error(err);
}
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 runtime_error(format("cursor->get: {}", libdb::db_strerror(ret)));
}
-bool DB::has(const std::string & key) noexcept {
+bool DB::has(const std::string & key) {
try {
this->get(key);
- } catch (...) {
+ } catch (std::out_of_range &) {
return false;
}
return true;
diff --git a/src/crepe/facade/DB.h b/src/crepe/facade/DB.h
index 5f8d939..629b0eb 100644
--- a/src/crepe/facade/DB.h
+++ b/src/crepe/facade/DB.h
@@ -34,7 +34,8 @@ public:
*
* \return The value
*
- * \throws Exception if value is not found in DB or other error occurs
+ * \throws std::out_of_range if value is not found in DB
+ * \throws std::runtime_error if other error occurs
*/
std::string get(const std::string & key);
/**
@@ -43,7 +44,7 @@ public:
* \param key The value key
* \param value The value to store
*
- * \throws Exception if an error occurs
+ * \throws std::runtime_error if an error occurs
*/
void set(const std::string & key, const std::string & value);
/**
@@ -53,7 +54,7 @@ public:
*
* \returns True if the key exists, or false if it does not
*/
- bool has(const std::string & key) noexcept;
+ bool has(const std::string & key);
private:
//! RAII wrapper around \c DB struct
diff --git a/src/crepe/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp
index e72b622..83e91f8 100644
--- a/src/crepe/facade/SDLContext.cpp
+++ b/src/crepe/facade/SDLContext.cpp
@@ -10,17 +10,16 @@
#include <iostream>
#include <memory>
#include <string>
-#include <utility>
#include "../api/Sprite.h"
#include "../api/Texture.h"
#include "../api/Transform.h"
-#include "../util/log.h"
-#include "Exception.h"
+#include "../util/Log.h"
#include "SDLContext.h"
using namespace crepe;
+using namespace std;
SDLContext & SDLContext::get_instance() {
static SDLContext instance;
@@ -160,7 +159,7 @@ SDLContext::texture_from_path(const std::string & path) {
= SDL_CreateTextureFromSurface(this->game_renderer.get(), img_surface.get());
if (tmp_texture == nullptr) {
- throw Exception("Texture cannot be load from %s", path.c_str());
+ throw runtime_error(format("Texture cannot be load from {}", path));
}
std::unique_ptr<SDL_Texture, std::function<void(SDL_Texture *)>> img_texture;
diff --git a/src/crepe/facade/Sound.cpp b/src/crepe/facade/Sound.cpp
index a1aef17..7aa89a9 100644
--- a/src/crepe/facade/Sound.cpp
+++ b/src/crepe/facade/Sound.cpp
@@ -1,21 +1,22 @@
-#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() {
SoundContext & ctx = SoundContext::get_instance();
diff --git a/src/crepe/facade/Sound.h b/src/crepe/facade/Sound.h
index adf1fef..32b6478 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/AnimatorSystem.cpp b/src/crepe/system/AnimatorSystem.cpp
index bf45362..9d18873 100644
--- a/src/crepe/system/AnimatorSystem.cpp
+++ b/src/crepe/system/AnimatorSystem.cpp
@@ -1,27 +1,17 @@
-
#include <cstdint>
#include <functional>
#include <vector>
#include "api/Animator.h"
#include "facade/SDLContext.h"
-#include "util/log.h"
#include "AnimatorSystem.h"
#include "ComponentManager.h"
using namespace crepe;
-AnimatorSystem::AnimatorSystem() { dbg_trace(); }
-AnimatorSystem::~AnimatorSystem() { dbg_trace(); }
-
-AnimatorSystem & AnimatorSystem::get_instance() {
- static AnimatorSystem instance;
- return instance;
-}
-
void AnimatorSystem::update() {
- ComponentManager & mgr = ComponentManager::get_instance();
+ ComponentManager & mgr = this->component_manager;
std::vector<std::reference_wrapper<Animator>> animations
= mgr.get_components_by_type<Animator>();
diff --git a/src/crepe/system/AnimatorSystem.h b/src/crepe/system/AnimatorSystem.h
index 29204d3..56cc7b3 100644
--- a/src/crepe/system/AnimatorSystem.h
+++ b/src/crepe/system/AnimatorSystem.h
@@ -17,16 +17,7 @@ namespace crepe {
class AnimatorSystem : public System {
public:
- /**
- * \brief Retrieves the singleton instance of the AnimatorSystem.
- *
- * \return A reference to the single instance of the AnimatorSystem.
- *
- * This method ensures that there is only one instance of the AnimatorSystem, following the
- * singleton design pattern. It can be used to access the system globally.
- */
- static AnimatorSystem & get_instance();
-
+ using System::System;
/**
* \brief Updates the Animator components.
*
@@ -35,11 +26,7 @@ public:
* looping).
*/
void update() override;
-
-private:
- // private because singleton
- AnimatorSystem(); // dbg_trace
- ~AnimatorSystem(); // dbg_trace
+ // FIXME: never say "likely" in the documentation lmao
};
} // namespace crepe
diff --git a/src/crepe/system/CMakeLists.txt b/src/crepe/system/CMakeLists.txt
index 4c18b87..d658b25 100644
--- a/src/crepe/system/CMakeLists.txt
+++ b/src/crepe/system/CMakeLists.txt
@@ -1,4 +1,5 @@
target_sources(crepe PUBLIC
+ System.cpp
ParticleSystem.cpp
ScriptSystem.cpp
PhysicsSystem.cpp
diff --git a/src/crepe/system/CollisionSystem.cpp b/src/crepe/system/CollisionSystem.cpp
index 55e0fdc..c74ca1d 100644
--- a/src/crepe/system/CollisionSystem.cpp
+++ b/src/crepe/system/CollisionSystem.cpp
@@ -2,6 +2,4 @@
using namespace crepe;
-CollisionSystem::CollisionSystem() {}
-
void CollisionSystem::update() {}
diff --git a/src/crepe/system/CollisionSystem.h b/src/crepe/system/CollisionSystem.h
index 1e9f1aa..c1a70d8 100644
--- a/src/crepe/system/CollisionSystem.h
+++ b/src/crepe/system/CollisionSystem.h
@@ -1,11 +1,13 @@
#pragma once
+#include "System.h"
+
namespace crepe {
-class CollisionSystem {
+class CollisionSystem : public System {
public:
- CollisionSystem();
- void update();
+ using System::System;
+ void update() override;
};
} // namespace crepe
diff --git a/src/crepe/system/ParticleSystem.cpp b/src/crepe/system/ParticleSystem.cpp
index 92e7d3f..7316309 100644
--- a/src/crepe/system/ParticleSystem.cpp
+++ b/src/crepe/system/ParticleSystem.cpp
@@ -13,7 +13,7 @@ using namespace crepe;
void ParticleSystem::update() {
// Get all emitters
- ComponentManager & mgr = ComponentManager::get_instance();
+ ComponentManager & mgr = this->component_manager;
std::vector<std::reference_wrapper<ParticleEmitter>> emitters
= mgr.get_components_by_type<ParticleEmitter>();
diff --git a/src/crepe/system/ParticleSystem.h b/src/crepe/system/ParticleSystem.h
index 843261e..c647284 100644
--- a/src/crepe/system/ParticleSystem.h
+++ b/src/crepe/system/ParticleSystem.h
@@ -15,6 +15,7 @@ class Transform;
*/
class ParticleSystem : public System {
public:
+ using System::System;
/**
* \brief Updates all particle emitters by emitting particles, updating particle states, and
* checking bounds.
@@ -68,7 +69,8 @@ private:
double generate_random_speed(double min_speed, double max_speed) const;
private:
- //! Counter to count updates to determine how many times emit_particle is called.
+ //! Counter to count updates to determine how many times emit_particle is
+ // called.
unsigned int update_count = 0;
//! Determines the lowest amount of emission rate (1000 = 0.001 = 1 particle per 1000
// updates).
diff --git a/src/crepe/system/PhysicsSystem.cpp b/src/crepe/system/PhysicsSystem.cpp
index 402dfab..4a7dbfb 100644
--- a/src/crepe/system/PhysicsSystem.cpp
+++ b/src/crepe/system/PhysicsSystem.cpp
@@ -11,7 +11,7 @@
using namespace crepe;
void PhysicsSystem::update() {
- ComponentManager & mgr = ComponentManager::get_instance();
+ ComponentManager & mgr = this->component_manager;
std::vector<std::reference_wrapper<Rigidbody>> rigidbodies
= mgr.get_components_by_type<Rigidbody>();
std::vector<std::reference_wrapper<Transform>> transforms
diff --git a/src/crepe/system/PhysicsSystem.h b/src/crepe/system/PhysicsSystem.h
index b635693..227ab69 100644
--- a/src/crepe/system/PhysicsSystem.h
+++ b/src/crepe/system/PhysicsSystem.h
@@ -3,6 +3,7 @@
#include "System.h"
namespace crepe {
+
/**
* \brief System that controls all physics
*
@@ -11,6 +12,7 @@ namespace crepe {
*/
class PhysicsSystem : public System {
public:
+ using System::System;
/**
* \brief updates the physics system.
*
diff --git a/src/crepe/system/RenderSystem.cpp b/src/crepe/system/RenderSystem.cpp
index a488370..fa3d0de 100644
--- a/src/crepe/system/RenderSystem.cpp
+++ b/src/crepe/system/RenderSystem.cpp
@@ -5,26 +5,17 @@
#include "../api/Sprite.h"
#include "../api/Transform.h"
#include "../facade/SDLContext.h"
-#include "../util/log.h"
+#include "../util/Log.h"
#include "RenderSystem.h"
using namespace crepe;
-RenderSystem::RenderSystem() { dbg_trace(); }
-
-RenderSystem::~RenderSystem() { dbg_trace(); }
-
-RenderSystem & RenderSystem::get_instance() {
- static RenderSystem instance;
- return instance;
-}
-
void RenderSystem::clear_screen() const { SDLContext::get_instance().clear_screen(); }
void RenderSystem::present_screen() const { SDLContext::get_instance().present_screen(); }
void RenderSystem::update_camera() {
- ComponentManager & mgr = ComponentManager::get_instance();
+ ComponentManager & mgr = this->component_manager;
std::vector<std::reference_wrapper<Camera>> cameras = mgr.get_components_by_type<Camera>();
@@ -34,8 +25,7 @@ void RenderSystem::update_camera() {
}
}
void RenderSystem::render_sprites() const {
-
- ComponentManager & mgr = ComponentManager::get_instance();
+ ComponentManager & mgr = this->component_manager;
std::vector<std::reference_wrapper<Sprite>> sprites = mgr.get_components_by_type<Sprite>();
diff --git a/src/crepe/system/RenderSystem.h b/src/crepe/system/RenderSystem.h
index b9bf94b..87ec494 100644
--- a/src/crepe/system/RenderSystem.h
+++ b/src/crepe/system/RenderSystem.h
@@ -15,14 +15,8 @@ namespace crepe {
* services for the application.
*/
class RenderSystem : public System {
-
public:
- /**
- * \brief Gets the singleton instance of RenderSystem.
- * \return Reference to the RenderSystem instance.
- */
- static RenderSystem & get_instance();
-
+ using System::System;
/**
* \brief Updates the RenderSystem for the current frame.
* This method is called to perform all rendering operations for the current game frame.
@@ -30,10 +24,6 @@ public:
void update() override;
private:
- // Private constructor to enforce singleton pattern.
- RenderSystem();
- ~RenderSystem();
-
//! Clears the screen in preparation for rendering.
void clear_screen() const;
@@ -61,4 +51,5 @@ private:
Camera * curr_cam = nullptr;
// TODO: needs a better solution
};
+
} // namespace crepe
diff --git a/src/crepe/system/ScriptSystem.cpp b/src/crepe/system/ScriptSystem.cpp
index f2673e7..c4d724c 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"
@@ -13,16 +12,23 @@ using namespace std;
using namespace crepe;
void ScriptSystem::update() {
- using namespace std;
dbg_trace();
- forward_list<Script *> scripts = this->get_scripts();
- for (Script * script : scripts) script->update();
+ forward_list<reference_wrapper<Script>> scripts = this->get_scripts();
+
+ for (auto & script_ref : scripts) {
+ Script & script = script_ref.get();
+ if (!script.initialized) {
+ script.init();
+ script.initialized = true;
+ }
+ script.update();
+ }
}
-forward_list<Script *> ScriptSystem::get_scripts() {
- forward_list<Script *> scripts = {};
- ComponentManager & mgr = ComponentManager::get_instance();
+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
= mgr.get_components_by_type<BehaviorScript>();
@@ -31,7 +37,7 @@ forward_list<Script *> ScriptSystem::get_scripts() {
if (!behavior_script.active) continue;
Script * script = behavior_script.script.get();
if (script == nullptr) continue;
- scripts.push_front(script);
+ scripts.push_front(*script);
}
return scripts;
diff --git a/src/crepe/system/ScriptSystem.h b/src/crepe/system/ScriptSystem.h
index 4fa6141..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:
- void update();
+ 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:
- // TODO: to forward_list<reference_wrapper>
- std::forward_list<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
new file mode 100644
index 0000000..937a423
--- /dev/null
+++ b/src/crepe/system/System.cpp
@@ -0,0 +1,7 @@
+#include "../util/Log.h"
+
+#include "System.h"
+
+using namespace crepe;
+
+System::System(ComponentManager & mgr) : component_manager(mgr) { dbg_trace(); }
diff --git a/src/crepe/system/System.h b/src/crepe/system/System.h
index 3b81bef..28ea20e 100644
--- a/src/crepe/system/System.h
+++ b/src/crepe/system/System.h
@@ -2,13 +2,28 @@
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:
- System() = default;
+ System(ComponentManager &);
virtual ~System() = default;
+
+protected:
+ ComponentManager & component_manager;
};
} // namespace crepe
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
new file mode 100644
index 0000000..84d80a8
--- /dev/null
+++ b/src/crepe/util/Log.cpp
@@ -0,0 +1,37 @@
+#include <iostream>
+#include <string>
+
+#include "../api/Config.h"
+
+#include "Log.h"
+
+using namespace crepe;
+using namespace std;
+
+string Log::prefix(const Level & level) {
+ switch (level) {
+ case Level::TRACE:
+ return LogColor().fg_white().str("[TRACE]") + " ";
+ case Level::DEBUG:
+ return LogColor().fg_magenta().str("[DEBUG]") + " ";
+ case Level::INFO:
+ return LogColor().fg_blue().str("[INFO]") + " ";
+ case Level::WARNING:
+ return LogColor().fg_yellow().str("[WARN]") + " ";
+ case Level::ERROR:
+ return LogColor().fg_red().str("[ERROR]") + " ";
+ }
+ return "";
+}
+
+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;
+ if (!out.ends_with("\n")) out += "\n";
+
+ // TODO: also log to file or smth
+ cout.write(out.data(), out.size());
+ cout.flush();
+}
diff --git a/src/crepe/util/Log.h b/src/crepe/util/Log.h
new file mode 100644
index 0000000..d55b11e
--- /dev/null
+++ b/src/crepe/util/Log.h
@@ -0,0 +1,84 @@
+#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
+ *
+ * \return Colored message severity prefix string
+ */
+ 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..c2156cd
--- /dev/null
+++ b/src/crepe/util/Log.hpp
@@ -0,0 +1,17 @@
+#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 c0c45a0..5411898 100644
--- a/src/crepe/util/LogColor.cpp
+++ b/src/crepe/util/LogColor.cpp
@@ -1,16 +1,15 @@
#include <cstdarg>
#include "../api/Config.h"
-#include "LogColor.h"
-#include "fmt.h"
+#include "LogColor.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 +18,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..132fb94 100644
--- a/src/crepe/util/LogColor.h
+++ b/src/crepe/util/LogColor.h
@@ -4,23 +4,35 @@
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;
+ /**
+ * \brief Get color code as STL string
+ *
+ * \param content If given, color this string and append a color reset escape sequence.
+ *
+ * \returns Color escape sequence
+ */
+ 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:
+ /**
+ * \name Foreground colors
+ *
+ * These functions set the foreground (text) color. The \c bright parameter
+ * makes the color brighter, or bold on some terminals.
+ * \{
+ */
LogColor & fg_black(bool bright = false);
LogColor & fg_red(bool bright = false);
LogColor & fg_green(bool bright = false);
@@ -29,8 +41,16 @@ public:
LogColor & fg_magenta(bool bright = false);
LogColor & fg_cyan(bool bright = false);
LogColor & fg_white(bool bright = false);
+ /// \}
public:
+ /**
+ * \name Background colors
+ *
+ * These functions set the background color. The \c bright parameter makes
+ * the color brighter.
+ * \{
+ */
LogColor & bg_black(bool bright = false);
LogColor & bg_red(bool bright = false);
LogColor & bg_green(bool bright = false);
@@ -39,13 +59,22 @@ public:
LogColor & bg_magenta(bool bright = false);
LogColor & bg_cyan(bool bright = false);
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.cpp b/src/crepe/util/log.cpp
deleted file mode 100644
index 4a8f8e8..0000000
--- a/src/crepe/util/log.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-#include <cstdarg>
-#include <cstdio>
-#include <cstdlib>
-#include <string>
-
-#include "../api/Config.h"
-#include "fmt.h"
-#include "log.h"
-
-using namespace crepe;
-using namespace std;
-
-string log_prefix(LogLevel level) {
- switch (level) {
- case LogLevel::TRACE:
- return LogColor().fg_white().str("[TRACE]") + " ";
- case LogLevel::DEBUG:
- return LogColor().fg_magenta().str("[DEBUG]") + " ";
- case LogLevel::INFO:
- return LogColor().fg_blue().str("[INFO]") + " ";
- case LogLevel::WARNING:
- return LogColor().fg_yellow().str("[WARN]") + " ";
- case LogLevel::ERROR:
- return LogColor().fg_red().str("[ERROR]") + " ";
- }
- return "";
-}
-
-static void log(LogLevel level, const string msg) {
- auto & cfg = Config::get_instance();
- if (level < cfg.log.level) return;
-
- 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
deleted file mode 100644
index 00b5810..0000000
--- a/src/crepe/util/log.h
+++ /dev/null
@@ -1,37 +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