diff --git a/include/Engine/Core/ComponentInfo.h b/include/Engine/Core/ComponentInfo.h index 985a057e..def2a323 100644 --- a/include/Engine/Core/ComponentInfo.h +++ b/include/Engine/Core/ComponentInfo.h @@ -9,7 +9,8 @@ struct ComponentInfo { std::string Annotation; unsigned int Allocation = 0; - unsigned int Stride = 0; + std::map FieldAnnotations; + std::map> FieldEnumDefinitions; }; struct Field_t @@ -23,8 +24,9 @@ struct ComponentInfo std::string Name; std::unordered_map Fields; std::vector FieldsInOrder; - Meta_t Meta; + unsigned int Stride = 0; std::shared_ptr Defaults = nullptr; + std::shared_ptr Meta = nullptr; }; template<> diff --git a/include/Engine/Core/ComponentPool.h b/include/Engine/Core/ComponentPool.h index 619aade8..ed81d72e 100644 --- a/include/Engine/Core/ComponentPool.h +++ b/include/Engine/Core/ComponentPool.h @@ -43,7 +43,7 @@ public: ComponentPool(const ::ComponentInfo& ci) : m_ComponentInfo(ci) - , m_Pool(ci.Meta.Allocation, sizeof(EntityID) + ci.Meta.Stride) + , m_Pool(ci.Meta->Allocation, sizeof(EntityID) + ci.Stride) { } ComponentPool(const ComponentPool& other) = delete; ComponentPool(const ComponentPool&& other) = delete; diff --git a/include/Engine/Core/ComponentWrapper.h b/include/Engine/Core/ComponentWrapper.h index 922b3d79..9d27b0f8 100644 --- a/include/Engine/Core/ComponentWrapper.h +++ b/include/Engine/Core/ComponentWrapper.h @@ -6,6 +6,7 @@ #include "ComponentInfo.h" #include "Util/Any.h" +// TODO: Change all instances "Property" to "Field" to remain consistent with ComponentInfo struct ComponentWrapper { ComponentWrapper(const ComponentInfo& componentInfo, char* data) @@ -18,6 +19,11 @@ struct ComponentWrapper const ::EntityID EntityID; char* Data; + int Enum(const char* fieldName, const char* enumKey) + { + return Info.Meta->FieldEnumDefinitions.at(fieldName).at(enumKey); + } + template T& Property(std::string name) { @@ -33,7 +39,7 @@ struct ComponentWrapper // Specialization for string literals template void SetProperty(std::string name, const char(&value)[N]) { Property(name) = std::string(value); } - + struct SubscriptProxy { friend struct ComponentWrapper; @@ -47,6 +53,9 @@ struct ComponentWrapper std::string m_PropertyName; public: + // Return the integer value of an enum type key for this field + int Enum(const char* enumKey) { return m_Component->Enum(m_PropertyName.c_str(), enumKey); } + template operator T&() { return m_Component->Property(m_PropertyName); } @@ -71,7 +80,7 @@ public: ComponentWrapperFactory(std::string componentTypeName, std::size_t allocation = 0) { m_ComponentInfo.Name = componentTypeName; - m_ComponentInfo.Meta.Allocation = allocation; + m_ComponentInfo.Meta->Allocation = allocation; } template @@ -79,14 +88,14 @@ public: { m_DefaultValues.push_back(defaultValue); m_ComponentInfo.Fields[fieldName].Name = typeid(T).name(); - m_ComponentInfo.Fields[fieldName].Offset = m_ComponentInfo.Meta.Stride; + m_ComponentInfo.Fields[fieldName].Offset = m_ComponentInfo.Stride; m_ComponentInfo.Fields[fieldName].Stride = sizeof(T); - m_ComponentInfo.Meta.Stride += sizeof(T); + m_ComponentInfo.Stride += sizeof(T); } ComponentInfo& Finalize() { - m_ComponentInfo.Defaults = std::shared_ptr(new char[m_ComponentInfo.Meta.Stride]); + m_ComponentInfo.Defaults = std::shared_ptr(new char[m_ComponentInfo.Stride]); std::size_t offset = 0; for (auto& val : m_DefaultValues) { memcpy(m_ComponentInfo.Defaults.get() + offset, val.Data.get(), val.Size); diff --git a/include/Engine/Core/EntityFactory.h b/include/Engine/Core/EntityFactory.h index d1dbce03..c3c964bc 100644 --- a/include/Engine/Core/EntityFactory.h +++ b/include/Engine/Core/EntityFactory.h @@ -285,7 +285,7 @@ private: XSValue::Status status; XSValue* val = XSValue::getActualValue(child->getNodeValue(), XSValue::dt_integer, status); - compInfo.Meta.Allocation += val->fData.fValue.f_int; + compInfo.Meta->Allocation += val->fData.fValue.f_int; } // Save documentation string @@ -293,11 +293,11 @@ private: if (documentationTags->getLength() != 0) { auto child = documentationTags->item(0)->getFirstChild(); if (child != nullptr) { - compInfo.Meta.Annotation = XSTR(child->getNodeValue()); + compInfo.Meta->Annotation = XSTR(child->getNodeValue()); } } // TODO: Parse annotation string XML - // compInfo.Meta.Allocation = ... + // compInfo.Meta->Allocation = ... } else { std::cout << "Warning: Component is missing an annotation!" << std::endl; } @@ -344,7 +344,7 @@ private: fieldOffset += getTypeStride(type); } - compInfo.Meta.Stride = fieldOffset; + compInfo.Stride = fieldOffset; m_ComponentInfo[compInfo.Name] = compInfo; } } @@ -367,14 +367,14 @@ private: std::string componentName = XSTR(component->getLocalName()); auto& compInfo = m_ComponentInfo.at(componentName); - compInfo.Meta.Allocation += 1; + compInfo.Meta->Allocation += 1; } std::cout << "COMPONENT INFO" << std::endl; for (auto& pair : m_ComponentInfo) { ComponentInfo& ci = pair.second; - std::cout << "Component: " << ci.Name << " (" << ci.Meta.Annotation << ")" << std::endl; - std::cout << " Allocation: " << ci.Meta.Allocation << std::endl; + std::cout << "Component: " << ci.Name << " (" << ci.Meta->Annotation << ")" << std::endl; + std::cout << " Allocation: " << ci.Meta->Allocation << std::endl; std::cout << " Fields:" << std::endl; // Calculate component size @@ -393,7 +393,7 @@ private: cs.ComponentName = ci.Name; cs.Stride = stride; cs.Info = ci; - cs.Data = new char[stride*ci.Meta.Allocation]; + cs.Data = new char[stride*ci.Meta->Allocation]; m_ComponentStore[cs.ComponentName] = cs; } } diff --git a/include/Engine/Core/EntityFile.h b/include/Engine/Core/EntityFile.h index b65c9f7d..2549ed06 100644 --- a/include/Engine/Core/EntityFile.h +++ b/include/Engine/Core/EntityFile.h @@ -73,88 +73,15 @@ public: ComponentField }; - EntityFileSAXHandler(const EntityFileHandler* handler, xercesc::SAX2XMLReader* reader) - : m_Handler(handler) - , m_Reader(reader) - { - // 0 is imaginary base parent - m_EntityStack.push(0); - m_StateStack.push(State::Unknown); - } + EntityFileSAXHandler(const EntityFileHandler* handler, xercesc::SAX2XMLReader* reader); - 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); + void startElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname, const xercesc::Attributes& attrs) override; + void characters(const XMLCh* const chars, const XMLSize_t length) override; + void endElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname) override; - if (m_StateStack.top() == State::Unknown || m_StateStack.top() == State::Entity) { - if (name == "Entity") { - m_StateStack.push(State::Entity); - onStartEntity(attrs); - return; - } - if (name == "EntityRef") { - onStartEntityRef(attrs); - return; - } - } - - std::string uri = XS::ToString(_uri); - if (m_StateStack.top() == State::Entity) { - if (uri == "components") { - m_StateStack.push(State::Component); - onStartComponent(name); - return; - } - } - - if (m_StateStack.top() == State::Component) { - m_StateStack.push(State::ComponentField); - onStartComponentField(name, attrs); - return; - } - } - - void characters(const XMLCh* const chars, const XMLSize_t length) override - { - if (m_StateStack.top() == 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_StateStack.top() == State::Entity) { - if (name == "Entity") { - m_StateStack.pop(); - onEndEntity(); - return; - } - } - - std::string uri = XS::ToString(_uri); - if (m_StateStack.top() == State::Component) { - //if (uri == "components") { - m_StateStack.pop(); - onEndComponent(name); - return; - //} - } - - if (m_StateStack.top() == State::ComponentField) { - m_StateStack.pop(); - 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; - } + void warning(const xercesc::SAXParseException& e); + void error(const xercesc::SAXParseException& e); + void fatalError(const xercesc::SAXParseException& e); private: const EntityFileHandler* m_Handler; @@ -168,73 +95,14 @@ private: std::string m_CurrentField; std::map m_CurrentAttributes; - void onStartEntity(const xercesc::Attributes& attrs) - { - EntityID parent = m_EntityStack.top(); - - if (m_Handler->m_OnStartEntityCallback) { - std::string name; - auto xName = attrs.getValue(XS::ToXMLCh("name")); - if (xName != nullptr) { - name = XS::ToString(xName); - } - m_Handler->m_OnStartEntityCallback(m_NextEntityID, parent, name); - } - - 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(const std::string& name) - { - //LOG_DEBUG(" Component: %s", name.c_str()); - m_CurrentComponent = name; - if (m_Handler->m_OnStartComponentCallback) { - m_Handler->m_OnStartComponentCallback(m_EntityStack.top(), name); - } - } - void onEndComponent(const std::string& name) { } - void onStartComponentField(const std::string& field, const xercesc::Attributes& attrs) - { - //LOG_DEBUG(" Field: %s", field.c_str()); - m_CurrentField = field; - m_CurrentAttributes.clear(); - 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(m_EntityStack.top(), m_CurrentComponent, field, m_CurrentAttributes); - } - } - void onEndComponentField(const std::string& field) { } - - void onFieldData(char* data) - { - //LOG_DEBUG(" Data: %s", data); - - if (m_Handler->m_OnStartFieldDataCallback) { - m_Handler->m_OnStartFieldDataCallback(m_EntityStack.top(), m_CurrentComponent, m_CurrentField, data); - } - - xercesc::XMLString::release(&data); - } + void onStartEntity(const xercesc::Attributes& attrs); + void onEndEntity(); + void onStartEntityRef(const xercesc::Attributes& attrs); + void onStartComponent(const std::string& name); + void onEndComponent(const std::string& name); + void onStartComponentField(const std::string& field, const xercesc::Attributes& attrs); + void onEndComponentField(const std::string& field); + void onFieldData(char* data); }; class EntityFileXMLErrorHandler : public xercesc::ErrorHandler @@ -269,6 +137,7 @@ private: class EntityFile : public Resource { friend class ResourceManager; + friend class EntityFileSAXHandler; private: EntityFile(boost::filesystem::path path); ~EntityFile(); @@ -288,6 +157,8 @@ private: xercesc::SAX2XMLReader* m_SAX2XMLReader; //std::map m_ComponentInfo; //std::vector m_EntityReferences; + + static void setReaderFeatures(xercesc::SAX2XMLReader* reader); }; #endif \ No newline at end of file diff --git a/include/Engine/Core/EntityFilePreprocessor.h b/include/Engine/Core/EntityFilePreprocessor.h index 3c3998b1..3139169f 100644 --- a/include/Engine/Core/EntityFilePreprocessor.h +++ b/include/Engine/Core/EntityFilePreprocessor.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -31,6 +32,7 @@ private: void onStartComponent(EntityID entity, std::string type); void parseComponentInfo(); void parseDefaults(); + std::string parseAnnotationXML(const XMLCh* xml); }; #endif \ No newline at end of file diff --git a/resources/Schema/Components.xsd b/resources/Schema/Components.xsd index 291cf938..88f09d6c 100644 --- a/resources/Schema/Components.xsd +++ b/resources/Schema/Components.xsd @@ -18,4 +18,5 @@ + \ No newline at end of file diff --git a/resources/Schema/Components/Team.xml b/resources/Schema/Components/Team.xml new file mode 100755 index 00000000..3eeb93bf --- /dev/null +++ b/resources/Schema/Components/Team.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/resources/Schema/Components/Team.xsd b/resources/Schema/Components/Team.xsd new file mode 100755 index 00000000..163d4a7f --- /dev/null +++ b/resources/Schema/Components/Team.xsd @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + Represents entity team affiliation + + + + + + + + diff --git a/resources/Schema/Types.xsd b/resources/Schema/Types.xsd index cd464201..fb584c64 100644 --- a/resources/Schema/Types.xsd +++ b/resources/Schema/Types.xsd @@ -4,6 +4,9 @@ + + + diff --git a/resources/Schema/Types/Entity.xsd b/resources/Schema/Types/Entity.xsd index 8fc52e1e..3ca6e545 100644 --- a/resources/Schema/Types/Entity.xsd +++ b/resources/Schema/Types/Entity.xsd @@ -27,6 +27,7 @@ + diff --git a/src/Engine/Core/EntityFile.cpp b/src/Engine/Core/EntityFile.cpp index 5589eddf..c1125e10 100644 --- a/src/Engine/Core/EntityFile.cpp +++ b/src/Engine/Core/EntityFile.cpp @@ -21,16 +21,24 @@ void EntityFile::Parse(const EntityFileHandler* handler) const using namespace xercesc; EntityFileSAXHandler saxHandler(handler, nullptr); - m_SAX2XMLReader->setFeature(XMLUni::fgXercesCacheGrammarFromParse, true); - m_SAX2XMLReader->setFeature(XMLUni::fgXercesUseCachedGrammarInParse, true); - m_SAX2XMLReader->setFeature(XMLUni::fgXercesSchema, true); - m_SAX2XMLReader->setFeature(XMLUni::fgXercesSchemaFullChecking, true); + setReaderFeatures(m_SAX2XMLReader); m_SAX2XMLReader->setContentHandler(&saxHandler); m_SAX2XMLReader->setErrorHandler(&saxHandler); m_SAX2XMLReader->setDeclarationHandler(&saxHandler); m_SAX2XMLReader->parse(m_FilePath.string().c_str()); } +void EntityFile::setReaderFeatures(xercesc::SAX2XMLReader* reader) +{ + using namespace xercesc; + reader->setFeature(XMLUni::fgXercesCacheGrammarFromParse, true); + reader->setFeature(XMLUni::fgXercesUseCachedGrammarInParse, true); + reader->setFeature(XMLUni::fgSAX2CoreValidation, true); + reader->setFeature(XMLUni::fgSAX2CoreNameSpaces, true); + reader->setFeature(XMLUni::fgXercesSchema, true); + reader->setFeature(XMLUni::fgXercesSchemaFullChecking, true); +} + std::size_t EntityFile::GetTypeStride(std::string typeName) { std::map typeStrides{ @@ -39,6 +47,7 @@ std::size_t EntityFile::GetTypeStride(std::string typeName) { "float", sizeof(float) }, { "double", sizeof(double) }, { "string", sizeof(std::string) }, + { "enum", sizeof(int) }, { "Vector", sizeof(glm::vec3) }, { "Quaternion", sizeof(glm::quat) }, { "Color", sizeof(glm::vec4) } @@ -77,7 +86,7 @@ void EntityFile::WriteAttributeData(char* outData, const ComponentInfo::Field_t& void EntityFile::WriteValueData(char* outData, const ComponentInfo::Field_t& field, const char* valueData) { - if (field.Type == "int") { + if (field.Type == "int" || field.Type == "enum") { int value = boost::lexical_cast(valueData); memcpy(outData, reinterpret_cast(&value), field.Stride); } else if (field.Type == "float") { @@ -95,3 +104,171 @@ void EntityFile::WriteValueData(char* outData, const ComponentInfo::Field_t& fie LOG_WARNING("Unknown value data type: %s", field.Type.c_str()); } } + +EntityFileSAXHandler::EntityFileSAXHandler(const EntityFileHandler* handler, xercesc::SAX2XMLReader* reader) : m_Handler(handler) +, m_Reader(reader) +{ + // 0 is imaginary base parent + m_EntityStack.push(0); + m_StateStack.push(State::Unknown); +} + +void EntityFileSAXHandler::startElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname, const xercesc::Attributes& attrs) +{ + std::string name = XS::ToString(_localName); + + if (m_StateStack.top() == State::Unknown || m_StateStack.top() == State::Entity) { + if (name == "Entity") { + m_StateStack.push(State::Entity); + onStartEntity(attrs); + return; + } + if (name == "EntityRef") { + onStartEntityRef(attrs); + return; + } + } + + std::string uri = XS::ToString(_uri); + if (m_StateStack.top() == State::Entity) { + if (uri == "components") { + m_StateStack.push(State::Component); + onStartComponent(name); + return; + } + } + + if (m_StateStack.top() == State::Component) { + m_StateStack.push(State::ComponentField); + onStartComponentField(name, attrs); + return; + } +} + +void EntityFileSAXHandler::endElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname) +{ + std::string name = XS::ToString(_localName); + if (m_StateStack.top() == State::Entity) { + if (name == "Entity") { + m_StateStack.pop(); + onEndEntity(); + return; + } + } + + std::string uri = XS::ToString(_uri); + if (m_StateStack.top() == State::Component) { + //if (uri == "components") { + m_StateStack.pop(); + onEndComponent(name); + return; + //} + } + + if (m_StateStack.top() == State::ComponentField) { + m_StateStack.pop(); + onEndComponentField(name); + return; + } +} + +void EntityFileSAXHandler::characters(const XMLCh* const chars, const XMLSize_t length) +{ + if (m_StateStack.top() == State::ComponentField) { + char* transcoded = xercesc::XMLString::transcode(chars); + onFieldData(transcoded); + } +} + +void EntityFileSAXHandler::fatalError(const xercesc::SAXParseException& e) +{ + XS::ToString s(e.getMessage()); + LOG_ERROR("SAXParseException: %s", ((std::string)s).c_str()); + //throw e; +} + +void EntityFileSAXHandler::error(const xercesc::SAXParseException& e) +{ + XS::ToString s(e.getMessage()); + LOG_ERROR("SAXParseException: %s", ((std::string)s).c_str()); +} + +void EntityFileSAXHandler::warning(const xercesc::SAXParseException& e) +{ + XS::ToString s(e.getMessage()); + LOG_ERROR("SAXParseException: %s", ((std::string)s).c_str()); +} + +void EntityFileSAXHandler::onStartEntity(const xercesc::Attributes& attrs) +{ + EntityID parent = m_EntityStack.top(); + + if (m_Handler->m_OnStartEntityCallback) { + std::string name; + auto xName = attrs.getValue(XS::ToXMLCh("name")); + if (xName != nullptr) { + name = XS::ToString(xName); + } + m_Handler->m_OnStartEntityCallback(m_NextEntityID, parent, name); + } + + m_EntityStack.push(m_NextEntityID); + m_NextEntityID++; +} + +void EntityFileSAXHandler::onEndEntity() +{ + m_EntityStack.pop(); +} + +void EntityFileSAXHandler::onStartEntityRef(const xercesc::Attributes& attrs) +{ + std::string path = XS::ToString(attrs.getValue(XS::ToXMLCh("file"))); + + xercesc::SAX2XMLReader* reader = xercesc::XMLReaderFactory::createXMLReader(); + EntityFile::setReaderFeatures(reader); + reader->setContentHandler(this); + reader->setErrorHandler(this); + reader->parse(path.c_str()); + delete reader; +} + +void EntityFileSAXHandler::onStartComponentField(const std::string& field, const xercesc::Attributes& attrs) +{ + //LOG_DEBUG(" Field: %s", field.c_str()); + m_CurrentField = field; + m_CurrentAttributes.clear(); + 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(m_EntityStack.top(), m_CurrentComponent, field, m_CurrentAttributes); + } +} + +void EntityFileSAXHandler::onEndComponent(const std::string& name) { } + +void EntityFileSAXHandler::onStartComponent(const std::string& name) +{ + //LOG_DEBUG(" Component: %s", name.c_str()); + m_CurrentComponent = name; + if (m_Handler->m_OnStartComponentCallback) { + m_Handler->m_OnStartComponentCallback(m_EntityStack.top(), name); + } +} + +void EntityFileSAXHandler::onEndComponentField(const std::string& field) { } + +void EntityFileSAXHandler::onFieldData(char* data) +{ + //LOG_DEBUG(" Data: %s", data); + if (m_Handler->m_OnStartFieldDataCallback) { + m_Handler->m_OnStartFieldDataCallback(m_EntityStack.top(), m_CurrentComponent, m_CurrentField, data); + } + + xercesc::XMLString::release(&data); +} diff --git a/src/Engine/Core/EntityFilePreprocessor.cpp b/src/Engine/Core/EntityFilePreprocessor.cpp index f9aae3d4..90151941 100644 --- a/src/Engine/Core/EntityFilePreprocessor.cpp +++ b/src/Engine/Core/EntityFilePreprocessor.cpp @@ -16,12 +16,12 @@ EntityFilePreprocessor::EntityFilePreprocessor(const EntityFile* entityFile) 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); + LOG_DEBUG("Component: %s (%s)", info.Name.c_str(), info.Meta->Annotation.c_str()); + LOG_DEBUG("Stride: %i", info.Stride); + LOG_DEBUG("Allocation: %i", info.Meta->Allocation); for (auto& kv : info.Fields) { auto& field = kv.second; - LOG_DEBUG("\t%i\t%s %s", field.Offset, field.Type, kv.first.c_str()); + LOG_DEBUG("\t%i\t%s %s", field.Offset, field.Type.c_str(), kv.first.c_str()); } } @@ -62,46 +62,16 @@ void EntityFilePreprocessor::parseComponentInfo() } ComponentInfo compInfo; + compInfo.Meta = std::make_shared(); // Name compInfo.Name = XS::ToString(element->getName()); // Known allocation - compInfo.Meta.Allocation = m_ComponentCounts[compInfo.Name]; + 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(&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()); - } - } + compInfo.Meta->Annotation = parseAnnotationXML(componentAnnotation->getAnnotationString()); } else { LOG_WARNING("Component \"%s\" is missing an annotation!", compInfo.Name.c_str()); } @@ -140,24 +110,58 @@ void EntityFilePreprocessor::parseComponentInfo() std::string name = XS::ToString(elementDeclaration->getName()); std::string type = XS::ToString(elementDeclaration->getTypeDefinition()->getName()); + std::string typeNamespace = XS::ToString(elementDeclaration->getTypeDefinition()->getNamespace()); + std::string baseType = XS::ToString(elementDeclaration->getTypeDefinition()->getBaseType()->getName()); + std::string effectiveType = type; size_t stride = EntityFile::GetTypeStride(type); if (stride == 0) { - LOG_WARNING("Field \"%s\" in component \"%s\" uses unexpected field type \"%s\". Skipping.", name.c_str(), compInfo.Name.c_str(), type.c_str()); - continue; + stride = EntityFile::GetTypeStride(baseType); + if (stride == 0) { + LOG_WARNING("Field \"%s\" in component \"%s\" uses unexpected field type \"%s\" with base type \"%s\". Skipping.", name.c_str(), compInfo.Name.c_str(), type.c_str(), baseType.c_str()); + continue; + } + effectiveType = baseType; + } + + // Annotation + auto fieldAnnotation = elementDeclaration->getAnnotation(); + if (fieldAnnotation != nullptr) { + compInfo.Meta->FieldAnnotations[name] = parseAnnotationXML(fieldAnnotation->getAnnotationString()); + } else { + LOG_WARNING("Component field \"%s.%s\" is missing an annotation!", compInfo.Name.c_str(), name.c_str()); + } + + if (effectiveType == "enum") { + // Parse potential enum type definition for field type + if (compInfo.Meta->FieldEnumDefinitions.count(name) == 0) { + auto enumTypeDefinition = xsModel->getTypeDefinition(XS::ToXMLCh(type), XS::ToXMLCh("components")); + auto xsComplexType = dynamic_cast(enumTypeDefinition); + auto xsComplexContent = xsComplexType->getParticle(); + auto xsExtension = xsComplexContent->getModelGroupTerm(); + auto xsExtensionParticles = xsExtension->getParticles(); + auto xsChoice = xsExtensionParticles->elementAt(0)->getModelGroupTerm(); + auto xsChoiceParticles = xsChoice->getParticles(); + for (int i = 0; i < xsChoiceParticles->size(); ++i) { + auto enumElement = xsChoiceParticles->elementAt(i)->getElementTerm(); + std::string enumName = XS::ToString(enumElement->getName()); + std::string enumValue = XS::ToString(enumElement->getConstraintValue()); + compInfo.Meta->FieldEnumDefinitions[name][enumName] = boost::lexical_cast(enumValue); + LOG_DEBUG("ENUM %s = %s", enumName.c_str(), enumValue.c_str()); + } + } } auto& field = compInfo.Fields[name]; field.Name = name; - field.Type = type; + field.Type = effectiveType; field.Offset = fieldOffset; field.Stride = stride; compInfo.FieldsInOrder.push_back(name); - fieldOffset += stride; } - compInfo.Meta.Stride = fieldOffset; + compInfo.Stride = fieldOffset; m_ComponentInfo[compInfo.Name] = compInfo; } } @@ -170,8 +174,10 @@ void EntityFilePreprocessor::parseDefaults() 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); + ci.second.Defaults = std::shared_ptr(new char[ci.second.Stride]); + memset(ci.second.Defaults.get(), 0, ci.second.Stride); + + std::string componentName = ci.first; XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager); parser.setDoSchema(true); @@ -179,8 +185,11 @@ void EntityFilePreprocessor::parseDefaults() parser.setErrorHandler(&errorHandler); parser.setValidationScheme(XercesDOMParser::Val_Always); parser.setValidationSchemaFullChecking(true); + //parser.setDoNamespaces(true); + //boost::filesystem::path schemaLocation = "Schema/Components/" + componentName + ".xsd"; + //std::string namespaceSchema = schemaLocation.string(); + //parser.setExternalNoNamespaceSchemaLocation("Teamasdasdasdasd.xsd"); - std::string componentName = ci.first; LOG_DEBUG("Parsing defaults for component %s", componentName.c_str()); boost::filesystem::path defaultsFile = "Schema/Components/" + componentName + ".xml"; @@ -192,7 +201,7 @@ void EntityFilePreprocessor::parseDefaults() } // Find the node in the components namespace matching the component name - std::string tagName = "c:" + componentName; + std::string tagName = 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()); @@ -225,9 +234,19 @@ void EntityFilePreprocessor::parseDefaults() EntityFile::WriteAttributeData(data, field, attributes); } - // Handle potential field values auto childNode = fieldElement->getFirstChild(); - if (childNode != nullptr && childNode->getNodeType() == DOMNode::TEXT_NODE) { + if (childNode == nullptr) { + continue; + } + + // An enum will either have an element node with a text node inside, + // or contain a text node directly. + if (childNode->getNodeType() == DOMNode::ELEMENT_NODE) { + childNode = childNode->getFirstChild(); + } + + // Handle potential field values + if (childNode->getNodeType() == DOMNode::TEXT_NODE) { char* cstrValue = XMLString::transcode(childNode->getNodeValue()); EntityFile::WriteValueData(data, field, cstrValue); XMLString::release(&cstrValue); @@ -236,3 +255,27 @@ void EntityFilePreprocessor::parseDefaults() } } +std::string EntityFilePreprocessor::parseAnnotationXML(const XMLCh* xml) +{ + using namespace xercesc; + + // Parse annotation XML + char* annotationString = XMLString::transcode(xml); + MemBufInputSource annotationInput(reinterpret_cast(annotationString), strlen(annotationString), "MemBuf: Annotation String"); + XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager); + //parser.setErrorHandler(&errorHandler); + parser.parse(annotationInput); + XMLString::release(&annotationString); + auto doc = parser.getDocument(); + + // Save documentation string + auto documentationTags = doc->getElementsByTagName(XS::ToXMLCh("xs:documentation")); + if (documentationTags->getLength() != 0) { + auto child = documentationTags->item(0)->getFirstChild(); + if (child != nullptr) { + return XS::ToString(child->getNodeValue()); + } + } + + return std::string(); +} diff --git a/src/Engine/Core/EntityFileWriter.cpp b/src/Engine/Core/EntityFileWriter.cpp index 5b6c466d..4d46be06 100644 --- a/src/Engine/Core/EntityFileWriter.cpp +++ b/src/Engine/Core/EntityFileWriter.cpp @@ -114,7 +114,7 @@ void EntityFileWriter::appentEntityComponents(xercesc::DOMElement* parentElement fieldElement->setAttribute(X("Y"), X(boost::lexical_cast(q.y))); fieldElement->setAttribute(X("Z"), X(boost::lexical_cast(q.z))); fieldElement->setAttribute(X("W"), X(boost::lexical_cast(q.w))); - } else if (field.Type == "int") { + } else if (field.Type == "int" || field.Type == "enum") { const int& value = c[fieldName]; fieldElement->appendChild(doc->createTextNode(X(boost::lexical_cast(value)))); } else if (field.Type == "float") { diff --git a/src/Engine/Core/World.cpp b/src/Engine/Core/World.cpp index 3104e4e9..477e2ab2 100644 --- a/src/Engine/Core/World.cpp +++ b/src/Engine/Core/World.cpp @@ -75,7 +75,7 @@ ComponentWrapper World::AttachComponent(EntityID entity, const std::string& comp // Allocate space for the component ComponentWrapper c = pool->Allocate(entity); // Write default values - memcpy(c.Data, ci.Defaults.get(), ci.Meta.Stride); + memcpy(c.Data, ci.Defaults.get(), ci.Stride); return c; } diff --git a/src/Engine/Editor/EditorSystem.cpp b/src/Engine/Editor/EditorSystem.cpp index 69889be5..22e1bfc0 100644 --- a/src/Engine/Editor/EditorSystem.cpp +++ b/src/Engine/Editor/EditorSystem.cpp @@ -484,8 +484,8 @@ void EditorSystem::drawUI(World* world, double dt) } if (ImGui::CollapsingHeader(componentType.c_str())) { - if (!ci.Meta.Annotation.empty()) { - ImGui::Text(ci.Meta.Annotation.c_str()); + if (!ci.Meta->Annotation.empty()) { + ImGui::Text(ci.Meta->Annotation.c_str()); } auto& component = world->GetComponent(m_Selection, componentType); @@ -529,6 +529,26 @@ void EditorSystem::drawUI(World* world, double dt) if (ImGui::InputFloat("", &tempVal, 0.01f, 1.f)) { component.SetProperty(fieldName, static_cast(tempVal)); } + } else if (field.Type == "int") { + int val = component.Property(fieldName); + ImGui::InputInt("", &val); + } else if (field.Type == "enum") { + int currentValue = component.Property(fieldName); + int item = -1; + std::stringstream enumKeys; + std::vector enumValues; + int i = 0; + for (auto& kv : ci.Meta->FieldEnumDefinitions.at(fieldName)) { + enumKeys << kv.first << " (" << kv.second << ")" << '\0'; + enumValues.push_back(kv.second); + if (currentValue == kv.second) { + item = i; + } + i++; + } + if (ImGui::Combo("", &item, enumKeys.str().c_str())) { + component.SetProperty(fieldName, enumValues.at(item)); + } } else if (field.Type == "bool") { auto& val = component.Property(fieldName); ImGui::Checkbox("", &val); diff --git a/src/Tests/ComponentPoolTest.cpp b/src/Tests/ComponentPoolTest.cpp index 25bdf1d3..1df13c10 100644 --- a/src/Tests/ComponentPoolTest.cpp +++ b/src/Tests/ComponentPoolTest.cpp @@ -10,8 +10,8 @@ BOOST_AUTO_TEST_CASE(ComponentPoolTest) //ci.Name = "Test"; //ci.FieldTypes["Field"] = "int"; //ci.FieldOffsets["Field"] = 0; - //ci.Meta.Allocation = 3; - //ci.Meta.Stride = sizeof(EntityID) + sizeof(int); + //ci.Meta->Allocation = 3; + //ci.Stride = sizeof(EntityID) + sizeof(int); //std::vector wrappers; //ComponentPool pool(ci);