diff options
32 files changed, 235 insertions, 207 deletions
diff --git a/contributing.md b/contributing.md index eec5bc0..2ff411a 100644 --- a/contributing.md +++ b/contributing.md @@ -22,6 +22,14 @@ - When using libraries of which the header include order is important, make sure to separate the include statements using a blank line (clang-format may sort include statements, but does not sort across empty lines). +- All engine-related code is implemented under the `crepe` namespace, + user-facing APIs under `crepe::api` (the folder structure should also reflect + this). +- `using namespace` may not be used in header files, only in source files. +- Do not (indirectly) include private dependency headers in API header files, + as these are no longer accessible when the engine is installed +- Getter and setter functions are appropriately prefixed with `get_` and + `set_`. ## CMakeLists specific @@ -6,6 +6,5 @@ doxygen: Doxyfile FORCE FMT += $(shell git ls-files '*.c' '*.cpp' '*.h' '*.hpp') format: FORCE clang-format -i $(FMT) -# clang tidy doesn't work that well :/ -# clang-tidy --fix-errors $(FMT) + $(MAKE) -C src $@ diff --git a/mwe/dynlink/exec/main.c b/mwe/dynlink/exec/main.c index ea55feb..ff884f2 100644 --- a/mwe/dynlink/exec/main.c +++ b/mwe/dynlink/exec/main.c @@ -5,4 +5,3 @@ int main() { return 0; } - @@ -7,7 +7,8 @@ This repository contains: |`lib/`|third-party libraries as git submodules| |`mwe/`|minimal working examples and proof-of-concepts| |`src/crepe/`|game engine source code| -|`test/`|game engine unit tests| +|`src/test/`|unit tests| +|`src/example`|standalone examples using game engine| ## Compilation diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 232d330..62ca9a0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -9,10 +9,12 @@ set(CMAKE_BUILD_TYPE Debug) add_compile_definitions(DEBUG) add_subdirectory(../lib/soloud soloud) +add_subdirectory(../lib/googletest googletest) project(crepe C CXX) add_library(crepe SHARED) +add_executable(test_main EXCLUDE_FROM_ALL) target_include_directories(crepe PUBLIC SYSTEM INTERFACE . @@ -24,13 +26,16 @@ target_link_libraries(crepe ) add_subdirectory(crepe) +add_subdirectory(test) +add_subdirectory(example) install( TARGETS crepe FILE_SET HEADERS DESTINATION include/crepe ) - -add_executable(dummy_audio dummy_audio.cpp) -target_link_libraries(dummy_audio PUBLIC crepe) +target_link_libraries(test_main + PRIVATE gtest_main + PUBLIC crepe +) diff --git a/src/crepe/Asset.cpp b/src/crepe/Asset.cpp new file mode 100644 index 0000000..15ddc27 --- /dev/null +++ b/src/crepe/Asset.cpp @@ -0,0 +1,14 @@ +#include <filesystem> + +#include "Asset.h" + +using namespace crepe; + +Asset::Asset(const std::string & src) { + this->src = std::filesystem::canonical(src); + this->file = std::ifstream(this->src, std::ios::in | std::ios::binary); +} + +const std::istream & Asset::read() { return this->file; } + +const char * Asset::canonical() { return this->src.c_str(); } diff --git a/src/crepe/Asset.h b/src/crepe/Asset.h new file mode 100644 index 0000000..0cb5834 --- /dev/null +++ b/src/crepe/Asset.h @@ -0,0 +1,33 @@ +#pragma once + +#include <fstream> +#include <iostream> +#include <string> + +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: + //! Get an input stream to the contents of this resource + const std::istream & read(); + //! Get the canonical path to this resource + const char * canonical(); + +private: + std::string src; + std::ifstream file; +}; + +} // namespace crepe diff --git a/src/crepe/CMakeLists.txt b/src/crepe/CMakeLists.txt index 9f7c91c..208ba1f 100644 --- a/src/crepe/CMakeLists.txt +++ b/src/crepe/CMakeLists.txt @@ -1,11 +1,13 @@ target_sources(crepe PUBLIC + Asset.cpp Sound.cpp - SoundSystem.cpp + SoundContext.cpp ) target_sources(crepe PUBLIC FILE_SET HEADERS FILES + Asset.h Sound.h - SoundSystem.h + SoundContext.h ) add_subdirectory(api) diff --git a/src/crepe/Sound.cpp b/src/crepe/Sound.cpp index 09ffd5f..64fa281 100644 --- a/src/crepe/Sound.cpp +++ b/src/crepe/Sound.cpp @@ -1,38 +1,60 @@ #include "util/log.h" #include "Sound.h" -#include "SoundSystem.h" +#include "SoundContext.h" using namespace crepe; -Sound::Sound(std::unique_ptr<api::Resource> res) { +Sound::Sound(std::unique_ptr<Asset> res) { dbg_trace(); this->load(std::move(res)); } Sound::Sound(const char * src) { dbg_trace(); - this->load(std::make_unique<api::Resource>(src)); + this->load(std::make_unique<Asset>(src)); } -void Sound::load(std::unique_ptr<api::Resource> res) { - this->sample.load(this->res->canonical()); +void Sound::load(std::unique_ptr<Asset> res) { + this->sample.load(res->canonical()); } void Sound::play() { - SoundSystem & system = SoundSystem::instance(); - if (system.engine.getPause(this->handle)) { + SoundContext & ctx = SoundContext::get_instance(); + if (ctx.engine.getPause(this->handle)) { // resume if paused - system.engine.setPause(this->handle, false); + ctx.engine.setPause(this->handle, false); } else { // or start new sound - this->handle = system.engine.play(this->sample); + this->handle = ctx.engine.play(this->sample, this->volume); + ctx.engine.setLooping(this->handle, this->looping); } } void Sound::pause() { - SoundSystem & system = SoundSystem::instance(); - if (system.engine.getPause(this->handle)) return; - system.engine.setPause(this->handle, true); + SoundContext & ctx = SoundContext::get_instance(); + if (ctx.engine.getPause(this->handle)) return; + ctx.engine.setPause(this->handle, true); } +void Sound::rewind() { + SoundContext & ctx = SoundContext::get_instance(); + if (!ctx.engine.isValidVoiceHandle(this->handle)) return; + ctx.engine.seek(this->handle, 0); +} + +void Sound::set_volume(float volume) { + this->volume = volume; + + SoundContext & ctx = SoundContext::get_instance(); + if (!ctx.engine.isValidVoiceHandle(this->handle)) return; + ctx.engine.setVolume(this->handle, this->volume); +} + +void Sound::set_looping(bool looping) { + this->looping = looping; + + SoundContext & ctx = SoundContext::get_instance(); + if (!ctx.engine.isValidVoiceHandle(this->handle)) return; + ctx.engine.setLooping(this->handle, this->looping); +} diff --git a/src/crepe/Sound.h b/src/crepe/Sound.h index 163c5b4..1ac20a7 100644 --- a/src/crepe/Sound.h +++ b/src/crepe/Sound.h @@ -5,7 +5,7 @@ #include <memory> -#include "api/Resource.h" +#include "Asset.h" namespace crepe { @@ -46,24 +46,37 @@ public: */ void set_volume(float volume); /** + * \brief Get playback volume / gain + * + * \return Volume + */ + float get_volume() const { return this->volume; } + /** * \brief Set looping behavior for this sample * * \param looping Looping behavior (false = one-shot, true = loop) */ void set_looping(bool looping); + /** + * \brief Get looping behavior + * + * \return true if looping, false if one-shot + */ + bool get_looping() const { return this->looping; } public: Sound(const char * src); - Sound(std::unique_ptr<api::Resource> res); + Sound(std::unique_ptr<Asset> res); private: - void load(std::unique_ptr<api::Resource> res); + void load(std::unique_ptr<Asset> res); private: - std::unique_ptr<api::Resource> res; SoLoud::Wav sample; SoLoud::handle handle; -}; -} + float volume = 1.0f; + bool looping = false; +}; +} // namespace crepe diff --git a/src/crepe/SoundContext.cpp b/src/crepe/SoundContext.cpp new file mode 100644 index 0000000..72047d2 --- /dev/null +++ b/src/crepe/SoundContext.cpp @@ -0,0 +1,20 @@ +#include "util/log.h" + +#include "SoundContext.h" + +using namespace crepe; + +SoundContext & SoundContext::get_instance() { + static SoundContext instance; + return instance; +} + +SoundContext::SoundContext() { + dbg_trace(); + engine.init(); +} + +SoundContext::~SoundContext() { + dbg_trace(); + engine.deinit(); +} diff --git a/src/crepe/SoundContext.h b/src/crepe/SoundContext.h new file mode 100644 index 0000000..090966d --- /dev/null +++ b/src/crepe/SoundContext.h @@ -0,0 +1,26 @@ +#pragma once + +#include <soloud.h> + +#include "Sound.h" + +namespace crepe { + +class SoundContext { +private: + SoundContext(); + virtual ~SoundContext(); + + // singleton + static SoundContext & get_instance(); + SoundContext(const SoundContext &) = delete; + SoundContext(SoundContext &&) = delete; + SoundContext & operator=(const SoundContext &) = delete; + SoundContext & operator=(SoundContext &&) = delete; + +private: + SoLoud::Soloud engine; + friend class Sound; +}; + +} // namespace crepe diff --git a/src/crepe/SoundSystem.cpp b/src/crepe/SoundSystem.cpp deleted file mode 100644 index 00f874c..0000000 --- a/src/crepe/SoundSystem.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "util/log.h" - -#include "SoundSystem.h" - -using namespace crepe; - -SoundSystem & SoundSystem::instance() { - static SoundSystem instance; - return instance; -} - -SoundSystem::SoundSystem() { - dbg_trace(); - engine.init(); -} - -SoundSystem::~SoundSystem() { - dbg_trace(); - engine.deinit(); -} - diff --git a/src/crepe/SoundSystem.h b/src/crepe/SoundSystem.h deleted file mode 100644 index da3927a..0000000 --- a/src/crepe/SoundSystem.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include <soloud.h> - -#include "Sound.h" - -namespace crepe { - -class SoundSystem { -private: - SoundSystem(); - virtual ~SoundSystem(); - - // singleton - static SoundSystem & instance(); - SoundSystem(const SoundSystem &) = delete; - SoundSystem(SoundSystem &&) = delete; - SoundSystem &operator=(const SoundSystem &) = delete; - SoundSystem &operator=(SoundSystem &&) = delete; - -private: - SoLoud::Soloud engine; - friend class Sound; -}; - -} - diff --git a/src/crepe/api/AudioSource.cpp b/src/crepe/api/AudioSource.cpp index cbde79f..b512d27 100644 --- a/src/crepe/api/AudioSource.cpp +++ b/src/crepe/api/AudioSource.cpp @@ -5,21 +5,18 @@ using namespace crepe::api; -AudioSource::AudioSource(std::unique_ptr<Resource> audio_clip) { - this->_sound = std::make_unique<crepe::Sound>(std::move(audio_clip)); +AudioSource::AudioSource(std::unique_ptr<Asset> audio_clip) { + this->sound = std::make_unique<crepe::Sound>(std::move(audio_clip)); } -void AudioSource::play() { - return this->play(false); -} +void AudioSource::play() { return this->play(false); } void AudioSource::play(bool looping) { - this->_sound->set_looping(looping); - this->_sound->play(); + this->sound->set_looping(looping); + this->sound->play(); } void AudioSource::stop() { - this->_sound->pause(); - this->_sound->rewind(); + this->sound->pause(); + this->sound->rewind(); } - diff --git a/src/crepe/api/AudioSource.h b/src/crepe/api/AudioSource.h index 6a038be..2d26cda 100644 --- a/src/crepe/api/AudioSource.h +++ b/src/crepe/api/AudioSource.h @@ -2,8 +2,8 @@ #include <memory> +#include "Asset.h" #include "Component.h" -#include "Resource.h" namespace crepe { class Sound; @@ -14,7 +14,7 @@ namespace crepe::api { //! Audio source component class AudioSource : Component { public: - AudioSource(std::unique_ptr<Resource> audio_clip); + AudioSource(std::unique_ptr<Asset> audio_clip); virtual ~AudioSource() = default; public: @@ -26,7 +26,7 @@ public: public: //! Sample file location - std::unique_ptr<Resource> audio_clip; + std::unique_ptr<Asset> audio_clip; //! TODO: ????? bool play_on_awake; //! Repeat the current audio clip during playback @@ -35,8 +35,7 @@ public: float volume; private: - std::unique_ptr<crepe::Sound> _sound; + std::unique_ptr<crepe::Sound> sound; }; -} - +} // namespace crepe::api diff --git a/src/crepe/api/CMakeLists.txt b/src/crepe/api/CMakeLists.txt index feb03ef..9548594 100644 --- a/src/crepe/api/CMakeLists.txt +++ b/src/crepe/api/CMakeLists.txt @@ -1,11 +1,9 @@ target_sources(crepe PUBLIC # AudioSource.cpp - Resource.cpp ) target_sources(crepe PUBLIC FILE_SET HEADERS FILES AudioSource.h Component.h - Resource.h ) diff --git a/src/crepe/api/Component.h b/src/crepe/api/Component.h index 2abb461..d5e0499 100644 --- a/src/crepe/api/Component.h +++ b/src/crepe/api/Component.h @@ -7,5 +7,4 @@ public: bool active; }; -} - +} // namespace crepe::api diff --git a/src/crepe/api/Resource.cpp b/src/crepe/api/Resource.cpp deleted file mode 100644 index 6bb081d..0000000 --- a/src/crepe/api/Resource.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include <filesystem> - -#include "Resource.h" - -using namespace crepe::api; - -Resource::Resource(const std::string & src) { - this->src = std::filesystem::canonical(src); - this->file = std::ifstream(this->src, std::ios::in | std::ios::binary); -} - -const std::istream & Resource::read() { - return this->file; -} - -const char * Resource::canonical() { - return this->src.c_str(); -} - diff --git a/src/crepe/api/Resource.h b/src/crepe/api/Resource.h deleted file mode 100644 index 2b62ff9..0000000 --- a/src/crepe/api/Resource.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include <string> -#include <fstream> -#include <iostream> - -namespace crepe::api { - -class Resource { -public: - Resource(const std::string & src); - -public: - //! Get an input stream to the contents of this resource - const std::istream & read(); - //! Get the canonical path to this resource - const char * canonical(); - -private: - std::string src; - std::ifstream file; -}; - -} - diff --git a/src/crepe/util/color.h b/src/crepe/util/color.h index 1af6c8f..066c9d3 100644 --- a/src/crepe/util/color.h +++ b/src/crepe/util/color.h @@ -38,5 +38,4 @@ constexpr const char * BG_MAGENTA_BRIGHT = "\e[105m"; constexpr const char * BG_CYAN_BRIGHT = "\e[106m"; constexpr const char * BG_WHITE_BRIGHT = "\e[107m"; -} - +} // namespace crepe::util::color diff --git a/src/crepe/util/log.cpp b/src/crepe/util/log.cpp index 796df49..6829ec3 100644 --- a/src/crepe/util/log.cpp +++ b/src/crepe/util/log.cpp @@ -48,4 +48,3 @@ void crepe::util::logf(log_level level, const char * fmt, ...) { va_logf(level, args, fmt); va_end(args); } - diff --git a/src/crepe/util/log.h b/src/crepe/util/log.h index 5295cb9..bfe7291 100644 --- a/src/crepe/util/log.h +++ b/src/crepe/util/log.h @@ -8,26 +8,29 @@ // utility macros #define _crepe_logf_here(fmt, ...) \ crepe::util::logf(util::log_level::debug, "%s%s (%s:%d)" fmt "\n", \ - crepe::util::color::FG_WHITE, \ - __PRETTY_FUNCTION__, \ - __FILE_NAME__, \ - __LINE__, \ - crepe::util::color::RESET, \ - __VA_ARGS__) + crepe::util::color::FG_WHITE, __PRETTY_FUNCTION__, \ + __FILE_NAME__, __LINE__, crepe::util::color::RESET, \ + __VA_ARGS__) +// very illegal global function-style macros +// NOLINTBEGIN #define dbg_logf(fmt, ...) _crepe_logf_here(": " fmt, __VA_ARGS__) #define dbg_log(str) _crepe_logf_here(": %s", str) #define dbg_trace() _crepe_logf_here("%s", "") +// NOLINTEND #endif namespace crepe::util { -enum log_level { debug, info, warning, error, }; +enum log_level { + debug, + info, + warning, + error, +}; void logf(const char * fmt, ...); void logf(enum log_level level, const char * fmt, ...); -} - - +} // namespace crepe::util diff --git a/src/example/CMakeLists.txt b/src/example/CMakeLists.txt new file mode 100644 index 0000000..bcc9271 --- /dev/null +++ b/src/example/CMakeLists.txt @@ -0,0 +1,3 @@ +add_executable(audio_internal EXCLUDE_FROM_ALL audio_internal.cpp) +target_link_libraries(audio_internal PUBLIC crepe) + diff --git a/src/dummy_audio.cpp b/src/example/audio_internal.cpp index 1249076..1199e2d 100644 --- a/src/dummy_audio.cpp +++ b/src/example/audio_internal.cpp @@ -1,5 +1,10 @@ -#include "crepe/util/log.h" -#include "crepe/Sound.h" +/** \file + * + * Standalone example for usage of the internal \c Sound class. + */ + +#include <crepe/Sound.h> +#include <crepe/util/log.h> #include <chrono> #include <thread> @@ -38,4 +43,3 @@ int main() { return 0; } - diff --git a/src/makefile b/src/makefile new file mode 100644 index 0000000..c1ef601 --- /dev/null +++ b/src/makefile @@ -0,0 +1,6 @@ +.PHONY: FORCE + +FMT += $(shell git ls-files '*.c' '*.cpp' '*.h' '*.hpp') +format: FORCE + clang-tidy -p build/compile_commands.json --fix-errors $(FMT) + diff --git a/src/readme.md b/src/readme.md new file mode 100644 index 0000000..1c5d3a2 --- /dev/null +++ b/src/readme.md @@ -0,0 +1,8 @@ +# engine source + +This folder contains the crêpe engine source files, unit tests, and some toy +examples. The only target built by default by the CMakeLists.txt in this folder +is the crêpe shared library object. Unit tests can be built by explicitly +specifying the target `test_main` when running the build command. Each source +file in the example/ folder corresponds to a CMake target as well. + diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt new file mode 100644 index 0000000..0d316d6 --- /dev/null +++ b/src/test/CMakeLists.txt @@ -0,0 +1,5 @@ +target_sources(test_main PUBLIC + dummy.cpp + # audio.cpp +) + diff --git a/src/test/audio.cpp b/src/test/audio.cpp new file mode 100644 index 0000000..d6ff689 --- /dev/null +++ b/src/test/audio.cpp @@ -0,0 +1,10 @@ +#include <gtest/gtest.h> + +using namespace std; +using namespace std::chrono_literals; + +// using namespace crepe; + +// TODO: mock internal audio class + +TEST(audio, play) { ASSERT_TRUE(true); } diff --git a/test/dummy.cpp b/src/test/dummy.cpp index a00a9c6..a00a9c6 100644 --- a/test/dummy.cpp +++ b/src/test/dummy.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt deleted file mode 100644 index f015570..0000000 --- a/test/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -cmake_minimum_required(VERSION 3.28) - -set(CMAKE_C_STANDARD 11) -set(CMAKE_CXX_STANDARD 20) -set(CMAKE_EXPORT_COMPILE_COMMANDS 1) - -set(CMAKE_BUILD_TYPE Debug) - -project(test C CXX) - -add_subdirectory(../lib/googletest googletest) -add_subdirectory(../src crepe) - -add_executable(test - dummy.cpp - # audio.cpp -) - -target_link_libraries(test - PRIVATE gtest_main - PUBLIC crepe # TODO: this does not work properly -) - diff --git a/test/audio.cpp b/test/audio.cpp deleted file mode 100644 index a415919..0000000 --- a/test/audio.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include <gtest/gtest.h> -#include <memory> - -#include <crepe/api/Resource.h> -#include <crepe/api/AudioSource.h> - -#include <chrono> -#include <thread> - -using namespace std; -using namespace std::chrono_literals; - -using namespace crepe::api; - -// TODO: mock internal audio class - -TEST(audio, play) { - auto res = std::make_unique<Resource>("../mwe/audio/bgm.ogg"); - auto bgm = AudioSource(std::move(res)); - - bgm.play(); - - this_thread::sleep_for(2s); - - bgm.stop(); - - ASSERT_TRUE(true); -} - |