diff options
author | Loek Le Blansch <loek@pipeframe.xyz> | 2024-11-14 13:57:13 +0100 |
---|---|---|
committer | Loek Le Blansch <loek@pipeframe.xyz> | 2024-11-14 13:57:13 +0100 |
commit | 07adbf48e0781cd8c95983c1871a84b6160ee5bf (patch) | |
tree | e3a55673b20ebaa3baec6665c107c177bd59ff14 | |
parent | 01c09a196c3f3e5cefaa4119a95a1cdeb7b9c263 (diff) |
implement asset + more WIP audio system
-rw-r--r-- | .crepe-root | 0 | ||||
-rw-r--r-- | .gitmodules | 4 | ||||
-rw-r--r-- | lib/whereami/CMakeLists.txt | 38 | ||||
m--------- | lib/whereami/lib | 0 | ||||
-rw-r--r-- | src/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/crepe/Asset.cpp | 46 | ||||
-rw-r--r-- | src/crepe/Asset.h | 32 | ||||
-rw-r--r-- | src/crepe/api/AudioSource.cpp | 6 | ||||
-rw-r--r-- | src/crepe/api/AudioSource.h | 5 | ||||
-rw-r--r-- | src/crepe/api/CMakeLists.txt | 4 | ||||
-rw-r--r-- | src/crepe/api/Config.h | 14 | ||||
-rw-r--r-- | src/crepe/api/Texture.cpp | 2 | ||||
-rw-r--r-- | src/crepe/facade/SDLContext.cpp | 2 | ||||
-rw-r--r-- | src/crepe/facade/Sound.cpp | 2 | ||||
-rw-r--r-- | src/example/asset_manager.cpp | 22 | ||||
-rw-r--r-- | src/example/audio_internal.cpp | 16 | ||||
-rw-r--r-- | src/example/particles.cpp | 5 | ||||
-rw-r--r-- | src/example/rendering.cpp | 6 | ||||
-rw-r--r-- | src/test/AssetTest.cpp | 33 | ||||
-rw-r--r-- | src/test/AudioTest.cpp | 4 | ||||
-rw-r--r-- | src/test/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/test/ParticleTest.cpp | 2 |
22 files changed, 191 insertions, 55 deletions
diff --git a/.crepe-root b/.crepe-root new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/.crepe-root 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 +Subproject dcb52a058dc14530ba9ae05e4339bd3ddfae0e0 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 index 9c41ecb..8692c6c 100644 --- a/src/crepe/Asset.cpp +++ b/src/crepe/Asset.cpp @@ -1,16 +1,50 @@ #include <filesystem> +#include <stdexcept> +#include <whereami.h> #include "Asset.h" +#include "api/Config.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); +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); } -istream & Asset::get_stream() { return this->file; } +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; +} -const string & Asset::get_canonical() const { return this->src; } diff --git a/src/crepe/Asset.h b/src/crepe/Asset.h index cb413f4..f6e6782 100644 --- a/src/crepe/Asset.h +++ b/src/crepe/Asset.h @@ -1,7 +1,5 @@ #pragma once -#include <fstream> -#include <iostream> #include <string> namespace crepe { @@ -9,8 +7,8 @@ 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. + * This class is used to locate game asset files, and should *always* be used + * instead of reading file paths directly. */ class Asset { public: @@ -18,24 +16,28 @@ 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 + * \param src Unique identifier to asset */ - std::istream & get_stream(); + Asset(const char * src); + +public: /** - * \brief Get the canonical path to this asset - * \return Canonical path to this asset + * \brief Get the path to this asset + * \return path to this asset */ - const std::string & get_canonical() const; + const std::string & get_path() const noexcept; private: - //! Canonical path to asset + //! path to asset const std::string src; - //! File handle (stream) - std::ifstream file; + +private: + std::string find_asset(const std::string & src) const; + /** + * \returns The path to the current executable + */ + std::string whereami() const noexcept; }; } // namespace crepe diff --git a/src/crepe/api/AudioSource.cpp b/src/crepe/api/AudioSource.cpp index b0cf28c..4baac9a 100644 --- a/src/crepe/api/AudioSource.cpp +++ b/src/crepe/api/AudioSource.cpp @@ -1,13 +1,11 @@ -#include <memory> - #include "AudioSource.h" using namespace crepe; using namespace std; -AudioSource::AudioSource(game_object_id_t id, unique_ptr<Asset> audio_clip) : +AudioSource::AudioSource(game_object_id_t id, const Asset & src) : Component(id), - audio_clip(std::move(audio_clip)) + source(src) { } void AudioSource::play(bool looping) { diff --git a/src/crepe/api/AudioSource.h b/src/crepe/api/AudioSource.h index 5bc70f9..0748267 100644 --- a/src/crepe/api/AudioSource.h +++ b/src/crepe/api/AudioSource.h @@ -21,8 +21,6 @@ public: void stop(); public: - //! Sample file location - const std::unique_ptr<Asset> audio_clip; //! Play when this component becomes active bool play_on_awake = false; //! Repeat the current audio clip during playback @@ -31,6 +29,9 @@ public: float volume = 1.0; private: + //! This audio source's clip + const Asset source; + //! If this source is playing audio bool playing = false; //! Rewind the sample location diff --git a/src/crepe/api/CMakeLists.txt b/src/crepe/api/CMakeLists.txt index 85696c4..93a1fac 100644 --- a/src/crepe/api/CMakeLists.txt +++ b/src/crepe/api/CMakeLists.txt @@ -1,5 +1,5 @@ target_sources(crepe PUBLIC - # AudioSource.cpp + AudioSource.cpp BehaviorScript.cpp Script.cpp GameObject.cpp @@ -23,7 +23,7 @@ target_sources(crepe PUBLIC ) target_sources(crepe PUBLIC FILE_SET HEADERS FILES - # AudioSource.h + AudioSource.h BehaviorScript.h Config.h Script.h diff --git a/src/crepe/api/Config.h b/src/crepe/api/Config.h index e3f86bf..c3f9474 100644 --- a/src/crepe/api/Config.h +++ b/src/crepe/api/Config.h @@ -58,6 +58,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<Asset> 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 a68d940..5527803 100644 --- a/src/crepe/facade/SDLContext.cpp +++ b/src/crepe/facade/SDLContext.cpp @@ -159,7 +159,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<SDL_Surface, std::function<void(SDL_Surface *)>> diff --git a/src/crepe/facade/Sound.cpp b/src/crepe/facade/Sound.cpp index 5cd31e8..b7bfeab 100644 --- a/src/crepe/facade/Sound.cpp +++ b/src/crepe/facade/Sound.cpp @@ -13,7 +13,7 @@ Sound::Sound(SoundContext & ctx) : context(ctx) { dbg_trace(); } unique_ptr<Resource> Sound::clone(const Asset & src) const { auto instance = make_unique<Sound>(*this); - instance->sample.load(src.get_canonical().c_str()); + instance->sample.load(src.get_path().c_str()); return instance; } diff --git a/src/example/asset_manager.cpp b/src/example/asset_manager.cpp index cf64f89..a2ca8c3 100644 --- a/src/example/asset_manager.cpp +++ b/src/example/asset_manager.cpp @@ -8,7 +8,7 @@ int main() { // this needs to be called before the asset manager otherwise the destructor // of sdl is not in the right order - { Texture test("../asset/texture/img.png"); } + { Texture test("asset/texture/img.png"); } // FIXME: make it so the issue described by the above comment is not possible // (i.e. the order in which internal classes are instantiated should not // impact the way the engine works). @@ -18,20 +18,20 @@ int main() { { // TODO: [design] the Sound class can't be directly included by the user as // it includes SoLoud headers. - auto bgm = mgr.cache<Sound>("../mwe/audio/bgm.ogg"); - auto sfx1 = mgr.cache<Sound>("../mwe/audio/sfx1.wav"); - auto sfx2 = mgr.cache<Sound>("../mwe/audio/sfx2.wav"); + auto bgm = mgr.cache<Sound>("mwe/audio/bgm.ogg"); + auto sfx1 = mgr.cache<Sound>("mwe/audio/sfx1.wav"); + auto sfx2 = mgr.cache<Sound>("mwe/audio/sfx2.wav"); - auto img = mgr.cache<Texture>("../asset/texture/img.png"); - auto img1 = mgr.cache<Texture>("../asset/texture/second.png"); + auto img = mgr.cache<Texture>("asset/texture/img.png"); + auto img1 = mgr.cache<Texture>("asset/texture/second.png"); } { - auto bgm = mgr.cache<Sound>("../mwe/audio/bgm.ogg"); - auto sfx1 = mgr.cache<Sound>("../mwe/audio/sfx1.wav"); - auto sfx2 = mgr.cache<Sound>("../mwe/audio/sfx2.wav"); + auto bgm = mgr.cache<Sound>("mwe/audio/bgm.ogg"); + auto sfx1 = mgr.cache<Sound>("mwe/audio/sfx1.wav"); + auto sfx2 = mgr.cache<Sound>("mwe/audio/sfx2.wav"); - auto img = mgr.cache<Texture>("../asset/texture/img.png"); - auto img1 = mgr.cache<Texture>("../asset/texture/second.png"); + auto img = mgr.cache<Texture>("asset/texture/img.png"); + auto img1 = mgr.cache<Texture>("asset/texture/second.png"); } } diff --git a/src/example/audio_internal.cpp b/src/example/audio_internal.cpp index ff55a59..9b60e6b 100644 --- a/src/example/audio_internal.cpp +++ b/src/example/audio_internal.cpp @@ -4,7 +4,9 @@ */ #include <crepe/api/Config.h> +#include <crepe/facade/SoundContext.h> #include <crepe/facade/Sound.h> +#include <crepe/Asset.h> #include <crepe/util/Log.h> #include <thread> @@ -24,12 +26,18 @@ int _ = []() { }(); int main() { + SoundContext ctx{}; + Sound sound{ctx}; // Load a background track (Ogg Vorbis) - auto bgm = Sound("../mwe/audio/bgm.ogg"); + auto _bgm = sound.clone(Asset{"mwe/audio/bgm.ogg"}); + Sound & bgm = *dynamic_cast<Sound *>(_bgm.get()); // 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.clone(Asset{"mwe/audio/sfx1.wav"}); + Sound & sfx1 = *dynamic_cast<Sound *>(_sfx1.get()); + auto _sfx2 = sound.clone(Asset{"mwe/audio/sfx2.wav"}); + Sound & sfx2 = *dynamic_cast<Sound *>(_sfx2.get()); + auto _sfx3 = sound.clone(Asset{"mwe/audio/sfx3.wav"}); + Sound & sfx3 = *dynamic_cast<Sound *>(_sfx3.get()); // Start the background track bgm.play(); diff --git a/src/example/particles.cpp b/src/example/particles.cpp index 6eab046..b65671a 100644 --- a/src/example/particles.cpp +++ b/src/example/particles.cpp @@ -14,10 +14,11 @@ using namespace crepe; using namespace std; int main(int argc, char * argv[]) { - GameObject game_object(0, "", "", Vector2{0, 0}, 0, 0); + 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<Sprite>( - make_shared<Texture>("../asset/texture/img.png"), color, + make_shared<Texture>("asset/texture/img.png"), color, FlipSettings{true, true}); game_object.add_component<ParticleEmitter>(ParticleEmitter::Data{ .position = {0, 0}, diff --git a/src/example/rendering.cpp b/src/example/rendering.cpp index abd11b1..2157bdc 100644 --- a/src/example/rendering.cpp +++ b/src/example/rendering.cpp @@ -31,21 +31,21 @@ int main() { { Color color(0, 0, 0, 0); obj.add_component<Sprite>( - make_shared<Texture>("../asset/texture/img.png"), color, + make_shared<Texture>("asset/texture/img.png"), color, FlipSettings{false, false}); obj.add_component<Camera>(Color::get_red()); } { Color color(0, 0, 0, 0); obj1.add_component<Sprite>( - make_shared<Texture>("../asset/texture/second.png"), color, + make_shared<Texture>("asset/texture/second.png"), color, FlipSettings{true, true}); } /* { Color color(0, 0, 0, 0); - auto img = mgr.cache<Texture>("../asset/texture/second.png"); + auto img = mgr.cache<Texture>("asset/texture/second.png"); obj2.add_component<Sprite>(img, color, FlipSettings{true, true}); } */ diff --git a/src/test/AssetTest.cpp b/src/test/AssetTest.cpp new file mode 100644 index 0000000..c3ff158 --- /dev/null +++ b/src/test/AssetTest.cpp @@ -0,0 +1,33 @@ +#include "api/Config.h" +#include <gtest/gtest.h> + +#include <crepe/Asset.h> + +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/AudioTest.cpp b/src/test/AudioTest.cpp index 6e2706c..e181de9 100644 --- a/src/test/AudioTest.cpp +++ b/src/test/AudioTest.cpp @@ -1,9 +1,9 @@ -#include "system/AudioSystem.h" #include <gtest/gtest.h> #include <crepe/ComponentManager.h> #include <crepe/api/AudioSource.h> #include <crepe/api/GameObject.h> +#include <crepe/system/AudioSystem.h> using namespace std; using namespace crepe; @@ -17,7 +17,7 @@ public: void SetUp() override { auto & mgr = this->component_manager; GameObject entity = mgr.new_object("name"); - entity.add_component<AudioSource>("../mwe/audio/sfx1.wav"); + entity.add_component<AudioSource>("mwe/audio/sfx1.wav"); } }; diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index 1a986bd..5ea90f7 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -4,5 +4,6 @@ target_sources(test_main PUBLIC ScriptTest.cpp ParticleTest.cpp AudioTest.cpp + AssetTest.cpp ) diff --git a/src/test/ParticleTest.cpp b/src/test/ParticleTest.cpp index 1a89e3a..cd2ec2a 100644 --- a/src/test/ParticleTest.cpp +++ b/src/test/ParticleTest.cpp @@ -29,7 +29,7 @@ public: Color color(0, 0, 0, 0); Sprite test_sprite = game_object.add_component<Sprite>( - make_shared<Texture>("../asset/texture/img.png"), color, + make_shared<Texture>("asset/texture/img.png"), color, FlipSettings{true, true}); game_object.add_component<ParticleEmitter>(ParticleEmitter::Data{ |