Cleaned up code
This commit is contained in:
@@ -275,79 +275,19 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
static std::size_t GetTypeStride(std::string typeName);
|
static std::size_t GetTypeStride(std::string typeName);
|
||||||
|
static void WriteAttributeData(char* outData, const std::string fieldType, const std::map<std::string, std::string>& attributes);
|
||||||
static void WriteAttributeData(char* outData, const std::string fieldType, const std::map<std::string, std::string>& attributes)
|
static void WriteValueData(char* outData, const std::string fieldType, const char* valueData);
|
||||||
{
|
|
||||||
if (fieldType == "Vector") {
|
|
||||||
glm::vec3 vec;
|
|
||||||
vec.x = boost::lexical_cast<float>(attributes.at("X"));
|
|
||||||
vec.y = boost::lexical_cast<float>(attributes.at("Y"));
|
|
||||||
vec.z = boost::lexical_cast<float>(attributes.at("Z"));
|
|
||||||
memcpy(outData, reinterpret_cast<char*>(&vec), EntityFile::GetTypeStride(fieldType));
|
|
||||||
} else if (fieldType == "Color") {
|
|
||||||
glm::vec4 vec;
|
|
||||||
vec.r = boost::lexical_cast<float>(attributes.at("R"));
|
|
||||||
vec.g = boost::lexical_cast<float>(attributes.at("G"));
|
|
||||||
vec.b = boost::lexical_cast<float>(attributes.at("B"));
|
|
||||||
vec.a = boost::lexical_cast<float>(attributes.at("A"));
|
|
||||||
memcpy(outData, reinterpret_cast<char*>(&vec), EntityFile::GetTypeStride(fieldType));
|
|
||||||
} else if (fieldType == "Quaternion") {
|
|
||||||
glm::quat q;
|
|
||||||
q.x = boost::lexical_cast<float>(attributes.at("X"));
|
|
||||||
q.y = boost::lexical_cast<float>(attributes.at("Y"));
|
|
||||||
q.z = boost::lexical_cast<float>(attributes.at("Z"));
|
|
||||||
q.w = boost::lexical_cast<float>(attributes.at("W"));
|
|
||||||
memcpy(outData, reinterpret_cast<char*>(&q), EntityFile::GetTypeStride(fieldType));
|
|
||||||
} else if (!attributes.empty()) {
|
|
||||||
LOG_WARNING("%i attributes not handled by any type conversion!", attributes.size());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void WriteValueData(char* outData, const std::string fieldType, const char* valueData)
|
|
||||||
{
|
|
||||||
if (fieldType == "int") {
|
|
||||||
int value = boost::lexical_cast<int>(valueData);
|
|
||||||
memcpy(outData, reinterpret_cast<char*>(&value), EntityFile::GetTypeStride(fieldType));
|
|
||||||
} else if (fieldType == "float") {
|
|
||||||
float value = boost::lexical_cast<float>(valueData);
|
|
||||||
memcpy(outData, reinterpret_cast<char*>(&value), EntityFile::GetTypeStride(fieldType));
|
|
||||||
} else if (fieldType == "double") {
|
|
||||||
double value = boost::lexical_cast<double>(valueData);
|
|
||||||
memcpy(outData, reinterpret_cast<char*>(&value), EntityFile::GetTypeStride(fieldType));
|
|
||||||
} else if (fieldType == "bool") {
|
|
||||||
bool value = (valueData[0] == 't'); // Lazy bool evaluation
|
|
||||||
memcpy(outData, reinterpret_cast<char*>(&value), EntityFile::GetTypeStride(fieldType));
|
|
||||||
} else if (fieldType == "string") {
|
|
||||||
new (outData) std::string(valueData);
|
|
||||||
} else {
|
|
||||||
LOG_WARNING("Unknown value data type: %s", fieldType.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Parse(const EntityFileHandler* handler);
|
|
||||||
//const std::map<std::string, ::ComponentInfo>& ComponentInfo() const { return m_ComponentInfo; }
|
|
||||||
//const std::vector<std::string>& EntityReferences() const { return m_EntityReferences; }
|
|
||||||
|
|
||||||
xercesc::XMLGrammarPool* GrammarPool() const { return m_GrammarPool; }
|
xercesc::XMLGrammarPool* GrammarPool() const { return m_GrammarPool; }
|
||||||
|
|
||||||
|
void Parse(const EntityFileHandler* handler) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
boost::filesystem::path m_FilePath;
|
boost::filesystem::path m_FilePath;
|
||||||
xercesc::XMLGrammarPool* m_GrammarPool;
|
xercesc::XMLGrammarPool* m_GrammarPool;
|
||||||
xercesc::SAX2XMLReader* m_SAX2XMLReader;
|
xercesc::SAX2XMLReader* m_SAX2XMLReader;
|
||||||
//std::map<std::string, ::ComponentInfo> m_ComponentInfo;
|
//std::map<std::string, ::ComponentInfo> m_ComponentInfo;
|
||||||
//std::vector<std::string> m_EntityReferences;
|
//std::vector<std::string> 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<float>(val->fData.fValue.f_double);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -4,67 +4,20 @@
|
|||||||
class EntityFileParser
|
class EntityFileParser
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
EntityFileParser(EntityFile* entityFile)
|
EntityFileParser(const EntityFile* entityFile);
|
||||||
: m_EntityFile(entityFile)
|
|
||||||
{
|
|
||||||
m_Handler.SetStartEntityCallback(std::bind(&EntityFileParser::onStartEntity, this, std::placeholders::_1, std::placeholders::_2));
|
|
||||||
m_Handler.SetStartComponentCallback(std::bind(&EntityFileParser::onStartComponent, this, std::placeholders::_1, std::placeholders::_2));
|
|
||||||
m_Handler.SetStartFieldCallback(std::bind(&EntityFileParser::onStartComponentField, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
|
|
||||||
m_Handler.SetStartFieldDataCallback(std::bind(&EntityFileParser::onFieldData, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
|
|
||||||
}
|
|
||||||
|
|
||||||
void MergeEntities(World* world)
|
void MergeEntities(World* world);
|
||||||
{
|
|
||||||
m_World = world;
|
|
||||||
m_EntityIDMapper[0] = 0;
|
|
||||||
m_EntityFile->Parse(&m_Handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EntityFile* m_EntityFile;
|
const EntityFile* m_EntityFile;
|
||||||
EntityFileHandler m_Handler;
|
EntityFileHandler m_Handler;
|
||||||
World* m_World = nullptr;
|
World* m_World = nullptr;
|
||||||
// Maps EntityIDs local to the file to real IDs in the world
|
// Maps EntityIDs local to the file to real IDs in the world after they've been
|
||||||
|
// created in order to resolve parent-child relationships.
|
||||||
std::map<EntityID, EntityID> m_EntityIDMapper;
|
std::map<EntityID, EntityID> m_EntityIDMapper;
|
||||||
|
|
||||||
void onStartEntity(EntityID entity, EntityID parent)
|
void onStartEntity(EntityID entity, EntityID parent);
|
||||||
{
|
void onStartComponent(EntityID entity, std::string component);
|
||||||
EntityID realParent = m_EntityIDMapper.at(parent);
|
void onStartComponentField(EntityID entity, std::string componentType, std::string fieldName, std::map<std::string, std::string> attributes);
|
||||||
EntityID realEntity = m_World->CreateEntity(realParent);
|
void onFieldData(EntityID entity, std::string componentType, std::string fieldName, const char* fieldData);
|
||||||
m_EntityIDMapper[entity] = realEntity;
|
|
||||||
LOG_DEBUG("Created entity #%i (%i) with parent %i (%i)", entity, realEntity, parent, realParent);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onStartComponent(EntityID entity, std::string component)
|
|
||||||
{
|
|
||||||
EntityID realEntity = m_EntityIDMapper.at(entity);
|
|
||||||
m_World->AttachComponent(entity, component);
|
|
||||||
LOG_DEBUG("Attached component of type \"%s\" to entity #%i (%i)", component.c_str(), entity, realEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onStartComponentField(EntityID entity, std::string componentType, std::string fieldName, std::map<std::string, std::string> attributes)
|
|
||||||
{
|
|
||||||
EntityID realEntity = m_EntityIDMapper.at(entity);
|
|
||||||
ComponentWrapper component = m_World->GetComponent(realEntity, componentType);
|
|
||||||
std::string fieldType = component.Info.FieldTypes.at(fieldName);
|
|
||||||
|
|
||||||
LOG_DEBUG("Field \"%s\" type \"%s\"", fieldName.c_str(), fieldType.c_str());
|
|
||||||
LOG_DEBUG("Attributes:");
|
|
||||||
for (auto& kv : attributes) {
|
|
||||||
LOG_DEBUG("\t%s = %s", kv.first.c_str(), kv.second.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
char* data = component.Data + component.Info.FieldOffsets.at(fieldName);
|
|
||||||
EntityFile::WriteAttributeData(data, fieldType, attributes);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onFieldData(EntityID entity, std::string componentType, std::string fieldName, const char* fieldData)
|
|
||||||
{
|
|
||||||
EntityID realEntity = m_EntityIDMapper.at(entity);
|
|
||||||
ComponentWrapper component = m_World->GetComponent(realEntity, componentType);
|
|
||||||
std::string fieldType = component.Info.FieldTypes.at(fieldName);
|
|
||||||
|
|
||||||
char* data = component.Data + component.Info.FieldOffsets.at(fieldName);
|
|
||||||
EntityFile::WriteValueData(data, fieldType, fieldData);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
@@ -16,233 +16,16 @@
|
|||||||
class EntityFilePreprocessor
|
class EntityFilePreprocessor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
EntityFilePreprocessor(std::string path)
|
EntityFilePreprocessor(const EntityFile* entityFile);
|
||||||
: m_FilePath(path)
|
|
||||||
{
|
|
||||||
m_EntityFile = ResourceManager::Load<EntityFile>(path);
|
|
||||||
EntityFileHandler handler;
|
|
||||||
handler.SetStartComponentCallback(std::bind(&EntityFilePreprocessor::onStartComponent, this, std::placeholders::_1, std::placeholders::_2));
|
|
||||||
m_EntityFile->Parse(&handler);
|
|
||||||
|
|
||||||
LOG_DEBUG("___ COMPONENT DEFINITIONS ___");
|
void RegisterComponents(World* world);
|
||||||
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:
|
private:
|
||||||
std::string m_FilePath;
|
const EntityFile* m_EntityFile;
|
||||||
EntityFile* m_EntityFile;
|
|
||||||
std::map<std::string, unsigned int> m_ComponentCounts;
|
std::map<std::string, unsigned int> m_ComponentCounts;
|
||||||
std::map<std::string, ComponentInfo> m_ComponentInfo;
|
std::map<std::string, ComponentInfo> m_ComponentInfo;
|
||||||
|
|
||||||
void onStartComponent(EntityID entity, std::string type)
|
void onStartComponent(EntityID entity, std::string type);
|
||||||
{
|
void parseComponentInfo();
|
||||||
//LOG_DEBUG("Component: %s", type.c_str());
|
void parseDefaults();
|
||||||
m_ComponentCounts[type]++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void parseComponentInfo()
|
|
||||||
{
|
|
||||||
using namespace xercesc;
|
|
||||||
EntityFileXMLErrorHandler errorHandler;
|
|
||||||
auto grammarPool = m_EntityFile->GrammarPool();
|
|
||||||
bool whateverTheFuckThisIs;
|
|
||||||
auto xsModel = grammarPool->getXSModel(whateverTheFuckThisIs);
|
|
||||||
|
|
||||||
// Find component xsd element declarations
|
|
||||||
std::cout << "Enumerating components..." << std::endl;
|
|
||||||
// <xs:element name="ComponentName">
|
|
||||||
auto topLevelElements = xsModel->getComponents(XSConstants::ELEMENT_DECLARATION);
|
|
||||||
for (unsigned int i = 0; i < topLevelElements->getLength(); ++i) {
|
|
||||||
auto element = static_cast<XSElementDeclaration*>(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<const XMLByte*>(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<DOMElement*>(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!");
|
|
||||||
}
|
|
||||||
|
|
||||||
// <xs:complexType>
|
|
||||||
auto typeDefinition = element->getTypeDefinition();
|
|
||||||
if (typeDefinition->getTypeCategory() != XSTypeDefinition::COMPLEX_TYPE) {
|
|
||||||
LOG_ERROR("Type definition wasn't COMPLEX_TYPE! Skipping.");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
auto complexTypeDefinition = dynamic_cast<XSComplexTypeDefinition*>(typeDefinition);
|
|
||||||
|
|
||||||
// <xs:all>
|
|
||||||
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();
|
|
||||||
|
|
||||||
// <xs:element...
|
|
||||||
// <xs:attribute...
|
|
||||||
unsigned int fieldOffset = 0;
|
|
||||||
auto particles = modelGroup->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;
|
|
||||||
|
|
||||||
EntityFileXMLErrorHandler errorHandler;
|
|
||||||
|
|
||||||
for (auto& ci : m_ComponentInfo) {
|
|
||||||
// Allocate memory for default values
|
|
||||||
ci.second.Defaults = std::shared_ptr<char>(new char[ci.second.Meta.Stride]);
|
|
||||||
memset(ci.second.Defaults.get(), 0, ci.second.Meta.Stride);
|
|
||||||
|
|
||||||
XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager);
|
|
||||||
parser.setErrorHandler(&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<DOMElement*>(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<DOMElement*>(fieldNode);
|
|
||||||
|
|
||||||
std::string fieldType = ci.second.FieldTypes.at(fieldName);
|
|
||||||
unsigned int fieldOffset = ci.second.FieldOffsets.at(fieldName);
|
|
||||||
char* data = ci.second.Defaults.get() + fieldOffset;
|
|
||||||
|
|
||||||
// Handle potential field attributes
|
|
||||||
if (fieldElement->hasAttributes()) {
|
|
||||||
std::map<std::string, std::string> attributes;
|
|
||||||
auto attributeMap = fieldElement->getAttributes();
|
|
||||||
for (int i = 0; i < attributeMap->getLength(); ++i) {
|
|
||||||
auto attribItem = attributeMap->item(i);
|
|
||||||
attributes[XS::ToString(attribItem->getNodeName())] = XS::ToString(attribItem->getNodeValue());
|
|
||||||
}
|
|
||||||
EntityFile::WriteAttributeData(data, fieldType, attributes);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle potential field values
|
|
||||||
auto childNode = fieldElement->getFirstChild();
|
|
||||||
if (childNode != nullptr && childNode->getNodeType() == DOMNode::TEXT_NODE) {
|
|
||||||
char* cstrValue = XMLString::transcode(childNode->getNodeValue());
|
|
||||||
EntityFile::WriteValueData(data, fieldType, cstrValue);
|
|
||||||
XMLString::release(&cstrValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
@@ -1,141 +0,0 @@
|
|||||||
#ifndef EntityXMLFile_h__
|
|
||||||
#define EntityXMLFile_h__
|
|
||||||
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
#include "../Common.h"
|
|
||||||
#include "../GLM.h"
|
|
||||||
#include <xercesc/dom/DOM.hpp>
|
|
||||||
#include <xercesc/dom/DOMLSInput.hpp>
|
|
||||||
#include <xercesc/dom/DOMElement.hpp>
|
|
||||||
#include <xercesc/framework/Wrapper4InputSource.hpp>
|
|
||||||
#include <xercesc/framework/LocalFileInputSource.hpp>
|
|
||||||
#include <xercesc/framework/LocalFileFormatTarget.hpp>
|
|
||||||
#include <xercesc/framework/MemBufFormatTarget.hpp>
|
|
||||||
#include <xercesc/framework/MemBufInputSource.hpp>
|
|
||||||
#include <xercesc/sax/HandlerBase.hpp>
|
|
||||||
#include <xercesc/util/PlatformUtils.hpp>
|
|
||||||
#include <xercesc/util/XMLFloat.hpp>
|
|
||||||
#include <xercesc/framework/XMLGrammarPoolImpl.hpp>
|
|
||||||
#include <xercesc/parsers/XercesDOMParser.hpp>
|
|
||||||
#include <xercesc/framework/psvi/XSElementDeclaration.hpp>
|
|
||||||
#include <xercesc/framework/psvi/XSComplexTypeDefinition.hpp>
|
|
||||||
#include <xercesc/framework/psvi/XSParticle.hpp>
|
|
||||||
#include <xercesc/framework/psvi/XSModelGroup.hpp>
|
|
||||||
#include <xercesc/framework/psvi/XSAnnotation.hpp>
|
|
||||||
#include <xercesc/framework/psvi/XSValue.hpp>
|
|
||||||
#include <xercesc/framework/XMLValidator.hpp>
|
|
||||||
|
|
||||||
#include "ResourceManager.h"
|
|
||||||
#include "Entity.h"
|
|
||||||
#include "ComponentInfo.h"
|
|
||||||
class World;
|
|
||||||
|
|
||||||
class EntityPreprocessorXMLErrorHandler : public xercesc::DOMErrorHandler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
bool handleError(const xercesc::DOMError &e) override
|
|
||||||
{
|
|
||||||
char* message = xercesc::XMLString::transcode(e.getMessage());
|
|
||||||
std::cerr << "Preprocessor DOMError: " << message << std::endl;
|
|
||||||
xercesc::XMLString::release(&message);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class EntityParserXMLErrorHandler : public xercesc::ErrorHandler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void warning(const xercesc::SAXParseException& e) override
|
|
||||||
{
|
|
||||||
reportParseException("Warning", e);
|
|
||||||
}
|
|
||||||
void error(const xercesc::SAXParseException& e) override
|
|
||||||
{
|
|
||||||
reportParseException("Error", e);
|
|
||||||
}
|
|
||||||
void fatalError(const xercesc::SAXParseException& e) override
|
|
||||||
{
|
|
||||||
reportParseException("FATAL ERROR", e);
|
|
||||||
}
|
|
||||||
void resetErrors() override { }
|
|
||||||
|
|
||||||
private:
|
|
||||||
void reportParseException(std::string type, const xercesc::SAXParseException& e)
|
|
||||||
{
|
|
||||||
char* message = xercesc::XMLString::transcode(e.getMessage());
|
|
||||||
char* systemID = xercesc::XMLString::transcode(e.getSystemId());
|
|
||||||
std::cerr << systemID << ":" << e.getLineNumber() << ":" << e.getColumnNumber() << std::endl;
|
|
||||||
std::cerr << type << ": " << message << std::endl;
|
|
||||||
xercesc::XMLString::release(&systemID);
|
|
||||||
xercesc::XMLString::release(&message);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class XSTR
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
XSTR(const XMLCh* const xmlString)
|
|
||||||
{
|
|
||||||
m_AsChar = xercesc::XMLString::transcode(xmlString);
|
|
||||||
}
|
|
||||||
|
|
||||||
XSTR(const char* normalString)
|
|
||||||
{
|
|
||||||
m_AsXMLCh = xercesc::XMLString::transcode(normalString);
|
|
||||||
}
|
|
||||||
|
|
||||||
~XSTR()
|
|
||||||
{
|
|
||||||
if (m_AsChar != nullptr) {
|
|
||||||
xercesc::XMLString::release(&m_AsChar);
|
|
||||||
}
|
|
||||||
if (m_AsXMLCh != nullptr) {
|
|
||||||
xercesc::XMLString::release(&m_AsXMLCh);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
operator const char*() const { return m_AsChar; }
|
|
||||||
operator const XMLCh*() const { return m_AsXMLCh; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
char* m_AsChar = nullptr;
|
|
||||||
XMLCh* m_AsXMLCh = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
class EntityXMLFile : public Resource
|
|
||||||
{
|
|
||||||
friend class ResourceManager;
|
|
||||||
|
|
||||||
private:
|
|
||||||
EntityXMLFile(std::string path);
|
|
||||||
|
|
||||||
public:
|
|
||||||
~EntityXMLFile();
|
|
||||||
|
|
||||||
void PopulateWorld(World* world);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static unsigned int InstanceCount;
|
|
||||||
|
|
||||||
std::string m_EntityFile;
|
|
||||||
xercesc::XMLGrammarPool* m_GrammarPool = nullptr;
|
|
||||||
EntityParserXMLErrorHandler* m_ErrorHandler = nullptr;
|
|
||||||
xercesc::XercesDOMParser* m_DOMParser = nullptr;
|
|
||||||
xercesc::DOMDocument* m_DOMDocument = nullptr;
|
|
||||||
std::map<std::string, ComponentInfo> m_ComponentInfo;
|
|
||||||
|
|
||||||
// Preprocesses the entity file to insert include-by-copy child entities
|
|
||||||
// TODO: Make this work in memory instead of saving to file
|
|
||||||
void preprocess(std::string inPath, std::string outPath);
|
|
||||||
|
|
||||||
void parseComponentInfo();
|
|
||||||
void parseDefaults();
|
|
||||||
void predictComponentAllocation();
|
|
||||||
void parseEntityGraph(World* world, xercesc::DOMElement* parent, EntityID parentEntity);
|
|
||||||
std::size_t getTypeStride(std::string typeName);
|
|
||||||
float getFloatAttribute(const xercesc::DOMElement* element, const char* attribute) const;
|
|
||||||
void writeData(const xercesc::DOMElement* element, std::string typeName, char* outData);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -13,7 +13,6 @@
|
|||||||
#include "Input/KeyboardInputHandler.h"
|
#include "Input/KeyboardInputHandler.h"
|
||||||
#include "Input/MouseInputHandler.h"
|
#include "Input/MouseInputHandler.h"
|
||||||
#include "Core/EKeyDown.h"
|
#include "Core/EKeyDown.h"
|
||||||
#include "Core/EntityXMLFile.h"
|
|
||||||
#include "Core/EntityFilePreprocessor.h"
|
#include "Core/EntityFilePreprocessor.h"
|
||||||
#include "Core/SystemPipeline.h"
|
#include "Core/SystemPipeline.h"
|
||||||
#include "RaptorCopterSystem.h"
|
#include "RaptorCopterSystem.h"
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ EntityFile::~EntityFile()
|
|||||||
xercesc::XMLPlatformUtils::Terminate();
|
xercesc::XMLPlatformUtils::Terminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityFile::Parse(const EntityFileHandler* handler)
|
void EntityFile::Parse(const EntityFileHandler* handler) const
|
||||||
{
|
{
|
||||||
using namespace xercesc;
|
using namespace xercesc;
|
||||||
|
|
||||||
@@ -45,3 +45,51 @@ std::size_t EntityFile::GetTypeStride(std::string typeName)
|
|||||||
auto it = typeStrides.find(typeName);
|
auto it = typeStrides.find(typeName);
|
||||||
return (it != typeStrides.end()) ? it->second : 0;
|
return (it != typeStrides.end()) ? it->second : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EntityFile::WriteAttributeData(char* outData, const std::string fieldType, const std::map<std::string, std::string>& attributes)
|
||||||
|
{
|
||||||
|
if (fieldType == "Vector") {
|
||||||
|
glm::vec3 vec;
|
||||||
|
vec.x = boost::lexical_cast<float>(attributes.at("X"));
|
||||||
|
vec.y = boost::lexical_cast<float>(attributes.at("Y"));
|
||||||
|
vec.z = boost::lexical_cast<float>(attributes.at("Z"));
|
||||||
|
memcpy(outData, reinterpret_cast<char*>(&vec), EntityFile::GetTypeStride(fieldType));
|
||||||
|
} else if (fieldType == "Color") {
|
||||||
|
glm::vec4 vec;
|
||||||
|
vec.r = boost::lexical_cast<float>(attributes.at("R"));
|
||||||
|
vec.g = boost::lexical_cast<float>(attributes.at("G"));
|
||||||
|
vec.b = boost::lexical_cast<float>(attributes.at("B"));
|
||||||
|
vec.a = boost::lexical_cast<float>(attributes.at("A"));
|
||||||
|
memcpy(outData, reinterpret_cast<char*>(&vec), EntityFile::GetTypeStride(fieldType));
|
||||||
|
} else if (fieldType == "Quaternion") {
|
||||||
|
glm::quat q;
|
||||||
|
q.x = boost::lexical_cast<float>(attributes.at("X"));
|
||||||
|
q.y = boost::lexical_cast<float>(attributes.at("Y"));
|
||||||
|
q.z = boost::lexical_cast<float>(attributes.at("Z"));
|
||||||
|
q.w = boost::lexical_cast<float>(attributes.at("W"));
|
||||||
|
memcpy(outData, reinterpret_cast<char*>(&q), EntityFile::GetTypeStride(fieldType));
|
||||||
|
} else if (!attributes.empty()) {
|
||||||
|
LOG_WARNING("%i attributes not handled by any type conversion!", attributes.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityFile::WriteValueData(char* outData, const std::string fieldType, const char* valueData)
|
||||||
|
{
|
||||||
|
if (fieldType == "int") {
|
||||||
|
int value = boost::lexical_cast<int>(valueData);
|
||||||
|
memcpy(outData, reinterpret_cast<char*>(&value), EntityFile::GetTypeStride(fieldType));
|
||||||
|
} else if (fieldType == "float") {
|
||||||
|
float value = boost::lexical_cast<float>(valueData);
|
||||||
|
memcpy(outData, reinterpret_cast<char*>(&value), EntityFile::GetTypeStride(fieldType));
|
||||||
|
} else if (fieldType == "double") {
|
||||||
|
double value = boost::lexical_cast<double>(valueData);
|
||||||
|
memcpy(outData, reinterpret_cast<char*>(&value), EntityFile::GetTypeStride(fieldType));
|
||||||
|
} else if (fieldType == "bool") {
|
||||||
|
bool value = (valueData[0] == 't'); // Lazy bool evaluation
|
||||||
|
memcpy(outData, reinterpret_cast<char*>(&value), EntityFile::GetTypeStride(fieldType));
|
||||||
|
} else if (fieldType == "string") {
|
||||||
|
new (outData) std::string(valueData);
|
||||||
|
} else {
|
||||||
|
LOG_WARNING("Unknown value data type: %s", fieldType.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
#include "Core/EntityFileParser.h"
|
||||||
|
|
||||||
|
EntityFileParser::EntityFileParser(const EntityFile* entityFile)
|
||||||
|
: m_EntityFile(entityFile)
|
||||||
|
{
|
||||||
|
m_Handler.SetStartEntityCallback(std::bind(&EntityFileParser::onStartEntity, this, std::placeholders::_1, std::placeholders::_2));
|
||||||
|
m_Handler.SetStartComponentCallback(std::bind(&EntityFileParser::onStartComponent, this, std::placeholders::_1, std::placeholders::_2));
|
||||||
|
m_Handler.SetStartFieldCallback(std::bind(&EntityFileParser::onStartComponentField, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
|
||||||
|
m_Handler.SetStartFieldDataCallback(std::bind(&EntityFileParser::onFieldData, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityFileParser::MergeEntities(World* world)
|
||||||
|
{
|
||||||
|
m_World = world;
|
||||||
|
m_EntityIDMapper[0] = 0;
|
||||||
|
m_EntityFile->Parse(&m_Handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityFileParser::onStartEntity(EntityID entity, EntityID parent)
|
||||||
|
{
|
||||||
|
EntityID realParent = m_EntityIDMapper.at(parent);
|
||||||
|
EntityID realEntity = m_World->CreateEntity(realParent);
|
||||||
|
m_EntityIDMapper[entity] = realEntity;
|
||||||
|
LOG_DEBUG("Created entity #%i (%i) with parent %i (%i)", entity, realEntity, parent, realParent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityFileParser::onStartComponent(EntityID entity, std::string component)
|
||||||
|
{
|
||||||
|
EntityID realEntity = m_EntityIDMapper.at(entity);
|
||||||
|
m_World->AttachComponent(entity, component);
|
||||||
|
LOG_DEBUG("Attached component of type \"%s\" to entity #%i (%i)", component.c_str(), entity, realEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityFileParser::onStartComponentField(EntityID entity, std::string componentType, std::string fieldName, std::map<std::string, std::string> attributes)
|
||||||
|
{
|
||||||
|
EntityID realEntity = m_EntityIDMapper.at(entity);
|
||||||
|
ComponentWrapper component = m_World->GetComponent(realEntity, componentType);
|
||||||
|
std::string fieldType = component.Info.FieldTypes.at(fieldName);
|
||||||
|
|
||||||
|
LOG_DEBUG("Field \"%s\" type \"%s\"", fieldName.c_str(), fieldType.c_str());
|
||||||
|
LOG_DEBUG("Attributes:");
|
||||||
|
for (auto& kv : attributes) {
|
||||||
|
LOG_DEBUG("\t%s = %s", kv.first.c_str(), kv.second.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
char* data = component.Data + component.Info.FieldOffsets.at(fieldName);
|
||||||
|
EntityFile::WriteAttributeData(data, fieldType, attributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityFileParser::onFieldData(EntityID entity, std::string componentType, std::string fieldName, const char* fieldData)
|
||||||
|
{
|
||||||
|
EntityID realEntity = m_EntityIDMapper.at(entity);
|
||||||
|
ComponentWrapper component = m_World->GetComponent(realEntity, componentType);
|
||||||
|
std::string fieldType = component.Info.FieldTypes.at(fieldName);
|
||||||
|
|
||||||
|
char* data = component.Data + component.Info.FieldOffsets.at(fieldName);
|
||||||
|
EntityFile::WriteValueData(data, fieldType, fieldData);
|
||||||
|
}
|
||||||
@@ -0,0 +1,225 @@
|
|||||||
|
#include "Core/EntityFilePreprocessor.h"
|
||||||
|
|
||||||
|
EntityFilePreprocessor::EntityFilePreprocessor(const EntityFile* entityFile)
|
||||||
|
: m_EntityFile(entityFile)
|
||||||
|
{
|
||||||
|
EntityFileHandler handler;
|
||||||
|
handler.SetStartComponentCallback(std::bind(&EntityFilePreprocessor::onStartComponent, this, std::placeholders::_1, std::placeholders::_2));
|
||||||
|
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 EntityFilePreprocessor::RegisterComponents(World* world)
|
||||||
|
{
|
||||||
|
for (auto& kv : m_ComponentInfo) {
|
||||||
|
world->RegisterComponent(kv.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityFilePreprocessor::onStartComponent(EntityID entity, std::string type)
|
||||||
|
{
|
||||||
|
//LOG_DEBUG("Component: %s", type.c_str());
|
||||||
|
m_ComponentCounts[type]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityFilePreprocessor::parseComponentInfo()
|
||||||
|
{
|
||||||
|
using namespace xercesc;
|
||||||
|
EntityFileXMLErrorHandler errorHandler;
|
||||||
|
auto grammarPool = m_EntityFile->GrammarPool();
|
||||||
|
bool whateverTheFuckThisIs;
|
||||||
|
auto xsModel = grammarPool->getXSModel(whateverTheFuckThisIs);
|
||||||
|
|
||||||
|
// Find component xsd element declarations
|
||||||
|
std::cout << "Enumerating components..." << std::endl;
|
||||||
|
// <xs:element name="ComponentName">
|
||||||
|
auto topLevelElements = xsModel->getComponents(XSConstants::ELEMENT_DECLARATION);
|
||||||
|
for (unsigned int i = 0; i < topLevelElements->getLength(); ++i) {
|
||||||
|
auto element = static_cast<XSElementDeclaration*>(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<const XMLByte*>(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<DOMElement*>(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!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// <xs:complexType>
|
||||||
|
auto typeDefinition = element->getTypeDefinition();
|
||||||
|
if (typeDefinition->getTypeCategory() != XSTypeDefinition::COMPLEX_TYPE) {
|
||||||
|
LOG_ERROR("Type definition wasn't COMPLEX_TYPE! Skipping.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto complexTypeDefinition = dynamic_cast<XSComplexTypeDefinition*>(typeDefinition);
|
||||||
|
|
||||||
|
// <xs:all>
|
||||||
|
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();
|
||||||
|
|
||||||
|
// <xs:element...
|
||||||
|
// <xs:attribute...
|
||||||
|
unsigned int fieldOffset = 0;
|
||||||
|
auto particles = modelGroup->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 EntityFilePreprocessor::parseDefaults()
|
||||||
|
{
|
||||||
|
using namespace xercesc;
|
||||||
|
|
||||||
|
EntityFileXMLErrorHandler errorHandler;
|
||||||
|
|
||||||
|
for (auto& ci : m_ComponentInfo) {
|
||||||
|
// Allocate memory for default values
|
||||||
|
ci.second.Defaults = std::shared_ptr<char>(new char[ci.second.Meta.Stride]);
|
||||||
|
memset(ci.second.Defaults.get(), 0, ci.second.Meta.Stride);
|
||||||
|
|
||||||
|
XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager);
|
||||||
|
parser.setErrorHandler(&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<DOMElement*>(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<DOMElement*>(fieldNode);
|
||||||
|
|
||||||
|
std::string fieldType = ci.second.FieldTypes.at(fieldName);
|
||||||
|
unsigned int fieldOffset = ci.second.FieldOffsets.at(fieldName);
|
||||||
|
char* data = ci.second.Defaults.get() + fieldOffset;
|
||||||
|
|
||||||
|
// Handle potential field attributes
|
||||||
|
if (fieldElement->hasAttributes()) {
|
||||||
|
std::map<std::string, std::string> attributes;
|
||||||
|
auto attributeMap = fieldElement->getAttributes();
|
||||||
|
for (int i = 0; i < attributeMap->getLength(); ++i) {
|
||||||
|
auto attribItem = attributeMap->item(i);
|
||||||
|
attributes[XS::ToString(attribItem->getNodeName())] = XS::ToString(attribItem->getNodeValue());
|
||||||
|
}
|
||||||
|
EntityFile::WriteAttributeData(data, fieldType, attributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle potential field values
|
||||||
|
auto childNode = fieldElement->getFirstChild();
|
||||||
|
if (childNode != nullptr && childNode->getNodeType() == DOMNode::TEXT_NODE) {
|
||||||
|
char* cstrValue = XMLString::transcode(childNode->getNodeValue());
|
||||||
|
EntityFile::WriteValueData(data, fieldType, cstrValue);
|
||||||
|
XMLString::release(&cstrValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,451 +0,0 @@
|
|||||||
#include "Core/EntityXMLFile.h"
|
|
||||||
#include "Core/World.h"
|
|
||||||
|
|
||||||
unsigned int EntityXMLFile::InstanceCount = 0;
|
|
||||||
|
|
||||||
EntityXMLFile::EntityXMLFile(std::string path)
|
|
||||||
: m_EntityFile(path)
|
|
||||||
{
|
|
||||||
using namespace xercesc;
|
|
||||||
|
|
||||||
if (InstanceCount == 0) {
|
|
||||||
XMLPlatformUtils::Initialize();
|
|
||||||
}
|
|
||||||
InstanceCount++;
|
|
||||||
|
|
||||||
m_GrammarPool = new XMLGrammarPoolImpl();
|
|
||||||
m_ErrorHandler = new EntityParserXMLErrorHandler();
|
|
||||||
m_DOMParser = new XercesDOMParser(nullptr, XMLPlatformUtils::fgMemoryManager, m_GrammarPool);
|
|
||||||
m_DOMParser->setErrorHandler(m_ErrorHandler);
|
|
||||||
m_DOMParser->setDoNamespaces(true);
|
|
||||||
m_DOMParser->setDoXInclude(true);
|
|
||||||
m_DOMParser->setDoSchema(true);
|
|
||||||
m_DOMParser->setValidationSchemaFullChecking(true);
|
|
||||||
m_DOMParser->setValidationScheme(xercesc::XercesDOMParser::Val_Auto);
|
|
||||||
m_DOMParser->setValidationSchemaFullChecking(true);
|
|
||||||
m_DOMParser->setValidationConstraintFatal(false);
|
|
||||||
m_DOMParser->setIncludeIgnorableWhitespace(false);
|
|
||||||
// Make sure schema grammar is kept after validation
|
|
||||||
m_DOMParser->cacheGrammarFromParse(true);
|
|
||||||
|
|
||||||
// HACK: Use Sax2 parser instead so the entire DOM doesn't have to reside in memory
|
|
||||||
m_DOMParser->parse(m_EntityFile.c_str());
|
|
||||||
m_DOMDocument = m_DOMParser->getDocument();
|
|
||||||
|
|
||||||
// 1. Fill in ComponentInfo name, fields, default values and metadata from PSVI
|
|
||||||
parseComponentInfo();
|
|
||||||
// 2. Parse default value files for those components
|
|
||||||
parseDefaults();
|
|
||||||
// 3. Allocate component structures
|
|
||||||
predictComponentAllocation();
|
|
||||||
}
|
|
||||||
|
|
||||||
EntityXMLFile::~EntityXMLFile()
|
|
||||||
{
|
|
||||||
using namespace xercesc;
|
|
||||||
|
|
||||||
if (m_DOMParser != nullptr) {
|
|
||||||
delete m_DOMParser;
|
|
||||||
}
|
|
||||||
if (m_ErrorHandler != nullptr) {
|
|
||||||
delete m_ErrorHandler;
|
|
||||||
}
|
|
||||||
if (m_GrammarPool != nullptr) {
|
|
||||||
delete m_GrammarPool;
|
|
||||||
}
|
|
||||||
|
|
||||||
InstanceCount--;
|
|
||||||
if (InstanceCount == 0) {
|
|
||||||
XMLPlatformUtils::Terminate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EntityXMLFile::PopulateWorld(World* world)
|
|
||||||
{
|
|
||||||
for (auto& pair : m_ComponentInfo) {
|
|
||||||
world->RegisterComponent(pair.second);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. Parse entity hierarchy
|
|
||||||
auto root = m_DOMDocument->getDocumentElement();
|
|
||||||
parseEntityGraph(world, root, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EntityXMLFile::preprocess(std::string inPath, std::string outPath)
|
|
||||||
{
|
|
||||||
using namespace xercesc;
|
|
||||||
|
|
||||||
static const XMLCh gLS[] = { 'L', 'S', '\0' };
|
|
||||||
DOMImplementationLS* di = static_cast<DOMImplementationLS*>(DOMImplementationRegistry::getDOMImplementation(gLS));
|
|
||||||
|
|
||||||
// Parse the file
|
|
||||||
DOMLSParser* parser = di->createLSParser(DOMImplementationLS::MODE_SYNCHRONOUS, nullptr);
|
|
||||||
DOMConfiguration* config = parser->getDomConfig();
|
|
||||||
config->setParameter(XMLUni::fgDOMNamespaces, true);
|
|
||||||
config->setParameter(XMLUni::fgXercesSchema, true);
|
|
||||||
config->setParameter(XMLUni::fgXercesHandleMultipleImports, true);
|
|
||||||
config->setParameter(XMLUni::fgXercesSchemaFullChecking, true);
|
|
||||||
config->setParameter(XMLUni::fgXercesDoXInclude, true);
|
|
||||||
auto errHandler = new EntityPreprocessorXMLErrorHandler();
|
|
||||||
config->setParameter(XMLUni::fgDOMErrorHandler, errHandler);
|
|
||||||
|
|
||||||
auto source = new LocalFileInputSource(XSTR(inPath.c_str()));
|
|
||||||
Wrapper4InputSource* domSourceWrapper = new Wrapper4InputSource(source);
|
|
||||||
DOMDocument* doc = parser->parse(dynamic_cast<DOMLSInput*>(domSourceWrapper));
|
|
||||||
|
|
||||||
// Serialize and output the new XML
|
|
||||||
DOMLSSerializer* writer = di->createLSSerializer();
|
|
||||||
DOMLSOutput* output = di->createLSOutput();
|
|
||||||
XMLFormatTarget* formatTarget = new LocalFileFormatTarget(outPath.c_str());
|
|
||||||
// TODO: MemBufFormatTarget* formatTarget = new MemBufFormatTarget()
|
|
||||||
output->setByteStream(formatTarget);
|
|
||||||
writer->write(doc, output);
|
|
||||||
|
|
||||||
delete formatTarget;
|
|
||||||
output->release();
|
|
||||||
writer->release();
|
|
||||||
parser->release();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EntityXMLFile::parseComponentInfo()
|
|
||||||
{
|
|
||||||
using namespace xercesc;
|
|
||||||
bool wasChanged;
|
|
||||||
XSModel* xsModel = m_GrammarPool->getXSModel(wasChanged);
|
|
||||||
|
|
||||||
// Find component xsd element declarations
|
|
||||||
std::cout << "Enumerating components..." << std::endl;
|
|
||||||
// <xs:element name="ComponentName">
|
|
||||||
auto topLevelElements = xsModel->getComponents(XSConstants::ELEMENT_DECLARATION);
|
|
||||||
for (unsigned int i = 0; i < topLevelElements->getLength(); ++i) {
|
|
||||||
auto element = static_cast<XSElementDeclaration*>(topLevelElements->item(i));
|
|
||||||
|
|
||||||
std::string nameSpace = XSTR(element->getNamespace());
|
|
||||||
if (nameSpace != "components") {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ComponentInfo compInfo;
|
|
||||||
|
|
||||||
// Name
|
|
||||||
compInfo.Name = (std::string)XSTR(element->getName());
|
|
||||||
// Annotation
|
|
||||||
auto componentAnnotation = element->getAnnotation();
|
|
||||||
if (componentAnnotation != nullptr) {
|
|
||||||
// Parse annotation XML
|
|
||||||
char* annotationString = XMLString::transcode(componentAnnotation->getAnnotationString());
|
|
||||||
MemBufInputSource annotationInput(reinterpret_cast<const XMLByte*>(annotationString), strlen(annotationString), "MemBuf: Annotation String");
|
|
||||||
XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager, m_GrammarPool);
|
|
||||||
parser.setErrorHandler(m_ErrorHandler);
|
|
||||||
parser.parse(annotationInput);
|
|
||||||
XMLString::release(&annotationString);
|
|
||||||
auto doc = parser.getDocument();
|
|
||||||
|
|
||||||
// Add allocation estimation(s)
|
|
||||||
auto allocationTags = doc->getElementsByTagName(XSTR("meta:allocation"));
|
|
||||||
for (int i = 0; i < allocationTags->getLength(); ++i) {
|
|
||||||
auto allocation = dynamic_cast<DOMElement*>(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(XSTR("xs:documentation"));
|
|
||||||
if (documentationTags->getLength() != 0) {
|
|
||||||
auto child = documentationTags->item(0)->getFirstChild();
|
|
||||||
if (child != nullptr) {
|
|
||||||
compInfo.Meta.Annotation = XSTR(child->getNodeValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO: Parse annotation string XML
|
|
||||||
// compInfo.Meta.Allocation = ...
|
|
||||||
} else {
|
|
||||||
std::cout << "Warning: Component is missing an annotation!" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// <xs:complexType>
|
|
||||||
auto typeDefinition = element->getTypeDefinition();
|
|
||||||
if (typeDefinition->getTypeCategory() != XSTypeDefinition::COMPLEX_TYPE) {
|
|
||||||
std::cerr << "Error: Type definition wasn't COMPLEX_TYPE! Skipping." << std::endl;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
auto complexTypeDefinition = dynamic_cast<XSComplexTypeDefinition*>(typeDefinition);
|
|
||||||
|
|
||||||
// <xs:all>
|
|
||||||
auto modelGroupParticle = complexTypeDefinition->getParticle();
|
|
||||||
if (modelGroupParticle->getTermType() != XSParticle::TERM_MODELGROUP) {
|
|
||||||
std::cerr << "Error: Model group particle wasn't TERM_MODELGROUP! Skipping." << std::endl;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
auto modelGroup = modelGroupParticle->getModelGroupTerm();
|
|
||||||
|
|
||||||
// <xs:element...
|
|
||||||
// <xs:attribute...
|
|
||||||
unsigned int fieldOffset = 0;
|
|
||||||
auto particles = modelGroup->getParticles();
|
|
||||||
for (unsigned int i = 0; i < particles->size(); ++i) {
|
|
||||||
auto particle = particles->elementAt(i);
|
|
||||||
if (particle->getTermType() != XSParticle::TERM_ELEMENT) {
|
|
||||||
std::cerr << "Error: Particle wasn't TERM_ELEMENT! Skipping." << std::endl;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
auto elementDeclaration = particle->getElementTerm();
|
|
||||||
|
|
||||||
std::string name = XSTR(elementDeclaration->getName());
|
|
||||||
std::string type = XSTR(elementDeclaration->getTypeDefinition()->getName());
|
|
||||||
|
|
||||||
size_t stride = 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 += getTypeStride(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
compInfo.Meta.Stride = fieldOffset;
|
|
||||||
m_ComponentInfo[compInfo.Name] = compInfo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EntityXMLFile::parseDefaults()
|
|
||||||
{
|
|
||||||
using namespace xercesc;
|
|
||||||
|
|
||||||
for (auto& ci : m_ComponentInfo) {
|
|
||||||
// Allocate memory for default values
|
|
||||||
ci.second.Defaults = std::shared_ptr<char>(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(XSTR(tagName.c_str()));
|
|
||||||
if (rootNodes->getLength() == 0) {
|
|
||||||
LOG_ERROR("Couldn't find defaults for component \"%s\"! Skipping.", componentName.c_str());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
auto componentElement = dynamic_cast<DOMElement*>(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(XSTR(fieldName.c_str()));
|
|
||||||
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<DOMElement*>(fieldNode);
|
|
||||||
|
|
||||||
std::string fieldType = ci.second.FieldTypes.at(fieldName);
|
|
||||||
unsigned int fieldOffset = ci.second.FieldOffsets.at(fieldName);
|
|
||||||
writeData(fieldElement, fieldType, ci.second.Defaults.get() + fieldOffset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EntityXMLFile::predictComponentAllocation()
|
|
||||||
{
|
|
||||||
using namespace xercesc;
|
|
||||||
|
|
||||||
auto root = m_DOMDocument->getDocumentElement();
|
|
||||||
|
|
||||||
// Count static instances of components present in entity hierarchy
|
|
||||||
auto components = m_DOMDocument->getElementsByTagNameNS(XSTR("components"), XSTR("*"));
|
|
||||||
for (int i = 0; i < components->getLength(); ++i) {
|
|
||||||
auto component = dynamic_cast<DOMElement*>(components->item(i));
|
|
||||||
|
|
||||||
std::string componentName = XSTR(component->getLocalName());
|
|
||||||
auto& compInfo = m_ComponentInfo.at(componentName);
|
|
||||||
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 << " Fields:" << std::endl;
|
|
||||||
|
|
||||||
// Calculate component size
|
|
||||||
std::size_t stride = 0;
|
|
||||||
// Add size of fields
|
|
||||||
for (auto& field : ci.FieldTypes) {
|
|
||||||
std::cout << " " << field.second << " " << field.first << " (" << getTypeStride(field.second) << " byte)" << std::endl;
|
|
||||||
stride += getTypeStride(field.second);
|
|
||||||
}
|
|
||||||
std::cout << " Stride: " << ci.Meta.Stride << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EntityXMLFile::parseEntityGraph(World* world, xercesc::DOMElement* element, EntityID parentEntity)
|
|
||||||
{
|
|
||||||
using namespace xercesc;
|
|
||||||
|
|
||||||
// Create entity
|
|
||||||
EntityID entity = world->CreateEntity(parentEntity);
|
|
||||||
LOG_DEBUG("Created entity %i, parent %i", entity, parentEntity);
|
|
||||||
|
|
||||||
// Add components
|
|
||||||
auto components = m_DOMDocument->evaluate(XSTR("Components/*"), element, nullptr, DOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE, nullptr);
|
|
||||||
for (int i = 0; i < components->getSnapshotLength(); i++) {
|
|
||||||
components->snapshotItem(i);
|
|
||||||
auto componentElement = dynamic_cast<DOMElement*>(components->getNodeValue());
|
|
||||||
std::string componentName = XSTR(componentElement->getLocalName());
|
|
||||||
auto& ci = m_ComponentInfo.at(componentName);
|
|
||||||
|
|
||||||
// Attach the component
|
|
||||||
auto c = world->AttachComponent(entity, componentName);
|
|
||||||
LOG_DEBUG("Attached %s component", componentName.c_str());
|
|
||||||
|
|
||||||
// Write field data
|
|
||||||
auto fields = componentElement->getChildNodes();
|
|
||||||
for (int j = 0; j < fields->getLength(); ++j) {
|
|
||||||
auto fieldNode = fields->item(j);
|
|
||||||
auto nodeType = fieldNode->getNodeType();
|
|
||||||
if (nodeType != DOMNode::ELEMENT_NODE) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
auto field = dynamic_cast<DOMElement*>(fields->item(j));
|
|
||||||
//const XMLCh* value = fields->item(j)->getTextContent();
|
|
||||||
std::string fieldName(XSTR(field->getLocalName()));
|
|
||||||
if (ci.FieldTypes.find(fieldName) == ci.FieldTypes.end()) {
|
|
||||||
std::cout << "Warning: Component \"" << componentName << "\" contains invalid field \"" << fieldName << "\". Skipping." << std::endl;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string fieldType = ci.FieldTypes.at(fieldName);
|
|
||||||
unsigned int fieldOffset = ci.FieldOffsets.at(fieldName);
|
|
||||||
std::string fieldValue(XSTR(field->getTextContent()));
|
|
||||||
LOG_DEBUG(" %s %s = %s", fieldType.c_str(), fieldName.c_str(), fieldValue.c_str());
|
|
||||||
writeData(field, fieldType, c.Data + fieldOffset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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<DOMElement*>(children->getNodeValue()), entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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<DOMElement*>(refs->getNodeValue());
|
|
||||||
auto attribute = entityRefElement->getAttribute(XSTR("file"));
|
|
||||||
if (attribute == nullptr) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string file((const char*)XSTR(attribute));
|
|
||||||
boost::filesystem::path absolutePath = boost::filesystem::path(m_EntityFile).parent_path() / file;
|
|
||||||
ResourceManager::Load<EntityXMLFile>(absolutePath.string())->PopulateWorld(world);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t EntityXMLFile::getTypeStride(std::string typeName)
|
|
||||||
{
|
|
||||||
std::map<std::string, size_t> 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
float EntityXMLFile::getFloatAttribute(const xercesc::DOMElement* element, const char* attribute) const
|
|
||||||
{
|
|
||||||
using namespace xercesc;
|
|
||||||
XSValue::Status status;
|
|
||||||
XSValue* val = XSValue::getActualValue(element->getAttribute(XSTR(attribute)), xercesc::XSValue::DataType::dt_double, status);
|
|
||||||
if (val == nullptr) {
|
|
||||||
LOG_ERROR("Element \"%s\" doesn't have an \"%s\" attribute!", XSTR(element->getTagName()), attribute);
|
|
||||||
return 0.f;
|
|
||||||
} else {
|
|
||||||
return static_cast<float>(val->fData.fValue.f_double);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EntityXMLFile::writeData(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<char*>(&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<char*>(&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<char*>(&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<char*>(&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<char*>(&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<char*>(&val->fData.fValue.f_bool), getTypeStride(typeName));
|
|
||||||
} else {
|
|
||||||
XSValue::DataType dataType = XSValue::getDataType(XSTR(typeName.c_str()));
|
|
||||||
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<char*>(&standardString), getTypeStride(typeName));
|
|
||||||
} else {
|
|
||||||
//XSValue::Status status;
|
|
||||||
//XSValue* val = XSValue::getActualValue(element->getTextContent(), dataType, status);
|
|
||||||
//memcpy(outData, reinterpret_cast<char*>(&val->fData.fValue), getTypeStride(typeName));
|
|
||||||
LOG_WARNING("Unknown native data type: %s", typeName.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+1
-2
@@ -8,7 +8,6 @@ Game::Game(int argc, char* argv[])
|
|||||||
ResourceManager::RegisterType<ConfigFile>("ConfigFile");
|
ResourceManager::RegisterType<ConfigFile>("ConfigFile");
|
||||||
ResourceManager::RegisterType<Model>("Model");
|
ResourceManager::RegisterType<Model>("Model");
|
||||||
ResourceManager::RegisterType<Texture>("Texture");
|
ResourceManager::RegisterType<Texture>("Texture");
|
||||||
ResourceManager::RegisterType<EntityXMLFile>("EntityXMLFile");
|
|
||||||
ResourceManager::RegisterType<ShaderProgram>("ShaderProgram");
|
ResourceManager::RegisterType<ShaderProgram>("ShaderProgram");
|
||||||
ResourceManager::RegisterType<EntityFile>("EntityFile");
|
ResourceManager::RegisterType<EntityFile>("EntityFile");
|
||||||
|
|
||||||
@@ -50,7 +49,7 @@ Game::Game(int argc, char* argv[])
|
|||||||
std::string mapToLoad = m_Config->Get<std::string>("Debug.LoadMap", "");
|
std::string mapToLoad = m_Config->Get<std::string>("Debug.LoadMap", "");
|
||||||
if (!mapToLoad.empty()) {
|
if (!mapToLoad.empty()) {
|
||||||
auto file = ResourceManager::Load<EntityFile>(mapToLoad);
|
auto file = ResourceManager::Load<EntityFile>(mapToLoad);
|
||||||
EntityFilePreprocessor fpp(mapToLoad);
|
EntityFilePreprocessor fpp(file);
|
||||||
fpp.RegisterComponents(m_World);
|
fpp.RegisterComponents(m_World);
|
||||||
EntityFileParser fp(file);
|
EntityFileParser fp(file);
|
||||||
fp.MergeEntities(m_World);
|
fp.MergeEntities(m_World);
|
||||||
|
|||||||
Reference in New Issue
Block a user