From 40a6fa6dd6868b04d18b5884dc475acb19b616e9 Mon Sep 17 00:00:00 2001 From: Engin Manap Date: Mon, 13 Jan 2025 21:31:58 +0100 Subject: [PATCH] Add editing custom tags of objects. This also shows the internal tags. --- src/GameObjects/GameObject.h | 19 +++++++++++++++++++ src/GameObjects/Model.cpp | 33 +++++++++++++++++++++++++++++++++ src/GameObjects/Model.h | 15 +++++++++++++++ src/Utils/HardCodedTag.cpp | 21 ++++++++++++++++++++- src/Utils/HardCodedTags.h | 2 ++ src/Utils/StringUtils.hpp | 16 ++++++++++++++++ src/WorldLoader.cpp | 14 +++++++++++++- 7 files changed, 118 insertions(+), 2 deletions(-) diff --git a/src/GameObjects/GameObject.h b/src/GameObjects/GameObject.h index 4d15e5d8..2dc9b38a 100644 --- a/src/GameObjects/GameObject.h +++ b/src/GameObjects/GameObject.h @@ -7,6 +7,7 @@ #include #include +#include #include "API/LimonAPI.h" #include "Editor/ImGuiRequest.h" @@ -59,10 +60,28 @@ class GameObject { return false; } + /** + * + * @return all tags, including hardcoded ones + */ const std::list& getTags() const { return tags; } + /** + * This method is here only for Editor. Don't use in game code, or refactor to remove rehashing of tags + * @return list of tags, filtered by HardCodedTags list. + */ + std::list getTagsCustomOnly() const { + std::list filteredTags; + for (const auto& currentTag: tags) { + if (std::find(HardCodedTags::ALL_TAGS.begin(), HardCodedTags::ALL_TAGS.end(), currentTag.text) == HardCodedTags::ALL_TAGS.end()) { + filteredTags.emplace_back(currentTag.text); + } + } + return filteredTags; + } + virtual void removeTag(const std::string& text) { HashUtil::HashedString tag(text); bool found = false; diff --git a/src/GameObjects/Model.cpp b/src/GameObjects/Model.cpp index 9b1b2edc..03fe206c 100644 --- a/src/GameObjects/Model.cpp +++ b/src/GameObjects/Model.cpp @@ -304,6 +304,20 @@ bool Model::fillObjects(tinyxml2::XMLDocument &document, tinyxml2::XMLElement *o } } + std::list customTags = getTagsCustomOnly(); + if (!customTags.empty()) { + tinyxml2::XMLElement *customTagsNode = document.NewElement("CustomTags"); + tinyxml2::XMLElement *customTagsCountNode = document.NewElement("Count"); + customTagsCountNode->SetText(std::to_string(customTags.size()).c_str()); + customTagsNode->InsertEndChild(customTagsCountNode); + objectElement->InsertEndChild(customTagsNode); + for (auto& customTag:customTags) { + tinyxml2::XMLElement *customTagNode = document.NewElement("CustomTag"); + customTagNode->SetText(customTag.text.c_str()); + customTagsNode->InsertEndChild(customTagNode); + } + } + modelAsset->serializeCustomizations(); return true; } @@ -326,6 +340,25 @@ ImGuiResult Model::addImGuiEditorElements(const ImGuiRequest &request) { } ImGui::NewLine(); + static char tempTagsBuffer[512] = {0}; + std::string joinedTags = StringUtils::join(this->getTagsCustomOnly(), ","); + strncpy(tempTagsBuffer, joinedTags.c_str(), std::min(joinedTags.length(), sizeof(tempTagsBuffer) - 1)); + tempTagsBuffer[std::min(joinedTags.length(), sizeof(tempTagsBuffer) - 1)] = 0; + std::vector internalTags; + for (auto currentTag : this->getTags()) { + if (std::find(HardCodedTags::ALL_TAGS.begin(), HardCodedTags::ALL_TAGS.end(), currentTag.text) != HardCodedTags::ALL_TAGS.end()) { + internalTags.emplace_back(currentTag.text); + } + } + char internalTagsBuffer[512] = {0}; + std::string internalTagsJoined = StringUtils::join(internalTags, ","); + strncpy(internalTagsBuffer, internalTagsJoined.c_str(), std::min(internalTagsJoined.length(), sizeof(internalTagsBuffer) - 1)); + tempTagsBuffer[std::min(internalTagsJoined.length(), sizeof(internalTagsBuffer) - 1)] = 0; + + ImGui::InputText("Automatic Tags##ForModelObject", internalTagsBuffer, sizeof(internalTagsBuffer), ImGuiInputTextFlags_ReadOnly); + ImGui::InputText("Custom Tags##ForModelObject",tempTagsBuffer, sizeof(tempTagsBuffer), ImGuiInputTextFlags_CharsNoBlank); + joinedTags = tempTagsBuffer; + this->setTagsCustomOnly(StringUtils::split(joinedTags, ",")); if (isAnimated()) { if (ImGui::CollapsingHeader("Model animation properties")) { if (ImGui::BeginCombo("Animation Name", animationName.c_str())) { diff --git a/src/GameObjects/Model.h b/src/GameObjects/Model.h index c39bffad..8e6a6580 100644 --- a/src/GameObjects/Model.h +++ b/src/GameObjects/Model.h @@ -291,6 +291,21 @@ class Model : public PhysicalRenderable, public GameObject { GameObject::removeTag(text); } +private: + /** + * This method is causing rehashing of all new tags. Don't use in game mode, only intended for Editor + * @param tagList custom tags to be set. + */ + void setTagsCustomOnly(const std::vector & tagList) { + std::list currentTags = this->getTagsCustomOnly(); + for (auto current_tag: currentTags) { + this->removeTag(current_tag.text); + } + for (auto it = tagList.begin(); it != tagList.end(); ++it) { + this->addTag(*it); + } + this->dirtyForFrustum = true; + } }; diff --git a/src/Utils/HardCodedTag.cpp b/src/Utils/HardCodedTag.cpp index 94220eb1..92e2196e 100644 --- a/src/Utils/HardCodedTag.cpp +++ b/src/Utils/HardCodedTag.cpp @@ -19,4 +19,23 @@ const std::string HardCodedTags::CAMERA_LIGHT_DIRECTIONAL = "directional_camer const std::string HardCodedTags::CAMERA_LIGHT_POINT = "point_camera"; const std::string HardCodedTags::CAMERA_PLAYER = "player_camera"; -const std::string HardCodedTags::PICKED_OBJECT = "picked_object"; \ No newline at end of file +const std::string HardCodedTags::PICKED_OBJECT = "picked_object"; + +const std::vector HardCodedTags::ALL_TAGS = { + HardCodedTags::OBJECT_MODEL_STATIC , + HardCodedTags::OBJECT_MODEL_PHYSICAL , + + HardCodedTags::OBJECT_MODEL_BASIC , + HardCodedTags::OBJECT_MODEL_ANIMATED , + HardCodedTags::OBJECT_MODEL_TRANSPARENT , + + HardCodedTags::OBJECT_PLAYER_BASIC , + HardCodedTags::OBJECT_PLAYER_ANIMATED , + HardCodedTags::OBJECT_PLAYER_TRANSPARENT , + + HardCodedTags::CAMERA_LIGHT_DIRECTIONAL , + HardCodedTags::CAMERA_LIGHT_POINT , + HardCodedTags::CAMERA_PLAYER , + + HardCodedTags::PICKED_OBJECT +}; \ No newline at end of file diff --git a/src/Utils/HardCodedTags.h b/src/Utils/HardCodedTags.h index 17b5fdb0..a37f261f 100644 --- a/src/Utils/HardCodedTags.h +++ b/src/Utils/HardCodedTags.h @@ -30,6 +30,8 @@ class HardCodedTags { static const std::string CAMERA_PLAYER; static const std::string PICKED_OBJECT; + + static const std::vector ALL_TAGS;//all tags }; #endif //LIMONENGINE_HARDCODEDTAGS_H diff --git a/src/Utils/StringUtils.hpp b/src/Utils/StringUtils.hpp index 06215fde..3e622bfa 100644 --- a/src/Utils/StringUtils.hpp +++ b/src/Utils/StringUtils.hpp @@ -9,6 +9,8 @@ #include #include #include +#include +#include "HashUtil.h" class StringUtils { public: @@ -49,6 +51,20 @@ class StringUtils { } return joinedStream.str(); } + + + std::string static join(const std::list& source, const std::string& delimiter) + { + std::ostringstream joinedStream; + if (source.empty()) { + return ""; + } + for (auto it = source.begin(); it != std::prev(source.end()); ++it) { + joinedStream << it->text << delimiter; + } + joinedStream << source.back().text; + return joinedStream.str(); + } }; diff --git a/src/WorldLoader.cpp b/src/WorldLoader.cpp index 75c6f052..d3b74120 100644 --- a/src/WorldLoader.cpp +++ b/src/WorldLoader.cpp @@ -591,7 +591,7 @@ WorldLoader::loadObject( std::shared_ptr assetManager, tinyxml2::X } //Now Load material changes std::vector>> custumizedMeshMaterialList; - tinyxml2::XMLElement* meshMaterialListNode = objectNode->FirstChildElement("MeshMaterialList"); + tinyxml2::XMLElement* meshMaterialListNode = objectNode->FirstChildElement("MeshMaterialList"); if (meshMaterialListNode != nullptr) { tinyxml2::XMLElement *meshMaterialNode = meshMaterialListNode->FirstChildElement("MeshMaterial"); while (meshMaterialNode != nullptr) { @@ -614,6 +614,18 @@ WorldLoader::loadObject( std::shared_ptr assetManager, tinyxml2::X loadedObjectInformation->model->loadOverriddenMeshMaterial(custumizedMeshMaterialList); } + tinyxml2::XMLElement* customTagsNode = objectNode->FirstChildElement("CustomTags"); + if (customTagsNode != nullptr) { + tinyxml2::XMLElement *customTagNode = customTagsNode->FirstChildElement("CustomTag"); + while (customTagNode != nullptr) { + if (customTagNode->GetText() != nullptr) { + loadedObjectInformation->model->addTag(customTagNode->GetText()); + } + customTagNode = customTagNode->NextSiblingElement("CustomTag"); + } + } + + loadedObjects.push_back(std::move(loadedObjectInformation));