aboutsummaryrefslogtreecommitdiff
path: root/src/crepe/api
diff options
context:
space:
mode:
Diffstat (limited to 'src/crepe/api')
-rw-r--r--src/crepe/api/Asset.cpp54
-rw-r--r--src/crepe/api/Asset.h84
-rw-r--r--src/crepe/api/CMakeLists.txt2
-rw-r--r--src/crepe/api/Config.h14
-rw-r--r--src/crepe/api/GameObject.cpp6
-rw-r--r--src/crepe/api/Script.h2
-rw-r--r--src/crepe/api/Script.hpp5
-rw-r--r--src/crepe/api/Texture.cpp2
8 files changed, 160 insertions, 9 deletions
diff --git a/src/crepe/api/Asset.cpp b/src/crepe/api/Asset.cpp
new file mode 100644
index 0000000..e148367
--- /dev/null
+++ b/src/crepe/api/Asset.cpp
@@ -0,0 +1,54 @@
+#include <filesystem>
+#include <stdexcept>
+#include <whereami.h>
+
+#include "api/Config.h"
+
+#include "Asset.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();
+ 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;
+
+ // 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..bfd0ac7
--- /dev/null
+++ b/src/crepe/api/Asset.h
@@ -0,0 +1,84 @@
+#pragma once
+
+#include <string>
+
+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:
+ /**
+ * \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
+ */
+ std::string whereami() const noexcept;
+};
+
+} // namespace crepe
+
+namespace std {
+
+//! Hash helper struct
+template <>
+struct hash<const crepe::Asset> {
+ /**
+ * \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;
+};
+
+} // namespace std
diff --git a/src/crepe/api/CMakeLists.txt b/src/crepe/api/CMakeLists.txt
index a185ca6..d6b6801 100644
--- a/src/crepe/api/CMakeLists.txt
+++ b/src/crepe/api/CMakeLists.txt
@@ -22,6 +22,7 @@ target_sources(crepe PUBLIC
IMouseListener.cpp
LoopManager.cpp
LoopTimer.cpp
+ Asset.cpp
EventHandler.cpp
)
@@ -56,4 +57,5 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES
IMouseListener.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/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<reference_wrapper<Metadata>> this_metadata
- = mgr.get_components_by_id<Metadata>(this->id);
+ RefVector<Metadata> this_metadata = mgr.get_components_by_id<Metadata>(this->id);
this_metadata.at(0).get().parent = parent.id;
// Add own id to children list of parent's Metadata component
- vector<reference_wrapper<Metadata>> parent_metadata
- = mgr.get_components_by_id<Metadata>(parent.id);
+ RefVector<Metadata> parent_metadata = mgr.get_components_by_id<Metadata>(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 <typename T>
- std::vector<std::reference_wrapper<T>> get_components() const;
+ RefVector<T> 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 <typename T>
T & Script::get_component() const {
using namespace std;
- vector<reference_wrapper<T>> all_components = this->get_components<T>();
+ RefVector<T> all_components = this->get_components<T>();
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 <typename T>
-std::vector<std::reference_wrapper<T>> Script::get_components() const {
+RefVector<T> Script::get_components() const {
auto & mgr = *this->component_manager_ref;
-
return mgr.get_components_by_id<T>(this->game_object_id);
}
diff --git a/src/crepe/api/Texture.cpp b/src/crepe/api/Texture.cpp
index 734a5bb..9be9421 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 {