aboutsummaryrefslogtreecommitdiff
path: root/src/crepe
diff options
context:
space:
mode:
Diffstat (limited to 'src/crepe')
-rw-r--r--src/crepe/Asset.cpp16
-rw-r--r--src/crepe/Asset.h41
-rw-r--r--src/crepe/CMakeLists.txt2
-rw-r--r--src/crepe/api/Asset.cpp58
-rw-r--r--src/crepe/api/Asset.h60
-rw-r--r--src/crepe/api/CMakeLists.txt2
-rw-r--r--src/crepe/api/Config.h14
-rw-r--r--src/crepe/api/Texture.cpp2
-rw-r--r--src/crepe/facade/SDLContext.cpp2
-rw-r--r--src/crepe/facade/Sound.cpp2
-rw-r--r--src/crepe/facade/Sound.h2
-rw-r--r--src/crepe/system/System.h2
-rw-r--r--src/crepe/util/CMakeLists.txt2
-rw-r--r--src/crepe/util/OptionalRef.h41
-rw-r--r--src/crepe/util/OptionalRef.hpp67
15 files changed, 250 insertions, 63 deletions
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 <filesystem>
-
-#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 <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:
- /**
- * \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 <filesystem>
+#include <stdexcept>
+#include <whereami.h>
+
+#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<const Asset>::operator()(const Asset & asset) const noexcept {
+ return std::hash<string>{}(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 <string>
+#include <unordered_map>
+
+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<const crepe::Asset> {
+ 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<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 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<SDL_Surface, std::function<void(SDL_Surface *)>> 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<Asset>(src));
}
-void Sound::load(unique_ptr<Asset> res) { this->sample.load(res->get_canonical().c_str()); }
+void Sound::load(unique_ptr<Asset> 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 <soloud/soloud.h>
#include <soloud/soloud_wav.h>
-#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 <typename T>
+class OptionalRef {
+public:
+ OptionalRef() = default;
+ OptionalRef(T &);
+ OptionalRef<T> & operator=(T &);
+ explicit operator bool() const noexcept;
+
+ void set(T &) noexcept;
+ T & get() const;
+ void clear() noexcept;
+
+ OptionalRef(const OptionalRef<T> &);
+ OptionalRef(OptionalRef<T> &&);
+ OptionalRef<T> & operator=(const OptionalRef<T> &);
+ OptionalRef<T> & operator=(OptionalRef<T> &&);
+
+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 <stdexcept>
+
+#include "OptionalRef.h"
+
+namespace crepe {
+
+template <typename T>
+OptionalRef<T>::OptionalRef(T & ref) {
+ this->set(ref);
+}
+
+template <typename T>
+OptionalRef<T>::OptionalRef(const OptionalRef<T> & other) {
+ this->ref = other.ref;
+}
+
+template <typename T>
+OptionalRef<T>::OptionalRef(OptionalRef<T> && other) {
+ this->ref = other.ref;
+ other.clear();
+}
+
+template <typename T>
+OptionalRef<T> & OptionalRef<T>::operator=(const OptionalRef<T> & other) {
+ this->ref = other.ref;
+ return *this;
+}
+
+template <typename T>
+OptionalRef<T> & OptionalRef<T>::operator=(OptionalRef<T> && other) {
+ this->ref = other.ref;
+ other.clear();
+ return *this;
+}
+
+template <typename T>
+T & OptionalRef<T>::get() const {
+ if (this->ref == nullptr)
+ throw std::runtime_error("OptionalRef: attempt to dereference nullptr");
+ return *this->ref;
+}
+
+template <typename T>
+void OptionalRef<T>::set(T & ref) noexcept {
+ this->ref = &ref;
+}
+
+template <typename T>
+void OptionalRef<T>::clear() noexcept {
+ this->ref = nullptr;
+}
+
+template <typename T>
+OptionalRef<T> & OptionalRef<T>::operator=(T & ref) {
+ this->set(ref);
+ return *this;
+}
+
+template <typename T>
+OptionalRef<T>::operator bool() const noexcept {
+ return this->ref != nullptr;
+}
+
+}
+