From 0bcbcda8b827954f560a5cb75e5940e95fd23f30 Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Thu, 17 Dec 2015 17:26:36 +0100 Subject: [PATCH] EntityFilePreprocessor WIP WIP EntityFilePreprocessor --- assets | 2 +- include/Engine/Core/EntityFile.h | 321 +++++++++++++++++++ include/Engine/Core/EntityFilePreprocessor.h | 226 +++++++++++++ include/Engine/Core/Util/XercesString.h | 46 +++ include/Game/Game.h | 2 + resources/Schema/Entities/RaptorCopter.xml | 68 ++++ resources/Schema/Types/Entity.xsd | 8 + src/Engine/Core/EntityFile.cpp | 47 +++ src/Engine/Core/EntityXMLFile.cpp | 78 +---- src/Engine/Core/World.cpp | 1 + src/Game/Game.cpp | 5 +- 11 files changed, 741 insertions(+), 63 deletions(-) create mode 100644 include/Engine/Core/EntityFile.h create mode 100644 include/Engine/Core/EntityFilePreprocessor.h create mode 100644 include/Engine/Core/Util/XercesString.h create mode 100644 resources/Schema/Entities/RaptorCopter.xml create mode 100644 src/Engine/Core/EntityFile.cpp diff --git a/assets b/assets index 673d4a4e..c8e631f4 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 673d4a4e4c5a3f5bc9fedf82234e8f8751f63a44 +Subproject commit c8e631f449515cdbe3647b96ce472839748e28f9 diff --git a/include/Engine/Core/EntityFile.h b/include/Engine/Core/EntityFile.h new file mode 100644 index 00000000..bca0bf96 --- /dev/null +++ b/include/Engine/Core/EntityFile.h @@ -0,0 +1,321 @@ +#ifndef EntityFile_h__ +#define EntityFile_h__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../GLM.h" +#include "Util/XercesString.h" +#include "ResourceManager.h" +#include "Entity.h" +#include "ComponentInfo.h" + +class EntityFileHandler +{ + friend class EntityFileSAXHandler; +public: + // @param EntityID The entity found + // @param EntityID The parent of the entity + typedef std::function OnStartEntityCallback; + void SetStartEntityCallback(OnStartEntityCallback c) { m_OnStartEntityCallback = c; } + // @param std::string Type name of the component + typedef std::function OnStartComponentCallback; + void SetStartComponentCallback(OnStartComponentCallback c) { m_OnStartComponentCallback = c; } + // @param std::string Field name + // @param std::string Field type + typedef std::function OnStartFieldCallback; + void SetStartFieldCallback(OnStartFieldCallback c) { m_OnStartFieldCallback = c; } + // @param char* Field data + typedef std::function OnStartFieldDataCallback; + void SetStartFieldDataCallback(OnStartFieldDataCallback c) { m_OnStartFieldDataCallback = c; } + +private: + OnStartEntityCallback m_OnStartEntityCallback = nullptr; + OnStartComponentCallback m_OnStartComponentCallback = nullptr; + OnStartFieldCallback m_OnStartFieldCallback = nullptr; + OnStartFieldDataCallback m_OnStartFieldDataCallback = nullptr; +}; + +class EntityFileSAXHandler : public xercesc::DefaultHandler +{ +public: + enum class State + { + Unknown, + Entity, + Component, + ComponentField + }; + + EntityFileSAXHandler(const EntityFileHandler* handler, xercesc::SAX2XMLReader* reader) + : m_Handler(handler) + , m_Reader(reader) + { + // 0 is imaginary world entity + m_EntityStack.push(0); + } + + void startElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname, const xercesc::Attributes& attrs) override + { + std::string name = XS::ToString(_localName); + + if (m_CurrentScope == State::Unknown) { + if (name == "Entity") { + m_CurrentScope = State::Entity; + onStartEntity(attrs); + return; + } + if (name == "EntityRef") { + onStartEntityRef(attrs); + return; + } + } + + std::string uri = XS::ToString(_uri); + if (m_CurrentScope == State::Entity) { + if (uri == "components") { + m_CurrentScope = State::Component; + onStartComponent(name); + return; + } + } + + if (m_CurrentScope == State::Component) { + m_CurrentScope = State::ComponentField; + onStartComponentField(name, attrs); + return; + } + } + + void characters(const XMLCh* const chars, const XMLSize_t length) override + { + if (m_CurrentScope == State::ComponentField) { + char* transcoded = xercesc::XMLString::transcode(chars); + onFieldData(transcoded); + } + } + + void endElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname) override + { + std::string name = XS::ToString(_localName); + if (m_CurrentScope == State::Entity) { + if (name == "Entity") { + m_CurrentScope = State::Unknown; + onEndEntity(); + return; + } + } + + std::string uri = XS::ToString(_uri); + if (m_CurrentScope == State::Component) { + //if (uri == "components") { + m_CurrentScope = State::Entity; + onEndComponent(name); + return; + //} + } + + if (m_CurrentScope == State::ComponentField) { + m_CurrentScope = State::Component; + onEndComponentField(name); + return; + } + } + + void fatalError(const xercesc::SAXParseException& e) + { + XS::ToString s(e.getMessage()); + LOG_ERROR("SAXParseException: %s", ((std::string)s).c_str()); + //throw e; + } + +private: + const EntityFileHandler* m_Handler; + xercesc::SAX2XMLReader* m_Reader; + State m_CurrentScope = State::Unknown; + unsigned int m_NextEntityID = 1; + std::stack m_EntityStack; + std::map m_CurrentAttributes; + + void onStartEntity(const xercesc::Attributes& attrs) + { + EntityID parent = m_EntityStack.top(); + + // TODO: Create entity here + auto xName = attrs.getValue(XS::ToXMLCh("name")); + std::string name = XS::ToString(xName); + //LOG_DEBUG("Entity %i (%i): %s", m_NextEntityID, parent, name.c_str()); + + if (m_Handler->m_OnStartEntityCallback) { + m_Handler->m_OnStartEntityCallback(m_NextEntityID, parent); + } + + m_EntityStack.push(m_NextEntityID); + m_NextEntityID++; + } + void onEndEntity() + { + m_EntityStack.pop(); + } + void onStartEntityRef(const xercesc::Attributes& attrs) + { + std::string path = XS::ToString(attrs.getValue(XS::ToXMLCh("file"))); + + xercesc::SAX2XMLReader* parser = xercesc::XMLReaderFactory::createXMLReader(); + parser->setContentHandler(this); + parser->setErrorHandler(this); + parser->parse(path.c_str()); + delete parser; + } + void onStartComponent(std::string name) + { + //LOG_DEBUG(" Component: %s", name.c_str()); + + if (m_Handler->m_OnStartComponentCallback) { + m_Handler->m_OnStartComponentCallback(name); + } + } + void onEndComponent(std::string name) + { + } + void onStartComponentField(std::string field, const xercesc::Attributes& attrs) + { + //LOG_DEBUG(" Field: %s", field.c_str()); + + for (int i = 0; i < attrs.getLength(); i++) { + auto name = attrs.getQName(i); + auto value = attrs.getValue(name); + + //LOG_DEBUG(" %s = %s", (char*)XS::ToString(name), (char*)XS::ToString(value)); + m_CurrentAttributes[XS::ToString(name).operator std::string()] = XS::ToString(value).operator std::string(); + } + + if (m_Handler->m_OnStartFieldCallback) { + m_Handler->m_OnStartFieldCallback(field, "comment?"); + } + } + void onEndComponentField(std::string field) + { + + } + + void onFieldData(char* data) + { + //LOG_DEBUG(" Data: %s", data); + + if (m_Handler->m_OnStartFieldDataCallback) { + m_Handler->m_OnStartFieldDataCallback(data); + } + + xercesc::XMLString::release(&data); + } +}; + +class EntityFile : public Resource +{ + friend class ResourceManager; +private: + EntityFile(boost::filesystem::path path); + ~EntityFile(); + +public: + static std::size_t GetTypeStride(std::string typeName); +static void WriteElementData(const xercesc::DOMElement* element, std::string typeName, char* outData) +{ + using namespace xercesc; + + if (typeName == "Vector") { + glm::vec3 vec; + vec.x = getFloatAttribute(element, "X"); + vec.y = getFloatAttribute(element, "Y"); + vec.z = getFloatAttribute(element, "Z"); + memcpy(outData, reinterpret_cast(&vec), GetTypeStride(typeName)); + } else if (typeName == "Color") { + glm::vec4 vec; + vec.r = getFloatAttribute(element, "R"); + vec.g = getFloatAttribute(element, "G"); + vec.b = getFloatAttribute(element, "B"); + vec.a = getFloatAttribute(element, "A"); + memcpy(outData, reinterpret_cast(&vec), GetTypeStride(typeName)); + } else if (typeName == "Quaternion") { + glm::quat q; + q.x = getFloatAttribute(element, "X"); + q.y = getFloatAttribute(element, "Y"); + q.z = getFloatAttribute(element, "Z"); + q.w = getFloatAttribute(element, "W"); + memcpy(outData, reinterpret_cast(&q), GetTypeStride(typeName)); + } else if (typeName == "float") { + XSValue::Status status; + XSValue* val = XSValue::getActualValue(element->getTextContent(), xercesc::XSValue::DataType::dt_float, status); + memcpy(outData, reinterpret_cast(&val->fData.fValue.f_float), GetTypeStride(typeName)); + } else if (typeName == "double") { + XSValue::Status status; + XSValue* val = XSValue::getActualValue(element->getTextContent(), xercesc::XSValue::DataType::dt_double, status); + memcpy(outData, reinterpret_cast(&val->fData.fValue.f_double), GetTypeStride(typeName)); + } else if (typeName == "bool") { + XSValue::Status status; + XSValue* val = XSValue::getActualValue(element->getTextContent(), xercesc::XSValue::DataType::dt_boolean, status); + memcpy(outData, reinterpret_cast(&val->fData.fValue.f_bool), GetTypeStride(typeName)); + } else { + XSValue::DataType dataType = XSValue::getDataType(XS::ToXMLCh(typeName)); + if (dataType == XSValue::DataType::dt_string) { + char* str = XMLString::transcode(element->getTextContent()); + std::string standardString(str); + new (outData) std::string(str); + XMLString::release(&str); + //memcpy(outData, reinterpret_cast(&standardString), getTypeStride(typeName)); + } else { + //XSValue::Status status; + //XSValue* val = XSValue::getActualValue(element->getTextContent(), dataType, status); + //memcpy(outData, reinterpret_cast(&val->fData.fValue), getTypeStride(typeName)); + LOG_WARNING("Unknown native data type: %s", typeName.c_str()); + } + } +} + + void Parse(const EntityFileHandler* handler); + //const std::map& ComponentInfo() const { return m_ComponentInfo; } + //const std::vector& EntityReferences() const { return m_EntityReferences; } + + xercesc::XMLGrammarPool* GrammarPool() const { return m_GrammarPool; } + +private: + boost::filesystem::path m_FilePath; + xercesc::XMLGrammarPool* m_GrammarPool; + xercesc::SAX2XMLReader* m_SAX2XMLReader; + //std::map m_ComponentInfo; + //std::vector m_EntityReferences; +static float getFloatAttribute(const xercesc::DOMElement* element, const char* attribute) +{ + using namespace xercesc; + XSValue::Status status; + XSValue* val = XSValue::getActualValue(element->getAttribute(XS::ToXMLCh(attribute)), xercesc::XSValue::DataType::dt_double, status); + if (val == nullptr) { + LOG_ERROR("Element \"%s\" doesn't have an \"%s\" attribute!", ((std::string)XS::ToString(element->getTagName())).c_str(), attribute); + return 0.f; + } else { + return static_cast(val->fData.fValue.f_double); + } +} +}; + +#endif \ No newline at end of file diff --git a/include/Engine/Core/EntityFilePreprocessor.h b/include/Engine/Core/EntityFilePreprocessor.h new file mode 100644 index 00000000..9df46722 --- /dev/null +++ b/include/Engine/Core/EntityFilePreprocessor.h @@ -0,0 +1,226 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Util/XercesString.h" +#include "ResourceManager.h" +#include "World.h" +#include "EntityFile.h" + +class EntityFilePreprocessor +{ +public: + EntityFilePreprocessor(std::string path) + : m_FilePath(path) + { + m_EntityFile = ResourceManager::Load(path); + EntityFileHandler handler; + handler.SetStartComponentCallback(std::bind(&EntityFilePreprocessor::onStartComponent, this, std::placeholders::_1)); + m_EntityFile->Parse(&handler); + + LOG_DEBUG("___ COMPONENT DEFINITIONS ___"); + for (auto& kv : m_ComponentCounts) { + LOG_DEBUG("%s: %i", kv.first.c_str(), kv.second); + } + + parseComponentInfo(); + + for (auto& kv : m_ComponentInfo) { + auto& info = kv.second; + LOG_DEBUG("Component: %s (%s)", info.Name.c_str(), info.Meta.Annotation.c_str()); + LOG_DEBUG("Stride: %i", info.Meta.Stride); + LOG_DEBUG("Allocation: %i", info.Meta.Allocation); + for (auto& kv : info.FieldTypes) { + LOG_DEBUG("\t%i\t%s %s", info.FieldOffsets[kv.first], kv.second.c_str(), kv.first.c_str()); + } + } + + parseDefaults(); + } + + void RegisterComponents(World* world) + { + for (auto& kv : m_ComponentInfo) { + world->RegisterComponent(kv.second); + } + } + +private: + std::string m_FilePath; + EntityFile* m_EntityFile; + std::map m_ComponentCounts; + std::map m_ComponentInfo; + + void onStartComponent(std::string type) + { + //LOG_DEBUG("Component: %s", type.c_str()); + m_ComponentCounts[type]++; + } + + void parseComponentInfo() + { + using namespace xercesc; + auto grammarPool = m_EntityFile->GrammarPool(); + bool whateverTheFuckThisIs; + auto xsModel = grammarPool->getXSModel(whateverTheFuckThisIs); + + // Find component xsd element declarations + std::cout << "Enumerating components..." << std::endl; + // + auto topLevelElements = xsModel->getComponents(XSConstants::ELEMENT_DECLARATION); + for (unsigned int i = 0; i < topLevelElements->getLength(); ++i) { + auto element = static_cast(topLevelElements->item(i)); + + std::string nameSpace = XS::ToString(element->getNamespace()); + if (nameSpace != "components") { + continue; + } + + ComponentInfo compInfo; + + // Name + compInfo.Name = XS::ToString(element->getName()); + // Known allocation + compInfo.Meta.Allocation = m_ComponentCounts[compInfo.Name]; + // Annotation + auto componentAnnotation = element->getAnnotation(); + if (componentAnnotation != nullptr) { + // Parse annotation XML + char* annotationString = XMLString::transcode(componentAnnotation->getAnnotationString()); + MemBufInputSource annotationInput(reinterpret_cast(annotationString), strlen(annotationString), "MemBuf: Annotation String"); + XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager, grammarPool); + //parser.setErrorHandler(m_ErrorHandler); + parser.parse(annotationInput); + XMLString::release(&annotationString); + auto doc = parser.getDocument(); + + // TODO: Add allocation estimations from external file on map-to-map basis + // Add allocation estimation(s) + //auto allocationTags = doc->getElementsByTagName(XSTR("meta:allocation")); + //for (int i = 0; i < allocationTags->getLength(); ++i) { + // auto allocation = dynamic_cast(allocationTags->item(i)); + // auto child = allocation->getFirstChild(); + // if (child == nullptr) { + // continue; + // } + + // XSValue::Status status; + // XSValue* val = XSValue::getActualValue(child->getNodeValue(), XSValue::dt_integer, status); + // compInfo.Meta.Allocation += val->fData.fValue.f_int; + //} + + // Save documentation string + auto documentationTags = doc->getElementsByTagName(XS::ToXMLCh("xs:documentation")); + if (documentationTags->getLength() != 0) { + auto child = documentationTags->item(0)->getFirstChild(); + if (child != nullptr) { + compInfo.Meta.Annotation = XS::ToString(child->getNodeValue()); + } + } + } else { + LOG_WARNING("Component is missing an annotation!"); + } + + // + auto typeDefinition = element->getTypeDefinition(); + if (typeDefinition->getTypeCategory() != XSTypeDefinition::COMPLEX_TYPE) { + LOG_ERROR("Type definition wasn't COMPLEX_TYPE! Skipping."); + continue; + } + auto complexTypeDefinition = dynamic_cast(typeDefinition); + + // + auto modelGroupParticle = complexTypeDefinition->getParticle(); + if (modelGroupParticle->getTermType() != XSParticle::TERM_MODELGROUP) { + LOG_ERROR("Model group particle wasn't TERM_MODELGROUP! Skipping."); + continue; + } + auto modelGroup = modelGroupParticle->getModelGroupTerm(); + + // getParticles(); + for (unsigned int i = 0; i < particles->size(); ++i) { + auto particle = particles->elementAt(i); + if (particle->getTermType() != XSParticle::TERM_ELEMENT) { + LOG_ERROR("Particle wasn't TERM_ELEMENT! Skipping."); + continue; + } + auto elementDeclaration = particle->getElementTerm(); + + std::string name = XS::ToString(elementDeclaration->getName()); + std::string type = XS::ToString(elementDeclaration->getTypeDefinition()->getName()); + + size_t stride = EntityFile::GetTypeStride(type); + if (stride == 0) { + std::cout << "Warning: Field \"" << name << "\" in component \"" << compInfo.Name << "\" uses unexpected field type \"" << type << "\". Skipping." << std::endl; + continue; + } + + compInfo.FieldTypes[name] = type; + compInfo.FieldOffsets[name] = fieldOffset; + fieldOffset += stride; + } + + compInfo.Meta.Stride = fieldOffset; + m_ComponentInfo[compInfo.Name] = compInfo; + } + } + +void parseDefaults() +{ + using namespace xercesc; + + for (auto& ci : m_ComponentInfo) { + // Allocate memory for default values + ci.second.Defaults = std::shared_ptr(new char[ci.second.Meta.Stride]); + memset(ci.second.Defaults.get(), 0, ci.second.Meta.Stride); + + XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager); + //parser.setErrorHandler(m_ErrorHandler); + + std::string componentName = ci.first; + LOG_DEBUG("Parsing defaults for component %s", componentName.c_str()); + boost::filesystem::path defaultsFile = "Schema/Components/" + componentName + ".xml"; + + parser.parse(defaultsFile.string().c_str()); + auto doc = parser.getDocument(); + if (doc == nullptr) { + LOG_ERROR("%s not found! Skipping.", defaultsFile.string().c_str()); + continue; + } + + // Find the node in the components namespace matching the component name + std::string tagName = "c:" + componentName; + auto rootNodes = doc->getElementsByTagName(XS::ToXMLCh(tagName)); + if (rootNodes->getLength() == 0) { + LOG_ERROR("Couldn't find defaults for component \"%s\"! Skipping.", componentName.c_str()); + continue; + } + auto componentElement = dynamic_cast(rootNodes->item(0)); + + // Fill the default value buffer with values + for (auto& field : ci.second.FieldOffsets) { + std::string fieldName = field.first; + auto fieldNodes = componentElement->getElementsByTagName(XS::ToXMLCh(fieldName)); + auto fieldNode = fieldNodes->item(0); + if (fieldNode == nullptr) { + LOG_ERROR("Defaults for component \"%s\" is missing field \"%s\"!", componentName.c_str(), fieldName.c_str()); + continue; + } + auto fieldElement = dynamic_cast(fieldNode); + + std::string fieldType = ci.second.FieldTypes.at(fieldName); + unsigned int fieldOffset = ci.second.FieldOffsets.at(fieldName); + EntityFile::WriteElementData(fieldElement, fieldType, ci.second.Defaults.get() + fieldOffset); + } + } +} +}; \ No newline at end of file diff --git a/include/Engine/Core/Util/XercesString.h b/include/Engine/Core/Util/XercesString.h new file mode 100644 index 00000000..b0b6fa76 --- /dev/null +++ b/include/Engine/Core/Util/XercesString.h @@ -0,0 +1,46 @@ +#ifndef Util_XercesString_h__ +#define Util_XercesString_h__ + +#include +#include +#include + +namespace XS +{ + +class ToString +{ +public: + ToString(const XMLCh* const str) { m_AsChar = xercesc::XMLString::transcode(str); } + ~ToString() + { + if (m_AsChar != nullptr) { + xercesc::XMLString::release(&m_AsChar); + } + } + + operator std::string() const { return std::string(m_AsChar); } +private: + char* m_AsChar = nullptr; +}; + +class ToXMLCh +{ +public: + ToXMLCh(const std::string str) { m_Transcoded = xercesc::XMLString::transcode(str.c_str()); } + ToXMLCh(const char* str) { m_Transcoded = xercesc::XMLString::transcode(str); } + ~ToXMLCh() + { + if (m_Transcoded != nullptr) { + xercesc::XMLString::release(&m_Transcoded); + } + } + + operator const XMLCh*() const { return m_Transcoded; } +private: + XMLCh* m_Transcoded = nullptr; +}; + +} + +#endif diff --git a/include/Game/Game.h b/include/Game/Game.h index 33dc88a6..3e2ff5ae 100644 --- a/include/Game/Game.h +++ b/include/Game/Game.h @@ -14,10 +14,12 @@ #include "Input/MouseInputHandler.h" #include "Core/EKeyDown.h" #include "Core/EntityXMLFile.h" +#include "Core/EntityFilePreprocessor.h" #include "Core/SystemPipeline.h" #include "RaptorCopterSystem.h" #include "PlayerSystem.h" #include "Editor/EditorSystem.h" +#include "Core/EntityFile.h" // Network #include diff --git a/resources/Schema/Entities/RaptorCopter.xml b/resources/Schema/Entities/RaptorCopter.xml new file mode 100644 index 00000000..0ee62368 --- /dev/null +++ b/resources/Schema/Entities/RaptorCopter.xml @@ -0,0 +1,68 @@ + + + + + + + + + + Models/Core/UnitRaptor.obj + + + + + + + + + + + + 20 + + + + + + + + + + + + Models/Core/UnitCylinder.obj + + + + + + + + + + + + + Models/Core/UnitCube.obj + + + + + + + + + + + + + Models/Core/UnitCube.obj + + + + + + + + \ No newline at end of file diff --git a/resources/Schema/Types/Entity.xsd b/resources/Schema/Types/Entity.xsd index 5178b525..6562f3ed 100644 --- a/resources/Schema/Types/Entity.xsd +++ b/resources/Schema/Types/Entity.xsd @@ -24,11 +24,19 @@ + + + + + + + + \ No newline at end of file diff --git a/src/Engine/Core/EntityFile.cpp b/src/Engine/Core/EntityFile.cpp new file mode 100644 index 00000000..672d3e84 --- /dev/null +++ b/src/Engine/Core/EntityFile.cpp @@ -0,0 +1,47 @@ +#include "Core/EntityFile.h" + +EntityFile::EntityFile(boost::filesystem::path path) + : m_FilePath(path) +{ + using namespace xercesc; + XMLPlatformUtils::Initialize(); + m_GrammarPool = new XMLGrammarPoolImpl(); + m_SAX2XMLReader = XMLReaderFactory::createXMLReader(XMLPlatformUtils::fgMemoryManager, m_GrammarPool); +} + +EntityFile::~EntityFile() +{ + delete m_SAX2XMLReader; + delete m_GrammarPool; + xercesc::XMLPlatformUtils::Terminate(); +} + +void EntityFile::Parse(const EntityFileHandler* handler) +{ + using namespace xercesc; + + EntityFileSAXHandler saxHandler(handler, nullptr); + m_SAX2XMLReader->setFeature(XMLUni::fgXercesCacheGrammarFromParse, true); + m_SAX2XMLReader->setFeature(XMLUni::fgXercesUseCachedGrammarInParse, true); + m_SAX2XMLReader->setContentHandler(&saxHandler); + m_SAX2XMLReader->setErrorHandler(&saxHandler); + m_SAX2XMLReader->setDeclarationHandler(&saxHandler); + m_SAX2XMLReader->parse(m_FilePath.string().c_str()); +} + +std::size_t EntityFile::GetTypeStride(std::string typeName) +{ + std::map typeStrides{ + { "bool", sizeof(bool) }, + { "int", sizeof(int) }, + { "float", sizeof(float) }, + { "double", sizeof(double) }, + { "string", sizeof(std::string) }, + { "Vector", sizeof(glm::vec3) }, + { "Quaternion", sizeof(glm::quat) }, + { "Color", sizeof(glm::vec4) } + }; + + auto it = typeStrides.find(typeName); + return (it != typeStrides.end()) ? it->second : 0; +} diff --git a/src/Engine/Core/EntityXMLFile.cpp b/src/Engine/Core/EntityXMLFile.cpp index c6e00a1b..58957347 100644 --- a/src/Engine/Core/EntityXMLFile.cpp +++ b/src/Engine/Core/EntityXMLFile.cpp @@ -71,7 +71,6 @@ void EntityXMLFile::PopulateWorld(World* world) parseEntityGraph(world, root, 0); } - void EntityXMLFile::preprocess(std::string inPath, std::string outPath) { using namespace xercesc; @@ -121,7 +120,7 @@ void EntityXMLFile::parseComponentInfo() for (unsigned int i = 0; i < topLevelElements->getLength(); ++i) { auto element = static_cast(topLevelElements->item(i)); - std::string nameSpace(XSTR(element->getNamespace())); + std::string nameSpace = XSTR(element->getNamespace()); if (nameSpace != "components") { continue; } @@ -129,7 +128,7 @@ void EntityXMLFile::parseComponentInfo() ComponentInfo compInfo; // Name - compInfo.Name = XSTR(element->getName()); + compInfo.Name = (std::string)XSTR(element->getName()); // Annotation auto componentAnnotation = element->getAnnotation(); if (componentAnnotation != nullptr) { @@ -345,69 +344,27 @@ void EntityXMLFile::parseEntityGraph(World* world, xercesc::DOMElement* element, } } - // Recurse children + // Recurse children entities auto children = m_DOMDocument->evaluate(XSTR("Children/Entity"), element, nullptr, DOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE, nullptr); for (int i = 0; i < children->getSnapshotLength(); i++) { children->snapshotItem(i); parseEntityGraph(world, dynamic_cast(children->getNodeValue()), entity); } - //auto components = m_DOMDocument->getElementsByTagNameNS(XSTR("components"), XSTR("*")); - //for (int i = 0; i < components->getLength(); ++i) { - // auto component = dynamic_cast(components->item(i)); + // Recurse children entity references + auto refs = m_DOMDocument->evaluate(XSTR("Children/EntityRef"), element, nullptr, DOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE, nullptr); + for (int i = 0; i < refs->getSnapshotLength(); i++) { + refs->snapshotItem(i); + auto entityRefElement = dynamic_cast(refs->getNodeValue()); + auto attribute = entityRefElement->getAttribute(XSTR("file")); + if (attribute == nullptr) { + continue; + } - // std::string componentName = XSTR(component->getLocalName()); - // auto& compStore = m_ComponentStore.at(componentName); - // auto& compInfo = compStore.Info; - - // char* data = &compStore.Data[compStore.Size*compStore.Stride]; - // compStore.Size += 1; - - // auto fields = component->getChildNodes(); - // for (int j = 0; j < fields->getLength(); ++j) { - // auto field = fields->item(j); - // auto nodeType = field->getNodeType(); - // if (nodeType != DOMNode::ELEMENT_NODE) { - // continue; - // } - // //auto field = dynamic_cast(fields->item(j)); - // //const XMLCh* value = fields->item(j)->getTextContent(); - // std::string fieldName = XSTR(field->getLocalName()); - // if (compInfo.FieldTypes.find(fieldName) == compInfo.FieldTypes.end()) { - // std::cout << "Warning: Component \"" << componentName << "\" contains invalid field \"" << fieldName << "\". Skipping." << std::endl; - // continue; - // } - - // std::string fieldType = compInfo.FieldTypes.at(fieldName); - // unsigned int fieldOffset = compInfo.FieldOffsets.at(fieldName); - - // XSValue::DataType dataType = XSValue::getDataType(XSTR(fieldType.c_str())); - // if (dataType == XSValue::DataType::dt_MAXCOUNT) { - // // TODO: - // continue; - // } - // if (dataType == XSValue::DataType::dt_string) { - // char* str = XMLString::transcode(field->getTextContent()); - // std::string standardString(str); - // XMLString::release(&str); - // memcpy(&data[fieldOffset], reinterpret_cast(&standardString), getTypeStride(fieldType)); - // } else { - // XSValue::Status status; - // XSValue* val = XSValue::getActualValue(field->getTextContent(), dataType, status); - // memcpy(&data[fieldOffset], reinterpret_cast(&val->fData.fValue), getTypeStride(fieldType)); - // } - // } - //} - - //auto entities = m_DOMDocument->getElementsByTagName(XSTR("Entity")); - //for (int i = 0; i < entities->getLength(); ++i) { - // auto entity = dynamic_cast(entities->item(i)); - - - // //entity->setIdAttribute() - - // std::cout << "ENTITY " << i + 1 << std::endl; - //} + std::string file((const char*)XSTR(attribute)); + boost::filesystem::path absolutePath = boost::filesystem::path(m_EntityFile).parent_path() / file; + ResourceManager::Load(absolutePath.string())->PopulateWorld(world); + } } std::size_t EntityXMLFile::getTypeStride(std::string typeName) @@ -491,5 +448,4 @@ void EntityXMLFile::writeData(const xercesc::DOMElement* element, std::string ty LOG_WARNING("Unknown native data type: %s", typeName.c_str()); } } -} - +} \ No newline at end of file diff --git a/src/Engine/Core/World.cpp b/src/Engine/Core/World.cpp index 5443d388..9957e0ec 100644 --- a/src/Engine/Core/World.cpp +++ b/src/Engine/Core/World.cpp @@ -55,6 +55,7 @@ void World::RegisterComponent(ComponentInfo& ci) ComponentWrapper World::AttachComponent(EntityID entity, std::string componentType) { + // TODO: Allocate dynamic pool if component isn't registered ComponentPool* pool = m_ComponentPools.at(componentType); const ComponentInfo& ci = pool->ComponentInfo(); diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index 7d294355..e349bb56 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -10,6 +10,7 @@ Game::Game(int argc, char* argv[]) ResourceManager::RegisterType("Texture"); ResourceManager::RegisterType("EntityXMLFile"); ResourceManager::RegisterType("ShaderProgram"); + ResourceManager::RegisterType("EntityFile"); m_Config = ResourceManager::Load("Config.ini"); LOG_LEVEL = static_cast<_LOG_LEVEL>(m_Config->Get("Debug.LogLevel", 1)); @@ -48,7 +49,9 @@ Game::Game(int argc, char* argv[]) m_World = new World(); std::string mapToLoad = m_Config->Get("Debug.LoadMap", ""); if (!mapToLoad.empty()) { - ResourceManager::Load(mapToLoad)->PopulateWorld(m_World); + //ResourceManager::Load(mapToLoad)->PopulateWorld(m_World); + EntityFilePreprocessor fp(mapToLoad); + fp.RegisterComponents(m_World); } // Create system pipeline