From 34d9a4b0402560dfe324b12c200070ef16028a0b Mon Sep 17 00:00:00 2001 From: fallenatlas Date: Mon, 30 Sep 2024 10:31:32 +0100 Subject: [PATCH] docs: update CHANGELOG.md --- CHANGELOG.md | 4 +- engine/include/cubos/engine/assets/asset.hpp | 12 +- engine/include/cubos/engine/assets/assets.hpp | 5 + engine/include/cubos/engine/assets/meta.hpp | 11 ++ engine/samples/games/cubosurfers/main.cpp | 6 +- engine/src/assets/asset.cpp | 39 ++++--- engine/src/assets/assets.cpp | 107 +++++++++++++++--- engine/src/assets/meta.cpp | 14 +++ .../solver/penetration_constraint/plugin.cpp | 8 +- .../src/render/g_buffer_rasterizer/plugin.cpp | 4 +- engine/src/render/mesh/plugin.cpp | 27 +++-- engine/src/scene/bridge.cpp | 2 +- .../src/tesseratos/scene_editor/plugin.cpp | 2 +- 13 files changed, 181 insertions(+), 60 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 66952c708b..56125d258a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,12 +21,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Print stacktrace with *cpptrace* on calls to CUBOS_FAIL (#1172, **@RiscadoA**). - Orthographic Camera component (#1182, **@mkuritsu**). - Importer plugin (#1299, **@Scarface1809**). +- Handle body rotation on penetration solving (#1272, **&fallenatlas**). ### Changed - Moved Glad and stb-image libs to another repositories, cubos-glad and cubos-stb, respectively (#1323, **@kuukitenshi**). - Moved most tools from Tesseratos to the engine (#1322, **@RiscadoA**). - +- Allow identifying assets in code from their path (#1177. **@GalaxyCrush**). + ### Fixed - Spot light angle mismatch between light and shadows (#1310, **@tomas7770**). diff --git a/engine/include/cubos/engine/assets/asset.hpp b/engine/include/cubos/engine/assets/asset.hpp index 1424f6106d..4152bb98fd 100644 --- a/engine/include/cubos/engine/assets/asset.hpp +++ b/engine/include/cubos/engine/assets/asset.hpp @@ -30,7 +30,7 @@ namespace cubos::engine /// @brief Avoid using this field, use @ref getId() instead. /// @todo This was added as a dirty fix for #692, should be removed once the issue is fixed. - uuids::uuid reflectedId; + std::string pathOrId; ~AnyAsset(); @@ -71,9 +71,13 @@ namespace cubos::engine /// @return Asset version. int getVersion() const; - /// @brief Gets the UUID of the asset. + /// @brief Gets the Path or UUID of the asset. + /// @return Asset Path or UUID. + std::string getIdString() const; + + /// @brief Gets the UUID of the asset if it is the case of having one. /// @return Asset UUID. - uuids::uuid getId() const; + std::optional getId() const; /// @brief Checks if the handle is null. /// @return Whether the handle is null. @@ -160,7 +164,7 @@ namespace cubos::engine inline AnyAsset::operator Asset() const { Asset asset; - asset.reflectedId = reflectedId; + asset.pathOrId = pathOrId; asset.mId = mId; asset.mRefCount = mRefCount; asset.mVersion = mVersion; diff --git a/engine/include/cubos/engine/assets/assets.hpp b/engine/include/cubos/engine/assets/assets.hpp index f80c0274c4..0166053f22 100644 --- a/engine/include/cubos/engine/assets/assets.hpp +++ b/engine/include/cubos/engine/assets/assets.hpp @@ -356,6 +356,11 @@ namespace cubos::engine /// @return Lock guard. std::unique_lock lockWrite(const AnyAsset& handle) const; + /// @brief Checks if the given path is a valid path to an asset. + /// @param path Path to check. + /// @return A string that says if the given string is a path, uuid or not a valid format string + std::string isPath(const std::string& path) const; + /// @brief Gets a pointer to the entry associated with the given handle. /// @param handle Handle to get the entry for. /// @return Entry for the given handle, or nullptr if there is no such entry. diff --git a/engine/include/cubos/engine/assets/meta.hpp b/engine/include/cubos/engine/assets/meta.hpp index b201fa060d..968b99bcf5 100644 --- a/engine/include/cubos/engine/assets/meta.hpp +++ b/engine/include/cubos/engine/assets/meta.hpp @@ -9,8 +9,11 @@ #include #include +#include + #include + namespace cubos::engine { /// @brief Stores metadata about an asset - the data stored in .meta files. @@ -44,6 +47,14 @@ namespace cubos::engine /// @return The value of the parameter, if the parameter exists. std::optional get(std::string_view key) const; + /// @brief Gets the ID of the asset. + /// @return ID of the asset. + uuids::uuid getId() const; + + /// @brief Gets the path of the asset. + /// @return Path of the asset. + std::string getPath() const; + /// @brief Sets a parameter on the asset's metadata. /// @param key Key of the parameter. /// @param value Value of the parameter. diff --git a/engine/samples/games/cubosurfers/main.cpp b/engine/samples/games/cubosurfers/main.cpp index 87af77ad43..bd38a6ecd3 100644 --- a/engine/samples/games/cubosurfers/main.cpp +++ b/engine/samples/games/cubosurfers/main.cpp @@ -16,9 +16,9 @@ using namespace cubos::engine; -static const Asset SceneAsset = AnyAsset("ee5bb451-05b7-430f-a641-a746f7009eef"); -static const Asset PaletteAsset = AnyAsset("101da567-3d23-46ae-a391-c10ec00e8718"); -static const Asset InputBindingsAsset = AnyAsset("b20900a4-20ee-4caa-8830-14585050bead"); +static const Asset SceneAsset = AnyAsset("/assets/scenes/main.cubos"); +static const Asset PaletteAsset = AnyAsset("/assets/main.pal"); +static const Asset InputBindingsAsset = AnyAsset("/assets/input.bind"); int main(int argc, char** argv) { diff --git a/engine/src/assets/asset.cpp b/engine/src/assets/asset.cpp index 03a8023cea..468c513598 100644 --- a/engine/src/assets/asset.cpp +++ b/engine/src/assets/asset.cpp @@ -27,7 +27,7 @@ AnyAsset::AnyAsset(std::nullptr_t) } AnyAsset::AnyAsset(uuids::uuid id) - : reflectedId(id) + : pathOrId(uuids::to_string(id)) , mId(id) , mRefCount(nullptr) , mVersion(-1) @@ -40,9 +40,13 @@ AnyAsset::AnyAsset(std::string_view str) { if (auto id = uuids::uuid::from_string(str)) { - reflectedId = id.value(); + pathOrId = str; mId = id.value(); } + else if (str.find('/') != std::string_view::npos || str.find('\\') != std::string_view::npos) + { + pathOrId = str; + } else { CUBOS_ERROR("Could not create asset handle, invalid UUID: \"{}\"", str); @@ -50,7 +54,7 @@ AnyAsset::AnyAsset(std::string_view str) } AnyAsset::AnyAsset(const AnyAsset& other) - : reflectedId(other.reflectedId) + : pathOrId(other.pathOrId) , mId(other.mId) , mRefCount(other.mRefCount) , mVersion(other.mVersion) @@ -59,7 +63,7 @@ AnyAsset::AnyAsset(const AnyAsset& other) } AnyAsset::AnyAsset(AnyAsset&& other) noexcept - : reflectedId(other.reflectedId) + : pathOrId(other.pathOrId) , mId(other.mId) , mRefCount(other.mRefCount) , mVersion(other.mVersion) @@ -75,7 +79,7 @@ AnyAsset& AnyAsset::operator=(const AnyAsset& other) } this->decRef(); - reflectedId = other.reflectedId; + pathOrId = other.pathOrId; mId = other.mId; mRefCount = other.mRefCount; mVersion = other.mVersion; @@ -91,7 +95,7 @@ AnyAsset& AnyAsset::operator=(AnyAsset&& other) noexcept } this->decRef(); - reflectedId = other.reflectedId; + pathOrId = other.pathOrId; mId = other.mId; mRefCount = other.mRefCount; mVersion = other.mVersion; @@ -101,27 +105,32 @@ AnyAsset& AnyAsset::operator=(AnyAsset&& other) noexcept bool AnyAsset::operator==(const AnyAsset& other) const { - return this->getId() == other.getId(); + return this->getIdString() == other.getIdString(); } int AnyAsset::getVersion() const { - return reflectedId == mId ? mVersion : 0; + return getId().has_value() && getId().value() == mId ? mVersion : 0; +} + +std::string AnyAsset::getIdString() const +{ + return pathOrId; } -uuids::uuid AnyAsset::getId() const +std::optional AnyAsset::getId() const { - return reflectedId; + return uuids::uuid::from_string(pathOrId); } bool AnyAsset::isNull() const { - return reflectedId.is_nil(); + return pathOrId.empty(); } bool AnyAsset::isStrong() const { - return reflectedId == mId && mRefCount != nullptr; + return getId().has_value() && getId().value() == mId && mRefCount != nullptr; } void AnyAsset::makeWeak() @@ -136,12 +145,12 @@ cubos::core::reflection::Type& AnyAsset::makeType(std::string name) return Type::create(std::move(name)) .with(ConstructibleTrait::typed().withBasicConstructors().build()) - .with(FieldsTrait().withField("id", &AnyAsset::reflectedId)); + .with(FieldsTrait().withField("id", &AnyAsset::pathOrId)); } void AnyAsset::incRef() const { - if (reflectedId == mId && mRefCount != nullptr) + if (getId().has_value() && getId().value() == mId && mRefCount != nullptr) { static_cast*>(mRefCount)->fetch_add(1); } @@ -149,7 +158,7 @@ void AnyAsset::incRef() const void AnyAsset::decRef() const { - if (reflectedId == mId && mRefCount != nullptr) + if (getId().has_value() && getId().value() == mId && mRefCount != nullptr) { static_cast*>(mRefCount)->fetch_sub(1); } diff --git a/engine/src/assets/assets.cpp b/engine/src/assets/assets.cpp index ee18796fec..96d3abfd21 100644 --- a/engine/src/assets/assets.cpp +++ b/engine/src/assets/assets.cpp @@ -219,7 +219,7 @@ void Assets::loadMeta(std::string_view path) // Get the UUID from the metadata, if it exists. if (meta.get("id").has_value()) { - id = uuids::uuid::from_string(meta.get("id").value()).value_or(uuids::uuid()); + id = meta.getId(); } // If the UUID is invalid, generate a new random one. @@ -287,6 +287,7 @@ AnyAsset Assets::load(AnyAsset handle) const // Return a strong handle to the asset. assetEntry->refCount += 1; handle.mRefCount = &assetEntry->refCount; + handle.mId = assetEntry->meta.getId(); return handle; } @@ -354,7 +355,7 @@ Assets::Status Assets::status(const AnyAsset& handle) const std::shared_lock lock(mMutex); // Do not use .entry() here because we don't want to log errors if the asset is unknown. - auto it = mEntries.find(handle.getId()); + auto it = mEntries.find(handle.getId().value()); if (it == mEntries.end()) { return Status::Unknown; @@ -372,9 +373,9 @@ bool Assets::update(AnyAsset& handle) const return false; } - if (handle.mId != handle.reflectedId) + if (handle.mId != assetEntry->meta.getId()) { - handle = AnyAsset{handle.reflectedId}; + handle = AnyAsset{assetEntry->meta.getId()}; handle.mVersion = assetEntry->version; return true; } @@ -596,6 +597,21 @@ std::unique_lock Assets::lockWrite(const AnyAsset& handle) co abort(); } +std::string Assets::isPath(const std::string& path) const +{ + if (path.find('/') != std::string::npos || path.find('\\') != std::string::npos) + { + return "Path"; + } + else if (auto id = uuids::uuid::from_string(path)) + { + return "UUID"; + } + else + { + return "Invalid format"; + } +} std::shared_ptr Assets::entry(const AnyAsset& handle) const { // If the handle is null, we can't access the asset. @@ -608,15 +624,36 @@ std::shared_ptr Assets::entry(const AnyAsset& handle) const // Lock the entries map for reading. auto sharedLock = std::shared_lock(mMutex); - // Search for the entry in the map. - auto it = mEntries.find(handle.getId()); - if (it == mEntries.end()) + auto sid = handle.getIdString(); + + if (isPath(sid) == "Path") { + for (const auto& [eid, entry] : mEntries) + { + if (entry->meta.getPath() == sid) + { + return entry; + } + } CUBOS_ERROR("No such asset {}", handle); return nullptr; } - - return it->second; + else if (isPath(sid) == "UUID") + { + // Search for the entry in the map. + auto it = mEntries.find(handle.getId().value()); + if (it == mEntries.end()) + { + CUBOS_ERROR("No such asset {}", handle); + return nullptr; + } + return it->second; + } + else + { + CUBOS_ERROR("Invalid asset handle"); + return nullptr; + } } std::shared_ptr Assets::entry(const AnyAsset& handle, bool create) @@ -641,18 +678,26 @@ std::shared_ptr Assets::entry(const AnyAsset& handle, bool create sharedLock.lock(); } - // Search for an existing entry for the asset. - auto it = mEntries.find(handle.getId()); - if (it == mEntries.end()) + auto sid = handle.getIdString(); + + if (isPath(sid) == "Path") { - // If we're creating the asset, create a new entry for it. - // Otherwise, return nullptr. + for (const auto& [eid, entry] : mEntries) + { + if (entry->meta.getPath() == sid) + { + return entry; + } + } if (create) { + auto n_uuid = uuids::uuid_random_generator(mRandom.value())(); auto entry = std::make_shared(); - entry->meta.set("id", uuids::to_string(handle.getId())); - it = mEntries.emplace(handle.getId(), std::move(entry)).first; + entry->meta.set("path", sid); + entry->meta.set("id", uuids::to_string(n_uuid)); + auto it = mEntries.emplace(n_uuid, std::move(entry)).first; CUBOS_TRACE("Created new asset entry for {}", handle); + return it->second; } else { @@ -660,8 +705,36 @@ std::shared_ptr Assets::entry(const AnyAsset& handle, bool create return nullptr; } } + else if (isPath(sid) == "UUID") + { - return it->second; + // Search for an existing entry for the asset. + auto it = mEntries.find(handle.getId().value()); + if (it == mEntries.end()) + { + // If we're creating the asset, create a new entry for it. + // Otherwise, return nullptr. + if (create) + { + auto entry = std::make_shared(); + entry->meta.set("id", uuids::to_string(handle.getId().value())); + it = mEntries.emplace(handle.getId().value(), std::move(entry)).first; + CUBOS_TRACE("Created new asset entry for {}", handle); + } + else + { + CUBOS_ERROR("No such asset {}", handle); + return nullptr; + } + } + + return it->second; + } + else + { + CUBOS_ERROR("Invalid asset handle"); + return nullptr; + } } std::shared_ptr Assets::bridge(const AnyAsset& handle, bool logError) const diff --git a/engine/src/assets/meta.cpp b/engine/src/assets/meta.cpp index e019e95cef..a248bb1262 100644 --- a/engine/src/assets/meta.cpp +++ b/engine/src/assets/meta.cpp @@ -21,3 +21,17 @@ void AssetMeta::remove(std::string_view key) { mParams.erase(std::string(key)); } + +uuids::uuid AssetMeta::getId() const +{ + return uuids::uuid::from_string(this->get("id").value()).value(); +} + +std::string AssetMeta::getPath() const +{ + if (auto path = this->get("path")) + { + return path.value(); + } + return {}; +} diff --git a/engine/src/physics/solver/penetration_constraint/plugin.cpp b/engine/src/physics/solver/penetration_constraint/plugin.cpp index 12a5edb6ef..f169b0b427 100644 --- a/engine/src/physics/solver/penetration_constraint/plugin.cpp +++ b/engine/src/physics/solver/penetration_constraint/plugin.cpp @@ -19,7 +19,7 @@ CUBOS_DEFINE_TAG(cubos::engine::penetrationConstraintSolveRelaxTag); CUBOS_DEFINE_TAG(cubos::engine::penetrationConstraintRestitutionTag); CUBOS_DEFINE_TAG(cubos::engine::penetrationConstraintCleanTag); -void getPlaneSpace(const glm::vec3& n, glm::vec3& tangent1, glm::vec3& tangent2) +static void getPlaneSpace(const glm::vec3& n, glm::vec3& tangent1, glm::vec3& tangent2) { if (glm::abs(n.z) > (1.0F / glm::sqrt(2.0F))) { @@ -33,8 +33,8 @@ void getPlaneSpace(const glm::vec3& n, glm::vec3& tangent1, glm::vec3& tangent2) } } -void getTangents(const glm::vec3& velocity1, const glm::vec3& velocity2, const glm::vec3& n, glm::vec3& tangent1, - glm::vec3& tangent2) +static void getTangents(const glm::vec3& velocity1, const glm::vec3& velocity2, const glm::vec3& n, glm::vec3& tangent1, + glm::vec3& tangent2) { // Use linear relative velocity for determining tangents. glm::vec3 linearVr = velocity2 - velocity1; @@ -77,7 +77,7 @@ static float mixValues(float value1, float value2, PhysicsMaterial::MixProperty } } -void solvePenetrationConstraint( +static void solvePenetrationConstraint( Query diff --git a/engine/src/render/g_buffer_rasterizer/plugin.cpp b/engine/src/render/g_buffer_rasterizer/plugin.cpp index 3cac723e6b..84e4f65721 100644 --- a/engine/src/render/g_buffer_rasterizer/plugin.cpp +++ b/engine/src/render/g_buffer_rasterizer/plugin.cpp @@ -151,7 +151,7 @@ void cubos::engine::gBufferRasterizerPlugin(Cubos& cubos) auto& rd = window->renderDevice(); // Update the palette's data if necessary (if the asset handle changed or the asset itself was modified). - if (state.paletteAsset.getId() != palette.asset.getId() || + if (state.paletteAsset != palette.asset || (!state.paletteAsset.isNull() && assets.update(state.paletteAsset))) { state.paletteAsset = assets.load(palette.asset); @@ -172,7 +172,7 @@ void cubos::engine::gBufferRasterizerPlugin(Cubos& cubos) // Send the data to the GPU. state.paletteTexture->update(0, 0, 256, 256, data.data()); - CUBOS_INFO("Updated GBufferRasterizer's palette texture to asset {}", state.paletteAsset.getId()); + CUBOS_INFO("Updated GBufferRasterizer's palette texture to asset {}", state.paletteAsset.getIdString()); } for (auto [ent, rasterizer, gBuffer, depth, picker] : targets) diff --git a/engine/src/render/mesh/plugin.cpp b/engine/src/render/mesh/plugin.cpp index 2e9ac8dbe1..23f16f4847 100644 --- a/engine/src/render/mesh/plugin.cpp +++ b/engine/src/render/mesh/plugin.cpp @@ -87,9 +87,11 @@ void cubos::engine::renderMeshPlugin(Cubos& cubos) continue; } + // If not loaded, the mId might be a nil UUID, so we need to load the asset first. + assets.load(grid.asset); // If the asset has never been loaded, or it has been updated since the last meshing, update the entry // and queue a meshing task. Otherwise, just reuse the existing mesh. - auto& entry = state.entries[grid.asset.getId()]; + auto& entry = state.entries[grid.asset.getId().value()]; entry.referenceCount += 1; if (entry.asset.isNull() || assets.update(entry.asset)) { @@ -111,7 +113,7 @@ void cubos::engine::renderMeshPlugin(Cubos& cubos) task.finish(std::move(vertices)); }); - state.meshing.insert(grid.asset.getId()); + state.meshing.insert(grid.asset.getId().value()); } else if (entry.firstBucketId != RenderMeshPool::BucketId::Invalid) { @@ -131,8 +133,8 @@ void cubos::engine::renderMeshPlugin(Cubos& cubos) continue; } - auto& entry = state.entries[grid.asset.getId()]; - if (!state.meshing.contains(grid.asset.getId())) + auto& entry = state.entries[grid.asset.getId().value()]; + if (!state.meshing.contains(grid.asset.getId().value())) { if (entry.asset.isNull() || assets.update(entry.asset)) { @@ -154,7 +156,7 @@ void cubos::engine::renderMeshPlugin(Cubos& cubos) task.finish(std::move(vertices)); }); - state.meshing.insert(grid.asset.getId()); + state.meshing.insert(grid.asset.getId().value()); } else { @@ -170,16 +172,16 @@ void cubos::engine::renderMeshPlugin(Cubos& cubos) cmds.remove(ent); cmds.add(ent, RenderMesh{.firstBucketId = firstBucketId}); CUBOS_INFO("Finished meshing voxel grid asset {} ({} vertices), allocated new render bucket", - grid.asset.getId(), vertices.size()); + grid.asset.getIdString(), vertices.size()); - auto& entry = state.entries[grid.asset.getId()]; + auto& entry = state.entries[grid.asset.getId().value()]; if (entry.firstBucketId != RenderMeshPool::BucketId::Invalid) { pool.deallocate(entry.firstBucketId); - CUBOS_INFO("Deallocated old render mesh bucket of asset {}", grid.asset.getId()); + CUBOS_INFO("Deallocated old render mesh bucket of asset {}", grid.asset.getIdString()); } entry.firstBucketId = firstBucketId; - state.meshing.erase(grid.asset.getId()); + state.meshing.erase(grid.asset.getId().value()); } } }); @@ -189,13 +191,14 @@ void cubos::engine::renderMeshPlugin(Cubos& cubos) .call([](Query query, RenderMeshPool& pool, State& state) { for (auto [ent, grid] : query) { - auto& entry = state.entries[grid.asset.getId()]; + auto& entry = state.entries[grid.asset.getId().value()]; entry.referenceCount -= 1; if (entry.referenceCount == 0) { pool.deallocate(entry.firstBucketId); - state.entries.erase(grid.asset.getId()); - CUBOS_INFO("Deallocated render mesh bucket of asset {} (no more references)", grid.asset.getId()); + state.entries.erase(grid.asset.getId().value()); + CUBOS_INFO("Deallocated render mesh bucket of asset {} (no more references)", + grid.asset.getIdString()); } } }); diff --git a/engine/src/scene/bridge.cpp b/engine/src/scene/bridge.cpp index 1cdac3d5b6..c71039945b 100644 --- a/engine/src/scene/bridge.cpp +++ b/engine/src/scene/bridge.cpp @@ -320,7 +320,7 @@ bool SceneBridge::saveToFile(const Assets& assets, const AnyAsset& handle, Strea auto importJson = nlohmann::json::object(); for (const auto& [name, subHandle] : scene->imports) { - importJson.emplace(name.c_str(), uuids::to_string(subHandle.getId())); + importJson.emplace(name.c_str(), subHandle.getIdString()); } json.push_back({"imports", importJson}); diff --git a/tools/tesseratos/src/tesseratos/scene_editor/plugin.cpp b/tools/tesseratos/src/tesseratos/scene_editor/plugin.cpp index c139dc78f2..4e92520feb 100644 --- a/tools/tesseratos/src/tesseratos/scene_editor/plugin.cpp +++ b/tools/tesseratos/src/tesseratos/scene_editor/plugin.cpp @@ -473,7 +473,7 @@ void tesseratos::sceneEditorPlugin(Cubos& cubos) } else { - auto id = uuids::to_string(state.asset.getId()); + auto id = state.asset.getIdString(); ImGui::Text("Editing scene %s", id.c_str()); if (ImGui::Button("Save"))