From 3d97f7c60536bf14f314cc703883f74345aacd21 Mon Sep 17 00:00:00 2001 From: heavydemon21 Date: Mon, 11 Nov 2024 20:49:49 +0100 Subject: rendering particle --- src/crepe/facade/SDLContext.cpp | 4 ++-- src/crepe/facade/SDLContext.h | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'src/crepe/facade') diff --git a/src/crepe/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp index e87a2c5..cc2e2f8 100644 --- a/src/crepe/facade/SDLContext.cpp +++ b/src/crepe/facade/SDLContext.cpp @@ -181,12 +181,12 @@ SDLContext::texture_from_path(const std::string & path) { return img_texture; } -int SDLContext::get_width(const Texture & ctx) const { +int SDLContext::get_width(const Texture & ctx) { int w; SDL_QueryTexture(ctx.texture.get(), NULL, NULL, &w, NULL); return w; } -int SDLContext::get_height(const Texture & ctx) const { +int SDLContext::get_height(const Texture & ctx) { int h; SDL_QueryTexture(ctx.texture.get(), NULL, NULL, NULL, &h); return h; diff --git a/src/crepe/facade/SDLContext.h b/src/crepe/facade/SDLContext.h index e358c21..7329b74 100644 --- a/src/crepe/facade/SDLContext.h +++ b/src/crepe/facade/SDLContext.h @@ -10,6 +10,7 @@ #include "../api/Sprite.h" #include "../api/Transform.h" #include "api/Camera.h" +#include "api/Vector2.h" // FIXME: this needs to be removed const int SCREEN_WIDTH = 640; @@ -97,14 +98,14 @@ private: * \param texture Reference to the Texture object. * \return Width of the texture as an integer. */ - int get_width(const Texture &) const; + int get_width(const Texture &) ; /** * \brief Gets the height of a texture. * \param texture Reference to the Texture object. * \return Height of the texture as an integer. */ - int get_height(const Texture &) const; + int get_height(const Texture &) ; private: //! Will use draw,clear_screen, present_screen, camera. @@ -119,6 +120,8 @@ private: void draw(const Sprite & sprite, const Transform & transform, const Camera & camera); + void draw_particle(const Vector2 & pos, const Camera & camera); + //! Clears the screen, preparing for a new frame. void clear_screen(); -- cgit v1.2.3 From e25aa67c4263b3a940ae9e92f2fcd31a4486f407 Mon Sep 17 00:00:00 2001 From: heavydemon21 Date: Thu, 14 Nov 2024 20:18:19 +0100 Subject: adjusted based on feedback of PR#31 --- src/crepe/facade/SDLContext.cpp | 33 +++++++++++---------------------- src/crepe/facade/SDLContext.h | 9 ++------- src/crepe/system/RenderSystem.cpp | 6 +++--- src/crepe/system/RenderSystem.h | 6 ++++++ 4 files changed, 22 insertions(+), 32 deletions(-) (limited to 'src/crepe/facade') diff --git a/src/crepe/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp index cacf238..febbe4b 100644 --- a/src/crepe/facade/SDLContext.cpp +++ b/src/crepe/facade/SDLContext.cpp @@ -7,10 +7,9 @@ #include #include #include -#include #include +#include #include -#include #include "../api/Sprite.h" #include "../api/Texture.h" @@ -32,31 +31,23 @@ SDLContext::SDLContext() { // FIXME: read window defaults from config manager if (SDL_Init(SDL_INIT_VIDEO) < 0) { - // FIXME: throw exception - std::cerr << "SDL could not initialize! SDL_Error: " << SDL_GetError() - << std::endl; - return; + throw std::runtime_error("SDL could not initialize!"); } + SDL_Window * tmp_window = SDL_CreateWindow( "Crepe Game Engine", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, this->viewport.w, this->viewport.h, 0); if (!tmp_window) { - // FIXME: throw exception - std::cerr << "Window could not be created! SDL_Error: " - << SDL_GetError() << std::endl; - return; + throw std::runtime_error("Window could not be created!"); } + this->game_window = {tmp_window, [](SDL_Window * window) { SDL_DestroyWindow(window); }}; SDL_Renderer * tmp_renderer = SDL_CreateRenderer( this->game_window.get(), -1, SDL_RENDERER_ACCELERATED); if (!tmp_renderer) { - // FIXME: throw exception - std::cerr << "Renderer could not be created! SDL_Error: " - << SDL_GetError() << std::endl; - SDL_DestroyWindow(this->game_window.get()); - return; + throw std::runtime_error("Renderer could not be created!"); } this->game_renderer = {tmp_renderer, [](SDL_Renderer * renderer) { @@ -65,9 +56,7 @@ SDLContext::SDLContext() { int img_flags = IMG_INIT_PNG; if (!(IMG_Init(img_flags) & img_flags)) { - // FIXME: throw exception - std::cout << "SDL_image could not initialize! SDL_image Error: " - << IMG_GetError() << std::endl; + throw std::runtime_error("SDL_image could not initialize!"); } } @@ -145,8 +134,8 @@ void SDLContext::draw(const Sprite & sprite, const Transform & transform, void SDLContext::camera(const Camera & cam) { this->viewport.w = static_cast(cam.aspect_width); this->viewport.h = static_cast(cam.aspect_height); - this->viewport.x = static_cast(cam.x) - (SCREEN_WIDTH / 2); - this->viewport.y = static_cast(cam.y) - (SCREEN_HEIGHT / 2); + this->viewport.x = static_cast(cam.x) - (this->viewport.w / 2); + this->viewport.y = static_cast(cam.y) - (this->viewport.h / 2); SDL_SetRenderDrawColor(this->game_renderer.get(), cam.bg_color.r, cam.bg_color.g, cam.bg_color.b, cam.bg_color.a); @@ -181,12 +170,12 @@ SDLContext::texture_from_path(const std::string & path) { return img_texture; } -int SDLContext::get_width(const Texture & ctx) { +int SDLContext::get_width(const Texture & ctx) const { int w; SDL_QueryTexture(ctx.texture.get(), NULL, NULL, &w, NULL); return w; } -int SDLContext::get_height(const Texture & ctx) { +int SDLContext::get_height(const Texture & ctx) const { int h; SDL_QueryTexture(ctx.texture.get(), NULL, NULL, NULL, &h); return h; diff --git a/src/crepe/facade/SDLContext.h b/src/crepe/facade/SDLContext.h index c4392bd..0614036 100644 --- a/src/crepe/facade/SDLContext.h +++ b/src/crepe/facade/SDLContext.h @@ -10,11 +10,6 @@ #include "../api/Sprite.h" #include "../api/Transform.h" #include "api/Camera.h" -#include "api/Vector2.h" - -// FIXME: this needs to be removed -const int SCREEN_WIDTH = 640; -const int SCREEN_HEIGHT = 480; namespace crepe { @@ -109,14 +104,14 @@ private: * \param texture Reference to the Texture object. * \return Width of the texture as an integer. */ - int get_width(const Texture &) ; + int get_width(const Texture &) const; /** * \brief Gets the height of a texture. * \param texture Reference to the Texture object. * \return Height of the texture as an integer. */ - int get_height(const Texture &) ; + int get_height(const Texture &) const; private: //! Will use draw,clear_screen, present_screen, camera. diff --git a/src/crepe/system/RenderSystem.cpp b/src/crepe/system/RenderSystem.cpp index 17a2337..6ecd604 100644 --- a/src/crepe/system/RenderSystem.cpp +++ b/src/crepe/system/RenderSystem.cpp @@ -85,13 +85,13 @@ void RenderSystem::render() { auto sprites = mgr.get_components_by_type(); for (const Sprite & sprite : sprites) { if (!sprite.active) continue; - auto transform = mgr.get_components_by_id(sprite.game_object_id); + auto transform = mgr.get_components_by_id(sprite.game_object_id).front().get(); - bool rendered_particles = this->render_particle(sprite, transform[0].get()); + bool rendered_particles = this->render_particle(sprite, transform); if (rendered_particles) continue; - this->render_normal(sprite, transform[0].get()); + this->render_normal(sprite, transform); } } diff --git a/src/crepe/system/RenderSystem.h b/src/crepe/system/RenderSystem.h index 6a87eec..3d6286f 100644 --- a/src/crepe/system/RenderSystem.h +++ b/src/crepe/system/RenderSystem.h @@ -31,6 +31,12 @@ public: */ void update() override; + + RenderSystem(const RenderSystem &) = delete; + RenderSystem(RenderSystem &&) = delete; + RenderSystem & operator=(const RenderSystem &) = delete; + RenderSystem & operator=(RenderSystem &&) = delete; + private: // Private constructor to enforce singleton pattern. RenderSystem(); -- cgit v1.2.3 From 8d78727d6e7badca16ba7a1328643928a0039569 Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Mon, 18 Nov 2024 18:02:09 +0100 Subject: move utilities from loek/audio --- .crepe-root | 0 .gitmodules | 4 +++ lib/whereami/CMakeLists.txt | 38 +++++++++++++++++++++++ lib/whereami/lib | 1 + src/CMakeLists.txt | 2 ++ src/crepe/Asset.cpp | 16 ---------- src/crepe/Asset.h | 41 ------------------------- src/crepe/CMakeLists.txt | 2 -- src/crepe/api/Asset.cpp | 58 +++++++++++++++++++++++++++++++++++ src/crepe/api/Asset.h | 60 ++++++++++++++++++++++++++++++++++++ src/crepe/api/CMakeLists.txt | 2 ++ src/crepe/api/Config.h | 14 +++++++++ src/crepe/api/Texture.cpp | 2 +- src/crepe/facade/SDLContext.cpp | 2 +- src/crepe/facade/Sound.cpp | 2 +- src/crepe/facade/Sound.h | 2 +- src/crepe/system/System.h | 2 ++ src/crepe/util/CMakeLists.txt | 2 ++ src/crepe/util/OptionalRef.h | 41 +++++++++++++++++++++++++ src/crepe/util/OptionalRef.hpp | 67 +++++++++++++++++++++++++++++++++++++++++ src/example/audio_internal.cpp | 8 ++--- src/example/particles.cpp | 2 +- src/example/rendering.cpp | 10 +++--- src/test/AssetTest.cpp | 33 ++++++++++++++++++++ src/test/CMakeLists.txt | 2 ++ src/test/OptionalRefTest.cpp | 38 +++++++++++++++++++++++ 26 files changed, 378 insertions(+), 73 deletions(-) create mode 100644 .crepe-root create mode 100644 lib/whereami/CMakeLists.txt create mode 160000 lib/whereami/lib delete mode 100644 src/crepe/Asset.cpp delete mode 100644 src/crepe/Asset.h create mode 100644 src/crepe/api/Asset.cpp create mode 100644 src/crepe/api/Asset.h create mode 100644 src/crepe/util/OptionalRef.h create mode 100644 src/crepe/util/OptionalRef.hpp create mode 100644 src/test/AssetTest.cpp create mode 100644 src/test/OptionalRefTest.cpp (limited to 'src/crepe/facade') diff --git a/.crepe-root b/.crepe-root new file mode 100644 index 0000000..e69de29 diff --git a/.gitmodules b/.gitmodules index 2f64601..bd6e7f7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,3 +22,7 @@ path = lib/libdb url = https://github.com/berkeleydb/libdb shallow = true +[submodule "lib/whereami/whereami"] + path = lib/whereami/lib + url = https://github.com/gpakosz/whereami + shallow = true diff --git a/lib/whereami/CMakeLists.txt b/lib/whereami/CMakeLists.txt new file mode 100644 index 0000000..96d3a23 --- /dev/null +++ b/lib/whereami/CMakeLists.txt @@ -0,0 +1,38 @@ +cmake_minimum_required(VERSION 3.28) +set(CMAKE_C_STANDARD 11) +project(whereami C) + +include(CMakePackageConfigHelpers) + +add_library(whereami SHARED) + +target_include_directories(whereami PRIVATE SYSTEM lib/src) +target_sources(whereami PRIVATE lib/src/whereami.c) + +install( + TARGETS whereami + EXPORT whereamiTargets + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib + RUNTIME DESTINATION lib + INCLUDES DESTINATION include +) +install( + FILES lib/src/whereami.h + DESTINATION include +) +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/whereami-config-version.cmake" + VERSION 0.0.0 + COMPATIBILITY AnyNewerVersion +) +install( + FILES + "${CMAKE_CURRENT_BINARY_DIR}/whereami-config-version.cmake" + DESTINATION lib/cmake/whereami +) +install( + EXPORT whereamiTargets + FILE whereami-config.cmake + DESTINATION lib/cmake/whereami +) diff --git a/lib/whereami/lib b/lib/whereami/lib new file mode 160000 index 0000000..dcb52a0 --- /dev/null +++ b/lib/whereami/lib @@ -0,0 +1 @@ +Subproject commit dcb52a058dc14530ba9ae05e4339bd3ddfae0e0e diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 445a8b2..c3f29da 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -11,6 +11,7 @@ find_package(SDL2 REQUIRED) find_package(SDL2_image REQUIRED) find_package(SoLoud REQUIRED) find_package(GTest REQUIRED) +find_package(whereami REQUIRED) find_library(BERKELEY_DB db) add_library(crepe SHARED) @@ -25,6 +26,7 @@ target_link_libraries(crepe PUBLIC SDL2 PUBLIC SDL2_image PUBLIC ${BERKELEY_DB} + PUBLIC whereami ) add_subdirectory(crepe) diff --git a/src/crepe/Asset.cpp b/src/crepe/Asset.cpp deleted file mode 100644 index 9c41ecb..0000000 --- a/src/crepe/Asset.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include - -#include "Asset.h" - -using namespace crepe; -using namespace std; - -// 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); -} - -istream & Asset::get_stream() { return this->file; } - -const string & Asset::get_canonical() const { return this->src; } diff --git a/src/crepe/Asset.h b/src/crepe/Asset.h deleted file mode 100644 index 9051c5e..0000000 --- a/src/crepe/Asset.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace crepe { - -/** - * \brief Asset location helper - * - * This class is used to locate and canonicalize paths to game asset files, and should *always* - * be used when retrieving files from disk. - */ -class Asset { -public: - /** - * \param src Unique identifier to asset - */ - Asset(const std::string & src); - -public: - /** - * \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: - //! Canonical path to asset - const std::string src; - //! File handle (stream) - std::ifstream file; -}; - -} // namespace crepe diff --git a/src/crepe/CMakeLists.txt b/src/crepe/CMakeLists.txt index 3b05742..7e176e7 100644 --- a/src/crepe/CMakeLists.txt +++ b/src/crepe/CMakeLists.txt @@ -1,5 +1,4 @@ target_sources(crepe PUBLIC - Asset.cpp Particle.cpp ComponentManager.cpp Component.cpp @@ -7,7 +6,6 @@ target_sources(crepe PUBLIC ) target_sources(crepe PUBLIC FILE_SET HEADERS FILES - Asset.h ComponentManager.h ComponentManager.hpp Component.h diff --git a/src/crepe/api/Asset.cpp b/src/crepe/api/Asset.cpp new file mode 100644 index 0000000..5271cf7 --- /dev/null +++ b/src/crepe/api/Asset.cpp @@ -0,0 +1,58 @@ +#include +#include +#include + +#include "Asset.h" +#include "api/Config.h" + +using namespace crepe; +using namespace std; + +Asset::Asset(const string & src) : src(find_asset(src)) { } +Asset::Asset(const char * src) : src(find_asset(src)) { } + +const string & Asset::get_path() const noexcept { return this->src; } + +string Asset::find_asset(const string & src) const { + auto & cfg = Config::get_instance(); + auto & root_pattern = cfg.asset.root_pattern; + + // if root_pattern is empty, find_asset must return all paths as-is + if (root_pattern.empty()) return src; + + // absolute paths do not need to be resolved, only canonicalized + filesystem::path path = src; + if (path.is_absolute()) + return filesystem::canonical(path); + + // find directory matching root_pattern + filesystem::path root = this->whereami(); + while (1) { + if (filesystem::exists(root / root_pattern)) + break; + if (!root.has_parent_path()) + throw runtime_error(format("Asset: Cannot find root pattern ({})", root_pattern)); + root = root.parent_path(); + } + + // join path to root (base directory) and canonicalize + return filesystem::canonical(root / path); +} + +string Asset::whereami() const noexcept { + string path; + size_t path_length = wai_getExecutablePath(NULL, 0, NULL); + path.resize(path_length + 1); // wai writes null byte + wai_getExecutablePath(path.data(), path_length, NULL); + path.resize(path_length); + return path; +} + +bool Asset::operator==(const Asset & other) const noexcept { + return this->src == other.src; +} + +size_t std::hash::operator()(const Asset & asset) const noexcept { + return std::hash{}(asset.get_path()); +}; + diff --git a/src/crepe/api/Asset.h b/src/crepe/api/Asset.h new file mode 100644 index 0000000..05dccba --- /dev/null +++ b/src/crepe/api/Asset.h @@ -0,0 +1,60 @@ +#pragma once + +#include +#include + +namespace crepe { + +/** + * \brief Asset location helper + * + * This class is used to locate game asset files, and should *always* be used + * instead of reading file paths directly. + */ +class Asset { +public: + /** + * \param src Unique identifier to asset + */ + Asset(const std::string & src); + /** + * \param src Unique identifier to asset + */ + Asset(const char * src); + +public: + /** + * \brief Get the path to this asset + * \return path to this asset + */ + const std::string & get_path() const noexcept; + + /** + * \brief Comparison operator + * \param other Possibly different instance of \c Asset to test equality against + * \return True if \c this and \c other are equal + */ + bool operator == (const Asset & other) const noexcept; + +private: + //! path to asset + const std::string src; + +private: + std::string find_asset(const std::string & src) const; + /** + * \returns The path to the current executable + */ + std::string whereami() const noexcept; +}; + +} // namespace crepe + +namespace std { + +template<> struct hash { + size_t operator()(const crepe::Asset & asset) const noexcept; +}; + +} + diff --git a/src/crepe/api/CMakeLists.txt b/src/crepe/api/CMakeLists.txt index f9b370f..6557656 100644 --- a/src/crepe/api/CMakeLists.txt +++ b/src/crepe/api/CMakeLists.txt @@ -19,6 +19,7 @@ target_sources(crepe PUBLIC Animator.cpp LoopManager.cpp LoopTimer.cpp + Asset.cpp ) target_sources(crepe PUBLIC FILE_SET HEADERS FILES @@ -45,4 +46,5 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES Animator.h LoopManager.h LoopTimer.h + Asset.h ) diff --git a/src/crepe/api/Config.h b/src/crepe/api/Config.h index 3ab877a..13eabd1 100644 --- a/src/crepe/api/Config.h +++ b/src/crepe/api/Config.h @@ -62,6 +62,20 @@ public: */ double gravity = 1; } physics; + + //! Asset loading options + struct { + /** + * \brief Pattern to match for Asset base directory + * + * All non-absolute paths resolved using \c Asset will be made relative to + * the first parent directory relative to the calling executable where + * appending this pattern results in a path that exists. If this string is + * empty, path resolution is disabled, and Asset will return all paths + * as-is. + */ + std::string root_pattern = ".crepe-root"; + } asset; }; } // namespace crepe diff --git a/src/crepe/api/Texture.cpp b/src/crepe/api/Texture.cpp index de0d0ea..6a1e4d8 100644 --- a/src/crepe/api/Texture.cpp +++ b/src/crepe/api/Texture.cpp @@ -26,7 +26,7 @@ Texture::~Texture() { void Texture::load(unique_ptr res) { SDLContext & ctx = SDLContext::get_instance(); - this->texture = std::move(ctx.texture_from_path(res->get_canonical())); + this->texture = std::move(ctx.texture_from_path(res->get_path())); } int Texture::get_width() const { diff --git a/src/crepe/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp index 83e91f8..f2daada 100644 --- a/src/crepe/facade/SDLContext.cpp +++ b/src/crepe/facade/SDLContext.cpp @@ -149,7 +149,7 @@ SDLContext::texture_from_path(const std::string & path) { SDL_Surface * tmp = IMG_Load(path.c_str()); if (tmp == nullptr) { - tmp = IMG_Load("../asset/texture/ERROR.png"); + tmp = IMG_Load("asset/texture/ERROR.png"); } std::unique_ptr> img_surface; diff --git a/src/crepe/facade/Sound.cpp b/src/crepe/facade/Sound.cpp index 7aa89a9..4d3abf5 100644 --- a/src/crepe/facade/Sound.cpp +++ b/src/crepe/facade/Sound.cpp @@ -16,7 +16,7 @@ Sound::Sound(const char * src) { this->load(make_unique(src)); } -void Sound::load(unique_ptr res) { this->sample.load(res->get_canonical().c_str()); } +void Sound::load(unique_ptr res) { this->sample.load(res->get_path().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 32b6478..4c68f32 100644 --- a/src/crepe/facade/Sound.h +++ b/src/crepe/facade/Sound.h @@ -4,7 +4,7 @@ #include #include -#include "../Asset.h" +#include "../api/Asset.h" namespace crepe { diff --git a/src/crepe/system/System.h b/src/crepe/system/System.h index 28ea20e..36f7edc 100644 --- a/src/crepe/system/System.h +++ b/src/crepe/system/System.h @@ -1,5 +1,7 @@ #pragma once +#include "../ComponentManager.h" + namespace crepe { class ComponentManager; diff --git a/src/crepe/util/CMakeLists.txt b/src/crepe/util/CMakeLists.txt index 4be738a..94ed906 100644 --- a/src/crepe/util/CMakeLists.txt +++ b/src/crepe/util/CMakeLists.txt @@ -9,5 +9,7 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES Log.hpp Proxy.h Proxy.hpp + OptionalRef.h + OptionalRef.hpp ) diff --git a/src/crepe/util/OptionalRef.h b/src/crepe/util/OptionalRef.h new file mode 100644 index 0000000..1ad3a6d --- /dev/null +++ b/src/crepe/util/OptionalRef.h @@ -0,0 +1,41 @@ +#pragma once + +namespace crepe { + +/** + * \brief Optional reference utility + * + * This class doesn't need to know the full definition of \c T to be used. + * + * \tparam T Value type + */ +template +class OptionalRef { +public: + OptionalRef() = default; + OptionalRef(T &); + OptionalRef & operator=(T &); + explicit operator bool() const noexcept; + + void set(T &) noexcept; + T & get() const; + void clear() noexcept; + + OptionalRef(const OptionalRef &); + OptionalRef(OptionalRef &&); + OptionalRef & operator=(const OptionalRef &); + OptionalRef & operator=(OptionalRef &&); + +private: + /** + * \brief Reference to the value of type \c T + * + * \note This raw pointer is *not* managed, and only used as a reference! + */ + T * ref = nullptr; +}; + +} + +#include "OptionalRef.hpp" + diff --git a/src/crepe/util/OptionalRef.hpp b/src/crepe/util/OptionalRef.hpp new file mode 100644 index 0000000..7b201b0 --- /dev/null +++ b/src/crepe/util/OptionalRef.hpp @@ -0,0 +1,67 @@ +#pragma once + +#include + +#include "OptionalRef.h" + +namespace crepe { + +template +OptionalRef::OptionalRef(T & ref) { + this->set(ref); +} + +template +OptionalRef::OptionalRef(const OptionalRef & other) { + this->ref = other.ref; +} + +template +OptionalRef::OptionalRef(OptionalRef && other) { + this->ref = other.ref; + other.clear(); +} + +template +OptionalRef & OptionalRef::operator=(const OptionalRef & other) { + this->ref = other.ref; + return *this; +} + +template +OptionalRef & OptionalRef::operator=(OptionalRef && other) { + this->ref = other.ref; + other.clear(); + return *this; +} + +template +T & OptionalRef::get() const { + if (this->ref == nullptr) + throw std::runtime_error("OptionalRef: attempt to dereference nullptr"); + return *this->ref; +} + +template +void OptionalRef::set(T & ref) noexcept { + this->ref = &ref; +} + +template +void OptionalRef::clear() noexcept { + this->ref = nullptr; +} + +template +OptionalRef & OptionalRef::operator=(T & ref) { + this->set(ref); + return *this; +} + +template +OptionalRef::operator bool() const noexcept { + return this->ref != nullptr; +} + +} + diff --git a/src/example/audio_internal.cpp b/src/example/audio_internal.cpp index 661161a..1647f20 100644 --- a/src/example/audio_internal.cpp +++ b/src/example/audio_internal.cpp @@ -25,11 +25,11 @@ int _ = []() { int main() { // Load a background track (Ogg Vorbis) - auto bgm = Sound("../mwe/audio/bgm.ogg"); + auto bgm = Sound("mwe/audio/bgm.ogg"); // Load three short samples (WAV) - auto sfx1 = Sound("../mwe/audio/sfx1.wav"); - auto sfx2 = Sound("../mwe/audio/sfx2.wav"); - auto sfx3 = Sound("../mwe/audio/sfx3.wav"); + auto sfx1 = Sound("mwe/audio/sfx1.wav"); + auto sfx2 = Sound("mwe/audio/sfx2.wav"); + auto sfx3 = Sound("mwe/audio/sfx3.wav"); // Start the background track bgm.play(); diff --git a/src/example/particles.cpp b/src/example/particles.cpp index 3d5f676..d4638a2 100644 --- a/src/example/particles.cpp +++ b/src/example/particles.cpp @@ -18,7 +18,7 @@ int main(int argc, char * argv[]) { GameObject game_object = mgr.new_object("", "", Vector2{0, 0}, 0, 0); Color color(0, 0, 0, 0); Sprite test_sprite = game_object.add_component( - make_shared("../asset/texture/img.png"), color, FlipSettings{true, true}); + make_shared("asset/texture/img.png"), color, FlipSettings{true, true}); game_object.add_component(ParticleEmitter::Data{ .position = {0, 0}, .max_particles = 100, diff --git a/src/example/rendering.cpp b/src/example/rendering.cpp index c9e62f1..c813524 100644 --- a/src/example/rendering.cpp +++ b/src/example/rendering.cpp @@ -30,20 +30,20 @@ int main() { // Normal adding components { Color color(0, 0, 0, 0); - obj.add_component(make_shared("../asset/texture/img.png"), color, - FlipSettings{false, false}); + obj.add_component( + make_shared("asset/texture/img.png"), color, FlipSettings{false, false}); obj.add_component(Color::get_red()); } { Color color(0, 0, 0, 0); - obj1.add_component(make_shared("../asset/texture/second.png"), color, - FlipSettings{true, true}); + obj1.add_component( + make_shared("asset/texture/second.png"), color, FlipSettings{true, true}); } /* { Color color(0, 0, 0, 0); - auto img = mgr.cache("../asset/texture/second.png"); + auto img = mgr.cache("asset/texture/second.png"); obj2.add_component(img, color, FlipSettings{true, true}); } */ diff --git a/src/test/AssetTest.cpp b/src/test/AssetTest.cpp new file mode 100644 index 0000000..563a253 --- /dev/null +++ b/src/test/AssetTest.cpp @@ -0,0 +1,33 @@ +#include + +#include +#include + +using namespace std; +using namespace crepe; +using namespace testing; + +class AssetTest : public Test { +public: + Config & cfg = Config::get_instance(); + void SetUp() override { + this->cfg.asset.root_pattern = ".crepe-root"; + } +}; + +TEST_F(AssetTest, Existant) { + ASSERT_NO_THROW(Asset{"asset/texture/img.png"}); +} + +TEST_F(AssetTest, Nonexistant) { + ASSERT_ANY_THROW(Asset{"asset/nonexistant"}); +} + +TEST_F(AssetTest, Rootless) { + cfg.asset.root_pattern.clear(); + + string arbitrary = "\\/this is / /../passed through as-is"; + Asset asset{arbitrary}; + ASSERT_EQ(arbitrary, asset.get_path()); +} + diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index 49c8151..f722082 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -3,5 +3,7 @@ target_sources(test_main PUBLIC PhysicsTest.cpp ScriptTest.cpp ParticleTest.cpp + AssetTest.cpp + OptionalRefTest.cpp ) diff --git a/src/test/OptionalRefTest.cpp b/src/test/OptionalRefTest.cpp new file mode 100644 index 0000000..219ccca --- /dev/null +++ b/src/test/OptionalRefTest.cpp @@ -0,0 +1,38 @@ +#include + +#include + +using namespace std; +using namespace crepe; +using namespace testing; + +TEST(OptionalRefTest, Explicit) { + string value = "foo"; + OptionalRef ref; + EXPECT_FALSE(ref); + ASSERT_THROW(ref.get(), runtime_error); + + ref.set(value); + EXPECT_TRUE(ref); + ASSERT_NO_THROW(ref.get()); + + ref.clear(); + EXPECT_FALSE(ref); + ASSERT_THROW(ref.get(), runtime_error); +} + +TEST(OptionalRefTest, Implicit) { + string value = "foo"; + OptionalRef ref = value; + EXPECT_TRUE(ref); + ASSERT_NO_THROW(ref.get()); + + ref.clear(); + EXPECT_FALSE(ref); + ASSERT_THROW(ref.get(), runtime_error); + + ref = value; + EXPECT_TRUE(ref); + ASSERT_NO_THROW(ref.get()); +} + -- cgit v1.2.3 From 66bbea079bf1ae84c355349d337db468c18eac32 Mon Sep 17 00:00:00 2001 From: heavydemon21 Date: Mon, 18 Nov 2024 21:07:26 +0100 Subject: feedback from PR#38 implemented --- src/crepe/facade/SDLContext.h | 5 ----- src/crepe/system/RenderSystem.cpp | 5 ++--- src/crepe/system/RenderSystem.h | 10 ++++++---- 3 files changed, 8 insertions(+), 12 deletions(-) (limited to 'src/crepe/facade') diff --git a/src/crepe/facade/SDLContext.h b/src/crepe/facade/SDLContext.h index 007092b..d437bc4 100644 --- a/src/crepe/facade/SDLContext.h +++ b/src/crepe/facade/SDLContext.h @@ -21,8 +21,6 @@ namespace crepe { // typedef is unusable when crepe is packaged. Wouter will fix this later. typedef SDL_Keycode CREPE_KEYCODES; -class Texture; -class LoopManager; /** * \class SDLContext @@ -91,9 +89,6 @@ private: //! Will use the funtions: texture_from_path, get_width,get_height. friend class Texture; - //! Will use the funtions: texture_from_path, get_width,get_height. - friend class Animator; - /** * \brief Loads a texture from a file path. * \param path Path to the image file. diff --git a/src/crepe/system/RenderSystem.cpp b/src/crepe/system/RenderSystem.cpp index bf5dade..11c20f5 100644 --- a/src/crepe/system/RenderSystem.cpp +++ b/src/crepe/system/RenderSystem.cpp @@ -22,7 +22,7 @@ void RenderSystem::update_camera() { for (Camera & cam : cameras) { SDLContext::get_instance().camera(cam); - this->curr_cam = &cam; + this->curr_cam_ref = &cam; } } @@ -35,7 +35,6 @@ bool sorting_comparison(const Sprite & a, const Sprite & b) { std::vector> RenderSystem::sort(std::vector> & objs) { - if (objs.empty()) return {}; std::vector> sorted_objs(objs); std::sort(sorted_objs.begin(), sorted_objs.end(), sorting_comparison); @@ -52,7 +51,7 @@ void RenderSystem::render_sprites() { SDLContext & render = SDLContext::get_instance(); for (const Sprite & sprite : sorted_sprites) { auto transforms = mgr.get_components_by_id(sprite.game_object_id); - render.draw(sprite, transforms[0], *curr_cam); + render.draw(sprite, transforms[0], *this->curr_cam_ref); } } diff --git a/src/crepe/system/RenderSystem.h b/src/crepe/system/RenderSystem.h index 7661cbd..1176b06 100644 --- a/src/crepe/system/RenderSystem.h +++ b/src/crepe/system/RenderSystem.h @@ -1,12 +1,14 @@ #pragma once -#include "api/Camera.h" -#include "System.h" -#include "api/Sprite.h" #include #include +#include "api/Sprite.h" +#include "api/Camera.h" + +#include "System.h" + namespace crepe { /** @@ -54,7 +56,7 @@ private: private: //! Pointer to the current active camera for rendering - Camera * curr_cam = nullptr; + Camera * curr_cam_ref = nullptr; // TODO: needs a better solution }; -- cgit v1.2.3 From 52e84ca0a81210cd1dc61e096c228586649c9bfc Mon Sep 17 00:00:00 2001 From: heavydemon21 Date: Wed, 20 Nov 2024 11:35:25 +0100 Subject: updated adjsuted rendering based on feedback --- src/crepe/facade/SDLContext.cpp | 51 +++++++++++++++++++++++++++++--------- src/crepe/facade/SDLContext.h | 26 +++++++++++++++++-- src/crepe/system/RenderSystem.cpp | 8 +++--- src/crepe/system/RenderSystem.h | 3 ++- src/example/rendering_particle.cpp | 11 ++++---- 5 files changed, 74 insertions(+), 25 deletions(-) (limited to 'src/crepe/facade') diff --git a/src/crepe/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp index 40189f6..8131df2 100644 --- a/src/crepe/facade/SDLContext.cpp +++ b/src/crepe/facade/SDLContext.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -15,6 +16,8 @@ #include "../api/Texture.h" #include "../api/Transform.h" #include "../util/Log.h" +#include "api/Camera.h" +#include "api/Vector2.h" #include "SDLContext.h" @@ -93,30 +96,54 @@ void SDLContext::handle_events(bool & running) { void SDLContext::clear_screen() { SDL_RenderClear(this->game_renderer.get()); } void SDLContext::present_screen() { SDL_RenderPresent(this->game_renderer.get()); } -void SDLContext::draw(const Sprite & sprite, const Transform & transform, const Camera & cam) { - - SDL_RendererFlip render_flip - = (SDL_RendererFlip) ((SDL_FLIP_HORIZONTAL * sprite.flip.flip_x) - | (SDL_FLIP_VERTICAL * sprite.flip.flip_y)); - - double adjusted_x = (transform.position.x - cam.x) * cam.zoom; - double adjusted_y = (transform.position.y - cam.y) * cam.zoom; - double adjusted_w = sprite.sprite_rect.w * transform.scale * cam.zoom; - double adjusted_h = sprite.sprite_rect.h * transform.scale * cam.zoom; - SDL_Rect srcrect = { +SDL_Rect SDLContext::get_src_rect(const Sprite & sprite) { + return SDL_Rect{ .x = sprite.sprite_rect.x, .y = sprite.sprite_rect.y, .w = sprite.sprite_rect.w, .h = sprite.sprite_rect.h, }; +} +SDL_Rect SDLContext::get_dst_rect(const Sprite & sprite, const Vector2 & pos, + const double & scale, const Camera & cam) { + + double adjusted_x = (pos.x - cam.x) * cam.zoom; + double adjusted_y = (pos.y - cam.y) * cam.zoom; + double adjusted_w = sprite.sprite_rect.w * scale * cam.zoom; + double adjusted_h = sprite.sprite_rect.h * scale * cam.zoom; - SDL_Rect dstrect = { + return SDL_Rect{ .x = static_cast(adjusted_x), .y = static_cast(adjusted_y), .w = static_cast(adjusted_w), .h = static_cast(adjusted_h), }; +} + +void SDLContext::draw_particle(const Sprite & sprite, const Vector2 & pos, + const double & angle, const double & scale, + const Camera & camera) { + + SDL_RendererFlip render_flip + = (SDL_RendererFlip) ((SDL_FLIP_HORIZONTAL * sprite.flip.flip_x) + | (SDL_FLIP_VERTICAL * sprite.flip.flip_y)); + + SDL_Rect srcrect = this->get_src_rect(sprite); + SDL_Rect dstrect = this->get_dst_rect(sprite, pos, scale, camera); + + SDL_RenderCopyEx(this->game_renderer.get(), sprite.sprite_image->texture.get(), &srcrect, + &dstrect, angle, NULL, render_flip); +} + +void SDLContext::draw(const Sprite & sprite, const Transform & transform, const Camera & cam) { + + SDL_RendererFlip render_flip + = (SDL_RendererFlip) ((SDL_FLIP_HORIZONTAL * sprite.flip.flip_x) + | (SDL_FLIP_VERTICAL * sprite.flip.flip_y)); + + SDL_Rect srcrect = this->get_src_rect(sprite); + SDL_Rect dstrect = this->get_dst_rect(sprite, transform.position, transform.scale, cam); SDL_RenderCopyEx(this->game_renderer.get(), sprite.sprite_image->texture.get(), &srcrect, &dstrect, transform.rotation, NULL, render_flip); diff --git a/src/crepe/facade/SDLContext.h b/src/crepe/facade/SDLContext.h index 78ac56b..fb09015 100644 --- a/src/crepe/facade/SDLContext.h +++ b/src/crepe/facade/SDLContext.h @@ -1,8 +1,10 @@ #pragma once #include +#include #include #include +#include #include #include #include @@ -10,6 +12,7 @@ #include "../api/Sprite.h" #include "../api/Transform.h" #include "api/Camera.h" +#include "api/Vector2.h" namespace crepe { @@ -122,8 +125,7 @@ private: * \param camera Reference to the Camera for view adjustments. */ void draw(const Sprite & sprite, const Transform & transform, const Camera & camera); - - void draw_particle(const Vector2 & pos, const Camera & camera); + void draw_particle(const Sprite & sprite, const Vector2 & pos, const double & angle, const double & scale, const Camera & camera); //! Clears the screen, preparing for a new frame. void clear_screen(); @@ -137,6 +139,26 @@ private: */ void camera(const Camera & camera); +private: + /** + * \brief calculates the sqaure size of the image + * + * \param sprite Reference to the sprite to calculate the rectangle + * \return sdl rectangle to draw a src image + */ + SDL_Rect get_src_rect(const Sprite & sprite); + /** + * \brief calculates the sqaure size of the image for an destination + * + * \param sprite Reference to the sprite to calculate the rectangle + * \param pos the pos in pixel positions + * \param scale the multiplier to increase of decrease for the specified sprite + * \param cam Reference to the current camera in the scene to calculate the position based + * on the camera + * \return sdl rectangle to draw a dst image to draw on the screen + */ + SDL_Rect get_dst_rect(const Sprite & sprite, const Vector2 & pos, const double & scale, const Camera & cam); + private: //! sdl Window std::unique_ptr> game_window; diff --git a/src/crepe/system/RenderSystem.cpp b/src/crepe/system/RenderSystem.cpp index 39e0e3f..1ae5ca7 100644 --- a/src/crepe/system/RenderSystem.cpp +++ b/src/crepe/system/RenderSystem.cpp @@ -27,7 +27,7 @@ void RenderSystem::update_camera() { } bool RenderSystem::render_particle(const Sprite & sprite, - Transform tm) { + const double & scale) { ComponentManager & mgr = this->component_manager; SDLContext & render = SDLContext::get_instance(); @@ -44,9 +44,7 @@ bool RenderSystem::render_particle(const Sprite & sprite, for (const Particle & p : em.data.particles) { if (!p.active) continue; - tm.position = p.position; - tm.rotation = p.angle; - render.draw(em.data.sprite, tm, *curr_cam); + render.draw_particle(sprite, p.position, p.angle, scale, *this->curr_cam); } } return rendering_particles; @@ -68,7 +66,7 @@ void RenderSystem::render() { if (!sprite.active) continue; auto transform = mgr.get_components_by_id(sprite.game_object_id).front().get(); - bool rendered_particles = this->render_particle(sprite, transform); + bool rendered_particles = this->render_particle(sprite, transform.scale); if (rendered_particles) continue; diff --git a/src/crepe/system/RenderSystem.h b/src/crepe/system/RenderSystem.h index c18b80b..6643084 100644 --- a/src/crepe/system/RenderSystem.h +++ b/src/crepe/system/RenderSystem.h @@ -5,6 +5,7 @@ #include "api/Transform.h" #include "System.h" +#include namespace crepe { @@ -51,7 +52,7 @@ private: * \param tm the Transform component for scale * \return true if particles have been rendered */ - bool render_particle(const Sprite &, Transform tm); + bool render_particle(const Sprite &, const double & scale); /** * \brief renders a sprite with a Transform component on the screen diff --git a/src/example/rendering_particle.cpp b/src/example/rendering_particle.cpp index 33013ef..71b50ba 100644 --- a/src/example/rendering_particle.cpp +++ b/src/example/rendering_particle.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -21,7 +20,11 @@ using namespace crepe; using namespace std; int main(int argc, char * argv[]) { - GameObject game_object(0, "", "", Vector2{100, 100}, 0, 0.1); + ComponentManager mgr; + GameObject game_object = mgr.new_object("", "", Vector2{100, 100}, 0, 0.1); + RenderSystem sys{mgr}; + ParticleSystem psys{mgr}; + Color color(255, 255, 255, 255); Sprite test_sprite = game_object.add_component( make_shared("../asset/texture/img.png"), color, @@ -47,11 +50,9 @@ int main(int argc, char * argv[]) { }); game_object.add_component(Color::get_white()); - auto & sys = crepe::RenderSystem::get_instance(); - auto sys_part = crepe::ParticleSystem(); auto start = std::chrono::steady_clock::now(); while (std::chrono::steady_clock::now() - start < std::chrono::seconds(5)) { - sys_part.update(); + psys.update(); sys.update(); SDL_Delay(10 ); } -- cgit v1.2.3 From 5121e95e5ba98ca5cadfb63b7603731dfb41a322 Mon Sep 17 00:00:00 2001 From: heavydemon21 Date: Wed, 20 Nov 2024 11:53:17 +0100 Subject: implemented feedback --- makefile | 2 +- mwe/events/include/event.h | 2 +- src/crepe/api/Sprite.h | 3 ++- src/crepe/facade/SDLContext.h | 1 - src/crepe/system/RenderSystem.cpp | 15 +++++++-------- src/crepe/system/RenderSystem.h | 20 +++++++++++--------- 6 files changed, 22 insertions(+), 21 deletions(-) (limited to 'src/crepe/facade') diff --git a/makefile b/makefile index dd7c587..32e68c0 100644 --- a/makefile +++ b/makefile @@ -6,5 +6,5 @@ doxygen: Doxyfile FORCE FMT += $(shell git ls-files '*.c' '*.cpp' '*.h' '*.hpp') format: FORCE clang-format -i $(FMT) - $(MAKE) -C src $@ + #$(MAKE) -C src $@ diff --git a/mwe/events/include/event.h b/mwe/events/include/event.h index ee1bf52..e1b220b 100644 --- a/mwe/events/include/event.h +++ b/mwe/events/include/event.h @@ -148,7 +148,7 @@ private: }; class ShutDownEvent : public Event { public: - ShutDownEvent() : Event("ShutDownEvent") {}; + ShutDownEvent() : Event("ShutDownEvent"){}; REGISTER_EVENT_TYPE(ShutDownEvent) diff --git a/src/crepe/api/Sprite.h b/src/crepe/api/Sprite.h index 0192793..74a55d4 100644 --- a/src/crepe/api/Sprite.h +++ b/src/crepe/api/Sprite.h @@ -2,8 +2,9 @@ #include +#include "../Component.h" + #include "Color.h" -#include "Component.h" #include "Texture.h" namespace crepe { diff --git a/src/crepe/facade/SDLContext.h b/src/crepe/facade/SDLContext.h index d437bc4..652a83e 100644 --- a/src/crepe/facade/SDLContext.h +++ b/src/crepe/facade/SDLContext.h @@ -21,7 +21,6 @@ namespace crepe { // typedef is unusable when crepe is packaged. Wouter will fix this later. typedef SDL_Keycode CREPE_KEYCODES; - /** * \class SDLContext * \brief Facade for the SDL library diff --git a/src/crepe/system/RenderSystem.cpp b/src/crepe/system/RenderSystem.cpp index 82257c4..96c5f27 100644 --- a/src/crepe/system/RenderSystem.cpp +++ b/src/crepe/system/RenderSystem.cpp @@ -12,10 +12,11 @@ #include "RenderSystem.h" using namespace crepe; +using namespace std; -void RenderSystem::clear_screen() const { SDLContext::get_instance().clear_screen(); } +void RenderSystem::clear_screen() { this->context.clear_screen(); } -void RenderSystem::present_screen() const { SDLContext::get_instance().present_screen(); } +void RenderSystem::present_screen() { this->context.present_screen(); } void RenderSystem::update_camera() { ComponentManager & mgr = this->component_manager; @@ -24,7 +25,7 @@ void RenderSystem::update_camera() { if (cameras.size() == 0) throw std::runtime_error("No cameras in current scene"); for (Camera & cam : cameras) { - SDLContext::get_instance().camera(cam); + this->context.camera(cam); this->curr_cam_ref = &cam; } } @@ -47,14 +48,12 @@ RenderSystem::sort(std::vector> & objs) { void RenderSystem::render_sprites() { ComponentManager & mgr = this->component_manager; + vector> sprites = mgr.get_components_by_type(); + vector> sorted_sprites = this->sort(sprites); - auto sprites = mgr.get_components_by_type(); - auto sorted_sprites = this->sort(sprites); - - SDLContext & render = SDLContext::get_instance(); for (const Sprite & sprite : sorted_sprites) { auto transforms = mgr.get_components_by_id(sprite.game_object_id); - render.draw(sprite, transforms[0], *this->curr_cam_ref); + this->context.draw(sprite, transforms[0], *this->curr_cam_ref); } } diff --git a/src/crepe/system/RenderSystem.h b/src/crepe/system/RenderSystem.h index 1176b06..8914b96 100644 --- a/src/crepe/system/RenderSystem.h +++ b/src/crepe/system/RenderSystem.h @@ -1,23 +1,23 @@ #pragma once - #include #include -#include "api/Sprite.h" -#include "api/Camera.h" +#include "facade/SDLContext.h" #include "System.h" namespace crepe { +class Camera; +class Sprite; + /** * \class RenderSystem * \brief Manages rendering operations for all game objects. * - * RenderSystem is responsible for rendering sprites, clearing and presenting the screen, and - * managing the active camera. It functions as a singleton, providing centralized rendering - * services for the application. + * RenderSystem is responsible for rendering, clearing and presenting the screen, and + * managing the active camera. */ class RenderSystem : public System { public: @@ -30,16 +30,16 @@ public: private: //! Clears the screen in preparation for rendering. - void clear_screen() const; + void clear_screen(); //! Presents the rendered frame to the display. - void present_screen() const; + void present_screen(); //! Updates the active camera used for rendering. void update_camera(); //! Renders all active sprites to the screen. - void render_sprites() ; + void render_sprites(); std::vector> sort(std::vector> & objs); @@ -58,6 +58,8 @@ private: //! Pointer to the current active camera for rendering Camera * curr_cam_ref = nullptr; // TODO: needs a better solution + + SDLContext & context = SDLContext::get_instance(); }; } // namespace crepe -- cgit v1.2.3 From 158022890cb9abd308a6a445588cc2fca8d84e67 Mon Sep 17 00:00:00 2001 From: heavydemon21 Date: Wed, 20 Nov 2024 13:25:44 +0100 Subject: implementing feedback --- src/crepe/facade/SDLContext.cpp | 3 ++- src/crepe/facade/SDLContext.h | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src/crepe/facade') diff --git a/src/crepe/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp index 8131df2..eacb10a 100644 --- a/src/crepe/facade/SDLContext.cpp +++ b/src/crepe/facade/SDLContext.cpp @@ -149,7 +149,7 @@ void SDLContext::draw(const Sprite & sprite, const Transform & transform, const &dstrect, transform.rotation, NULL, render_flip); } -void SDLContext::camera(const Camera & cam) { +void SDLContext::set_camera(const Camera & cam) { this->viewport.w = static_cast(cam.aspect_width); this->viewport.h = static_cast(cam.aspect_height); this->viewport.x = static_cast(cam.x) - (this->viewport.w / 2); @@ -167,6 +167,7 @@ SDLContext::texture_from_path(const std::string & path) { SDL_Surface * tmp = IMG_Load(path.c_str()); if (tmp == nullptr) { tmp = IMG_Load("../asset/texture/ERROR.png"); + if (tmp == nullptr) throw runtime_error("cannot load image"); } std::unique_ptr> img_surface; diff --git a/src/crepe/facade/SDLContext.h b/src/crepe/facade/SDLContext.h index fb09015..287ad5d 100644 --- a/src/crepe/facade/SDLContext.h +++ b/src/crepe/facade/SDLContext.h @@ -125,6 +125,7 @@ private: * \param camera Reference to the Camera for view adjustments. */ void draw(const Sprite & sprite, const Transform & transform, const Camera & camera); + void draw_particle(const Sprite & sprite, const Vector2 & pos, const double & angle, const double & scale, const Camera & camera); //! Clears the screen, preparing for a new frame. @@ -134,10 +135,10 @@ private: void present_screen(); /** - * \brief Sets the current camera for rendering. + * \brief sets the background of the camera (will be adjusted in future PR) * \param camera Reference to the Camera object. */ - void camera(const Camera & camera); + void set_camera(const Camera & camera); private: /** -- cgit v1.2.3 From 3344e0df01435be903e38ccbd3b9cee608d574e7 Mon Sep 17 00:00:00 2001 From: heavydemon21 Date: Wed, 20 Nov 2024 14:06:54 +0100 Subject: implemented feedback --- src/crepe/facade/SDLContext.cpp | 18 +++++++++--------- src/crepe/facade/SDLContext.h | 10 ++++++---- src/crepe/system/RenderSystem.cpp | 18 +++++++++--------- src/crepe/system/RenderSystem.h | 14 ++++---------- src/example/rendering_particle.cpp | 14 ++++++-------- 5 files changed, 34 insertions(+), 40 deletions(-) (limited to 'src/crepe/facade') diff --git a/src/crepe/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp index eacb10a..daf0050 100644 --- a/src/crepe/facade/SDLContext.cpp +++ b/src/crepe/facade/SDLContext.cpp @@ -12,12 +12,12 @@ #include #include +#include "../api/Camera.h" #include "../api/Sprite.h" #include "../api/Texture.h" #include "../api/Transform.h" +#include "../api/Vector2.h" #include "../util/Log.h" -#include "api/Camera.h" -#include "api/Vector2.h" #include "SDLContext.h" @@ -96,8 +96,7 @@ void SDLContext::handle_events(bool & running) { void SDLContext::clear_screen() { SDL_RenderClear(this->game_renderer.get()); } void SDLContext::present_screen() { SDL_RenderPresent(this->game_renderer.get()); } - -SDL_Rect SDLContext::get_src_rect(const Sprite & sprite) { +SDL_Rect SDLContext::get_src_rect(const Sprite & sprite) const { return SDL_Rect{ .x = sprite.sprite_rect.x, .y = sprite.sprite_rect.y, @@ -106,7 +105,7 @@ SDL_Rect SDLContext::get_src_rect(const Sprite & sprite) { }; } SDL_Rect SDLContext::get_dst_rect(const Sprite & sprite, const Vector2 & pos, - const double & scale, const Camera & cam) { + const double & scale, const Camera & cam) const { double adjusted_x = (pos.x - cam.x) * cam.zoom; double adjusted_y = (pos.y - cam.y) * cam.zoom; @@ -123,20 +122,21 @@ SDL_Rect SDLContext::get_dst_rect(const Sprite & sprite, const Vector2 & pos, void SDLContext::draw_particle(const Sprite & sprite, const Vector2 & pos, const double & angle, const double & scale, - const Camera & camera) { + const Camera & camera) const { SDL_RendererFlip render_flip = (SDL_RendererFlip) ((SDL_FLIP_HORIZONTAL * sprite.flip.flip_x) - | (SDL_FLIP_VERTICAL * sprite.flip.flip_y)); + | (SDL_FLIP_VERTICAL * sprite.flip.flip_y)); SDL_Rect srcrect = this->get_src_rect(sprite); SDL_Rect dstrect = this->get_dst_rect(sprite, pos, scale, camera); SDL_RenderCopyEx(this->game_renderer.get(), sprite.sprite_image->texture.get(), &srcrect, - &dstrect, angle, NULL, render_flip); + &dstrect, angle, NULL, render_flip); } -void SDLContext::draw(const Sprite & sprite, const Transform & transform, const Camera & cam) { +void SDLContext::draw(const Sprite & sprite, const Transform & transform, + const Camera & cam) const { SDL_RendererFlip render_flip = (SDL_RendererFlip) ((SDL_FLIP_HORIZONTAL * sprite.flip.flip_x) diff --git a/src/crepe/facade/SDLContext.h b/src/crepe/facade/SDLContext.h index 287ad5d..718c40f 100644 --- a/src/crepe/facade/SDLContext.h +++ b/src/crepe/facade/SDLContext.h @@ -124,9 +124,10 @@ private: * \param transform Reference to the Transform for positioning. * \param camera Reference to the Camera for view adjustments. */ - void draw(const Sprite & sprite, const Transform & transform, const Camera & camera); + void draw(const Sprite & sprite, const Transform & transform, const Camera & camera) const; - void draw_particle(const Sprite & sprite, const Vector2 & pos, const double & angle, const double & scale, const Camera & camera); + void draw_particle(const Sprite & sprite, const Vector2 & pos, const double & angle, + const double & scale, const Camera & camera) const; //! Clears the screen, preparing for a new frame. void clear_screen(); @@ -147,7 +148,7 @@ private: * \param sprite Reference to the sprite to calculate the rectangle * \return sdl rectangle to draw a src image */ - SDL_Rect get_src_rect(const Sprite & sprite); + SDL_Rect get_src_rect(const Sprite & sprite) const; /** * \brief calculates the sqaure size of the image for an destination * @@ -158,7 +159,8 @@ private: * on the camera * \return sdl rectangle to draw a dst image to draw on the screen */ - SDL_Rect get_dst_rect(const Sprite & sprite, const Vector2 & pos, const double & scale, const Camera & cam); + SDL_Rect get_dst_rect(const Sprite & sprite, const Vector2 & pos, const double & scale, + const Camera & cam) const; private: //! sdl Window diff --git a/src/crepe/system/RenderSystem.cpp b/src/crepe/system/RenderSystem.cpp index 1ae5ca7..28bcf56 100644 --- a/src/crepe/system/RenderSystem.cpp +++ b/src/crepe/system/RenderSystem.cpp @@ -2,11 +2,11 @@ #include #include "../ComponentManager.h" +#include "../api/ParticleEmitter.h" #include "../api/Sprite.h" #include "../api/Transform.h" -#include "../facade/SDLContext.h" -#include "../api/ParticleEmitter.h" #include "../api/Vector2.h" +#include "../facade/SDLContext.h" #include "RenderSystem.h" @@ -21,13 +21,12 @@ void RenderSystem::update_camera() { auto cameras = mgr.get_components_by_type(); for (Camera & cam : cameras) { - SDLContext::get_instance().camera(cam); + SDLContext::get_instance().set_camera(cam); this->curr_cam = &cam; } } -bool RenderSystem::render_particle(const Sprite & sprite, - const double & scale) { +bool RenderSystem::render_particle(const Sprite & sprite, const double & scale) const { ComponentManager & mgr = this->component_manager; SDLContext & render = SDLContext::get_instance(); @@ -49,22 +48,23 @@ bool RenderSystem::render_particle(const Sprite & sprite, } return rendering_particles; } -void RenderSystem::render_normal(const Sprite & sprite, const Transform & tm) { +void RenderSystem::render_normal(const Sprite & sprite, const Transform & tm) const { ComponentManager & mgr = this->component_manager; SDLContext & render = SDLContext::get_instance(); - + render.draw(sprite, tm, *curr_cam); } -void RenderSystem::render() { +void RenderSystem::render() const { ComponentManager & mgr = this->component_manager; auto sprites = mgr.get_components_by_type(); for (const Sprite & sprite : sprites) { if (!sprite.active) continue; - auto transform = mgr.get_components_by_id(sprite.game_object_id).front().get(); + const Transform & transform + = mgr.get_components_by_id(sprite.game_object_id).front().get(); bool rendered_particles = this->render_particle(sprite, transform.scale); diff --git a/src/crepe/system/RenderSystem.h b/src/crepe/system/RenderSystem.h index 6643084..8841f72 100644 --- a/src/crepe/system/RenderSystem.h +++ b/src/crepe/system/RenderSystem.h @@ -25,13 +25,7 @@ public: * This method is called to perform all rendering operations for the current game frame. */ void update() override; - - - RenderSystem(const RenderSystem &) = delete; - RenderSystem(RenderSystem &&) = delete; - RenderSystem & operator=(const RenderSystem &) = delete; - RenderSystem & operator=(RenderSystem &&) = delete; - + private: //! Clears the screen in preparation for rendering. void clear_screen() const; @@ -43,7 +37,7 @@ private: void update_camera(); //! Renders the whole screen - void render(); + void render() const; /** * \brief Renders all the particles on the screen from a given sprite. @@ -52,7 +46,7 @@ private: * \param tm the Transform component for scale * \return true if particles have been rendered */ - bool render_particle(const Sprite &, const double & scale); + bool render_particle(const Sprite & sprite, const double & scale) const; /** * \brief renders a sprite with a Transform component on the screen @@ -60,7 +54,7 @@ private: * \param sprite the sprite component that holds all the data * \param tm the Transform component that holds the position,rotation and scale */ - void render_normal(const Sprite &, const Transform & tm); + void render_normal(const Sprite & sprite, const Transform & tm) const; /** * \todo Include color handling for sprites. diff --git a/src/example/rendering_particle.cpp b/src/example/rendering_particle.cpp index 71b50ba..3f71750 100644 --- a/src/example/rendering_particle.cpp +++ b/src/example/rendering_particle.cpp @@ -4,15 +4,15 @@ #include #include +#include #include #include #include +#include #include #include -#include -#include -#include #include +#include #include @@ -20,15 +20,14 @@ using namespace crepe; using namespace std; int main(int argc, char * argv[]) { - ComponentManager mgr; + ComponentManager mgr; GameObject game_object = mgr.new_object("", "", Vector2{100, 100}, 0, 0.1); RenderSystem sys{mgr}; ParticleSystem psys{mgr}; Color color(255, 255, 255, 255); Sprite test_sprite = game_object.add_component( - make_shared("../asset/texture/img.png"), color, - FlipSettings{false, false}); + make_shared("../asset/texture/img.png"), color, FlipSettings{false, false}); game_object.add_component(ParticleEmitter::Data{ .position = {0, 0}, .max_particles = 10, @@ -54,9 +53,8 @@ int main(int argc, char * argv[]) { while (std::chrono::steady_clock::now() - start < std::chrono::seconds(5)) { psys.update(); sys.update(); - SDL_Delay(10 ); + SDL_Delay(10); } return 0; } - -- cgit v1.2.3 From ce14236bd08469737185962d0be11d72c442b60e Mon Sep 17 00:00:00 2001 From: WBoerenkamps Date: Wed, 20 Nov 2024 15:39:27 +0100 Subject: most tests done --- src/crepe/api/Event.h | 12 +- src/crepe/api/EventHandler.cpp | 3 +- src/crepe/api/EventHandler.h | 6 +- src/crepe/api/EventHandler.hpp | 8 +- src/crepe/api/EventManager.cpp | 11 +- src/crepe/api/EventManager.h | 32 ++- src/crepe/api/EventManager.hpp | 24 +- src/crepe/api/IKeyListener.cpp | 35 +-- src/crepe/api/IKeyListener.h | 21 +- src/crepe/api/IMouseListener.cpp | 34 +-- src/crepe/api/IMouseListener.h | 22 +- src/crepe/facade/SDLContext.cpp | 1 - src/example/events.cpp | 74 +++--- src/test/CMakeLists.txt | 1 + src/test/EventTest.cpp | 470 +++++++++++++++++++++++++++++++++++++++ 15 files changed, 584 insertions(+), 170 deletions(-) create mode 100644 src/test/EventTest.cpp (limited to 'src/crepe/facade') diff --git a/src/crepe/api/Event.h b/src/crepe/api/Event.h index d5ddf0a..33f3add 100644 --- a/src/crepe/api/Event.h +++ b/src/crepe/api/Event.h @@ -7,17 +7,15 @@ /** * \brief Base class for all event types in the system. */ -class Event { -public: -}; +class Event {}; /** * \brief Event triggered when a key is pressed. */ class KeyPressEvent : public Event { public: - //! Number of times the key press is repeated (e.g., for long presses). - int repeat = 0; + //! false if first time press, true if key is repeated + bool repeat = false; //! The key that was pressed. Keycode key = Keycode::NONE; @@ -110,6 +108,4 @@ public: /** * \brief Event triggered to indicate the application is shutting down. */ -class ShutDownEvent : public Event { -public: -}; +class ShutDownEvent : public Event {}; diff --git a/src/crepe/api/EventHandler.cpp b/src/crepe/api/EventHandler.cpp index 186ec9c..4dc232f 100644 --- a/src/crepe/api/EventHandler.cpp +++ b/src/crepe/api/EventHandler.cpp @@ -2,5 +2,4 @@ using namespace crepe; -// Implementation of IEventHandlerWrapper::exec -bool IEventHandlerWrapper::exec(const Event & e) { return call(e); } +bool IEventHandlerWrapper::exec(const Event & e) { return this->call(e); } diff --git a/src/crepe/api/EventHandler.h b/src/crepe/api/EventHandler.h index db51d04..90886aa 100644 --- a/src/crepe/api/EventHandler.h +++ b/src/crepe/api/EventHandler.h @@ -13,6 +13,8 @@ namespace crepe { * indicating whether the event is handled. * * \tparam EventType The type of event this handler will handle. + * + * Returning \c false from an event handler results in the event being propogated to other listeners for the same event type, while returning \c true stops propogation altogether. */ template using EventHandler = std::function; @@ -105,9 +107,9 @@ private: std::string get_type() const override; //! The event handler function. - EventHandler m_handler; + EventHandler handler; //! The type name of the handler function. - const std::string m_handler_type; + const std::string handler_type; }; } // namespace crepe diff --git a/src/crepe/api/EventHandler.hpp b/src/crepe/api/EventHandler.hpp index 9c47da2..a1e774d 100644 --- a/src/crepe/api/EventHandler.hpp +++ b/src/crepe/api/EventHandler.hpp @@ -8,19 +8,19 @@ namespace crepe { // Implementation of EventHandlerWrapper constructor template EventHandlerWrapper::EventHandlerWrapper(const EventHandler & handler) - : m_handler(handler), - m_handler_type(m_handler.target_type().name()) {} + : handler(handler), + handler_type(handler.target_type().name()) {} // Implementation of EventHandlerWrapper::call template bool EventHandlerWrapper::call(const Event & e) { - return m_handler(static_cast(e)); + return this->handler(static_cast(e)); } // Implementation of EventHandlerWrapper::get_type template std::string EventHandlerWrapper::get_type() const { - return m_handler_type; + return this->handler_type; } } //namespace crepe diff --git a/src/crepe/api/EventManager.cpp b/src/crepe/api/EventManager.cpp index b465e89..27a304f 100644 --- a/src/crepe/api/EventManager.cpp +++ b/src/crepe/api/EventManager.cpp @@ -13,9 +13,9 @@ void EventManager::dispatch_events() { using HandlersVec = std::vector>; for (auto event_it = this->events_queue.begin(); event_it != this->events_queue.end();) { - std::unique_ptr & event = std::get<0>(*event_it); - int channel = std::get<1>(*event_it); - std::type_index event_type = std::get<2>(*event_it); + std::unique_ptr & event = (*event_it).event; + int channel = (*event_it).channel; + std::type_index event_type = (*event_it).type; bool event_handled = false; @@ -58,3 +58,8 @@ void EventManager::dispatch_events() { } } } +void EventManager::clear(){ + this->subscribers.clear(); + this->events_queue.clear(); + this->subscribers_by_event_id.clear(); +} diff --git a/src/crepe/api/EventManager.h b/src/crepe/api/EventManager.h index 92273df..8fd22f4 100644 --- a/src/crepe/api/EventManager.h +++ b/src/crepe/api/EventManager.h @@ -11,7 +11,7 @@ #include "EventHandler.h" namespace crepe { - +static constexpr int CHANNEL_ALL = -1; /** * \class EventManager * \brief The EventManager class is responsible for managing the subscription, triggering, @@ -19,6 +19,7 @@ namespace crepe { */ class EventManager { public: + /** * \brief Get the singleton instance of the EventManager. * @@ -38,7 +39,7 @@ public: * \param channel The channel number to subscribe to (default is 0). */ template - void subscribe(EventHandler && callback, int channel = 0); + void subscribe(const EventHandler & callback, int channel = CHANNEL_ALL, int priority = 0); /** * \brief Unsubscribe from an event. @@ -50,7 +51,7 @@ public: * \param channel The event ID to unsubscribe from. */ template - void unsubscribe(const EventHandler &, int channel = 0); + void unsubscribe(const EventHandler &, int channel = CHANNEL_ALL); /** * \brief Trigger an event. @@ -62,7 +63,7 @@ public: * \param channel The channel from which to trigger the event (default is 0). */ template - void trigger_event(const EventType & event, int channel = 0); + void trigger_event(const EventType & event, int channel = CHANNEL_ALL); /** * \brief Queue an event for later processing. @@ -75,7 +76,7 @@ public: * \param channel The channel number for the event (default is 0). */ template - void queue_event(EventType && event, int channel = 0); + void queue_event(const EventType & event, int channel = CHANNEL_ALL,int priority = 0); /** * \brief Dispatch all queued events. @@ -84,8 +85,24 @@ public: * callbacks for each event. */ void dispatch_events(); - + /** + * \brief clears all subscribers + * + */ + void clear(); private: + struct QueueEntry { + std::unique_ptr event; + int channel = 0; + std::type_index type; + int priority = 0; + }; + struct CallbackEntry { + std::unique_ptr callback; + int channel = 0; + std::type_index type; + int priority = 0; + }; /** * \brief Default constructor for the EventManager. * @@ -94,7 +111,7 @@ private: EventManager() = default; //! The queue of events to be processed. - std::vector, int, std::type_index>> events_queue; + std::vector events_queue; //! Registered event handlers. std::unordered_map>> subscribers; @@ -103,6 +120,7 @@ private: std::type_index, std::unordered_map>>> subscribers_by_event_id; + }; } // namespace crepe diff --git a/src/crepe/api/EventManager.hpp b/src/crepe/api/EventManager.hpp index b20b88f..9090a3f 100644 --- a/src/crepe/api/EventManager.hpp +++ b/src/crepe/api/EventManager.hpp @@ -3,7 +3,7 @@ namespace crepe { template -void EventManager::subscribe(EventHandler && callback, int channel) { +void EventManager::subscribe(const EventHandler & callback, int channel, int priority) { using HandlersMap = std::unordered_map>>; using HandlersVec = std::vector>; @@ -27,14 +27,20 @@ void EventManager::subscribe(EventHandler && callback, int channel) { } template -void EventManager::queue_event(EventType && event, int channel) { - std::type_index event_type = std::type_index(typeid(EventType)); +void EventManager::queue_event(const EventType & event, int channel,int priority) { + static_assert(std::is_base_of::value, "EventType must derive from Event"); + std::type_index event_type = typeid(EventType); - auto event_ptr = std::make_unique(std::forward(event)); + auto event_ptr = std::make_unique(event); - std::tuple, int, std::type_index> tuple(std::move(event_ptr), - channel, event_type); - this->events_queue.push_back(std::move(tuple)); + + this->events_queue.push_back( + QueueEntry{ + .event = std::move(event_ptr), + .channel = channel, + .type = event_type + } + ); } template @@ -43,7 +49,7 @@ void EventManager::trigger_event(const EventType & event, int channel) { = std::unordered_map>>; using HandlersVec = std::vector>; - std::type_index event_type = std::type_index(typeid(EventType)); + std::type_index event_type = typeid(EventType); if (channel > 0) { HandlersMap & handlers_map = this->subscribers_by_event_id[event_type]; @@ -75,7 +81,7 @@ void EventManager::unsubscribe(const EventHandler & callback, int cha = std::unordered_map>>; using HandlersVec = std::vector>; - std::type_index event_type(typeid(EventType)); + std::type_index event_type = typeid(EventType); std::string handler_name = callback.target_type().name(); if (channel) { diff --git a/src/crepe/api/IKeyListener.cpp b/src/crepe/api/IKeyListener.cpp index f5426be..5e7d9bb 100644 --- a/src/crepe/api/IKeyListener.cpp +++ b/src/crepe/api/IKeyListener.cpp @@ -2,13 +2,6 @@ using namespace crepe; -// Constructor with default channel -IKeyListener::IKeyListener() - : channel(0), - active(true), - event_manager(EventManager::get_instance()) { - this->subscribe_events(); -} // Constructor with specified channel IKeyListener::IKeyListener(int channel) @@ -28,9 +21,9 @@ void IKeyListener::subscribe_events() { key_released_handler = [this](const KeyReleaseEvent & event) { return this->on_key_released(event); }; - event_manager.subscribe(std::move(this->key_pressed_handler), + event_manager.subscribe(this->key_pressed_handler, this->channel); - event_manager.subscribe(std::move(this->key_released_handler), + event_manager.subscribe(this->key_released_handler, this->channel); } @@ -40,27 +33,3 @@ void IKeyListener::unsubscribe_events() { event_manager.unsubscribe(this->key_released_handler, this->channel); } -// Activate key listening -void IKeyListener::activate_keys() { - if (this->active) { - return; - } - this->active = true; - this->subscribe_events(); -} - -// Deactivate key listening -void IKeyListener::deactivate_keys() { - if (!this->active) { - return; - } - this->active = false; - this->unsubscribe_events(); -} - -// Set a new channel for key events -void IKeyListener::set_channel(int channel) { - this->unsubscribe_events(); - this->channel = channel; - this->subscribe_events(); -} diff --git a/src/crepe/api/IKeyListener.h b/src/crepe/api/IKeyListener.h index d492387..70243b4 100644 --- a/src/crepe/api/IKeyListener.h +++ b/src/crepe/api/IKeyListener.h @@ -16,11 +16,11 @@ public: * \brief Constructs an IKeyListener with a specified channel. * \param channel The channel ID for event handling. */ - IKeyListener(int channel); - IKeyListener(); + IKeyListener(int channel = CHANNEL_ALL); virtual ~IKeyListener(); IKeyListener(const IKeyListener &) = delete; IKeyListener & operator=(const IKeyListener &) = delete; + IKeyListener & operator=(IKeyListener &&) = delete; IKeyListener(IKeyListener &&) = delete; /** @@ -36,23 +36,6 @@ public: * \return True if the event was handled, false otherwise. */ virtual bool on_key_released(const KeyReleaseEvent & event) = 0; - - /** - * \brief Activates key listening. - */ - void activate_keys(); - - /** - * \brief Deactivates key listening. - */ - void deactivate_keys(); - - /** - * \brief Sets the channel ID for event handling. - * \param channel The channel ID to set. - */ - void set_channel(int channel); - protected: /** * \brief Subscribes to key events. diff --git a/src/crepe/api/IMouseListener.cpp b/src/crepe/api/IMouseListener.cpp index 5ee2814..6fd6c4b 100644 --- a/src/crepe/api/IMouseListener.cpp +++ b/src/crepe/api/IMouseListener.cpp @@ -8,10 +8,6 @@ IMouseListener::IMouseListener(int channel) this->subscribe_events(); } -IMouseListener::IMouseListener() : event_manager(EventManager::get_instance()) { - this->subscribe_events(); -} - IMouseListener::~IMouseListener() { this->unsubscribe_events(); } void IMouseListener::subscribe_events() { @@ -26,11 +22,11 @@ void IMouseListener::subscribe_events() { = [this](const MouseMoveEvent & event) { return this->on_mouse_moved(event); }; // Subscribe event handlers (no need for std::move) - event_manager.subscribe(std::move(mouse_click_handler), this->channel); - event_manager.subscribe(std::move(mouse_press_handler), this->channel); - event_manager.subscribe(std::move(mouse_release_handler), + event_manager.subscribe(mouse_click_handler, this->channel); + event_manager.subscribe(mouse_press_handler, this->channel); + event_manager.subscribe(mouse_release_handler, this->channel); - event_manager.subscribe(std::move(mouse_move_handler), this->channel); + event_manager.subscribe(mouse_move_handler, this->channel); } void IMouseListener::unsubscribe_events() { @@ -40,25 +36,3 @@ void IMouseListener::unsubscribe_events() { event_manager.unsubscribe(mouse_release_handler, this->channel); event_manager.unsubscribe(mouse_move_handler, this->channel); } - -void IMouseListener::activate_mouse() { - if (this->active) { - return; - } - this->subscribe_events(); - this->active = true; -} - -void IMouseListener::deactivate_mouse() { - if (!this->active) { - return; - } - this->unsubscribe_events(); - this->active = false; -} - -void IMouseListener::set_channel(int channel) { - this->unsubscribe_events(); - this->channel = channel; - this->subscribe_events(); -} diff --git a/src/crepe/api/IMouseListener.h b/src/crepe/api/IMouseListener.h index 921a760..1195a4e 100644 --- a/src/crepe/api/IMouseListener.h +++ b/src/crepe/api/IMouseListener.h @@ -12,16 +12,15 @@ namespace crepe { */ class IMouseListener { public: - IMouseListener(); /** * \brief Constructs an IMouseListener with a specified channel. * \param channel The channel ID for event handling. */ - IMouseListener(int channel); + IMouseListener(int channel = CHANNEL_ALL); virtual ~IMouseListener(); IMouseListener & operator=(const IMouseListener &) = delete; IMouseListener(const IMouseListener &) = delete; - IMouseListener && operator=(const IMouseListener &&) = delete; + IMouseListener & operator=(const IMouseListener &&) = delete; IMouseListener(IMouseListener &&) = delete; /** @@ -56,23 +55,6 @@ public: * \return True if the event was handled, false otherwise. */ virtual bool on_mouse_moved(const MouseMoveEvent & event) = 0; - - /** - * \brief Activates mouse listening. - */ - void activate_mouse(); - - /** - * \brief Deactivates mouse listening. - */ - void deactivate_mouse(); - - /** - * \brief Sets the channel ID for event handling. - * \param channel The channel ID to set. - */ - void set_channel(int channel); - protected: /** * \brief Subscribes to mouse events on the specified channel. diff --git a/src/crepe/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp index 83e91f8..9464c31 100644 --- a/src/crepe/facade/SDLContext.cpp +++ b/src/crepe/facade/SDLContext.cpp @@ -78,7 +78,6 @@ SDLContext::~SDLContext() { IMG_Quit(); SDL_Quit(); } - void SDLContext::handle_events(bool & running) { //TODO: wouter i need events /* diff --git a/src/example/events.cpp b/src/example/events.cpp index 6431c67..402a857 100644 --- a/src/example/events.cpp +++ b/src/example/events.cpp @@ -2,7 +2,6 @@ #include #include -#include #include #include @@ -27,7 +26,6 @@ class MyScript : public Script, public IKeyListener, public IMouseListener { bool on_key_pressed(const KeyPressEvent & event) override { std::cout << "KeyPressed function" << std::endl; - this->deactivate_keys(); return false; } bool on_key_released(const KeyReleaseEvent & event) override { @@ -65,48 +63,60 @@ public: } }; int main() { - // two events to trigger - KeyPressEvent key_press; - key_press.key = Keycode::A; - key_press.repeat = 0; - MouseClickEvent click_event; - click_event.button = MouseButton::LEFT_MOUSE; - click_event.mouse_x = 100; - click_event.mouse_y = 200; - // queue events to test queue - EventManager::get_instance().queue_event(std::move(key_press), 0); - EventManager::get_instance().queue_event(std::move(click_event), 0); + { + // two events to trigger + KeyPressEvent key_press; + key_press.key = Keycode::A; + key_press.repeat = 0; + MouseClickEvent click_event; + click_event.button = MouseButton::LEFT_MOUSE; + click_event.mouse_x = 100; + click_event.mouse_y = 200; + // queue events to test queue + EventManager::get_instance().queue_event(key_press); + EventManager::get_instance().queue_event(click_event); TestKeyListener test_listener; - test_listener.set_channel(1); - auto obj = GameObject(0, "name", "tag", Vector2{1.2, 3.4}, 0, 1); - obj.add_component().set_script(); + //auto obj = GameObject(0, "name", "tag", Vector2{1.2, 3.4}, 0, 1); + //obj.add_component().set_script(); - ScriptSystem sys; - sys.update(); + //ScriptSystem sys; + //sys.update(); // Trigger the events while `testListener` is in scope - EventManager::get_instance().trigger_event(key_press, 1); - EventManager::get_instance().trigger_event( - MouseClickEvent{ - .mouse_x = 100, - .mouse_y = 100, - .button = MouseButton::LEFT_MOUSE, - }, - 1); + //EventManager::get_instance().trigger_event(key_press, 1); + // EventManager::get_instance().trigger_event( + // MouseClickEvent{ + // .mouse_x = 100, + // .mouse_y = 100, + // .button = MouseButton::LEFT_MOUSE, + // }, + // 1); + //EventManager::get_instance().trigger_event(click_event, 0); } // custom lambda event handler EventHandler event_handler = [](const KeyPressEvent & e) { - std::cout << "lambda test" << std::endl; + std::cout << "key lambda test" << std::endl; + return true; + }; + EventHandler event_handler2 = [](const MouseClickEvent & e) { + std::cout << "mouse lambda test" << std::endl; return false; }; - EventManager::get_instance().subscribe(std::move(event_handler), 0); + EventManager::get_instance().subscribe(event_handler, CHANNEL_ALL); + EventManager::get_instance().subscribe(event_handler, CHANNEL_ALL); + EventManager::get_instance().subscribe(event_handler2, CHANNEL_ALL); + EventManager::get_instance().trigger_event(KeyPressEvent{ + .repeat = false, + .key = Keycode::A + }); + //EventManager::get_instance().unsubscribe(event_handler, 0); // testing trigger with testListener not in scope (unsubscribed) - EventManager::get_instance().trigger_event(key_press, 0); - EventManager::get_instance().trigger_event(click_event, 0); + // EventManager::get_instance().trigger_event(key_press, 0); + // EventManager::get_instance().trigger_event(click_event, 0); // dispatching queued events - EventManager::get_instance().dispatch_events(); + //EventManager::get_instance().dispatch_events(); - EventManager::get_instance().unsubscribe(event_handler, 0); + EventManager::get_instance().unsubscribe(event_handler); return EXIT_SUCCESS; } diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index 49c8151..6f6ad79 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -3,5 +3,6 @@ target_sources(test_main PUBLIC PhysicsTest.cpp ScriptTest.cpp ParticleTest.cpp + EventTest.cpp ) diff --git a/src/test/EventTest.cpp b/src/test/EventTest.cpp new file mode 100644 index 0000000..19f6d2e --- /dev/null +++ b/src/test/EventTest.cpp @@ -0,0 +1,470 @@ + +#include "api/EventManager.h" +#include "api/Event.h" +#include "api/IKeyListener.h" +#include "api/IMouseListener.h" +#include +#include +#include +using namespace std; +using namespace std::chrono_literals; +using namespace crepe; + + +class EventManagerTest : public ::testing::Test { +protected: + void SetUp() override { + // Clear any existing subscriptions or events before each test + EventManager::get_instance().clear(); + } + + void TearDown() override { + // Ensure cleanup after each test + EventManager::get_instance().clear(); + } +}; +class MockKeyListener : public IKeyListener { +public: + MOCK_METHOD(bool, on_key_pressed, (const KeyPressEvent& event), (override)); + MOCK_METHOD(bool, on_key_released, (const KeyReleaseEvent& event), (override)); +}; + +class MockMouseListener : public IMouseListener { +public: + MOCK_METHOD(bool, on_mouse_clicked, (const MouseClickEvent& event), (override)); + MOCK_METHOD(bool, on_mouse_pressed, (const MousePressEvent& event), (override)); + MOCK_METHOD(bool, on_mouse_released, (const MouseReleaseEvent& event), (override)); + MOCK_METHOD(bool, on_mouse_moved, (const MouseMoveEvent& event), (override)); +}; +TEST_F(EventManagerTest, EventSubscription) { + EventHandler key_handler = [](const KeyPressEvent& e) { + std::cout << "Key Event Triggered" << std::endl; + return true; + }; + + // Subscribe to KeyPressEvent + EventManager::get_instance().subscribe(key_handler, 1); + + // Verify subscription (not directly verifiable; test by triggering event) + + EventManager::get_instance().trigger_event(KeyPressEvent{ + .repeat = true, + .key = Keycode::A, + }, 1); + EventManager::get_instance().trigger_event(KeyPressEvent{ + .repeat = true, + .key = Keycode::A, + + }, CHANNEL_ALL); + +} +TEST_F(EventManagerTest, EventManagerTest_trigger_all_channels) { + bool triggered = false; + + EventHandler mouse_handler = [&](const MouseClickEvent& e) { + triggered = true; + std::cout << "mouse handled" <(mouse_handler, CHANNEL_ALL); + + MouseClickEvent click_event{ + .mouse_x = 100, + .mouse_y = 200, + .button = MouseButton::LEFT_MOUSE + }; + EventManager::get_instance().trigger_event(click_event, CHANNEL_ALL); + + EXPECT_TRUE(triggered); +} + +TEST_F(EventManagerTest, EventManagerTest_priority_order) { + EventManager& event_manager = EventManager::get_instance(); + + // Vector to track call order + std::vector call_order; + + // Handlers with different priorities + EventHandler handler_priority_3 = [&](const MouseClickEvent& e) { + call_order.push_back(3); + return false; // Allow propagation + }; + + EventHandler handler_priority_1 = [&](const MouseClickEvent& e) { + call_order.push_back(1); + return false; // Allow propagation + }; + + EventHandler handler_priority_2 = [&](const MouseClickEvent& e) { + call_order.push_back(2); + return false; // Allow propagation + }; + + // Subscribe handlers with different priorities + event_manager.subscribe(handler_priority_1, CHANNEL_ALL, 1); + event_manager.subscribe(handler_priority_2, CHANNEL_ALL, 2); + event_manager.subscribe(handler_priority_3, CHANNEL_ALL, 3); + + // Trigger the event + event_manager.trigger_event(MouseClickEvent{ + .mouse_x = 100, + .mouse_y = 200, + .button = MouseButton::LEFT_MOUSE + }, CHANNEL_ALL); + + // Check the call order matches the expected priority order + std::vector expected_order = {3, 2, 1}; + EXPECT_EQ(call_order, expected_order); + +} + +TEST_F(EventManagerTest, EventManagerTest_callback_propagation) { + EventManager& event_manager = EventManager::get_instance(); + + // Flags to track handler calls + bool triggered_true = false; + bool triggered_false = false; + + // Handlers + EventHandler mouse_handler_true = [&](const MouseClickEvent& e) { + triggered_true = true; + EXPECT_EQ(e.mouse_x, 100); + EXPECT_EQ(e.mouse_y, 200); + EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE); + return true; // Stops propagation + }; + + EventHandler mouse_handler_false = [&](const MouseClickEvent& e) { + triggered_false = true; + EXPECT_EQ(e.mouse_x, 100); + EXPECT_EQ(e.mouse_y, 200); + EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE); + return false; // Allows propagation + }; + + // Test event + MouseClickEvent click_event{ + .mouse_x = 100, + .mouse_y = 200, + .button = MouseButton::LEFT_MOUSE + }; + + // First Scenario: True handler has higher priority + event_manager.subscribe(mouse_handler_true, CHANNEL_ALL, 1); + event_manager.subscribe(mouse_handler_false, CHANNEL_ALL, 0); + + // Trigger event + event_manager.trigger_event(click_event, CHANNEL_ALL); + + // Check that only the true handler was triggered + EXPECT_TRUE(triggered_true); + EXPECT_FALSE(triggered_false); + + // Reset and clear + triggered_true = false; + triggered_false = false; + event_manager.clear(); + + // Second Scenario: False handler has higher priority + event_manager.subscribe(mouse_handler_true, CHANNEL_ALL, 0); + event_manager.subscribe(mouse_handler_false, CHANNEL_ALL, 1); + + // Trigger event again + event_manager.trigger_event(click_event, CHANNEL_ALL); + + // Check that both handlers were triggered + EXPECT_TRUE(triggered_true); + EXPECT_TRUE(triggered_false); +} + +TEST_F(EventManagerTest, EventManagerTest_queue_dispatch) { + EventManager& event_manager = EventManager::get_instance(); + bool triggered1 = false; + bool triggered2 = false; + int test_channel = 1; + EventHandler mouse_handler1 = [&](const MouseClickEvent& e) { + triggered1 = true; + EXPECT_EQ(e.mouse_x, 100); + EXPECT_EQ(e.mouse_y, 200); + EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE); + return false; // Allows propagation + }; + EventHandler mouse_handler2 = [&](const MouseClickEvent& e) { + triggered2 = true; + EXPECT_EQ(e.mouse_x, 100); + EXPECT_EQ(e.mouse_y, 200); + EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE); + return false; // Allows propagation + }; + event_manager.subscribe(mouse_handler1); + event_manager.subscribe(mouse_handler2,test_channel); + + event_manager.queue_event(MouseClickEvent{ + .mouse_x = 100, + .mouse_y = 200, + .button = MouseButton::LEFT_MOUSE + }); + event_manager.queue_event(MouseClickEvent{ + .mouse_x = 100, + .mouse_y = 200, + .button = MouseButton::LEFT_MOUSE + },test_channel); + event_manager.dispatch_events(); + EXPECT_TRUE(triggered1); + EXPECT_TRUE(triggered2); +} + +TEST_F(EventManagerTest, EventManagerTest_dispatch_priority) { + EventManager& event_manager = EventManager::get_instance(); + std::vector call_order; + int test_channel = 1; + EventHandler mouse_handler1 = [&](const MouseClickEvent& e) { + call_order.push_back(1); + EXPECT_EQ(e.mouse_x, 100); + EXPECT_EQ(e.mouse_y, 200); + EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE); + return false; // Allows propagation + }; + EventHandler mouse_handler2 = [&](const MouseClickEvent& e) { + call_order.push_back(2); + EXPECT_EQ(e.mouse_x, 100); + EXPECT_EQ(e.mouse_y, 200); + EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE); + return false; // Allows propagation + }; + EventHandler mouse_handler3 = [&](const MouseClickEvent& e) { + call_order.push_back(3); + EXPECT_EQ(e.mouse_x, 100); + EXPECT_EQ(e.mouse_y, 200); + EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE); + return false; // Allows propagation + }; + event_manager.subscribe(mouse_handler1,CHANNEL_ALL,1); + event_manager.subscribe(mouse_handler2,CHANNEL_ALL,2); + event_manager.subscribe(mouse_handler2,CHANNEL_ALL,3); + event_manager.queue_event(MouseClickEvent{ + .mouse_x = 100, + .mouse_y = 200, + .button = MouseButton::LEFT_MOUSE + }); + event_manager.dispatch_events(); + std::vector expected_order = {3, 2, 1}; + EXPECT_EQ(call_order, expected_order); +} + +TEST_F(EventManagerTest, EventManagerTest_unsubscribe) { + EventManager& event_manager = EventManager::get_instance(); + + // Flags to track if handlers are triggered + bool triggered1 = false; + bool triggered2 = false; + + // Define EventHandlers + EventHandler mouse_handler1 = [&](const MouseClickEvent& e) { + triggered1 = true; + EXPECT_EQ(e.mouse_x, 100); + EXPECT_EQ(e.mouse_y, 200); + EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE); + return false; // Allows propagation + }; + + EventHandler mouse_handler2 = [&](const MouseClickEvent& e) { + triggered2 = true; + EXPECT_EQ(e.mouse_x, 100); + EXPECT_EQ(e.mouse_y, 200); + EXPECT_EQ(e.button, MouseButton::LEFT_MOUSE); + return false; // Allows propagation + }; + + // Subscribe handlers + event_manager.subscribe(mouse_handler1); + event_manager.subscribe(mouse_handler2); + + // Queue events + event_manager.queue_event(MouseClickEvent{ + .mouse_x = 100, + .mouse_y = 200, + .button = MouseButton::LEFT_MOUSE + }); + + // Dispatch events - both handlers should be triggered + event_manager.dispatch_events(); + EXPECT_TRUE(triggered1); // Handler 1 should be triggered + EXPECT_TRUE(triggered2); // Handler 2 should be triggered + + // Reset flags + triggered1 = false; + triggered2 = false; + + // Unsubscribe handler1 + event_manager.unsubscribe(mouse_handler1); + + // Queue the same event again + event_manager.queue_event(MouseClickEvent{ + .mouse_x = 100, + .mouse_y = 200, + .button = MouseButton::LEFT_MOUSE + }); + + // Dispatch events - only handler 2 should be triggered, handler 1 should NOT + event_manager.dispatch_events(); + EXPECT_FALSE(triggered1); // Handler 1 should NOT be triggered + EXPECT_TRUE(triggered2); // Handler 2 should be triggered + + // Reset flags + triggered2 = false; + + // Unsubscribe handler2 + event_manager.unsubscribe(mouse_handler2); + + // Queue the event again + event_manager.queue_event(MouseClickEvent{ + .mouse_x = 100, + .mouse_y = 200, + .button = MouseButton::LEFT_MOUSE + }); + + // Dispatch events - no handler should be triggered + event_manager.dispatch_events(); + EXPECT_FALSE(triggered1); // Handler 1 should NOT be triggered + EXPECT_FALSE(triggered2); // Handler 2 should NOT be triggered +} + +// TEST_F(EventManagerTest, OnKeyPressedTest) { +// MockKeyListener mock_key_listener; +// EventManager& event_manager = EventManager::get_instance(); + +// // Create the KeyPressEvent object +// KeyPressEvent key_event = KeyPressEvent{ +// .key = Keycode::A, +// .repeat = false +// }; + +// // Set up the mock expectation with direct object passing +// EXPECT_CALL(mock_key_listener, on_key_pressed(key_event)) +// .Times(1) // Expect it to be called exactly once +// .WillOnce(::testing::Return(true)); // Return value (can be true/false) + + +// // Queue the event +// event_manager.queue_event(key_event); + +// // Dispatch the event to trigger the mock +// event_manager.dispatch_events(); // Trigger event dispatch + +// // The mock will ensure the on_key_pressed method is called +// } + + + +// TEST_F(EventManagerTest, OnKeyReleaseTest) { +// MockKeyListener mock_key_listener; +// EventManager& event_manager = EventManager::get_instance(); + +// // Create the KeyPressEvent object +// KeyReleaseEvent key_event = KeyReleaseEvent{ +// .key = Keycode::A, +// }; + +// // Set up the mock expectation with direct object passing +// EXPECT_CALL(mock_key_listener, on_key_released(key_event)) +// .Times(1) // Expect it to be called exactly once +// .WillOnce(::testing::Return(true)); // Return value (can be true/false) + + +// // Queue the event +// event_manager.queue_event(key_event); + +// // Dispatch the event to trigger the mock +// event_manager.dispatch_events(); // Trigger event dispatch + +// // The mock will ensure the on_key_pressed method is called +// } + +// TEST_F(EventManagerTest, UnsubscribeEventsTest) { +// EventManager& event_manager = EventManager::get_instance(); +// KeyPressEvent key_event{ +// .key = Keycode::A, +// .repeat = false +// }; + +// // Create the mock listener +// MockKeyListener mock_key_listener; + +// // Set up the mock expectation that on_key_pressed will be called once initially +// EXPECT_CALL(mock_key_listener, on_key_pressed(key_event)) +// .Times(1) // Expect it to be called exactly once +// .WillOnce(::testing::Return(true)); // Return value (can be true/false) + +// event_manager.queue_event(key_event); +// event_manager.dispatch_events(); // Should trigger on_key_pressed once + +// // Now unsubscribe the listener +// event_manager.unsubscribe(std::bind(&MockKeyListener::on_key_pressed, &mock_key_listener, std::placeholders::_1)); + +// // Set up the expectation that on_key_pressed will NOT be called after unsubscribing +// EXPECT_CALL(mock_key_listener, on_key_pressed(key_event)) +// .Times(0); // Should not be called after unsubscribe + +// // Queue and dispatch the event again (after unsubscribe) +// event_manager.queue_event(key_event); +// event_manager.dispatch_events(); // Should NOT trigger on_key_pressed after unsubscribe +// } + +// TEST_F(EventManagerTest, OnMouseButtonPressedTest) { +// MockMouseListener mock_mouse_listener; +// EventManager& event_manager = EventManager::get_instance(); + +// // Create the MouseButtonPressEvent object +// MousePressEvent mouse_event{ +// .mouse_x = 100, +// .mouse_y = 150, +// .button = MouseButton::LEFT_MOUSE +// }; + +// // Set up the mock expectation with direct object passing +// EXPECT_CALL(mock_mouse_listener, on_mouse_pressed(mouse_event)) +// .Times(1) // Expect it to be called exactly once +// .WillOnce(::testing::Return(true)); // Return value (can be true/false) + +// // Queue the event +// event_manager.queue_event(mouse_event); + +// // Dispatch the event to trigger the mock +// event_manager.dispatch_events(); // Should trigger on_mouse_button_pressed once +// } + +// TEST_F(EventManagerTest, UnsubscribeMouseEventsTest) { +// EventManager& event_manager = EventManager::get_instance(); +// MousePressEvent mouse_event{ +// .mouse_x = 100, +// .mouse_y = 150, +// .button = MouseButton::LEFT_MOUSE +// }; + +// // Create the mock listener +// MockMouseListener mock_mouse_listener; + +// // Set up the mock expectation that on_mouse_button_pressed will be called once initially +// EXPECT_CALL(mock_mouse_listener, on_mouse_pressed(mouse_event)) +// .Times(1) // Expect it to be called exactly once +// .WillOnce(::testing::Return(true)); // Return value (can be true/false) + +// // Queue and dispatch the event (should trigger on_mouse_button_pressed) +// event_manager.queue_event(mouse_event); +// event_manager.dispatch_events(); // Should trigger on_mouse_button_pressed once + +// // Now unsubscribe the listener +// event_manager.unsubscribe(std::bind(&MockMouseListener::on_mouse_pressed, &mock_mouse_listener, std::placeholders::_1)); + +// // Set up the expectation that on_mouse_button_pressed will NOT be called after unsubscribing +// EXPECT_CALL(mock_mouse_listener, on_mouse_pressed(mouse_event)) +// .Times(0); // Should not be called after unsubscribe + +// // Queue and dispatch the event again (after unsubscribe) +// event_manager.queue_event(mouse_event); +// event_manager.dispatch_events(); // Should NOT trigger on_mouse_button_pressed after unsubscribe +// } -- cgit v1.2.3 From fdf91122ddc1fa9942c8790d2c8c845f877df11d Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Wed, 20 Nov 2024 16:46:00 +0100 Subject: convert more examples to unit tests --- src/crepe/facade/DB.cpp | 4 +-- src/crepe/facade/DB.h | 4 ++- src/example/CMakeLists.txt | 5 --- src/example/audio_internal.cpp | 56 -------------------------------- src/example/db.cpp | 30 ------------------ src/example/particles.cpp | 43 ------------------------- src/example/physics.cpp | 24 -------------- src/example/rendering.cpp | 72 ------------------------------------------ src/test/CMakeLists.txt | 1 + src/test/DBTest.cpp | 29 +++++++++++++++++ 10 files changed, 35 insertions(+), 233 deletions(-) delete mode 100644 src/example/audio_internal.cpp delete mode 100644 src/example/db.cpp delete mode 100644 src/example/particles.cpp delete mode 100644 src/example/physics.cpp delete mode 100644 src/example/rendering.cpp create mode 100644 src/test/DBTest.cpp (limited to 'src/crepe/facade') diff --git a/src/crepe/facade/DB.cpp b/src/crepe/facade/DB.cpp index d5d19dc..95cf606 100644 --- a/src/crepe/facade/DB.cpp +++ b/src/crepe/facade/DB.cpp @@ -18,8 +18,8 @@ DB::DB(const string & path) { this->db = {db, [](libdb::DB * db) { db->close(db, 0); }}; // load or create database file - ret = this->db->open(this->db.get(), NULL, path.c_str(), NULL, libdb::DB_BTREE, DB_CREATE, - 0); + const char * file = path.empty() ? NULL : path.c_str(); + ret = this->db->open(this->db.get(), NULL, file, NULL, libdb::DB_BTREE, DB_CREATE, 0); if (ret != 0) throw runtime_error(format("db->open: {}", libdb::db_strerror(ret))); // create cursor diff --git a/src/crepe/facade/DB.h b/src/crepe/facade/DB.h index 629b0eb..115c0f1 100644 --- a/src/crepe/facade/DB.h +++ b/src/crepe/facade/DB.h @@ -22,8 +22,10 @@ class DB { public: /** * \param path The path of the database (created if nonexistant) + * + * \note If \p path is empty, the database is entirely in-memory */ - DB(const std::string & path); + DB(const std::string & path = ""); virtual ~DB() = default; public: diff --git a/src/example/CMakeLists.txt b/src/example/CMakeLists.txt index f21bd24..c75a4b5 100644 --- a/src/example/CMakeLists.txt +++ b/src/example/CMakeLists.txt @@ -16,12 +16,7 @@ function(add_example target_name) add_dependencies(examples ${target_name}) endfunction() -add_example(audio_internal) -add_example(rendering) add_example(asset_manager) -add_example(physics) add_example(savemgr) -add_example(db) -add_example(particles) add_example(gameloop) diff --git a/src/example/audio_internal.cpp b/src/example/audio_internal.cpp deleted file mode 100644 index 661161a..0000000 --- a/src/example/audio_internal.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/** \file - * - * Standalone example for usage of the internal \c Sound class. - */ - -#include -#include -#include - -#include - -using namespace crepe; -using namespace std; -using namespace std::chrono_literals; -using std::make_unique; - -// Unrelated stuff that is not part of this POC -int _ = []() { - // Show dbg_trace() output - auto & cfg = Config::get_instance(); - cfg.log.level = Log::Level::TRACE; - - return 0; // satisfy compiler -}(); - -int main() { - // Load a background track (Ogg Vorbis) - auto bgm = Sound("../mwe/audio/bgm.ogg"); - // Load three short samples (WAV) - auto sfx1 = Sound("../mwe/audio/sfx1.wav"); - auto sfx2 = Sound("../mwe/audio/sfx2.wav"); - auto sfx3 = Sound("../mwe/audio/sfx3.wav"); - - // Start the background track - bgm.play(); - - // Play each sample sequentially while pausing and resuming the background track - this_thread::sleep_for(500ms); - sfx1.play(); - this_thread::sleep_for(500ms); - sfx2.play(); - bgm.pause(); - this_thread::sleep_for(500ms); - sfx3.play(); - bgm.play(); - this_thread::sleep_for(500ms); - - // Play all samples simultaniously - sfx1.play(); - sfx2.play(); - sfx3.play(); - this_thread::sleep_for(1000ms); - - // Stop all audio and exit - return EXIT_SUCCESS; -} diff --git a/src/example/db.cpp b/src/example/db.cpp deleted file mode 100644 index ee4e8fc..0000000 --- a/src/example/db.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include -#include - -using namespace crepe; -using namespace std; - -// run before main -static auto _ = []() { - auto & cfg = Config::get_instance(); - cfg.log.level = Log::Level::TRACE; - return 0; -}(); - -int main() { - dbg_trace(); - - DB db("file.db"); - - const char * test_key = "test-key"; - string test_data = "Hello world!"; - - dbg_logf("DB has key = {}", db.has(test_key)); - - db.set(test_key, test_data); - - dbg_logf("key = \"{}\"", db.get(test_key)); - - return 0; -} diff --git a/src/example/particles.cpp b/src/example/particles.cpp deleted file mode 100644 index 3d5f676..0000000 --- a/src/example/particles.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace crepe; -using namespace std; - -int main(int argc, char * argv[]) { - ComponentManager mgr{}; - GameObject game_object = mgr.new_object("", "", Vector2{0, 0}, 0, 0); - Color color(0, 0, 0, 0); - Sprite test_sprite = game_object.add_component( - make_shared("../asset/texture/img.png"), color, FlipSettings{true, true}); - game_object.add_component(ParticleEmitter::Data{ - .position = {0, 0}, - .max_particles = 100, - .emission_rate = 0, - .min_speed = 0, - .max_speed = 0, - .min_angle = 0, - .max_angle = 0, - .begin_lifespan = 0, - .end_lifespan = 0, - .force_over_time = Vector2{0, 0}, - .boundary{ - .width = 0, - .height = 0, - .offset = Vector2{0, 0}, - .reset_on_exit = false, - }, - .sprite = test_sprite, - }); - - return 0; -} diff --git a/src/example/physics.cpp b/src/example/physics.cpp deleted file mode 100644 index ad663a0..0000000 --- a/src/example/physics.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include -#include -#include -#include -#include - -using namespace crepe; -using namespace std; - -int main(int argc, char * argv[]) { - ComponentManager mgr{}; - - GameObject game_object = mgr.new_object("Name", "Tag", Vector2{0, 0}, 0, 0); - game_object.add_component(Rigidbody::Data{ - .mass = 1, - .gravity_scale = 1, - .body_type = Rigidbody::BodyType::DYNAMIC, - .constraints = {0, 0, 0}, - .use_gravity = true, - .bounce = false, - }); - return 0; -} diff --git a/src/example/rendering.cpp b/src/example/rendering.cpp deleted file mode 100644 index ecd3f6a..0000000 --- a/src/example/rendering.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include "api/Camera.h" -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -using namespace std; -using namespace crepe; - -int main() { - dbg_trace(); - - ComponentManager mgr{}; - RenderSystem sys{mgr}; - - GameObject obj = mgr.new_object("name", "tag", Vector2{0, 0}, 1, 1); - GameObject obj1 = mgr.new_object("name", "tag", Vector2{500, 0}, 1, 0.1); - GameObject obj2 = mgr.new_object("name", "tag", Vector2{800, 0}, 1, 0.1); - - // Normal adding components - { - Color color(0, 0, 0, 0); - Sprite & sprite - = obj.add_component(make_shared("../asset/texture/img.png"), - color, FlipSettings{false, false}); - sprite.sorting_in_layer = 2; - sprite.order_in_layer = 1; - obj.add_component(Color::get_red()); - } - { - Color color(0, 0, 0, 0); - Sprite & sprite = obj1.add_component( - make_shared("../asset/texture/img.png"), color, FlipSettings{true, true}); - sprite.sorting_in_layer = 2; - sprite.order_in_layer = 2; - } - - { - Color color(0, 0, 0, 0); - Sprite & sprite = obj2.add_component( - make_shared("../asset/texture/img.png"), color, FlipSettings{true, true}); - sprite.sorting_in_layer = 1; - sprite.order_in_layer = 2; - } - - /* - { - Color color(0, 0, 0, 0); - auto img = mgr.cache("../asset/texture/second.png"); - obj2.add_component(img, color, FlipSettings{true, true}); - } - */ - - sys.update(); - /* - - auto start = std::chrono::steady_clock::now(); - while (std::chrono::steady_clock::now() - start < std::chrono::seconds(5)) { - sys.update(); - } - */ -} diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index c1f935d..61dd2d9 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -6,5 +6,6 @@ target_sources(test_main PUBLIC ECSTest.cpp SceneManagerTest.cpp ValueBrokerTest.cpp + DBTest.cpp ) diff --git a/src/test/DBTest.cpp b/src/test/DBTest.cpp new file mode 100644 index 0000000..b57eba9 --- /dev/null +++ b/src/test/DBTest.cpp @@ -0,0 +1,29 @@ +#include +#include + +using namespace std; +using namespace crepe; +using namespace testing; + +class DBTest : public Test { +public: + DB db; +}; + +TEST_F(DBTest, ReadWrite) { + db.set("foo", "bar"); + EXPECT_EQ(db.get("foo"), "bar"); +} + +TEST_F(DBTest, Nonexistant) { + EXPECT_THROW(db.get("foo"), std::out_of_range); + db.set("foo", "bar"); + EXPECT_NO_THROW(db.get("foo")); +} + +TEST_F(DBTest, Has) { + EXPECT_EQ(db.has("foo"), false); + db.set("foo", "bar"); + EXPECT_EQ(db.has("foo"), true); +} + -- cgit v1.2.3 From 700892e9a2801902da31835c0069ae27da54cf4c Mon Sep 17 00:00:00 2001 From: heavydemon21 Date: Wed, 20 Nov 2024 19:21:46 +0100 Subject: implemented feedback --- src/crepe/facade/SDLContext.h | 4 ++-- src/crepe/system/RenderSystem.cpp | 11 ++++++----- src/crepe/system/RenderSystem.h | 10 +++++----- 3 files changed, 13 insertions(+), 12 deletions(-) (limited to 'src/crepe/facade') diff --git a/src/crepe/facade/SDLContext.h b/src/crepe/facade/SDLContext.h index 9a514cb..3b17c0b 100644 --- a/src/crepe/facade/SDLContext.h +++ b/src/crepe/facade/SDLContext.h @@ -118,10 +118,10 @@ private: * \param transform Reference to the Transform for positioning. * \param camera Reference to the Camera for view adjustments. */ - void draw(const Sprite & sprite, const Transform & transform, const Camera & camera) const; + void draw(const Sprite & sprite, const Transform & transform, const Camera & camera) ; void draw_particle(const Sprite & sprite, const Vector2 & pos, const double & angle, - const double & scale, const Camera & camera) const; + const double & scale, const Camera & camera) ; //! Clears the screen, preparing for a new frame. void clear_screen(); diff --git a/src/crepe/system/RenderSystem.cpp b/src/crepe/system/RenderSystem.cpp index 05b7337..e379771 100644 --- a/src/crepe/system/RenderSystem.cpp +++ b/src/crepe/system/RenderSystem.cpp @@ -18,9 +18,9 @@ using namespace crepe; using namespace std; -void RenderSystem::clear_screen() const { this->context.clear_screen(); } +void RenderSystem::clear_screen() { this->context.clear_screen(); } -void RenderSystem::present_screen() const { this->context.present_screen(); } +void RenderSystem::present_screen() { this->context.present_screen(); } void RenderSystem::update_camera() { ComponentManager & mgr = this->component_manager; @@ -29,6 +29,7 @@ void RenderSystem::update_camera() { if (cameras.size() == 0) throw std::runtime_error("No cameras in current scene"); for (Camera & cam : cameras) { + if (!cam.active) continue; this->context.set_camera(cam); this->curr_cam_ref = &cam; } @@ -57,7 +58,7 @@ void RenderSystem::update() { this->present_screen(); } -bool RenderSystem::render_particle(const Sprite & sprite, const double & scale) const { +bool RenderSystem::render_particle(const Sprite & sprite, const double & scale) { ComponentManager & mgr = this->component_manager; @@ -79,11 +80,11 @@ bool RenderSystem::render_particle(const Sprite & sprite, const double & scale) } return rendering_particles; } -void RenderSystem::render_normal(const Sprite & sprite, const Transform & tm) const { +void RenderSystem::render_normal(const Sprite & sprite, const Transform & tm) { this->context.draw(sprite, tm, *this->curr_cam_ref); } -void RenderSystem::render() const { +void RenderSystem::render() { ComponentManager & mgr = this->component_manager; vector> sprites = mgr.get_components_by_type(); diff --git a/src/crepe/system/RenderSystem.h b/src/crepe/system/RenderSystem.h index 1a11d5b..5a2af17 100644 --- a/src/crepe/system/RenderSystem.h +++ b/src/crepe/system/RenderSystem.h @@ -31,16 +31,16 @@ public: private: //! Clears the screen in preparation for rendering. - void clear_screen() const; + void clear_screen() ; //! Presents the rendered frame to the display. - void present_screen() const; + void present_screen() ; //! Updates the active camera used for rendering. void update_camera(); //! Renders the whole screen - void render() const; + void render(); /** * \brief Renders all the particles on the screen from a given sprite. @@ -49,7 +49,7 @@ private: * \param tm the Transform component for scale * \return true if particles have been rendered */ - bool render_particle(const Sprite & sprite, const double & scale) const; + bool render_particle(const Sprite & sprite, const double & scale); /** * \brief renders a sprite with a Transform component on the screen @@ -57,7 +57,7 @@ private: * \param sprite the sprite component that holds all the data * \param tm the Transform component that holds the position,rotation and scale */ - void render_normal(const Sprite & sprite, const Transform & tm) const; + void render_normal(const Sprite & sprite, const Transform & tm); /** * \brief sort a vector sprite objects with -- cgit v1.2.3 From c23c7d03522456ac580cb7acd93fbfd95d5b846d Mon Sep 17 00:00:00 2001 From: heavydemon21 Date: Wed, 20 Nov 2024 19:27:30 +0100 Subject: fixed compile warning and tested the prerequisite that user needs to set explicity and reference --- src/crepe/facade/SDLContext.cpp | 4 ++-- src/example/rendering_particle.cpp | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'src/crepe/facade') diff --git a/src/crepe/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp index daf0050..f78ec8f 100644 --- a/src/crepe/facade/SDLContext.cpp +++ b/src/crepe/facade/SDLContext.cpp @@ -122,7 +122,7 @@ SDL_Rect SDLContext::get_dst_rect(const Sprite & sprite, const Vector2 & pos, void SDLContext::draw_particle(const Sprite & sprite, const Vector2 & pos, const double & angle, const double & scale, - const Camera & camera) const { + const Camera & camera) { SDL_RendererFlip render_flip = (SDL_RendererFlip) ((SDL_FLIP_HORIZONTAL * sprite.flip.flip_x) @@ -136,7 +136,7 @@ void SDLContext::draw_particle(const Sprite & sprite, const Vector2 & pos, } void SDLContext::draw(const Sprite & sprite, const Transform & transform, - const Camera & cam) const { + const Camera & cam) { SDL_RendererFlip render_flip = (SDL_RendererFlip) ((SDL_FLIP_HORIZONTAL * sprite.flip.flip_x) diff --git a/src/example/rendering_particle.cpp b/src/example/rendering_particle.cpp index 5030bc6..4571afb 100644 --- a/src/example/rendering_particle.cpp +++ b/src/example/rendering_particle.cpp @@ -32,7 +32,8 @@ int main(int argc, char * argv[]) { Sprite & test_sprite = game_object.add_component( make_shared("../asset/texture/img.png"), color, FlipSettings{false, false}); test_sprite.order_in_layer = 5; - auto test = game_object.add_component(ParticleEmitter::Data{ + + auto & test = game_object.add_component(ParticleEmitter::Data{ .position = {0, 0}, .max_particles = 10, .emission_rate = 0.1, -- cgit v1.2.3 From 30492d9eee7ee47a42e2471dd0716044f59df705 Mon Sep 17 00:00:00 2001 From: heavydemon21 Date: Wed, 20 Nov 2024 19:30:34 +0100 Subject: make format --- src/crepe/Component.h | 8 ++++---- src/crepe/facade/SDLContext.cpp | 3 +-- src/crepe/facade/SDLContext.h | 4 ++-- src/crepe/system/RenderSystem.h | 4 ++-- 4 files changed, 9 insertions(+), 10 deletions(-) (limited to 'src/crepe/facade') diff --git a/src/crepe/Component.h b/src/crepe/Component.h index 6d405c7..dc17721 100644 --- a/src/crepe/Component.h +++ b/src/crepe/Component.h @@ -27,10 +27,10 @@ protected: //! Only the ComponentManager can create components friend class ComponentManager; - Component(const Component &) = delete; - Component(Component &&) = delete; - virtual Component & operator=(const Component &) = delete; - virtual Component & operator=(Component &&) = delete; + Component(const Component &) = delete; + Component(Component &&) = delete; + virtual Component & operator=(const Component &) = delete; + virtual Component & operator=(Component &&) = delete; public: virtual ~Component() = default; diff --git a/src/crepe/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp index f78ec8f..26a1bdc 100644 --- a/src/crepe/facade/SDLContext.cpp +++ b/src/crepe/facade/SDLContext.cpp @@ -135,8 +135,7 @@ void SDLContext::draw_particle(const Sprite & sprite, const Vector2 & pos, &dstrect, angle, NULL, render_flip); } -void SDLContext::draw(const Sprite & sprite, const Transform & transform, - const Camera & cam) { +void SDLContext::draw(const Sprite & sprite, const Transform & transform, const Camera & cam) { SDL_RendererFlip render_flip = (SDL_RendererFlip) ((SDL_FLIP_HORIZONTAL * sprite.flip.flip_x) diff --git a/src/crepe/facade/SDLContext.h b/src/crepe/facade/SDLContext.h index 3b17c0b..841ffc9 100644 --- a/src/crepe/facade/SDLContext.h +++ b/src/crepe/facade/SDLContext.h @@ -118,10 +118,10 @@ private: * \param transform Reference to the Transform for positioning. * \param camera Reference to the Camera for view adjustments. */ - void draw(const Sprite & sprite, const Transform & transform, const Camera & camera) ; + void draw(const Sprite & sprite, const Transform & transform, const Camera & camera); void draw_particle(const Sprite & sprite, const Vector2 & pos, const double & angle, - const double & scale, const Camera & camera) ; + const double & scale, const Camera & camera); //! Clears the screen, preparing for a new frame. void clear_screen(); diff --git a/src/crepe/system/RenderSystem.h b/src/crepe/system/RenderSystem.h index 5a2af17..d25a6e3 100644 --- a/src/crepe/system/RenderSystem.h +++ b/src/crepe/system/RenderSystem.h @@ -31,10 +31,10 @@ public: private: //! Clears the screen in preparation for rendering. - void clear_screen() ; + void clear_screen(); //! Presents the rendered frame to the display. - void present_screen() ; + void present_screen(); //! Updates the active camera used for rendering. void update_camera(); -- cgit v1.2.3 From b6aea9de9c9c8d86856bcd6c3b521e385bc00a69 Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Wed, 20 Nov 2024 20:19:10 +0100 Subject: nitpick #31 --- src/crepe/facade/SDLContext.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'src/crepe/facade') diff --git a/src/crepe/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp index 26a1bdc..d352ea6 100644 --- a/src/crepe/facade/SDLContext.cpp +++ b/src/crepe/facade/SDLContext.cpp @@ -33,21 +33,21 @@ SDLContext::SDLContext() { dbg_trace(); // FIXME: read window defaults from config manager - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - throw std::runtime_error("SDL could not initialize!"); + if (SDL_Init(SDL_INIT_VIDEO) != 0) { + throw runtime_error(format("SDLContext: SDL_Init error: {}", SDL_GetError())); } SDL_Window * tmp_window = SDL_CreateWindow("Crepe Game Engine", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, this->viewport.w, this->viewport.h, 0); if (!tmp_window) { - throw std::runtime_error("Window could not be created!"); + throw runtime_error(format("SDLContext: SDL_Window error: {}", SDL_GetError())); } this->game_window = {tmp_window, [](SDL_Window * window) { SDL_DestroyWindow(window); }}; SDL_Renderer * tmp_renderer = SDL_CreateRenderer(this->game_window.get(), -1, SDL_RENDERER_ACCELERATED); if (!tmp_renderer) { - throw std::runtime_error("Renderer could not be created!"); + throw runtime_error(format("SDLContext: SDL_CreateRenderer error: {}", SDL_GetError())); } this->game_renderer @@ -55,7 +55,7 @@ SDLContext::SDLContext() { int img_flags = IMG_INIT_PNG; if (!(IMG_Init(img_flags) & img_flags)) { - throw std::runtime_error("SDL_image could not initialize!"); + throw runtime_error("SDLContext: SDL_image could not initialize!"); } } @@ -164,10 +164,8 @@ std::unique_ptr> SDLContext::texture_from_path(const std::string & path) { SDL_Surface * tmp = IMG_Load(path.c_str()); - if (tmp == nullptr) { - tmp = IMG_Load("../asset/texture/ERROR.png"); - if (tmp == nullptr) throw runtime_error("cannot load image"); - } + if (tmp == nullptr) + throw runtime_error(format("SDLContext: IMG_Load error: {}", SDL_GetError())); std::unique_ptr> img_surface; img_surface = {tmp, [](SDL_Surface * surface) { SDL_FreeSurface(surface); }}; @@ -176,7 +174,7 @@ SDLContext::texture_from_path(const std::string & path) { = SDL_CreateTextureFromSurface(this->game_renderer.get(), img_surface.get()); if (tmp_texture == nullptr) { - throw runtime_error(format("Texture cannot be load from {}", path)); + throw runtime_error(format("SDLContext: Texture cannot be load from {}", path)); } std::unique_ptr> img_texture; -- cgit v1.2.3 From 8e72968e294cbc4ac6e9ff09bd94cde1775d735b Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Wed, 20 Nov 2024 21:51:30 +0100 Subject: nitpick #34 --- mwe/events/include/event.h | 2 +- src/crepe/api/EventManager.cpp | 54 +++++++++++++++++----------------------- src/crepe/api/EventManager.h | 39 +++++++++++++++++++++-------- src/crepe/api/EventManager.hpp | 36 +++++++++------------------ src/crepe/api/IKeyListener.cpp | 3 ++- src/crepe/api/IKeyListener.h | 4 +-- src/crepe/api/IMouseListener.cpp | 3 ++- src/crepe/api/IMouseListener.h | 2 +- src/crepe/facade/SDLContext.cpp | 3 ++- src/example/CMakeLists.txt | 6 ----- src/test/DBTest.cpp | 3 +-- src/test/ValueBrokerTest.cpp | 5 ++-- 12 files changed, 77 insertions(+), 83 deletions(-) (limited to 'src/crepe/facade') diff --git a/mwe/events/include/event.h b/mwe/events/include/event.h index e1b220b..ee1bf52 100644 --- a/mwe/events/include/event.h +++ b/mwe/events/include/event.h @@ -148,7 +148,7 @@ private: }; class ShutDownEvent : public Event { public: - ShutDownEvent() : Event("ShutDownEvent"){}; + ShutDownEvent() : Event("ShutDownEvent") {}; REGISTER_EVENT_TYPE(ShutDownEvent) diff --git a/src/crepe/api/EventManager.cpp b/src/crepe/api/EventManager.cpp index 993db86..20f0dd3 100644 --- a/src/crepe/api/EventManager.cpp +++ b/src/crepe/api/EventManager.cpp @@ -1,6 +1,7 @@ #include "EventManager.h" using namespace crepe; +using namespace std; EventManager & EventManager::get_instance() { static EventManager instance; @@ -8,30 +9,23 @@ EventManager & EventManager::get_instance() { } void EventManager::dispatch_events() { - for (auto event_it = this->events_queue.begin(); event_it != this->events_queue.end();) { - std::unique_ptr & event = (*event_it).event; - int channel = (*event_it).channel; - std::type_index event_type = (*event_it).type; - - bool event_handled = false; - auto handlers_it = this->subscribers.find(event_type); - if (handlers_it == this->subscribers.end()) { - continue; - } - std::vector & handlers = handlers_it->second; - - for (auto handler_it = handlers.begin(); handler_it != handlers.end(); ++handler_it) { - // If callback is executed and returns true, remove the event from the queue - if ((*handler_it).callback->exec(*event)) { - event_it = this->events_queue.erase(event_it); - event_handled = true; - break; - } - } + for (auto & event : this->events_queue) { + this->handle_event(event.type, event.channel, *event.event.get()); + } + this->events_queue.clear(); +} - if (!event_handled) { - ++event_it; - } +void EventManager::handle_event(type_index type, event_channel_t channel, const Event & data) { + auto handlers_it = this->subscribers.find(type); + if (handlers_it == this->subscribers.end()) return; + + vector & handlers = handlers_it->second; + for (auto & handler : handlers) { + bool check_channel = handler.channel != CHANNEL_ALL || channel != CHANNEL_ALL; + if (check_channel && handler.channel != channel) continue; + + bool handled = handler.callback->exec(data); + if (handled) return; } } @@ -40,15 +34,13 @@ void EventManager::clear() { this->events_queue.clear(); } -void EventManager::unsubscribe(subscription_t event_id) { +void EventManager::unsubscribe(subscription_t id) { for (auto & [event_type, handlers] : this->subscribers) { - for (auto it = handlers.begin(); it != handlers.end();) { - if (it->id == event_id) { - it = handlers.erase(it); - return; - } else { - ++it; - } + for (auto it = handlers.begin(); it != handlers.end(); it++) { + // find listener with subscription id + if ((*it).id != id) continue; + it = handlers.erase(it); + return; } } } diff --git a/src/crepe/api/EventManager.h b/src/crepe/api/EventManager.h index bd9772a..348a04d 100644 --- a/src/crepe/api/EventManager.h +++ b/src/crepe/api/EventManager.h @@ -1,8 +1,6 @@ #pragma once -#include #include -#include #include #include #include @@ -11,8 +9,17 @@ #include "EventHandler.h" namespace crepe { -//! typedef for subscription value -typedef int subscription_t; + +//! Event listener unique ID +typedef size_t subscription_t; + +/** + * \brief Event channel + * + * Events can be sent to a specific channel, which prevents listeners on other channels from + * being called. The default channel is EventManager::CHANNEL_ALL, which calls all listeners. + */ +typedef size_t event_channel_t; /** * \class EventManager @@ -24,7 +31,7 @@ typedef int subscription_t; */ class EventManager { public: - static constexpr int CHANNEL_ALL = -1; + static constexpr const event_channel_t CHANNEL_ALL = -1; /** * \brief Get the singleton instance of the EventManager. @@ -49,7 +56,7 @@ public: */ template subscription_t subscribe(const EventHandler & callback, - int channel = CHANNEL_ALL); + event_channel_t channel = CHANNEL_ALL); /** * \brief Unsubscribe a previously registered callback. @@ -70,7 +77,7 @@ public: * \param channel The channel to trigger the event on (default is CHANNEL_ALL, which triggers on all channels). */ template - void trigger_event(const EventType & event, int channel = CHANNEL_ALL); + void trigger_event(const EventType & event, event_channel_t channel = CHANNEL_ALL); /** * \brief Queue an event for later processing. @@ -82,7 +89,7 @@ public: * \param channel The channel to associate with the event (default is CHANNEL_ALL). */ template - void queue_event(const EventType & event, int channel = CHANNEL_ALL); + void queue_event(const EventType & event, event_channel_t channel = CHANNEL_ALL); /** * \brief Process all queued events. @@ -113,17 +120,29 @@ private: */ struct QueueEntry { std::unique_ptr event; ///< The event instance. - int channel = CHANNEL_ALL; ///< The channel associated with the event. + event_channel_t channel = CHANNEL_ALL; ///< The channel associated with the event. std::type_index type; ///< The type of the event. }; + /** + * \brief Internal event handler + * + * This function processes a single event, and is used to process events both during + * EventManager::dispatch_events and inside EventManager::trigger_event + * + * \param type \c typeid of concrete Event class + * \param channel Event channel + * \param data Event data + */ + void handle_event(std::type_index type, event_channel_t channel, const Event & data); + /** * \struct CallbackEntry * \brief Represents a registered event handler callback. */ struct CallbackEntry { std::unique_ptr callback; ///< The callback function wrapper. - int channel = CHANNEL_ALL; ///< The channel this callback listens to. + event_channel_t channel = CHANNEL_ALL; ///< The channel this callback listens to. subscription_t id = -1; ///< Unique subscription ID. }; diff --git a/src/crepe/api/EventManager.hpp b/src/crepe/api/EventManager.hpp index b2a94bd..a5f4556 100644 --- a/src/crepe/api/EventManager.hpp +++ b/src/crepe/api/EventManager.hpp @@ -1,9 +1,12 @@ +#pragma once + #include "EventManager.h" namespace crepe { template -subscription_t EventManager::subscribe(const EventHandler & callback, int channel) { +subscription_t EventManager::subscribe(const EventHandler & callback, + event_channel_t channel) { subscription_counter++; std::type_index event_type = typeid(EventType); std::unique_ptr> handler @@ -15,34 +18,19 @@ subscription_t EventManager::subscribe(const EventHandler & callback, } template -void EventManager::queue_event(const EventType & event, int channel) { +void EventManager::queue_event(const EventType & event, event_channel_t channel) { static_assert(std::is_base_of::value, "EventType must derive from Event"); - std::type_index event_type = typeid(EventType); - - auto event_ptr = std::make_unique(event); - - this->events_queue.push_back( - QueueEntry{.event = std::move(event_ptr), .channel = channel, .type = event_type}); + this->events_queue.push_back(QueueEntry{ + .event = std::make_unique(event), + .channel = channel, + .type = typeid(EventType), + }); } template -void EventManager::trigger_event(const EventType & event, int channel) { - std::type_index event_type = typeid(EventType); - - auto handlers_it = this->subscribers.find(event_type); - if (handlers_it != this->subscribers.end()) { - const std::vector & handlers = handlers_it->second; - - for (const CallbackEntry & handler : handlers) { - if (handler.channel != channel && handler.channel != CHANNEL_ALL) { - continue; - } - if (handler.callback->exec(event)) { - break; - } - } - } +void EventManager::trigger_event(const EventType & event, event_channel_t channel) { + this->handle_event(typeid(EventType), channel, event); } } // namespace crepe diff --git a/src/crepe/api/IKeyListener.cpp b/src/crepe/api/IKeyListener.cpp index 7aefaf7..8642655 100644 --- a/src/crepe/api/IKeyListener.cpp +++ b/src/crepe/api/IKeyListener.cpp @@ -3,7 +3,8 @@ using namespace crepe; // Constructor with specified channel -IKeyListener::IKeyListener(int channel) : event_manager(EventManager::get_instance()) { +IKeyListener::IKeyListener(event_channel_t channel) + : event_manager(EventManager::get_instance()) { this->press_id = event_manager.subscribe( [this](const KeyPressEvent & event) { return this->on_key_pressed(event); }, channel); this->release_id = event_manager.subscribe( diff --git a/src/crepe/api/IKeyListener.h b/src/crepe/api/IKeyListener.h index 2a89cbc..328a4c2 100644 --- a/src/crepe/api/IKeyListener.h +++ b/src/crepe/api/IKeyListener.h @@ -16,7 +16,7 @@ public: * \brief Constructs an IKeyListener with a specified channel. * \param channel The channel ID for event handling. */ - IKeyListener(int channel = EventManager::CHANNEL_ALL); + IKeyListener(event_channel_t channel = EventManager::CHANNEL_ALL); virtual ~IKeyListener(); IKeyListener(const IKeyListener &) = delete; IKeyListener & operator=(const IKeyListener &) = delete; @@ -43,7 +43,7 @@ private: //! Key release event id subscription_t release_id = -1; //! EventManager reference - EventManager & event_manager;; + EventManager & event_manager; }; } // namespace crepe diff --git a/src/crepe/api/IMouseListener.cpp b/src/crepe/api/IMouseListener.cpp index 7d38280..989aeb3 100644 --- a/src/crepe/api/IMouseListener.cpp +++ b/src/crepe/api/IMouseListener.cpp @@ -2,7 +2,8 @@ using namespace crepe; -IMouseListener::IMouseListener(int channel) : event_manager(EventManager::get_instance()) { +IMouseListener::IMouseListener(event_channel_t channel) + : event_manager(EventManager::get_instance()) { this->click_id = event_manager.subscribe( [this](const MouseClickEvent & event) { return this->on_mouse_clicked(event); }, channel); diff --git a/src/crepe/api/IMouseListener.h b/src/crepe/api/IMouseListener.h index 91b33e1..15e1619 100644 --- a/src/crepe/api/IMouseListener.h +++ b/src/crepe/api/IMouseListener.h @@ -16,7 +16,7 @@ public: * \brief Constructs an IMouseListener with a specified channel. * \param channel The channel ID for event handling. */ - IMouseListener(int channel = EventManager::CHANNEL_ALL); + IMouseListener(event_channel_t channel = EventManager::CHANNEL_ALL); virtual ~IMouseListener(); IMouseListener & operator=(const IMouseListener &) = delete; IMouseListener(const IMouseListener &) = delete; diff --git a/src/crepe/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp index b8b2bda..00523a6 100644 --- a/src/crepe/facade/SDLContext.cpp +++ b/src/crepe/facade/SDLContext.cpp @@ -47,7 +47,8 @@ SDLContext::SDLContext() { SDL_Renderer * tmp_renderer = SDL_CreateRenderer(this->game_window.get(), -1, SDL_RENDERER_ACCELERATED); if (!tmp_renderer) { - throw runtime_error(format("SDLContext: SDL_CreateRenderer error: {}", SDL_GetError())); + throw runtime_error( + format("SDLContext: SDL_CreateRenderer error: {}", SDL_GetError())); } this->game_renderer diff --git a/src/example/CMakeLists.txt b/src/example/CMakeLists.txt index 7b4cc43..560e2bc 100644 --- a/src/example/CMakeLists.txt +++ b/src/example/CMakeLists.txt @@ -18,12 +18,6 @@ endfunction() add_example(asset_manager) add_example(savemgr) -add_example(proxy) -add_example(db) -add_example(ecs) -add_example(scene_manager) -add_example(events) -add_example(particles) add_example(rendering_particle) add_example(gameloop) diff --git a/src/test/DBTest.cpp b/src/test/DBTest.cpp index b57eba9..e80814c 100644 --- a/src/test/DBTest.cpp +++ b/src/test/DBTest.cpp @@ -1,5 +1,5 @@ -#include #include +#include using namespace std; using namespace crepe; @@ -26,4 +26,3 @@ TEST_F(DBTest, Has) { db.set("foo", "bar"); EXPECT_EQ(db.has("foo"), true); } - diff --git a/src/test/ValueBrokerTest.cpp b/src/test/ValueBrokerTest.cpp index 10a4654..e6bb058 100644 --- a/src/test/ValueBrokerTest.cpp +++ b/src/test/ValueBrokerTest.cpp @@ -13,7 +13,7 @@ public: int write_count = 0; int value = 0; - ValueBroker broker { + ValueBroker broker{ [this](const int & target) -> void { this->write_count++; this->value = target; @@ -49,7 +49,7 @@ TEST_F(ValueBrokerTest, ProxyWrite) { EXPECT_EQ(write_count, 1); } -void dummy(int) { } +void dummy(int) {} TEST_F(ValueBrokerTest, ProxyRead) { dummy(proxy); EXPECT_EQ(read_count, 1); @@ -61,4 +61,3 @@ TEST_F(ValueBrokerTest, ProxyReadWrite) { ASSERT_EQ(read_count, 1); ASSERT_EQ(write_count, 1); } - -- cgit v1.2.3