aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/crepe/api/AudioSource.h11
-rw-r--r--src/crepe/facade/Sound.h4
-rw-r--r--src/crepe/system/AudioSystem.cpp17
-rw-r--r--src/crepe/system/AudioSystem.h21
-rw-r--r--src/crepe/util/CMakeLists.txt3
-rw-r--r--src/crepe/util/Private.cpp29
-rw-r--r--src/crepe/util/Private.h34
-rw-r--r--src/crepe/util/Private.hpp31
-rw-r--r--src/example/CMakeLists.txt1
-rw-r--r--src/example/asset_manager.cpp36
-rw-r--r--src/test/AudioTest.cpp5
-rw-r--r--src/test/CMakeLists.txt1
-rw-r--r--src/test/PrivateTest.cpp66
13 files changed, 210 insertions, 49 deletions
diff --git a/src/crepe/api/AudioSource.h b/src/crepe/api/AudioSource.h
index 0950129..9d76f0b 100644
--- a/src/crepe/api/AudioSource.h
+++ b/src/crepe/api/AudioSource.h
@@ -2,6 +2,7 @@
#include "../Component.h"
#include "../types.h"
+#include "../util/Private.h"
#include "GameObject.h"
#include "Asset.h"
@@ -47,14 +48,8 @@ private:
bool rewind = false;
private:
- //! Value of \c active after last system update
- bool last_active = false;
- //! Value of \c playing after last system update
- bool last_playing = false;
- //! Value of \c volume after last system update
- float last_volume = 1.0;
- //! Value of \c loop after last system update
- bool last_loop = false;
+ //! AudioSystem::ComponentPrivate
+ Private private_data;
};
} // namespace crepe
diff --git a/src/crepe/facade/Sound.h b/src/crepe/facade/Sound.h
index b0b80f8..f33ee58 100644
--- a/src/crepe/facade/Sound.h
+++ b/src/crepe/facade/Sound.h
@@ -9,6 +9,10 @@ namespace crepe {
class SoundContext;
+struct SoundHandle {
+ SoLoud::handle handle;
+};
+
/**
* \brief Sound resource facade
*
diff --git a/src/crepe/system/AudioSystem.cpp b/src/crepe/system/AudioSystem.cpp
index 97cf966..0f943be 100644
--- a/src/crepe/system/AudioSystem.cpp
+++ b/src/crepe/system/AudioSystem.cpp
@@ -1,6 +1,5 @@
#include "AudioSystem.h"
-#include "../api/AudioSource.h"
#include "../manager/ComponentManager.h"
#include "../manager/ResourceManager.h"
#include "../types.h"
@@ -13,12 +12,24 @@ void AudioSystem::update() {
ResourceManager & resource_manager = this->mediator.resource_manager;
RefVector<AudioSource> components = component_manager.get_components_by_type<AudioSource>();
- for (auto component_ref : components) {
- AudioSource & component = component_ref.get();
+ for (AudioSource & component : components) {
if (!component.active) continue;
Sound & sound = resource_manager.get<Sound>(component.source);
+ if (component.private_data.empty())
+ component.private_data.set<ComponentPrivate>();
+ auto & data = component.private_data.get<ComponentPrivate>();
// TODO: lots of state diffing
+
+
+ this->update_private(component, data);
}
}
+void AudioSystem::update_private(const AudioSource & component, ComponentPrivate & data) {
+ data.last_active = component.active;
+ data.last_loop = component.loop;
+ data.last_playing = component.playing;
+ data.last_volume = component.volume;
+}
+
diff --git a/src/crepe/system/AudioSystem.h b/src/crepe/system/AudioSystem.h
index e037f51..7f41fda 100644
--- a/src/crepe/system/AudioSystem.h
+++ b/src/crepe/system/AudioSystem.h
@@ -1,6 +1,7 @@
#pragma once
#include "../facade/SoundContext.h"
+#include "../api/AudioSource.h"
#include "System.h"
@@ -12,6 +13,26 @@ public:
void update() override;
private:
+ /**
+ * \brief Private data stored by AudioSystem on AudioSource component
+ */
+ struct ComponentPrivate {
+ //! This sample's voice handle
+ SoLoud::handle handle;
+
+ //! Value of \c active after last system update
+ bool last_active = false;
+ //! Value of \c playing after last system update
+ bool last_playing = false;
+ //! Value of \c volume after last system update
+ float last_volume = 1.0;
+ //! Value of \c loop after last system update
+ bool last_loop = false;
+ };
+
+ void update_private(const AudioSource & component, ComponentPrivate & data);
+
+private:
SoundContext context {};
};
diff --git a/src/crepe/util/CMakeLists.txt b/src/crepe/util/CMakeLists.txt
index 94ed906..f49d851 100644
--- a/src/crepe/util/CMakeLists.txt
+++ b/src/crepe/util/CMakeLists.txt
@@ -1,6 +1,7 @@
target_sources(crepe PUBLIC
LogColor.cpp
Log.cpp
+ Private.cpp
)
target_sources(crepe PUBLIC FILE_SET HEADERS FILES
@@ -11,5 +12,7 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES
Proxy.hpp
OptionalRef.h
OptionalRef.hpp
+ Private.h
+ Private.hpp
)
diff --git a/src/crepe/util/Private.cpp b/src/crepe/util/Private.cpp
new file mode 100644
index 0000000..c5b5b30
--- /dev/null
+++ b/src/crepe/util/Private.cpp
@@ -0,0 +1,29 @@
+#include "Private.h"
+
+using namespace crepe;
+
+bool Private::empty() const noexcept {
+ return this->instance == nullptr;
+}
+
+Private::~Private() {
+ if (this->instance == nullptr) return;
+ this->destructor(this->instance);
+}
+
+Private::Private(Private && other) {
+ *this = std::move(other);
+}
+
+Private & Private::operator=(Private && other) {
+ // TODO: ideally this function checks for self-assignment
+ this->instance = other.instance;
+ this->destructor = other.destructor;
+ this->type = other.type;
+
+ other.instance = nullptr;
+ other.destructor = [](void*){};
+
+ return *this;
+}
+
diff --git a/src/crepe/util/Private.h b/src/crepe/util/Private.h
new file mode 100644
index 0000000..fc3728f
--- /dev/null
+++ b/src/crepe/util/Private.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include <typeindex>
+#include <functional>
+
+namespace crepe {
+
+class Private {
+public:
+ Private() = default;
+ ~Private();
+ Private(Private &&);
+ Private & operator=(Private &&);
+ Private(const Private &) = delete;
+ Private & operator=(const Private &) = delete;
+
+ template <typename T>
+ T & get();
+
+ template <typename T, typename... Args>
+ void set(Args &&... args);
+
+ bool empty() const noexcept;
+
+private:
+ std::function<void(void *)> destructor;
+ std::type_index type = typeid(void);
+ void * instance = nullptr;
+};
+
+}
+
+#include "Private.hpp"
+
diff --git a/src/crepe/util/Private.hpp b/src/crepe/util/Private.hpp
new file mode 100644
index 0000000..30c8146
--- /dev/null
+++ b/src/crepe/util/Private.hpp
@@ -0,0 +1,31 @@
+#pragma once
+
+#include <stdexcept>
+#include <format>
+
+#include "Private.h"
+
+namespace crepe {
+
+template <typename T, typename... Args>
+void Private::set(Args &&... args) {
+ T * instance = new T(std::forward<Args>(args)...);
+ this->instance = static_cast<void*>(instance);
+ this->destructor = [](void * instance) {
+ delete static_cast<T*>(instance);
+ };
+ this->type = typeid(T);
+}
+
+template <typename T>
+T & Private::get() {
+ using namespace std;
+ if (this->empty())
+ throw out_of_range("Private: get() called on empty object");
+ type_index requested_type = typeid(T);
+ if (this->type != requested_type)
+ throw logic_error(format("Private: get() called with [T = {}] (actual is [T = {}])", requested_type.name(), this->type.name()));
+ return *static_cast<T*>(this->instance);
+}
+
+}
diff --git a/src/example/CMakeLists.txt b/src/example/CMakeLists.txt
index 560e2bc..9c3c550 100644
--- a/src/example/CMakeLists.txt
+++ b/src/example/CMakeLists.txt
@@ -16,7 +16,6 @@ function(add_example target_name)
add_dependencies(examples ${target_name})
endfunction()
-add_example(asset_manager)
add_example(savemgr)
add_example(rendering_particle)
add_example(gameloop)
diff --git a/src/example/asset_manager.cpp b/src/example/asset_manager.cpp
deleted file mode 100644
index 660b318..0000000
--- a/src/example/asset_manager.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-#include <crepe/api/AssetManager.h>
-#include <crepe/api/Texture.h>
-#include <crepe/facade/Sound.h>
-
-using namespace crepe;
-
-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"); }
- // 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).
-
- auto & mgr = AssetManager::get_instance();
-
- {
- // 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 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 img = mgr.cache<Texture>("asset/texture/img.png");
- auto img1 = mgr.cache<Texture>("asset/texture/second.png");
- }
-}
diff --git a/src/test/AudioTest.cpp b/src/test/AudioTest.cpp
index afd2672..3be5afa 100644
--- a/src/test/AudioTest.cpp
+++ b/src/test/AudioTest.cpp
@@ -1,6 +1,7 @@
#include <gtest/gtest.h>
#include <crepe/manager/ComponentManager.h>
+#include <crepe/manager/ResourceManager.h>
#include <crepe/api/AudioSource.h>
#include <crepe/api/GameObject.h>
#include <crepe/system/AudioSystem.h>
@@ -13,15 +14,17 @@ class AudioTest : public Test {
Mediator mediator;
public:
ComponentManager component_manager{mediator};
+ ResourceManager resource_manager{mediator};
AudioSystem system {mediator};
void SetUp() override {
auto & mgr = this->component_manager;
GameObject entity = mgr.new_object("name");
- entity.add_component<AudioSource>("mwe/audio/sfx1.wav");
+ AudioSource & audio_source = entity.add_component<AudioSource>("mwe/audio/sfx1.wav");
}
};
TEST_F(AudioTest, Default) {
+ system.update();
}
diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt
index 4174926..8c4b855 100644
--- a/src/test/CMakeLists.txt
+++ b/src/test/CMakeLists.txt
@@ -16,4 +16,5 @@ target_sources(test_main PUBLIC
Vector2Test.cpp
ScriptEventTest.cpp
ScriptSceneTest.cpp
+ PrivateTest.cpp
)
diff --git a/src/test/PrivateTest.cpp b/src/test/PrivateTest.cpp
new file mode 100644
index 0000000..f0d2b1a
--- /dev/null
+++ b/src/test/PrivateTest.cpp
@@ -0,0 +1,66 @@
+#include <gtest/gtest.h>
+
+#include <crepe/util/Private.h>
+
+using namespace std;
+using namespace crepe;
+using namespace testing;
+
+class PrivateTest : public Test {
+public:
+ static unsigned constructors;
+ static unsigned destructors;
+
+ void SetUp() override {
+ PrivateTest::constructors = 0;
+ PrivateTest::destructors = 0;
+ }
+
+ class TestClass {
+ public:
+ TestClass() { PrivateTest::constructors++; }
+ ~TestClass() { PrivateTest::destructors++; }
+ };
+ class Unrelated {};
+};
+unsigned PrivateTest::constructors;
+unsigned PrivateTest::destructors;
+
+TEST_F(PrivateTest, Empty) {
+ {
+ Private foo;
+ }
+
+ EXPECT_EQ(PrivateTest::constructors, 0);
+ EXPECT_EQ(PrivateTest::destructors, 0);
+}
+
+TEST_F(PrivateTest, WithObject) {
+ {
+ Private foo;
+ foo.set<TestClass>();
+
+ EXPECT_EQ(PrivateTest::constructors, 1);
+ EXPECT_EQ(PrivateTest::destructors, 0);
+ }
+
+ EXPECT_EQ(PrivateTest::constructors, 1);
+ EXPECT_EQ(PrivateTest::destructors, 1);
+}
+
+TEST_F(PrivateTest, EmptyException) {
+ Private foo;
+ EXPECT_THROW(foo.get<TestClass>(), std::out_of_range);
+
+ foo.set<TestClass>();
+ EXPECT_NO_THROW(foo.get<TestClass>());
+}
+
+TEST_F(PrivateTest, IncorrectTypeException) {
+ Private foo;
+ foo.set<TestClass>();
+
+ EXPECT_THROW(foo.get<Unrelated>(), std::logic_error);
+ EXPECT_NO_THROW(foo.get<TestClass>());
+}
+