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 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 9770b548c5619821d7b6ea7a017df2b5a6898d0a Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Mon, 18 Nov 2024 18:10:31 +0100 Subject: add doxygen comments --- src/crepe/api/Asset.h | 10 +++++++++- src/crepe/util/OptionalRef.h | 37 +++++++++++++++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/src/crepe/api/Asset.h b/src/crepe/api/Asset.h index 05dccba..685dd3a 100644 --- a/src/crepe/api/Asset.h +++ b/src/crepe/api/Asset.h @@ -1,7 +1,6 @@ #pragma once #include -#include namespace crepe { @@ -52,7 +51,16 @@ private: namespace std { +//! Hash helper struct template<> struct hash { + /** + * \brief Hash operator for crepe::Asset + * + * This function hashes a crepe::Asset instance, allowing it to be used as a key in an \c + * std::unordered_map. + * + * \returns Hash value + */ size_t operator()(const crepe::Asset & asset) const noexcept; }; diff --git a/src/crepe/util/OptionalRef.h b/src/crepe/util/OptionalRef.h index 1ad3a6d..8417a25 100644 --- a/src/crepe/util/OptionalRef.h +++ b/src/crepe/util/OptionalRef.h @@ -12,18 +12,51 @@ namespace crepe { template class OptionalRef { public: + //! Initialize empty (nonexistant) reference OptionalRef() = default; - OptionalRef(T &); - OptionalRef & operator=(T &); + //! Initialize reference with value + OptionalRef(T & ref); + /** + * \brief Assign new reference + * + * \param ref Reference to assign + * + * \return Reference to this (required for operator) + */ + OptionalRef & operator=(T & ref); + /** + * \brief Check if this reference is not empty + * + * \returns `true` if reference is set, or `false` if it is not + */ explicit operator bool() const noexcept; + /** + * \brief Assign new reference + * + * \param ref Reference to assign + */ void set(T &) noexcept; + /** + * \brief Retrieve this reference + * + * \returns Internal reference if it is set + * + * \throws std::runtime_error if this function is called while the reference it not set + */ T & get() const; + /** + * \brief Make this reference empty + */ void clear() noexcept; + //! Copy constructor OptionalRef(const OptionalRef &); + //! Move constructor OptionalRef(OptionalRef &&); + //! Copy assignment OptionalRef & operator=(const OptionalRef &); + //! Move assignment OptionalRef & operator=(OptionalRef &&); private: -- cgit v1.2.3 From 5f39dc386cce357a7c71a81c523a90496f7b1e67 Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Mon, 18 Nov 2024 18:18:27 +0100 Subject: update contributing.md --- contributing.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/contributing.md b/contributing.md index 5b0c79d..e4f075f 100644 --- a/contributing.md +++ b/contributing.md @@ -15,7 +15,11 @@ that you can click on to open them. `name/feature` (i.e. `loek/dll-so-poc` or `jaro/class2`) - The master branch is considered stable, and should always contain a working/compiling version of the project +- Pull requests for new code include either automated tests for the new code or + an explanation as to why the code can not (reliably) be tested + # Code style @@ -790,6 +794,7 @@ that you can click on to open them. } ``` +- Do not implement new classes as singletons ## CMakeLists-specific -- cgit v1.2.3 From 4d1c6f1831e0a95029ff7af4cf8097e837dc2a5d Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Tue, 19 Nov 2024 15:05:30 +0100 Subject: add RefVector --- src/crepe/types.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/crepe/types.h b/src/crepe/types.h index 0d459e8..86730cc 100644 --- a/src/crepe/types.h +++ b/src/crepe/types.h @@ -1,9 +1,16 @@ #pragma once #include +#include +#include namespace crepe { +//! GameObject ID typedef uint32_t game_object_id_t; +//! vector of reference_wrapper +template +using RefVector = std::vector>; + } -- cgit v1.2.3 From 02845c3d25130e9473604cb2eeee42a7a7a8eadf Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Wed, 20 Nov 2024 14:01:31 +0100 Subject: `make format` --- src/crepe/api/Asset.cpp | 15 +++++---------- src/crepe/api/Asset.h | 8 ++++---- src/crepe/types.h | 4 ++-- src/crepe/util/OptionalRef.h | 13 ++++++------- src/crepe/util/OptionalRef.hpp | 3 +-- src/example/rendering.cpp | 5 ++--- src/test/AssetTest.cpp | 13 +++---------- src/test/OptionalRefTest.cpp | 1 - 8 files changed, 23 insertions(+), 39 deletions(-) diff --git a/src/crepe/api/Asset.cpp b/src/crepe/api/Asset.cpp index 5271cf7..3fe3ceb 100644 --- a/src/crepe/api/Asset.cpp +++ b/src/crepe/api/Asset.cpp @@ -8,8 +8,8 @@ using namespace crepe; using namespace std; -Asset::Asset(const string & src) : src(find_asset(src)) { } -Asset::Asset(const char * src) : src(find_asset(src)) { } +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; } @@ -22,14 +22,12 @@ string Asset::find_asset(const string & src) const { // absolute paths do not need to be resolved, only canonicalized filesystem::path path = src; - if (path.is_absolute()) - return filesystem::canonical(path); + 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 (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(); @@ -48,11 +46,8 @@ string Asset::whereami() const noexcept { return path; } -bool Asset::operator==(const Asset & other) const noexcept { - return this->src == other.src; -} +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 index 685dd3a..77596ac 100644 --- a/src/crepe/api/Asset.h +++ b/src/crepe/api/Asset.h @@ -33,7 +33,7 @@ public: * \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; + bool operator==(const Asset & other) const noexcept; private: //! path to asset @@ -52,7 +52,8 @@ private: namespace std { //! Hash helper struct -template<> struct hash { +template <> +struct hash { /** * \brief Hash operator for crepe::Asset * @@ -64,5 +65,4 @@ template<> struct hash { size_t operator()(const crepe::Asset & asset) const noexcept; }; -} - +} // namespace std diff --git a/src/crepe/types.h b/src/crepe/types.h index 86730cc..914c76c 100644 --- a/src/crepe/types.h +++ b/src/crepe/types.h @@ -1,8 +1,8 @@ #pragma once #include -#include #include +#include namespace crepe { @@ -13,4 +13,4 @@ typedef uint32_t game_object_id_t; template using RefVector = std::vector>; -} +} // namespace crepe diff --git a/src/crepe/util/OptionalRef.h b/src/crepe/util/OptionalRef.h index 8417a25..0a94ae5 100644 --- a/src/crepe/util/OptionalRef.h +++ b/src/crepe/util/OptionalRef.h @@ -23,7 +23,7 @@ public: * * \return Reference to this (required for operator) */ - OptionalRef & operator=(T & ref); + OptionalRef & operator=(T & ref); /** * \brief Check if this reference is not empty * @@ -51,13 +51,13 @@ public: void clear() noexcept; //! Copy constructor - OptionalRef(const OptionalRef &); + OptionalRef(const OptionalRef &); //! Move constructor - OptionalRef(OptionalRef &&); + OptionalRef(OptionalRef &&); //! Copy assignment - OptionalRef & operator=(const OptionalRef &); + OptionalRef & operator=(const OptionalRef &); //! Move assignment - OptionalRef & operator=(OptionalRef &&); + OptionalRef & operator=(OptionalRef &&); private: /** @@ -68,7 +68,6 @@ private: T * ref = nullptr; }; -} +} // namespace crepe #include "OptionalRef.hpp" - diff --git a/src/crepe/util/OptionalRef.hpp b/src/crepe/util/OptionalRef.hpp index 7b201b0..ee41f61 100644 --- a/src/crepe/util/OptionalRef.hpp +++ b/src/crepe/util/OptionalRef.hpp @@ -63,5 +63,4 @@ OptionalRef::operator bool() const noexcept { return this->ref != nullptr; } -} - +} // namespace crepe diff --git a/src/example/rendering.cpp b/src/example/rendering.cpp index 522ec0f..01794f8 100644 --- a/src/example/rendering.cpp +++ b/src/example/rendering.cpp @@ -30,9 +30,8 @@ int main() { // 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 & 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::RED); diff --git a/src/test/AssetTest.cpp b/src/test/AssetTest.cpp index 563a253..8aa7629 100644 --- a/src/test/AssetTest.cpp +++ b/src/test/AssetTest.cpp @@ -10,18 +10,12 @@ using namespace testing; class AssetTest : public Test { public: Config & cfg = Config::get_instance(); - void SetUp() override { - this->cfg.asset.root_pattern = ".crepe-root"; - } + 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, Existant) { ASSERT_NO_THROW(Asset{"asset/texture/img.png"}); } -TEST_F(AssetTest, Nonexistant) { - ASSERT_ANY_THROW(Asset{"asset/nonexistant"}); -} +TEST_F(AssetTest, Nonexistant) { ASSERT_ANY_THROW(Asset{"asset/nonexistant"}); } TEST_F(AssetTest, Rootless) { cfg.asset.root_pattern.clear(); @@ -30,4 +24,3 @@ TEST_F(AssetTest, Rootless) { Asset asset{arbitrary}; ASSERT_EQ(arbitrary, asset.get_path()); } - diff --git a/src/test/OptionalRefTest.cpp b/src/test/OptionalRefTest.cpp index 219ccca..2072d56 100644 --- a/src/test/OptionalRefTest.cpp +++ b/src/test/OptionalRefTest.cpp @@ -35,4 +35,3 @@ TEST(OptionalRefTest, Implicit) { EXPECT_TRUE(ref); ASSERT_NO_THROW(ref.get()); } - -- cgit v1.2.3 From 22a7e9f3c40b4b6eb68a5343e4870e76c4bfcf63 Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Wed, 20 Nov 2024 14:24:08 +0100 Subject: process feedback on #39 --- readme.md | 7 +++++++ src/crepe/ComponentManager.h | 5 +++-- src/crepe/ComponentManager.hpp | 9 ++++----- src/crepe/api/Asset.cpp | 5 +++-- src/crepe/api/Asset.h | 16 ++++++++++++++++ src/crepe/system/System.h | 2 -- src/crepe/util/OptionalRef.h | 11 +---------- src/crepe/util/OptionalRef.hpp | 24 ------------------------ 8 files changed, 34 insertions(+), 45 deletions(-) diff --git a/readme.md b/readme.md index c83853d..d309b30 100644 --- a/readme.md +++ b/readme.md @@ -32,6 +32,7 @@ This project uses the following libraries |`SoLoud`|(latest git `master` version)| |Google Test (`GTest`)|1.15.2| |Berkeley DB (`libdb`)|5.3.21| +|Where Am I?|(latest git `master` version) > [!NOTE] > Most of these libraries are likely available from your package manager if you @@ -49,6 +50,11 @@ $ git submodule update --init --recursive --depth 1 Then, follow these steps for each library you want to install: +> [!IMPORTANT] +> A dollar sign prompt (`$`) indicates commands to be run as a regular user, +> while a hashtag (`#`) is used to denote commands that must be run with +> privileges (e.g. as root or using `sudo`). + 1. Change into the library folder (run **one** of these): ``` $ cd lib/googletest @@ -56,6 +62,7 @@ Then, follow these steps for each library you want to install: $ cd lib/soloud/contrib $ cd lib/sdl_image $ cd lib/sdl_ttf + $ cd lib/whereami ``` 2. Use CMake to configure the build, run the build and install (run **all** of these): diff --git a/src/crepe/ComponentManager.h b/src/crepe/ComponentManager.h index 2107453..0956d1e 100644 --- a/src/crepe/ComponentManager.h +++ b/src/crepe/ComponentManager.h @@ -8,6 +8,7 @@ #include "api/Vector2.h" #include "Component.h" +#include "types.h" namespace crepe { @@ -112,7 +113,7 @@ public: * \return A vector of all components of the specific type and id */ template - std::vector> get_components_by_id(game_object_id_t id) const; + RefVector get_components_by_id(game_object_id_t id) const; /** * \brief Get all components of a specific type * @@ -122,7 +123,7 @@ public: * \return A vector of all components of the specific type */ template - std::vector> get_components_by_type() const; + RefVector get_components_by_type() const; private: /** diff --git a/src/crepe/ComponentManager.hpp b/src/crepe/ComponentManager.hpp index be99cac..4d5eaf4 100644 --- a/src/crepe/ComponentManager.hpp +++ b/src/crepe/ComponentManager.hpp @@ -81,15 +81,14 @@ void ComponentManager::delete_components() { } template -std::vector> -ComponentManager::get_components_by_id(game_object_id_t id) const { +RefVector ComponentManager::get_components_by_id(game_object_id_t id) const { using namespace std; // Determine the type of T (this is used as the key of the unordered_map<>) type_index type = typeid(T); // Create an empty vector<> - vector> component_vector; + RefVector component_vector; if (this->components.find(type) == this->components.end()) return component_vector; @@ -114,14 +113,14 @@ ComponentManager::get_components_by_id(game_object_id_t id) const { } template -std::vector> ComponentManager::get_components_by_type() const { +RefVector ComponentManager::get_components_by_type() const { using namespace std; // Determine the type of T (this is used as the key of the unordered_map<>) type_index type = typeid(T); // Create an empty vector<> - vector> component_vector; + RefVector component_vector; // Find the type (in the unordered_map<>) if (this->components.find(type) == this->components.end()) return component_vector; diff --git a/src/crepe/api/Asset.cpp b/src/crepe/api/Asset.cpp index 3fe3ceb..e148367 100644 --- a/src/crepe/api/Asset.cpp +++ b/src/crepe/api/Asset.cpp @@ -2,9 +2,10 @@ #include #include -#include "Asset.h" #include "api/Config.h" +#include "Asset.h" + using namespace crepe; using namespace std; @@ -15,7 +16,7 @@ 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; + string & 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; diff --git a/src/crepe/api/Asset.h b/src/crepe/api/Asset.h index 77596ac..bfd0ac7 100644 --- a/src/crepe/api/Asset.h +++ b/src/crepe/api/Asset.h @@ -40,6 +40,22 @@ private: const std::string src; private: + /** + * \brief Locate asset path, or throw exception if it cannot be found + * + * This function resolves asset locations relative to crepe::Config::root_pattern if it is + * set and \p src is a relative path. If \p src is an absolute path, it is canonicalized. + * This function only returns if the file can be found. + * + * \param src Arbitrary path to resource file + * + * \returns \p src if crepe::Config::root_pattern is empty + * \returns Canonical path to \p src + * + * \throws std::runtime_error if root_pattern cannot be found + * \throws std::filesystem::filesystem_error if the resolved path does not exist + * \throws std::filesystem::filesystem_error if the path cannot be canonicalized + */ std::string find_asset(const std::string & src) const; /** * \returns The path to the current executable diff --git a/src/crepe/system/System.h b/src/crepe/system/System.h index 36f7edc..28ea20e 100644 --- a/src/crepe/system/System.h +++ b/src/crepe/system/System.h @@ -1,7 +1,5 @@ #pragma once -#include "../ComponentManager.h" - namespace crepe { class ComponentManager; diff --git a/src/crepe/util/OptionalRef.h b/src/crepe/util/OptionalRef.h index 0a94ae5..57f9635 100644 --- a/src/crepe/util/OptionalRef.h +++ b/src/crepe/util/OptionalRef.h @@ -36,7 +36,7 @@ public: * * \param ref Reference to assign */ - void set(T &) noexcept; + void set(T & ref) noexcept; /** * \brief Retrieve this reference * @@ -50,15 +50,6 @@ public: */ void clear() noexcept; - //! Copy constructor - OptionalRef(const OptionalRef &); - //! Move constructor - OptionalRef(OptionalRef &&); - //! Copy assignment - OptionalRef & operator=(const OptionalRef &); - //! Move assignment - OptionalRef & operator=(OptionalRef &&); - private: /** * \brief Reference to the value of type \c T diff --git a/src/crepe/util/OptionalRef.hpp b/src/crepe/util/OptionalRef.hpp index ee41f61..71e2a39 100644 --- a/src/crepe/util/OptionalRef.hpp +++ b/src/crepe/util/OptionalRef.hpp @@ -11,30 +11,6 @@ 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) -- cgit v1.2.3 From e2c27d8c99a71e5d94ffe49027ec13afeb74b021 Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Wed, 20 Nov 2024 14:59:34 +0100 Subject: replace more vector> with RefVector --- src/crepe/api/GameObject.cpp | 6 ++---- src/crepe/api/Script.h | 2 +- src/crepe/api/Script.hpp | 5 ++--- src/crepe/system/AnimatorSystem.cpp | 5 +---- src/crepe/system/ParticleSystem.cpp | 3 +-- src/crepe/system/PhysicsSystem.cpp | 6 ++---- src/crepe/system/RenderSystem.cpp | 13 +++++-------- src/crepe/system/RenderSystem.h | 3 +-- src/crepe/system/ScriptSystem.cpp | 13 +++++-------- src/crepe/system/ScriptSystem.h | 6 +++--- 10 files changed, 23 insertions(+), 39 deletions(-) diff --git a/src/crepe/api/GameObject.cpp b/src/crepe/api/GameObject.cpp index 287e81d..4874426 100644 --- a/src/crepe/api/GameObject.cpp +++ b/src/crepe/api/GameObject.cpp @@ -23,12 +23,10 @@ void GameObject::set_parent(const GameObject & parent) { ComponentManager & mgr = this->component_manager; // Set parent on own Metadata component - vector> this_metadata - = mgr.get_components_by_id(this->id); + RefVector this_metadata = mgr.get_components_by_id(this->id); this_metadata.at(0).get().parent = parent.id; // Add own id to children list of parent's Metadata component - vector> parent_metadata - = mgr.get_components_by_id(parent.id); + RefVector parent_metadata = mgr.get_components_by_id(parent.id); parent_metadata.at(0).get().children.push_back(this->id); } diff --git a/src/crepe/api/Script.h b/src/crepe/api/Script.h index 2b70379..839d937 100644 --- a/src/crepe/api/Script.h +++ b/src/crepe/api/Script.h @@ -62,7 +62,7 @@ protected: * \returns List of component references */ template - std::vector> get_components() const; + RefVector get_components() const; protected: // NOTE: Script must have a constructor without arguments so the game programmer doesn't need diff --git a/src/crepe/api/Script.hpp b/src/crepe/api/Script.hpp index a064a90..a85d814 100644 --- a/src/crepe/api/Script.hpp +++ b/src/crepe/api/Script.hpp @@ -10,7 +10,7 @@ namespace crepe { template T & Script::get_component() const { using namespace std; - vector> all_components = this->get_components(); + RefVector all_components = this->get_components(); if (all_components.size() < 1) throw runtime_error( format("Script: no component found with type = {}", typeid(T).name())); @@ -19,9 +19,8 @@ T & Script::get_component() const { } template -std::vector> Script::get_components() const { +RefVector Script::get_components() const { auto & mgr = *this->component_manager_ref; - return mgr.get_components_by_id(this->game_object_id); } diff --git a/src/crepe/system/AnimatorSystem.cpp b/src/crepe/system/AnimatorSystem.cpp index 9d18873..676e485 100644 --- a/src/crepe/system/AnimatorSystem.cpp +++ b/src/crepe/system/AnimatorSystem.cpp @@ -1,6 +1,4 @@ #include -#include -#include #include "api/Animator.h" #include "facade/SDLContext.h" @@ -13,8 +11,7 @@ using namespace crepe; void AnimatorSystem::update() { ComponentManager & mgr = this->component_manager; - std::vector> animations - = mgr.get_components_by_type(); + RefVector animations = mgr.get_components_by_type(); uint64_t tick = SDLContext::get_instance().get_ticks(); for (Animator & a : animations) { diff --git a/src/crepe/system/ParticleSystem.cpp b/src/crepe/system/ParticleSystem.cpp index 7316309..fcf7522 100644 --- a/src/crepe/system/ParticleSystem.cpp +++ b/src/crepe/system/ParticleSystem.cpp @@ -14,8 +14,7 @@ using namespace crepe; void ParticleSystem::update() { // Get all emitters ComponentManager & mgr = this->component_manager; - std::vector> emitters - = mgr.get_components_by_type(); + RefVector emitters = mgr.get_components_by_type(); for (ParticleEmitter & emitter : emitters) { // Get transform linked to emitter diff --git a/src/crepe/system/PhysicsSystem.cpp b/src/crepe/system/PhysicsSystem.cpp index 4a7dbfb..bcde431 100644 --- a/src/crepe/system/PhysicsSystem.cpp +++ b/src/crepe/system/PhysicsSystem.cpp @@ -12,10 +12,8 @@ using namespace crepe; void PhysicsSystem::update() { ComponentManager & mgr = this->component_manager; - std::vector> rigidbodies - = mgr.get_components_by_type(); - std::vector> transforms - = mgr.get_components_by_type(); + RefVector rigidbodies = mgr.get_components_by_type(); + RefVector transforms = mgr.get_components_by_type(); double gravity = Config::get_instance().physics.gravity; for (Rigidbody & rigidbody : rigidbodies) { diff --git a/src/crepe/system/RenderSystem.cpp b/src/crepe/system/RenderSystem.cpp index 96c5f27..7ee03e5 100644 --- a/src/crepe/system/RenderSystem.cpp +++ b/src/crepe/system/RenderSystem.cpp @@ -1,6 +1,5 @@ #include #include -#include #include #include @@ -20,7 +19,7 @@ void RenderSystem::present_screen() { this->context.present_screen(); } void RenderSystem::update_camera() { ComponentManager & mgr = this->component_manager; - std::vector> cameras = mgr.get_components_by_type(); + RefVector cameras = mgr.get_components_by_type(); if (cameras.size() == 0) throw std::runtime_error("No cameras in current scene"); @@ -37,10 +36,8 @@ bool sorting_comparison(const Sprite & a, const Sprite & b) { return false; } -std::vector> -RenderSystem::sort(std::vector> & objs) { - - std::vector> sorted_objs(objs); +RefVector RenderSystem::sort(RefVector & objs) { + RefVector sorted_objs(objs); std::sort(sorted_objs.begin(), sorted_objs.end(), sorting_comparison); return sorted_objs; @@ -48,8 +45,8 @@ 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); + RefVector sprites = mgr.get_components_by_type(); + RefVector sorted_sprites = this->sort(sprites); for (const Sprite & sprite : sorted_sprites) { auto transforms = mgr.get_components_by_id(sprite.game_object_id); diff --git a/src/crepe/system/RenderSystem.h b/src/crepe/system/RenderSystem.h index 57b9c73..40978ae 100644 --- a/src/crepe/system/RenderSystem.h +++ b/src/crepe/system/RenderSystem.h @@ -47,8 +47,7 @@ private: * \param objs the vector that will do a sorting algorithm on * \return returns a sorted reference vector */ - std::vector> - sort(std::vector> & objs); + RefVector sort(RefVector & objs); /** * \todo Include color handling for sprites. diff --git a/src/crepe/system/ScriptSystem.cpp b/src/crepe/system/ScriptSystem.cpp index c4d724c..c33309c 100644 --- a/src/crepe/system/ScriptSystem.cpp +++ b/src/crepe/system/ScriptSystem.cpp @@ -1,6 +1,4 @@ -#include #include -#include #include "../ComponentManager.h" #include "../api/BehaviorScript.h" @@ -14,7 +12,7 @@ using namespace crepe; void ScriptSystem::update() { dbg_trace(); - forward_list> scripts = this->get_scripts(); + RefVector