From 71659eb74d6b995b932c3ae4ee35ebdc67e7be29 Mon Sep 17 00:00:00 2001 From: Pham Hong Duc Date: Sat, 21 May 2022 15:48:51 +0700 Subject: [PATCH] #123 Implement ArraySerializable for Array UI Property (update CLightProbes save/load data) --- Projects/Editor/Source/Editor/CEditor.cpp | 2 +- .../Editor/Source/Selection/CSelection.cpp | 3 + .../Source/LightProbes/CLightProbes.cpp | 57 +++++++-------- .../Source/LightProbes/CProbeSerializable.cpp | 64 ++++++++++++++++ .../Source/LightProbes/CProbeSerializable.h | 47 ++++++++++++ .../Serializable/CArraySerializable.cpp | 73 +++++++++++++++++++ .../Source/Serializable/CArraySerializable.h | 62 ++++++++++++++++ .../Serializable/CObjectSerializable.cpp | 30 +++++++- .../Source/Serializable/CObjectSerializable.h | 24 ++++++ .../Serializable/CSerializableLoader.cpp | 25 ++++++- .../Source/Serializable/CSerializableLoader.h | 3 +- .../Source/Serializable/CValueProperty.h | 6 ++ Projects/Skylicht/Engine/Source/Skylicht.cpp | 3 + 13 files changed, 361 insertions(+), 38 deletions(-) create mode 100644 Projects/Skylicht/Engine/Source/LightProbes/CProbeSerializable.cpp create mode 100644 Projects/Skylicht/Engine/Source/LightProbes/CProbeSerializable.h create mode 100644 Projects/Skylicht/Engine/Source/Serializable/CArraySerializable.cpp create mode 100644 Projects/Skylicht/Engine/Source/Serializable/CArraySerializable.h diff --git a/Projects/Editor/Source/Editor/CEditor.cpp b/Projects/Editor/Source/Editor/CEditor.cpp index 6aece94f2..3fb0465dd 100644 --- a/Projects/Editor/Source/Editor/CEditor.cpp +++ b/Projects/Editor/Source/Editor/CEditor.cpp @@ -98,8 +98,8 @@ namespace Skylicht CAssetPropertyController::releaseInstance(); CAssetCreateController::releaseInstance(); CPropertyController::releaseInstance(); - CSceneController::releaseInstance(); CSelection::releaseInstance(); + CSceneController::releaseInstance(); CProjectSettings::releaseInstance(); delete m_spriteIcon; diff --git a/Projects/Editor/Source/Selection/CSelection.cpp b/Projects/Editor/Source/Selection/CSelection.cpp index 854ed8160..f3a41c7a1 100644 --- a/Projects/Editor/Source/Selection/CSelection.cpp +++ b/Projects/Editor/Source/Selection/CSelection.cpp @@ -48,6 +48,9 @@ namespace Skylicht delete selectObject; m_selected.clear(); + + CSceneHistory* history = CSceneController::getInstance()->getHistory(); + history->endSaveHistory(); } std::vector CSelection::getSelectedByType(CSelectObject::ESelectType type) diff --git a/Projects/Skylicht/Engine/Source/LightProbes/CLightProbes.cpp b/Projects/Skylicht/Engine/Source/LightProbes/CLightProbes.cpp index a81087e4b..0a8c9c04a 100644 --- a/Projects/Skylicht/Engine/Source/LightProbes/CLightProbes.cpp +++ b/Projects/Skylicht/Engine/Source/LightProbes/CLightProbes.cpp @@ -26,6 +26,8 @@ This file is part of the "Skylicht Engine". #include "CLightProbes.h" #include "CLightProbeData.h" #include "CLightProbeRender.h" +#include "CProbeSerializable.h" + #include "Entity/CEntityManager.h" #include "GameObject/CGameObject.h" #include "Transform/CWorldTransformData.h" @@ -74,34 +76,28 @@ namespace Skylicht { CObjectSerializable* object = CComponentSystem::createSerializable(); - // num probes - int numProbes = (int)m_entities.size(); - object->addAutoRelease(new CIntProperty(object, "numprobes", numProbes)); - - // probes container - CObjectSerializable* probes = new CObjectSerializable("probes"); + CArraySerializable* probes = new CArraySerializable("Probes"); object->addProperty(probes); object->addAutoRelease(probes); - // entity data + int numProbes = (int)m_entities.size(); for (int i = 0; i < numProbes; i++) { - CObjectSerializable* shData = new CObjectSerializable("data"); - probes->addProperty(shData); - probes->addAutoRelease(shData); + CProbeSerializable* probeData = new CProbeSerializable(probes); + probes->addAutoRelease(probeData); CWorldTransformData* world = (CWorldTransformData*)m_entities[i]->getDataByIndex(CWorldTransformData::DataTypeIndex); CLightProbeData* light = (CLightProbeData*)m_entities[i]->getDataByIndex(CLightProbeData::DataTypeIndex); - shData->addAutoRelease(new CStringProperty(shData, "entityID", m_entities[i]->getID().c_str())); - shData->addAutoRelease(new CMatrixProperty(shData, "transform", world->Relative)); + // save id + probeData->EntityID.set(m_entities[i]->getID()); + // save transform + probeData->Transform.set(world->Relative); + + // save sh data for (int j = 0; j < 9; j++) - { - char name[64]; - sprintf(name, "sh%d", j); - shData->addAutoRelease(new CVector3Property(shData, name, light->SH[j])); - } + probeData->SH[j]->set(light->SH[j]); } return object; @@ -111,39 +107,36 @@ namespace Skylicht { CComponentSystem::loadSerializable(object); - int numProbes = object->get("numprobes", 0); - - CObjectSerializable* probes = (CObjectSerializable*)object->getProperty("probes"); + CArraySerializable* probes = (CArraySerializable*)object->getProperty("Probes"); + int numProbes = probes->getElementCount(); clearAll(); if (probes == NULL) return; - if (probes->getNumProperty() < numProbes) + if (probes->getElementCount() < numProbes) return; for (int i = 0; i < numProbes; i++) { - CObjectSerializable* shData = (CObjectSerializable*)probes->getPropertyID(i); + CProbeSerializable* shData = (CProbeSerializable*)probes->getElement(i); if (shData == NULL) return; CEntity* entity = addLightProbe(core::vector3df()); + CWorldTransformData* world = (CWorldTransformData*)entity->getDataByIndex(CWorldTransformData::DataTypeIndex); + CLightProbeData* light = (CLightProbeData*)entity->getDataByIndex(CLightProbeData::DataTypeIndex); - CWorldTransformData* world = (CWorldTransformData*)m_entities[i]->getDataByIndex(CWorldTransformData::DataTypeIndex); - CLightProbeData* light = (CLightProbeData*)m_entities[i]->getDataByIndex(CLightProbeData::DataTypeIndex); + // set id + entity->setID(shData->EntityID.getString()); - std::string entityID = shData->get("entityID", std::string()); - m_entities[i]->setID(entityID.c_str()); + // set transform + world->Relative = shData->Transform.get(); - world->Relative = shData->get("transform", core::IdentityMatrix); + // set sh data for (int j = 0; j < 9; j++) - { - char name[64]; - sprintf(name, "sh%d", j); - light->SH[j] = shData->get(name, core::vector3df()); - } + light->SH[j] = shData->SH[j]->get(); } } diff --git a/Projects/Skylicht/Engine/Source/LightProbes/CProbeSerializable.cpp b/Projects/Skylicht/Engine/Source/LightProbes/CProbeSerializable.cpp new file mode 100644 index 000000000..d5bfd3ce4 --- /dev/null +++ b/Projects/Skylicht/Engine/Source/LightProbes/CProbeSerializable.cpp @@ -0,0 +1,64 @@ +/* +!@ +MIT License + +Copyright (c) 2022 Skylicht Technology CO., LTD + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files +(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +This file is part of the "Skylicht Engine". +https://github.com/skylicht-lab/skylicht-engine +!# +*/ + +#include "pch.h" +#include "CProbeSerializable.h" + +namespace Skylicht +{ + SERIALIZABLE_REGISTER(CProbeSerializable); + + CProbeSerializable::CProbeSerializable() : + CObjectSerializable(getTypeName().c_str()), + EntityID(this, "entity_id"), + Transform(this, "transform") + { + char name[64]; + for (int i = 0; i < 9; i++) + { + sprintf(name, "sh%d", i); + SH[i] = new CVector3Property(this, name); + addAutoRelease(SH[i]); + } + } + + CProbeSerializable::CProbeSerializable(CObjectSerializable* parent) : + CObjectSerializable(getTypeName().c_str(), parent), + EntityID(this, "entity_id"), + Transform(this, "transform") + { + char name[64]; + for (int i = 0; i < 9; i++) + { + sprintf(name, "sh%d", i); + SH[i] = new CVector3Property(this, name); + addAutoRelease(SH[i]); + } + } + + CProbeSerializable::~CProbeSerializable() + { + + } +} \ No newline at end of file diff --git a/Projects/Skylicht/Engine/Source/LightProbes/CProbeSerializable.h b/Projects/Skylicht/Engine/Source/LightProbes/CProbeSerializable.h new file mode 100644 index 000000000..03743f540 --- /dev/null +++ b/Projects/Skylicht/Engine/Source/LightProbes/CProbeSerializable.h @@ -0,0 +1,47 @@ +/* +!@ +MIT License + +Copyright (c) 2022 Skylicht Technology CO., LTD + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files +(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +This file is part of the "Skylicht Engine". +https://github.com/skylicht-lab/skylicht-engine +!# +*/ + +#pragma once + +#include "Serializable/CArraySerializable.h" + +namespace Skylicht +{ + class CProbeSerializable : public CObjectSerializable + { + public: + CStringProperty EntityID; + CMatrixProperty Transform; + CVector3Property* SH[9]; + + public: + CProbeSerializable(); + + CProbeSerializable(CObjectSerializable* parent); + + virtual ~CProbeSerializable(); + + DECLARE_GETTYPENAME(CProbeSerializable); + }; +} \ No newline at end of file diff --git a/Projects/Skylicht/Engine/Source/Serializable/CArraySerializable.cpp b/Projects/Skylicht/Engine/Source/Serializable/CArraySerializable.cpp new file mode 100644 index 000000000..573d8096f --- /dev/null +++ b/Projects/Skylicht/Engine/Source/Serializable/CArraySerializable.cpp @@ -0,0 +1,73 @@ +/* +!@ +MIT License + +Copyright (c) 2022 Skylicht Technology CO., LTD + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files +(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +This file is part of the "Skylicht Engine". +https://github.com/skylicht-lab/skylicht-engine +!# +*/ + +#include "pch.h" +#include "CArraySerializable.h" +#include "CValuePropertyTemplate.h" + +namespace Skylicht +{ + CArraySerializable::CArraySerializable(const char* name) : + CObjectSerializable(name) + { + } + + CArraySerializable::CArraySerializable(const char* name, CObjectSerializable* parent) : + CObjectSerializable(name, parent) + { + } + + CArraySerializable::~CArraySerializable() + { + + } + + void CArraySerializable::removeElement(CValueProperty* element) + { + std::vector::iterator i = m_value.begin(), e = m_value.end(); + while (i != e) + { + if ((*i) == element) + { + m_value.erase(i); + break; + } + ++i; + } + + i = m_autoRelease.begin(); + e = m_autoRelease.end(); + + while (i != e) + { + if ((*i) == element) + { + m_autoRelease.erase(i); + delete (*i); + break; + } + ++i; + } + } +} \ No newline at end of file diff --git a/Projects/Skylicht/Engine/Source/Serializable/CArraySerializable.h b/Projects/Skylicht/Engine/Source/Serializable/CArraySerializable.h new file mode 100644 index 000000000..6f63bbdb8 --- /dev/null +++ b/Projects/Skylicht/Engine/Source/Serializable/CArraySerializable.h @@ -0,0 +1,62 @@ +/* +!@ +MIT License + +Copyright (c) 2022 Skylicht Technology CO., LTD + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files +(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +This file is part of the "Skylicht Engine". +https://github.com/skylicht-lab/skylicht-engine +!# +*/ + +#pragma once + +#include "CObjectSerializable.h" +#include + +namespace Skylicht +{ + class CArraySerializable : public CObjectSerializable + { + public: + + std::function OnCreateElement; + + public: + CArraySerializable(const char* name); + + CArraySerializable(const char* name, CObjectSerializable* parent); + + virtual ~CArraySerializable(); + + int getElementCount() + { + return getNumProperty(); + } + + CValueProperty* getElement(int i) + { + return getPropertyID(i); + } + + virtual void removeElement(CValueProperty* element); + + virtual bool isArray() + { + return true; + } + }; +} \ No newline at end of file diff --git a/Projects/Skylicht/Engine/Source/Serializable/CObjectSerializable.cpp b/Projects/Skylicht/Engine/Source/Serializable/CObjectSerializable.cpp index 4078248e0..c05f74fa4 100644 --- a/Projects/Skylicht/Engine/Source/Serializable/CObjectSerializable.cpp +++ b/Projects/Skylicht/Engine/Source/Serializable/CObjectSerializable.cpp @@ -110,7 +110,11 @@ namespace Skylicht void CObjectSerializable::save(io::IXMLWriter* writer) { char elementName[512]; - sprintf(elementName, "node type=\"%s\"", Name.c_str()); + + if (!isArray()) + sprintf(elementName, "node type=\"%s\"", Name.c_str()); + else + sprintf(elementName, "node type=\"%s\" array=\"true\"", Name.c_str()); writer->writeElement(CStringImp::convertUTF8ToUnicode(elementName).c_str(), false); writer->writeLineBreak(); @@ -249,4 +253,28 @@ namespace Skylicht return object; } + + + + + bool CSerializableActivator::registerType(const char* type, SerializableCreateInstance func) + { + std::map::iterator i = m_factoryName.find(type); + if (i != m_factoryName.end()) + return false; + + m_factoryName[type] = (int)m_factoryFunc.size(); + m_factoryFunc.push_back(func); + return true; + } + + CObjectSerializable* CSerializableActivator::createInstance(const char* type) + { + std::map::iterator i = m_factoryName.find(type); + if (i == m_factoryName.end()) + return NULL; + + int id = (*i).second; + return m_factoryFunc[id](); + } } \ No newline at end of file diff --git a/Projects/Skylicht/Engine/Source/Serializable/CObjectSerializable.h b/Projects/Skylicht/Engine/Source/Serializable/CObjectSerializable.h index 64f9dfd93..9d0c9f7ca 100644 --- a/Projects/Skylicht/Engine/Source/Serializable/CObjectSerializable.h +++ b/Projects/Skylicht/Engine/Source/Serializable/CObjectSerializable.h @@ -27,6 +27,9 @@ This file is part of the "Skylicht Engine". #include "CValueProperty.h" #include "CValuePropertyTemplate.h" +#include "Utils/CGameSingleton.h" +#include "Utils/CActivator.h" + namespace Skylicht { class CObjectSerializable : public CValueProperty @@ -110,4 +113,25 @@ namespace Skylicht virtual CObjectSerializable* clone(); }; + + + +#define SERIALIZABLE_REGISTER(type) \ + CObjectSerializable* type##CreateFunc() { return new type(); } \ + bool type##_activator = CSerializableActivator::createGetInstance()->registerType(#type, &type##CreateFunc); + + typedef CObjectSerializable* (*SerializableCreateInstance)(); + + class CSerializableActivator : public CGameSingleton + { + protected: + std::map m_factoryName; + + std::vector m_factoryFunc; + + public: + bool registerType(const char* type, SerializableCreateInstance func); + + CObjectSerializable* createInstance(const char* type); + }; } \ No newline at end of file diff --git a/Projects/Skylicht/Engine/Source/Serializable/CSerializableLoader.cpp b/Projects/Skylicht/Engine/Source/Serializable/CSerializableLoader.cpp index b3bcdb364..7788f9651 100644 --- a/Projects/Skylicht/Engine/Source/Serializable/CSerializableLoader.cpp +++ b/Projects/Skylicht/Engine/Source/Serializable/CSerializableLoader.cpp @@ -41,7 +41,11 @@ namespace Skylicht if (nodeName == reader->getNodeName() && attributeName == reader->getAttributeValue(L"type")) { attr->read(reader); - initProperty(object, attr); + + if (object->getNumProperty() > 0) + object->deserialize(attr); // for SerializableActivator + else + initProperty(object, attr); } else { @@ -64,10 +68,25 @@ namespace Skylicht if (nodeName == reader->getNodeName()) { std::wstring type = reader->getAttributeValue(L"type"); - std::string name = CStringImp::convertUnicodeToUTF8(type.c_str()); - CObjectSerializable* data = new CObjectSerializable(name.c_str()); + + const wchar_t* isArray = reader->getAttributeValue(L"array"); + + CObjectSerializable* data; + + // activator + data = CSerializableActivator::getInstance()->createInstance(name.c_str()); + if (data == NULL) + { + // default serializable + if (isArray) + data = new CArraySerializable(name.c_str()); + else + data = new CObjectSerializable(name.c_str()); + } + load(reader, data, exitNode); + object->addProperty(data); object->addAutoRelease(data); diff --git a/Projects/Skylicht/Engine/Source/Serializable/CSerializableLoader.h b/Projects/Skylicht/Engine/Source/Serializable/CSerializableLoader.h index d153249af..bfbb3b090 100644 --- a/Projects/Skylicht/Engine/Source/Serializable/CSerializableLoader.h +++ b/Projects/Skylicht/Engine/Source/Serializable/CSerializableLoader.h @@ -26,13 +26,14 @@ This file is part of the "Skylicht Engine". #include "CValuePropertyTemplate.h" #include "CObjectSerializable.h" +#include "CArraySerializable.h" namespace Skylicht { class CSerializableLoader { public: - static void load(io::IXMLReader* reader, CObjectSerializable* object, const char *exitNode); + static void load(io::IXMLReader* reader, CObjectSerializable* object, const char* exitNode); protected: diff --git a/Projects/Skylicht/Engine/Source/Serializable/CValueProperty.h b/Projects/Skylicht/Engine/Source/Serializable/CValueProperty.h index 2f8a2cde1..0afba103d 100644 --- a/Projects/Skylicht/Engine/Source/Serializable/CValueProperty.h +++ b/Projects/Skylicht/Engine/Source/Serializable/CValueProperty.h @@ -57,6 +57,7 @@ namespace Skylicht // ui editor interface std::string m_uiHeader; + float m_uiSpace; public: @@ -82,6 +83,11 @@ namespace Skylicht virtual CValueProperty* clone() = 0; + virtual bool isArray() + { + return false; + } + inline void setUIHeader(const char* header) { m_uiHeader = header; diff --git a/Projects/Skylicht/Engine/Source/Skylicht.cpp b/Projects/Skylicht/Engine/Source/Skylicht.cpp index fdd9f2d4a..8b8d0cc24 100644 --- a/Projects/Skylicht/Engine/Source/Skylicht.cpp +++ b/Projects/Skylicht/Engine/Source/Skylicht.cpp @@ -49,6 +49,7 @@ This file is part of the "Skylicht Engine". #include "Tween/CTweenManager.h" // Activator +#include "Serializable/CObjectSerializable.h" #include "Utils/CActivator.h" #include "Components/CDependentComponent.h" #include "Components/CComponentCategory.h" @@ -86,6 +87,7 @@ namespace Skylicht CTweenManager::createGetInstance(); CActivator::createGetInstance(); + CSerializableActivator::createGetInstance(); CDependentComponent::createGetInstance(); CComponentCategory::createGetInstance(); @@ -115,6 +117,7 @@ namespace Skylicht CComponentCategory::releaseInstance(); CDependentComponent::releaseInstance(); CActivator::releaseInstance(); + CSerializableActivator::releaseInstance(); CTweenManager::releaseInstance(); CMaterialManager::releaseInstance();