From 03bbe25a1e119c21cd0c938c2b7498477caca5f3 Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Tue, 8 Dec 2015 17:42:59 +0100 Subject: [PATCH 01/17] Fixed FindXerces.cmake --- cmake/FindXerces.cmake | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/cmake/FindXerces.cmake b/cmake/FindXerces.cmake index 8ea0fb1d..651453bd 100644 --- a/cmake/FindXerces.cmake +++ b/cmake/FindXerces.cmake @@ -1,13 +1,13 @@ -# XERCES_FOUND -# XERCES_INCLUDE_DIRS -# XERCES_LIBRARIES +# Xerces_FOUND +# Xerces_INCLUDE_DIRS +# Xerces_LIBRARIES -find_path(XERCES_INCLUDE_DIR xercesc/dom/dom.hpp +find_path(Xerces_INCLUDE_DIR xercesc/dom/dom.hpp /usr/local/include /usr/include ) -find_library(XERCES_LIBRARY +find_library(Xerces_LIBRARY NAMES xerces-c_3 xerces-c_3D @@ -16,8 +16,8 @@ find_library(XERCES_LIBRARY /usr/lib ) -set(XERCES_INCLUDE_DIRS ${XERCES_INCLUDE_DIR}) -set(XERCES_LIBRARIES ${XERCES_LIBRARY}) +set(Xerces_INCLUDE_DIRS ${Xerces_INCLUDE_DIR}) +set(Xerces_LIBRARIES ${Xerces_LIBRARY}) -find_package_handle_standard_args(Xerces DEFAULT_MSG XERCES_LIBRARY XERCES_INCLUDE_DIR) -mark_as_advanced(Xerces_FOUND XERCES_INCLUDE_DIR XERCES_LIBRARY) \ No newline at end of file +find_package_handle_standard_args(Xerces DEFAULT_MSG Xerces_LIBRARY Xerces_INCLUDE_DIR) +mark_as_advanced(Xerces_FOUND Xerces_INCLUDE_DIR Xerces_LIBRARY) From d7de4fc6940a9d371bcea95da59a82c50d263934 Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Tue, 8 Dec 2015 18:07:32 +0100 Subject: [PATCH 02/17] Component definitions now loaded from schema. No default values yet. --- include/Engine/Core/ComponentWrapper.h | 4 +- include/Engine/Core/Entity.h | 6 + include/Engine/Core/EntityFile.h | 12 - include/Engine/Core/EntityWrapper.h | 15 -- include/Engine/Core/EntityXMLFile.h | 139 ++++++++++ include/Engine/Core/World.h | 3 +- include/Game/HardcodedTestWorld.h | 23 +- src/Engine/Core/EntityXMLFile.cpp | 342 +++++++++++++++++++++++++ src/Engine/Core/World.cpp | 6 +- 9 files changed, 504 insertions(+), 46 deletions(-) create mode 100644 include/Engine/Core/Entity.h delete mode 100644 include/Engine/Core/EntityFile.h delete mode 100644 include/Engine/Core/EntityWrapper.h create mode 100644 include/Engine/Core/EntityXMLFile.h create mode 100644 src/Engine/Core/EntityXMLFile.cpp diff --git a/include/Engine/Core/ComponentWrapper.h b/include/Engine/Core/ComponentWrapper.h index 95a31240..56ae943f 100644 --- a/include/Engine/Core/ComponentWrapper.h +++ b/include/Engine/Core/ComponentWrapper.h @@ -2,7 +2,7 @@ #define ComponentWrapper_h__ #include "../Common.h" -#include "EntityWrapper.h" +#include "Entity.h" #include "ComponentInfo.h" #include "Util/Any.h" @@ -11,7 +11,7 @@ struct ComponentWrapper ComponentWrapper(const ComponentInfo& componentInfo, char* data) : Info(componentInfo) , EntityID(*reinterpret_cast<::EntityID*>(data)) - , Data(data + sizeof(EntityID)) + , Data(data + sizeof(::EntityID)) { } const ComponentInfo& Info; diff --git a/include/Engine/Core/Entity.h b/include/Engine/Core/Entity.h new file mode 100644 index 00000000..c6a475e3 --- /dev/null +++ b/include/Engine/Core/Entity.h @@ -0,0 +1,6 @@ +#ifndef Entity_h__ +#define Entity_h__ + +typedef unsigned int EntityID; + +#endif \ No newline at end of file diff --git a/include/Engine/Core/EntityFile.h b/include/Engine/Core/EntityFile.h deleted file mode 100644 index 7fa423d6..00000000 --- a/include/Engine/Core/EntityFile.h +++ /dev/null @@ -1,12 +0,0 @@ -#include "ResourceManager.h" - -class EntityFile : public Resource -{ - friend class ResourceManager; - -private: - EntityFile(std::string path); - -public: - -}; \ No newline at end of file diff --git a/include/Engine/Core/EntityWrapper.h b/include/Engine/Core/EntityWrapper.h deleted file mode 100644 index d5e723ca..00000000 --- a/include/Engine/Core/EntityWrapper.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef Entity_h__ -#define Entity_h__ - -typedef unsigned int EntityID; - -struct EntityWrapper -{ - EntityWrapper(EntityID entityID) - : ID(entityID) - { } - - EntityID ID; -}; - -#endif \ No newline at end of file diff --git a/include/Engine/Core/EntityXMLFile.h b/include/Engine/Core/EntityXMLFile.h new file mode 100644 index 00000000..5217e555 --- /dev/null +++ b/include/Engine/Core/EntityXMLFile.h @@ -0,0 +1,139 @@ +#ifndef EntityXMLFile_h__ +#define EntityXMLFile_h__ + +#include + +#include "../Common.h" +#include "../GLM.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 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(); + std::size_t getTypeStride(std::string typeName); +}; + +#endif \ No newline at end of file diff --git a/include/Engine/Core/World.h b/include/Engine/Core/World.h index 20bbe288..ab6f43fa 100644 --- a/include/Engine/Core/World.h +++ b/include/Engine/Core/World.h @@ -2,7 +2,7 @@ #define World_h__ #include "../Common.h" -#include "EntityWrapper.h" +#include "Entity.h" #include "ObjectPool.h" #include "ComponentPool.h" @@ -12,6 +12,7 @@ public: World() = default; ~World(); + // Create empty entity EntityID CreateEntity(EntityID parent = 0); // Register a component type and allocate space for it diff --git a/include/Game/HardcodedTestWorld.h b/include/Game/HardcodedTestWorld.h index 1176402d..bf3f2f07 100644 --- a/include/Game/HardcodedTestWorld.h +++ b/include/Game/HardcodedTestWorld.h @@ -4,6 +4,7 @@ #include "GLM.h" #include "Core/World.h" #include "Core/Util/Any.h" +#include "Core/EntityXMLFile.h" class HardcodedTestWorld : public World { @@ -30,11 +31,11 @@ private: f.AddProperty("Name", std::string("Unnamed")); RegisterComponent(f); - f = ComponentWrapperFactory("Transform"); - f.AddProperty("Position", glm::vec3(0.f, 0.f, 0.f)); - f.AddProperty("Orientation", glm::quat()); - f.AddProperty("Scale", glm::vec3(1.f, 1.f, 1.f)); - RegisterComponent(f); + //f = ComponentWrapperFactory("Transform"); + //f.AddProperty("Position", glm::vec3(0.f, 0.f, 0.f)); + //f.AddProperty("Orientation", glm::quat()); + //f.AddProperty("Scale", glm::vec3(1.f, 1.f, 1.f)); + //RegisterComponent(f); f = ComponentWrapperFactory("Model"); f.AddProperty("Resource", std::string()); @@ -45,16 +46,14 @@ private: void createTestEntities() { + ResourceManager::RegisterType("EntityXMLFile"); + ResourceManager::Load("Schema/Entities/Test.xml")->PopulateWorld(this); + World& world = *this; // Create an entity EntityID e = world.CreateEntity(); - // Attach a Debug component - ComponentWrapper debug = world.AttachComponent(e, "Debug"); - // Set the Name field of the Debug component using subscript operator - debug["Name"] = "Carlito"; - // Attach a Transform component world.AttachComponent(e, "Transform"); // Fetch the component based on EntityID and component type @@ -74,10 +73,6 @@ private: std::cout << "Position: " << pos.x << " " << pos.y << " " << pos.z << std::endl; glm::vec3 scale = transform["Scale"]; std::cout << "Scale: " << scale.x << " " << scale.y << " " << scale.z << std::endl; - - // Fetch the Debug component also present in this entity - ComponentWrapper debug = world.GetComponent(transform.EntityID, "Debug"); - std::cout << "Name: " << (std::string)debug["Name"] << std::endl; } } }; \ No newline at end of file diff --git a/src/Engine/Core/EntityXMLFile.cpp b/src/Engine/Core/EntityXMLFile.cpp new file mode 100644 index 00000000..450a8c13 --- /dev/null +++ b/src/Engine/Core/EntityXMLFile.cpp @@ -0,0 +1,342 @@ +#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 + //parseEntityGraph(); +} + + +void EntityXMLFile::preprocess(std::string inPath, std::string outPath) +{ + using namespace xercesc; + + static const XMLCh gLS[] = { 'L', 'S', '\0' }; + DOMImplementationLS* di = static_cast(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(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; + // + auto topLevelElements = xsModel->getComponents(XSConstants::ELEMENT_DECLARATION); + for (unsigned int i = 0; i < topLevelElements->getLength(); ++i) { + auto element = static_cast(topLevelElements->item(i)); + + std::string nameSpace(XSTR(element->getNamespace())); + if (nameSpace != "components") { + continue; + } + + ComponentInfo compInfo; + + // Name + compInfo.Name = XSTR(element->getName()); + // 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, 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(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; + } + + // + 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(typeDefinition); + + // + 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(); + + // 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() +{ + +} + +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(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; + + // TODO: ALLOCATE HERE + /*ComponentPool cs; + cs.ComponentName = ci.Name; + cs.Stride = stride; + cs.Info = ci; + cs.Data = new char[stride*ci.Meta.Allocation]; + m_ComponentStore[cs.ComponentName] = cs;*/ + } +} + +void EntityXMLFile::parseEntityGraph() +{ + //using namespace xercesc; + + //auto root = m_DOMDocument->getDocumentElement(); + + //auto components = m_DOMDocument->getElementsByTagNameNS(XSTR("components"), XSTR("*")); + //for (int i = 0; i < components->getLength(); ++i) { + // auto component = dynamic_cast(components->item(i)); + + // std::string componentName = XSTR(component->getLocalName()); + // auto& compStore = m_ComponentStore.at(componentName); + // auto& compInfo = compStore.Info; + + // char* data = &compStore.Data[compStore.Size*compStore.Stride]; + // compStore.Size += 1; + + // auto fields = component->getChildNodes(); + // for (int j = 0; j < fields->getLength(); ++j) { + // auto field = fields->item(j); + // auto nodeType = field->getNodeType(); + // if (nodeType != DOMNode::ELEMENT_NODE) { + // continue; + // } + // //auto field = dynamic_cast(fields->item(j)); + // //const XMLCh* value = fields->item(j)->getTextContent(); + // std::string fieldName = XSTR(field->getLocalName()); + // if (compInfo.FieldTypes.find(fieldName) == compInfo.FieldTypes.end()) { + // std::cout << "Warning: Component \"" << componentName << "\" contains invalid field \"" << fieldName << "\". Skipping." << std::endl; + // continue; + // } + + // std::string fieldType = compInfo.FieldTypes.at(fieldName); + // unsigned int fieldOffset = compInfo.FieldOffsets.at(fieldName); + + // XSValue::DataType dataType = XSValue::getDataType(XSTR(fieldType.c_str())); + // if (dataType == XSValue::DataType::dt_MAXCOUNT) { + // // TODO: + // continue; + // } + // if (dataType == XSValue::DataType::dt_string) { + // char* str = XMLString::transcode(field->getTextContent()); + // std::string standardString(str); + // XMLString::release(&str); + // memcpy(&data[fieldOffset], reinterpret_cast(&standardString), getTypeStride(fieldType)); + // } else { + // XSValue::Status status; + // XSValue* val = XSValue::getActualValue(field->getTextContent(), dataType, status); + // memcpy(&data[fieldOffset], reinterpret_cast(&val->fData.fValue), getTypeStride(fieldType)); + // } + // } + //} + + //auto entities = m_DOMDocument->getElementsByTagName(XSTR("Entity")); + //for (int i = 0; i < entities->getLength(); ++i) { + // auto entity = dynamic_cast(entities->item(i)); + + + // //entity->setIdAttribute() + + // std::cout << "ENTITY " << i + 1 << std::endl; + //} +} + +std::size_t EntityXMLFile::getTypeStride(std::string typeName) +{ + std::map typeStrides{ + { "int", sizeof(int) }, + { "double", sizeof(double) }, + { "string", sizeof(std::string) }, + { "Vector", sizeof(glm::vec3) }, + { "Quaternion", sizeof(glm::quat) }, + }; + + auto it = typeStrides.find(typeName); + return (it != typeStrides.end()) ? it->second : 0; +} diff --git a/src/Engine/Core/World.cpp b/src/Engine/Core/World.cpp index 26d3f1e4..7f9fd43a 100644 --- a/src/Engine/Core/World.cpp +++ b/src/Engine/Core/World.cpp @@ -29,8 +29,10 @@ ComponentWrapper World::AttachComponent(EntityID entity, std::string componentTy // Allocate space for the component ComponentWrapper c = pool->Allocate(entity); - // Write default values - memcpy(c.Data, ci.Defaults.get(), ci.Meta.Stride); + // TODO: Write default values + if (ci.Defaults != nullptr) { + //memcpy(c.Data, ci.Defaults.get(), ci.Meta.Stride); + } return c; } From 9fbea18330772034da2a8f93b16dd91bb4771e08 Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Tue, 8 Dec 2015 18:20:42 +0100 Subject: [PATCH 03/17] fixup! Merge remote-tracking branch 'origin/master' into ecs --- include/Engine/Rendering/RenderQueue.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/Engine/Rendering/RenderQueue.h b/include/Engine/Rendering/RenderQueue.h index 982b1813..2942c743 100644 --- a/include/Engine/Rendering/RenderQueue.h +++ b/include/Engine/Rendering/RenderQueue.h @@ -7,7 +7,7 @@ #include "../Common.h" #include "../GLM.h" #include "../Core/Util/Rectangle.h" -#include "../Core/EntityWrapper.h" +#include "../Core/Entity.h" class Model; class Skeleton; From 1e1ce4e127dcd9460d52287a44ea27044da339a0 Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Tue, 8 Dec 2015 18:21:24 +0100 Subject: [PATCH 04/17] Added Model component to schema --- include/Game/HardcodedTestWorld.h | 60 ++++----------------------- resources/Schema/Components.xsd | 1 + resources/Schema/Components/Model.xml | 5 +++ resources/Schema/Components/Model.xsd | 24 +++++++++++ resources/Schema/Types.xsd | 4 ++ resources/Schema/Types/Color.xsd | 10 +++++ src/Engine/Core/EntityXMLFile.cpp | 2 + 7 files changed, 55 insertions(+), 51 deletions(-) create mode 100644 resources/Schema/Components/Model.xml create mode 100644 resources/Schema/Components/Model.xsd create mode 100644 resources/Schema/Types/Color.xsd diff --git a/include/Game/HardcodedTestWorld.h b/include/Game/HardcodedTestWorld.h index 30cf8535..dee03f18 100644 --- a/include/Game/HardcodedTestWorld.h +++ b/include/Game/HardcodedTestWorld.h @@ -21,7 +21,6 @@ private: { ComponentWrapperFactory f; - f = ComponentWrapperFactory("Test"); f.AddProperty("TestInteger", 1337); f.AddProperty("TestFloat", 13.37f); @@ -31,18 +30,6 @@ private: f = ComponentWrapperFactory("Debug"); f.AddProperty("Name", std::string("Unnamed")); RegisterComponent(f); - - //f = ComponentWrapperFactory("Transform"); - //f.AddProperty("Position", glm::vec3(0.f, 0.f, 0.f)); - //f.AddProperty("Orientation", glm::quat()); - //f.AddProperty("Scale", glm::vec3(1.f, 1.f, 1.f)); - //RegisterComponent(f); - - f = ComponentWrapperFactory("Model"); - f.AddProperty("Resource", std::string()); - f.AddProperty("Color", glm::vec4(1.f, 1.f, 1.f, 1.f)); - f.AddProperty("Visible", true); - RegisterComponent(f); } void createTestEntities() @@ -50,56 +37,27 @@ private: ResourceManager::RegisterType("EntityXMLFile"); ResourceManager::Load("Schema/Entities/Test.xml")->PopulateWorld(this); - World& world = *this; - - // Create an entity - EntityID e = world.CreateEntity(); - - // Attach a Transform component - world.AttachComponent(e, "Transform"); - // Fetch the component based on EntityID and component type - ComponentWrapper transform = world.GetComponent(e, "Transform"); - // Set the fields of the Transform component - transform["Position"] = glm::vec3(0.f, 0.f, 0.f); - transform["Scale"] = glm::vec3(1.f, 1.f, 1.f); - - // Move on the X axis by fetching field as reference - ((glm::vec3&)transform["Position"]).x += 10.f; - // Shrink by a factor of 100 - ((glm::vec3&)transform["Scale"]) /= 100.f; - - // Loop through all Transform components and print them - for (auto& transform : world.GetComponents("Transform")) { - glm::vec3 pos = transform["Position"]; - std::cout << "Position: " << pos.x << " " << pos.y << " " << pos.z << std::endl; - glm::vec3 scale = transform["Scale"]; - std::cout << "Scale: " << scale.x << " " << scale.y << " " << scale.z << std::endl; - } - //Create some test widgets { - EntityID entityScaleWidget = world.CreateEntity(); - ComponentWrapper transform = world.AttachComponent(entityScaleWidget, "Transform"); + EntityID entityScaleWidget = CreateEntity(); + ComponentWrapper transform = AttachComponent(entityScaleWidget, "Transform"); transform["Position"] = glm::vec3(-1.5f, 0.f, 0.f); - ComponentWrapper model = world.AttachComponent(entityScaleWidget, "Model"); + ComponentWrapper model = AttachComponent(entityScaleWidget, "Model"); model["Resource"] = "Models/ScaleWidget.obj"; } { - EntityID entityRotationWidget = world.CreateEntity(); - ComponentWrapper transform = world.AttachComponent(entityRotationWidget, "Transform"); + EntityID entityRotationWidget = CreateEntity(); + ComponentWrapper transform = AttachComponent(entityRotationWidget, "Transform"); transform["Position"] = glm::vec3(1.5f, 0.f, 0.f); - ComponentWrapper model = world.AttachComponent(entityRotationWidget, "Model"); + ComponentWrapper model = AttachComponent(entityRotationWidget, "Model"); model["Resource"] = "Models/RotationWidget.obj"; } { - EntityID entityDummyScene = world.CreateEntity(); - ComponentWrapper transform = world.AttachComponent(entityDummyScene, "Transform"); + EntityID entityDummyScene = CreateEntity(); + ComponentWrapper transform = AttachComponent(entityDummyScene, "Transform"); transform["Position"] = glm::vec3(0, 0.f, 0.f); - ComponentWrapper model = world.AttachComponent(entityDummyScene, "Model"); + ComponentWrapper model = AttachComponent(entityDummyScene, "Model"); model["Resource"] = "Models/DummyScene.obj"; } - - - } }; \ No newline at end of file diff --git a/resources/Schema/Components.xsd b/resources/Schema/Components.xsd index 41564706..54896b69 100644 --- a/resources/Schema/Components.xsd +++ b/resources/Schema/Components.xsd @@ -2,5 +2,6 @@ + \ No newline at end of file diff --git a/resources/Schema/Components/Model.xml b/resources/Schema/Components/Model.xml new file mode 100644 index 00000000..bd20147f --- /dev/null +++ b/resources/Schema/Components/Model.xml @@ -0,0 +1,5 @@ + + + + true + \ No newline at end of file diff --git a/resources/Schema/Components/Model.xsd b/resources/Schema/Components/Model.xsd new file mode 100644 index 00000000..fb0774f8 --- /dev/null +++ b/resources/Schema/Components/Model.xsd @@ -0,0 +1,24 @@ + + + + + + + + A visible model loaded from disk + + + + + Model file + + + Color tint + + + Wether the model is visible or not + + + + + \ No newline at end of file diff --git a/resources/Schema/Types.xsd b/resources/Schema/Types.xsd index 939c88da..cd464201 100644 --- a/resources/Schema/Types.xsd +++ b/resources/Schema/Types.xsd @@ -3,6 +3,10 @@ + + + + diff --git a/resources/Schema/Types/Color.xsd b/resources/Schema/Types/Color.xsd new file mode 100644 index 00000000..4fb9572e --- /dev/null +++ b/resources/Schema/Types/Color.xsd @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/Engine/Core/EntityXMLFile.cpp b/src/Engine/Core/EntityXMLFile.cpp index 450a8c13..9d51cc7f 100644 --- a/src/Engine/Core/EntityXMLFile.cpp +++ b/src/Engine/Core/EntityXMLFile.cpp @@ -330,11 +330,13 @@ void EntityXMLFile::parseEntityGraph() std::size_t EntityXMLFile::getTypeStride(std::string typeName) { std::map typeStrides{ + { "bool", sizeof(bool) }, { "int", sizeof(int) }, { "double", sizeof(double) }, { "string", sizeof(std::string) }, { "Vector", sizeof(glm::vec3) }, { "Quaternion", sizeof(glm::quat) }, + { "Color", sizeof(glm::vec4) } }; auto it = typeStrides.find(typeName); From 0dbe0fe48ef4fe6ca357e6a694327329e8e8a4ed Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Tue, 8 Dec 2015 21:38:52 +0100 Subject: [PATCH 05/17] Component definitions and default values loading from schema --- include/Game/HardcodedTestWorld.h | 22 +--- resources/Schema/Components/Test.xml | 2 +- resources/Schema/Components/Transform.xml | 6 +- src/Engine/Core/EntityXMLFile.cpp | 121 ++++++++++++++++++++++ src/Engine/Core/World.cpp | 6 +- 5 files changed, 130 insertions(+), 27 deletions(-) diff --git a/include/Game/HardcodedTestWorld.h b/include/Game/HardcodedTestWorld.h index dee03f18..ec7e3267 100644 --- a/include/Game/HardcodedTestWorld.h +++ b/include/Game/HardcodedTestWorld.h @@ -12,31 +12,15 @@ public: HardcodedTestWorld() : World() { - registerTestComponents(); + ResourceManager::RegisterType("EntityXMLFile"); + ResourceManager::Load("Schema/Entities/Test.xml")->PopulateWorld(this); + createTestEntities(); } private: - void registerTestComponents() - { - ComponentWrapperFactory f; - - f = ComponentWrapperFactory("Test"); - f.AddProperty("TestInteger", 1337); - f.AddProperty("TestFloat", 13.37f); - f.AddProperty("TestString", std::string("Carlito")); - RegisterComponent(f); - - f = ComponentWrapperFactory("Debug"); - f.AddProperty("Name", std::string("Unnamed")); - RegisterComponent(f); - } - void createTestEntities() { - ResourceManager::RegisterType("EntityXMLFile"); - ResourceManager::Load("Schema/Entities/Test.xml")->PopulateWorld(this); - //Create some test widgets { EntityID entityScaleWidget = CreateEntity(); diff --git a/resources/Schema/Components/Test.xml b/resources/Schema/Components/Test.xml index ccf459fe..9e49d37a 100644 --- a/resources/Schema/Components/Test.xml +++ b/resources/Schema/Components/Test.xml @@ -2,5 +2,5 @@ 1 1.333 - + \ No newline at end of file diff --git a/resources/Schema/Components/Transform.xml b/resources/Schema/Components/Transform.xml index e093c41a..276b89e7 100644 --- a/resources/Schema/Components/Transform.xml +++ b/resources/Schema/Components/Transform.xml @@ -1,5 +1,5 @@ - + - + - \ No newline at end of file + \ No newline at end of file diff --git a/src/Engine/Core/EntityXMLFile.cpp b/src/Engine/Core/EntityXMLFile.cpp index 9d51cc7f..7881ad46 100644 --- a/src/Engine/Core/EntityXMLFile.cpp +++ b/src/Engine/Core/EntityXMLFile.cpp @@ -218,7 +218,128 @@ void EntityXMLFile::parseComponentInfo() void EntityXMLFile::parseDefaults() { + using namespace xercesc; + for (auto& ci : m_ComponentInfo) { + // Allocate memory for default values + ci.second.Defaults = std::shared_ptr(new char[ci.second.Meta.Stride]); + memset(ci.second.Defaults.get(), 0, ci.second.Meta.Stride); + + XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager); + parser.setErrorHandler(m_ErrorHandler); + + std::string componentName = ci.first; + LOG_DEBUG("Parsing defaults for component %s", componentName.c_str()); + boost::filesystem::path defaultsFile = "Schema/Components/" + componentName + ".xml"; + + parser.parse(defaultsFile.string().c_str()); + auto doc = parser.getDocument(); + if (doc == nullptr) { + LOG_ERROR("%s not found! Skipping.", defaultsFile.string().c_str()); + continue; + } + + // Find the node in the components namespace matching the component name + std::string tagName = "c:" + componentName; + auto rootNodes = doc->getElementsByTagName(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(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(fieldNode); + + std::string fieldType = ci.second.FieldTypes.at(fieldName); + unsigned int fieldOffset = ci.second.FieldOffsets.at(fieldName); + + XSValue::DataType dataType = XSValue::getDataType(XSTR(fieldType.c_str())); + if (dataType == XSValue::DataType::dt_MAXCOUNT) { + if (fieldType == "Vector") { + glm::vec3 vec; + + XSValue::Status status; + XSValue* val; + + val = XSValue::getActualValue(fieldElement->getAttribute(XSTR("X")), XSValue::DataType::dt_float, status); + vec.x = val->fData.fValue.f_float; + val = XSValue::getActualValue(fieldElement->getAttribute(XSTR("Y")), XSValue::DataType::dt_float, status); + vec.y = val->fData.fValue.f_float; + val = XSValue::getActualValue(fieldElement->getAttribute(XSTR("Z")), XSValue::DataType::dt_float, status); + vec.z = val->fData.fValue.f_float; + + memcpy(ci.second.Defaults.get() + fieldOffset, reinterpret_cast(&vec), getTypeStride(fieldType)); + } else if (fieldType == "Color") { + glm::vec4 vec; + + XSValue::Status status; + XSValue* val; + + val = XSValue::getActualValue(fieldElement->getAttribute(XSTR("R")), XSValue::DataType::dt_float, status); + vec.r = val->fData.fValue.f_float; + val = XSValue::getActualValue(fieldElement->getAttribute(XSTR("G")), XSValue::DataType::dt_float, status); + vec.g = val->fData.fValue.f_float; + val = XSValue::getActualValue(fieldElement->getAttribute(XSTR("B")), XSValue::DataType::dt_float, status); + vec.b = val->fData.fValue.f_float; + val = XSValue::getActualValue(fieldElement->getAttribute(XSTR("A")), XSValue::DataType::dt_float, status); + vec.a = val->fData.fValue.f_float; + + memcpy(ci.second.Defaults.get() + fieldOffset, reinterpret_cast(&vec), getTypeStride(fieldType)); + } else if (fieldType == "Quaternion") { + glm::quat q; + + XSValue::Status status; + XSValue* val; + + val = XSValue::getActualValue(fieldElement->getAttribute(XSTR("X")), XSValue::DataType::dt_float, status); + if (val == nullptr) { + LOG_ERROR("Default field \"%s\" for component \"%s\" missing \"%s\" attribute!", fieldName.c_str(), componentName.c_str(), "X"); + } else { + q.x = val->fData.fValue.f_float; + } + val = XSValue::getActualValue(fieldElement->getAttribute(XSTR("Y")), XSValue::DataType::dt_float, status); + if (val == nullptr) { + LOG_ERROR("Default field \"%s\" for component \"%s\" missing \"%s\" attribute!", fieldName.c_str(), componentName.c_str(), "Y"); + } else { + q.y = val->fData.fValue.f_float; + } + val = XSValue::getActualValue(fieldElement->getAttribute(XSTR("Z")), XSValue::DataType::dt_float, status); + if (val == nullptr) { + LOG_ERROR("Default field \"%s\" for component \"%s\" missing \"%s\" attribute!", fieldName.c_str(), componentName.c_str(), "Z"); + } else { + q.z = val->fData.fValue.f_float; + } + val = XSValue::getActualValue(fieldElement->getAttribute(XSTR("W")), XSValue::DataType::dt_float, status); + if (val == nullptr) { + LOG_ERROR("Default field \"%s\" for component \"%s\" missing \"%s\" attribute!", fieldName.c_str(), componentName.c_str(), "W"); + } else { + q.w = val->fData.fValue.f_float; + } + + memcpy(ci.second.Defaults.get() + fieldOffset, reinterpret_cast(&q), getTypeStride(fieldType)); + } + } else if (dataType == XSValue::DataType::dt_string) { + char* str = XMLString::transcode(fieldElement->getTextContent()); + std::string standardString(str); + new (ci.second.Defaults.get() + fieldOffset) std::string(str); + XMLString::release(&str); + //memcpy(ci.second.Defaults.get() + fieldOffset, &standardString, getTypeStride(fieldType)); + } else { + XSValue::Status status; + XSValue* val = XSValue::getActualValue(fieldElement->getTextContent(), dataType, status); + memcpy(ci.second.Defaults.get() + fieldOffset, reinterpret_cast(&val->fData.fValue), getTypeStride(fieldType)); + } + } + } } void EntityXMLFile::predictComponentAllocation() diff --git a/src/Engine/Core/World.cpp b/src/Engine/Core/World.cpp index 7f9fd43a..26d3f1e4 100644 --- a/src/Engine/Core/World.cpp +++ b/src/Engine/Core/World.cpp @@ -29,10 +29,8 @@ ComponentWrapper World::AttachComponent(EntityID entity, std::string componentTy // Allocate space for the component ComponentWrapper c = pool->Allocate(entity); - // TODO: Write default values - if (ci.Defaults != nullptr) { - //memcpy(c.Data, ci.Defaults.get(), ci.Meta.Stride); - } + // Write default values + memcpy(c.Data, ci.Defaults.get(), ci.Meta.Stride); return c; } From d597c7e60e47e96acf38a1e392f10ba9fab6036e Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Tue, 8 Dec 2015 22:51:35 +0100 Subject: [PATCH 06/17] Cleaned up custom type conversion code --- include/Engine/Core/EntityXMLFile.h | 1 + src/Engine/Core/EntityXMLFile.cpp | 89 +++++++++-------------------- 2 files changed, 27 insertions(+), 63 deletions(-) diff --git a/include/Engine/Core/EntityXMLFile.h b/include/Engine/Core/EntityXMLFile.h index 5217e555..d7c34e3a 100644 --- a/include/Engine/Core/EntityXMLFile.h +++ b/include/Engine/Core/EntityXMLFile.h @@ -134,6 +134,7 @@ private: void predictComponentAllocation(); void parseEntityGraph(); std::size_t getTypeStride(std::string typeName); + float getFloatAttribute(const xercesc::DOMElement* element, const char* attribute) const; }; #endif \ No newline at end of file diff --git a/src/Engine/Core/EntityXMLFile.cpp b/src/Engine/Core/EntityXMLFile.cpp index 7881ad46..f64faeb6 100644 --- a/src/Engine/Core/EntityXMLFile.cpp +++ b/src/Engine/Core/EntityXMLFile.cpp @@ -266,73 +266,31 @@ void EntityXMLFile::parseDefaults() if (dataType == XSValue::DataType::dt_MAXCOUNT) { if (fieldType == "Vector") { glm::vec3 vec; - - XSValue::Status status; - XSValue* val; - - val = XSValue::getActualValue(fieldElement->getAttribute(XSTR("X")), XSValue::DataType::dt_float, status); - vec.x = val->fData.fValue.f_float; - val = XSValue::getActualValue(fieldElement->getAttribute(XSTR("Y")), XSValue::DataType::dt_float, status); - vec.y = val->fData.fValue.f_float; - val = XSValue::getActualValue(fieldElement->getAttribute(XSTR("Z")), XSValue::DataType::dt_float, status); - vec.z = val->fData.fValue.f_float; - + vec.x = getFloatAttribute(fieldElement, "X"); + vec.y = getFloatAttribute(fieldElement, "Y"); + vec.z = getFloatAttribute(fieldElement, "Z"); memcpy(ci.second.Defaults.get() + fieldOffset, reinterpret_cast(&vec), getTypeStride(fieldType)); } else if (fieldType == "Color") { glm::vec4 vec; - - XSValue::Status status; - XSValue* val; - - val = XSValue::getActualValue(fieldElement->getAttribute(XSTR("R")), XSValue::DataType::dt_float, status); - vec.r = val->fData.fValue.f_float; - val = XSValue::getActualValue(fieldElement->getAttribute(XSTR("G")), XSValue::DataType::dt_float, status); - vec.g = val->fData.fValue.f_float; - val = XSValue::getActualValue(fieldElement->getAttribute(XSTR("B")), XSValue::DataType::dt_float, status); - vec.b = val->fData.fValue.f_float; - val = XSValue::getActualValue(fieldElement->getAttribute(XSTR("A")), XSValue::DataType::dt_float, status); - vec.a = val->fData.fValue.f_float; - + vec.r = getFloatAttribute(fieldElement, "R"); + vec.g = getFloatAttribute(fieldElement, "G"); + vec.b = getFloatAttribute(fieldElement, "B"); + vec.a = getFloatAttribute(fieldElement, "A"); memcpy(ci.second.Defaults.get() + fieldOffset, reinterpret_cast(&vec), getTypeStride(fieldType)); } else if (fieldType == "Quaternion") { glm::quat q; - - XSValue::Status status; - XSValue* val; - - val = XSValue::getActualValue(fieldElement->getAttribute(XSTR("X")), XSValue::DataType::dt_float, status); - if (val == nullptr) { - LOG_ERROR("Default field \"%s\" for component \"%s\" missing \"%s\" attribute!", fieldName.c_str(), componentName.c_str(), "X"); - } else { - q.x = val->fData.fValue.f_float; - } - val = XSValue::getActualValue(fieldElement->getAttribute(XSTR("Y")), XSValue::DataType::dt_float, status); - if (val == nullptr) { - LOG_ERROR("Default field \"%s\" for component \"%s\" missing \"%s\" attribute!", fieldName.c_str(), componentName.c_str(), "Y"); - } else { - q.y = val->fData.fValue.f_float; - } - val = XSValue::getActualValue(fieldElement->getAttribute(XSTR("Z")), XSValue::DataType::dt_float, status); - if (val == nullptr) { - LOG_ERROR("Default field \"%s\" for component \"%s\" missing \"%s\" attribute!", fieldName.c_str(), componentName.c_str(), "Z"); - } else { - q.z = val->fData.fValue.f_float; - } - val = XSValue::getActualValue(fieldElement->getAttribute(XSTR("W")), XSValue::DataType::dt_float, status); - if (val == nullptr) { - LOG_ERROR("Default field \"%s\" for component \"%s\" missing \"%s\" attribute!", fieldName.c_str(), componentName.c_str(), "W"); - } else { - q.w = val->fData.fValue.f_float; - } - + q.x = getFloatAttribute(fieldElement, "X"); + q.y = getFloatAttribute(fieldElement, "Y"); + q.z = getFloatAttribute(fieldElement, "Z"); + q.w = getFloatAttribute(fieldElement, "W"); memcpy(ci.second.Defaults.get() + fieldOffset, reinterpret_cast(&q), getTypeStride(fieldType)); } } else if (dataType == XSValue::DataType::dt_string) { char* str = XMLString::transcode(fieldElement->getTextContent()); std::string standardString(str); - new (ci.second.Defaults.get() + fieldOffset) std::string(str); + //new (ci.second.Defaults.get() + fieldOffset) std::string(str); XMLString::release(&str); - //memcpy(ci.second.Defaults.get() + fieldOffset, &standardString, getTypeStride(fieldType)); + memcpy(ci.second.Defaults.get() + fieldOffset, &standardString, getTypeStride(fieldType)); } else { XSValue::Status status; XSValue* val = XSValue::getActualValue(fieldElement->getTextContent(), dataType, status); @@ -373,14 +331,6 @@ void EntityXMLFile::predictComponentAllocation() stride += getTypeStride(field.second); } std::cout << " Stride: " << ci.Meta.Stride << std::endl; - - // TODO: ALLOCATE HERE - /*ComponentPool cs; - cs.ComponentName = ci.Name; - cs.Stride = stride; - cs.Info = ci; - cs.Data = new char[stride*ci.Meta.Allocation]; - m_ComponentStore[cs.ComponentName] = cs;*/ } } @@ -463,3 +413,16 @@ std::size_t EntityXMLFile::getTypeStride(std::string typeName) 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_float, status); + if (val == nullptr) { + LOG_ERROR("Element \"%s\" doesn't have an \"%s\" attribute!", XSTR(element->getTagName()), attribute); + return 0.f; + } else { + return val->fData.fValue.f_float; + } +} \ No newline at end of file From c9d1ba6caead8464508733ad892ff74496a1c15e Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Wed, 9 Dec 2015 11:07:46 +0100 Subject: [PATCH 07/17] EntityIDs should start at 1, because 0 is world --- include/Engine/Core/World.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/Engine/Core/World.h b/include/Engine/Core/World.h index ab6f43fa..1ac10df1 100644 --- a/include/Engine/Core/World.h +++ b/include/Engine/Core/World.h @@ -25,7 +25,7 @@ public: const ComponentPool& GetComponents(std::string componentType); private: - EntityID m_CurrentEntityID = 0; + EntityID m_CurrentEntityID = 1; std::unordered_map m_EntityParents; std::unordered_multimap m_EntityChildren; From c9b140bd6b28cfbb4a90fcfafac704de7a000852 Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Wed, 9 Dec 2015 11:59:58 +0100 Subject: [PATCH 08/17] Semi-working entity loading from XML files! --- include/Engine/Core/EntityXMLFile.h | 3 +- resources/Schema/Entities/Test.xml | 10 +- resources/Schema/Types/Entity.xsd | 1 + src/Engine/Core/EntityXMLFile.cpp | 133 ++++++++++++++------ src/Engine/Rendering/RawModel.cpp | 32 ++--- src/Engine/Rendering/RenderQueueFactory.cpp | 5 +- 6 files changed, 121 insertions(+), 63 deletions(-) diff --git a/include/Engine/Core/EntityXMLFile.h b/include/Engine/Core/EntityXMLFile.h index d7c34e3a..6fa71dad 100644 --- a/include/Engine/Core/EntityXMLFile.h +++ b/include/Engine/Core/EntityXMLFile.h @@ -132,9 +132,10 @@ private: void parseComponentInfo(); void parseDefaults(); void predictComponentAllocation(); - void parseEntityGraph(); + 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 \ No newline at end of file diff --git a/resources/Schema/Entities/Test.xml b/resources/Schema/Entities/Test.xml index 8ca6b684..9b379495 100644 --- a/resources/Schema/Entities/Test.xml +++ b/resources/Schema/Entities/Test.xml @@ -3,10 +3,12 @@ - - - + + + + Models/Core/UnitSphere.obj + 12 11.11 @@ -14,7 +16,5 @@ - - \ No newline at end of file diff --git a/resources/Schema/Types/Entity.xsd b/resources/Schema/Types/Entity.xsd index 2f0a6311..bd7de5a3 100644 --- a/resources/Schema/Types/Entity.xsd +++ b/resources/Schema/Types/Entity.xsd @@ -11,6 +11,7 @@ + diff --git a/src/Engine/Core/EntityXMLFile.cpp b/src/Engine/Core/EntityXMLFile.cpp index f64faeb6..b96e366e 100644 --- a/src/Engine/Core/EntityXMLFile.cpp +++ b/src/Engine/Core/EntityXMLFile.cpp @@ -67,7 +67,8 @@ void EntityXMLFile::PopulateWorld(World* world) } // 4. Parse entity hierarchy - //parseEntityGraph(); + auto root = m_DOMDocument->getDocumentElement(); + parseEntityGraph(world, root, 0); } @@ -261,41 +262,7 @@ void EntityXMLFile::parseDefaults() std::string fieldType = ci.second.FieldTypes.at(fieldName); unsigned int fieldOffset = ci.second.FieldOffsets.at(fieldName); - - XSValue::DataType dataType = XSValue::getDataType(XSTR(fieldType.c_str())); - if (dataType == XSValue::DataType::dt_MAXCOUNT) { - if (fieldType == "Vector") { - glm::vec3 vec; - vec.x = getFloatAttribute(fieldElement, "X"); - vec.y = getFloatAttribute(fieldElement, "Y"); - vec.z = getFloatAttribute(fieldElement, "Z"); - memcpy(ci.second.Defaults.get() + fieldOffset, reinterpret_cast(&vec), getTypeStride(fieldType)); - } else if (fieldType == "Color") { - glm::vec4 vec; - vec.r = getFloatAttribute(fieldElement, "R"); - vec.g = getFloatAttribute(fieldElement, "G"); - vec.b = getFloatAttribute(fieldElement, "B"); - vec.a = getFloatAttribute(fieldElement, "A"); - memcpy(ci.second.Defaults.get() + fieldOffset, reinterpret_cast(&vec), getTypeStride(fieldType)); - } else if (fieldType == "Quaternion") { - glm::quat q; - q.x = getFloatAttribute(fieldElement, "X"); - q.y = getFloatAttribute(fieldElement, "Y"); - q.z = getFloatAttribute(fieldElement, "Z"); - q.w = getFloatAttribute(fieldElement, "W"); - memcpy(ci.second.Defaults.get() + fieldOffset, reinterpret_cast(&q), getTypeStride(fieldType)); - } - } else if (dataType == XSValue::DataType::dt_string) { - char* str = XMLString::transcode(fieldElement->getTextContent()); - std::string standardString(str); - //new (ci.second.Defaults.get() + fieldOffset) std::string(str); - XMLString::release(&str); - memcpy(ci.second.Defaults.get() + fieldOffset, &standardString, getTypeStride(fieldType)); - } else { - XSValue::Status status; - XSValue* val = XSValue::getActualValue(fieldElement->getTextContent(), dataType, status); - memcpy(ci.second.Defaults.get() + fieldOffset, reinterpret_cast(&val->fData.fValue), getTypeStride(fieldType)); - } + writeData(fieldElement, fieldType, ci.second.Defaults.get() + fieldOffset); } } } @@ -334,11 +301,56 @@ void EntityXMLFile::predictComponentAllocation() } } -void EntityXMLFile::parseEntityGraph() +void EntityXMLFile::parseEntityGraph(World* world, xercesc::DOMElement* element, EntityID parentEntity) { - //using namespace xercesc; + using namespace xercesc; - //auto root = m_DOMDocument->getDocumentElement(); + // 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(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(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 + auto children = m_DOMDocument->evaluate(XSTR("Children/Entity"), element, nullptr, DOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE, nullptr); + for (int i = 0; i < children->getSnapshotLength(); i++) { + children->snapshotItem(i); + parseEntityGraph(world, dynamic_cast(children->getNodeValue()), entity); + } //auto components = m_DOMDocument->getElementsByTagNameNS(XSTR("components"), XSTR("*")); //for (int i = 0; i < components->getLength(); ++i) { @@ -425,4 +437,45 @@ float EntityXMLFile::getFloatAttribute(const xercesc::DOMElement* element, const } else { return val->fData.fValue.f_float; } -} \ No newline at end of file +} + +void EntityXMLFile::writeData(const xercesc::DOMElement* element, std::string typeName, char* outData) +{ + using namespace xercesc; + + XSValue::DataType dataType = XSValue::getDataType(XSTR(typeName.c_str())); + if (dataType == XSValue::DataType::dt_MAXCOUNT) { + if (typeName == "Vector") { + glm::vec3 vec; + vec.x = getFloatAttribute(element, "X"); + vec.y = getFloatAttribute(element, "Y"); + vec.z = getFloatAttribute(element, "Z"); + memcpy(outData, reinterpret_cast(&vec), getTypeStride(typeName)); + } else if (typeName == "Color") { + glm::vec4 vec; + vec.r = getFloatAttribute(element, "R"); + vec.g = getFloatAttribute(element, "G"); + vec.b = getFloatAttribute(element, "B"); + vec.a = getFloatAttribute(element, "A"); + memcpy(outData, reinterpret_cast(&vec), getTypeStride(typeName)); + } else if (typeName == "Quaternion") { + glm::quat q; + q.x = getFloatAttribute(element, "X"); + q.y = getFloatAttribute(element, "Y"); + q.z = getFloatAttribute(element, "Z"); + q.w = getFloatAttribute(element, "W"); + memcpy(outData, reinterpret_cast(&q), getTypeStride(typeName)); + } + } else if (dataType == XSValue::DataType::dt_string) { + char* str = XMLString::transcode(element->getTextContent()); + std::string standardString(str); + new (outData) std::string(str); + XMLString::release(&str); + //memcpy(outData, reinterpret_cast(&standardString), getTypeStride(typeName)); + } else { + XSValue::Status status; + XSValue* val = XSValue::getActualValue(element->getTextContent(), dataType, status); + memcpy(outData, reinterpret_cast(&val->fData.fValue), getTypeStride(typeName)); + } +} + diff --git a/src/Engine/Rendering/RawModel.cpp b/src/Engine/Rendering/RawModel.cpp index c14fec08..962c278f 100644 --- a/src/Engine/Rendering/RawModel.cpp +++ b/src/Engine/Rendering/RawModel.cpp @@ -34,10 +34,10 @@ RawModel::RawModel(std::string fileName) numIndices += face.mNumIndices; } } - LOG_DEBUG("Vertex count %i", numVertices); - LOG_DEBUG("Index count %i", numIndices); + //LOG_DEBUG("Vertex count %i", numVertices); + //LOG_DEBUG("Index count %i", numIndices); - LOG_DEBUG("Model has %i embedded textures", scene->mNumTextures); + //LOG_DEBUG("Model has %i embedded textures", scene->mNumTextures); std::vector> boneInfo; std::map boneNameMapping; @@ -132,35 +132,35 @@ RawModel::RawModel(std::string fileName) matGroup.EndIndex = m_Indices.size() - 1; // Material shininess material->Get(AI_MATKEY_SHININESS, matGroup.Shininess); - LOG_DEBUG("Shininess: %f", matGroup.Shininess); + //LOG_DEBUG("Shininess: %f", matGroup.Shininess); // Diffuse texture - LOG_DEBUG("%i diffuse textures found", material->GetTextureCount(aiTextureType_DIFFUSE)); + //LOG_DEBUG("%i diffuse textures found", material->GetTextureCount(aiTextureType_DIFFUSE)); if (material->GetTextureCount(aiTextureType_DIFFUSE)) { aiString path; aiTextureMapping mapping; material->GetTexture(aiTextureType_DIFFUSE, 0, &path, &mapping); std::string absolutePath = (boost::filesystem::path(fileName).branch_path() / path.C_Str()).string(); - LOG_DEBUG("Diffuse texture: %s", absolutePath.c_str()); + //LOG_DEBUG("Diffuse texture: %s", absolutePath.c_str()); matGroup.Texture = std::shared_ptr(ResourceManager::Load(absolutePath)); } // Normal map - LOG_DEBUG("%i normal maps found", material->GetTextureCount(aiTextureType_HEIGHT)); + //LOG_DEBUG("%i normal maps found", material->GetTextureCount(aiTextureType_HEIGHT)); if (material->GetTextureCount(aiTextureType_HEIGHT)) { aiString path; aiTextureMapping mapping; material->GetTexture(aiTextureType_HEIGHT, 0, &path, &mapping); std::string absolutePath = (boost::filesystem::path(fileName).branch_path() / path.C_Str()).string(); - LOG_DEBUG("Normal map: %s", absolutePath.c_str()); + //LOG_DEBUG("Normal map: %s", absolutePath.c_str()); matGroup.NormalMap = std::shared_ptr(ResourceManager::Load(absolutePath)); } // Specular map - LOG_DEBUG("%i specular maps found", material->GetTextureCount(aiTextureType_SPECULAR)); + //LOG_DEBUG("%i specular maps found", material->GetTextureCount(aiTextureType_SPECULAR)); if (material->GetTextureCount(aiTextureType_SPECULAR)) { aiString path; aiTextureMapping mapping; material->GetTexture(aiTextureType_SPECULAR, 0, &path, &mapping); std::string absolutePath = (boost::filesystem::path(fileName).branch_path() / path.C_Str()).string(); - LOG_DEBUG("Specular map: %s", absolutePath.c_str()); + //LOG_DEBUG("Specular map: %s", absolutePath.c_str()); matGroup.SpecularMap = std::shared_ptr(ResourceManager::Load(absolutePath)); } TextureGroups.push_back(matGroup); @@ -216,20 +216,20 @@ RawModel::RawModel(std::string fileName) m_Skeleton = new Skeleton(); CreateSkeleton(boneInfo, boneNameMapping, scene->mRootNode, -1); int numBones = m_Skeleton->Bones.size(); - LOG_DEBUG("Bone count: %i", numBones); + //LOG_DEBUG("Bone count: %i", numBones); if (numBones > 0) { m_Skeleton->PrintSkeleton(); } } // Animations - LOG_DEBUG("Animation count: %i", scene->mNumAnimations); + //LOG_DEBUG("Animation count: %i", scene->mNumAnimations); for (int i = 0; i < scene->mNumAnimations; ++i) { auto animation = scene->mAnimations[i]; std::string animationName = animation->mName.C_Str(); - LOG_DEBUG("Animation: %s", animationName.c_str()); - LOG_DEBUG("Duration: %f", animation->mDuration); - LOG_DEBUG("Ticks per second: %f", animation->mTicksPerSecond); + //LOG_DEBUG("Animation: %s", animationName.c_str()); + //LOG_DEBUG("Duration: %f", animation->mDuration); + //LOG_DEBUG("Ticks per second: %f", animation->mTicksPerSecond); Skeleton::Animation skelAnim; skelAnim.Name = animationName; @@ -303,7 +303,7 @@ void RawModel::CreateSkeleton(std::vector> &b // Find the bone by name in the bone info list if (boneNameMapping.find(nodeName) == boneNameMapping.end()) { - LOG_DEBUG("Node \"%s\" was not a bone", nodeName.c_str()); + //LOG_DEBUG("Node \"%s\" was not a bone", nodeName.c_str()); } else { glm::mat4 offsetMatrix; int ID = boneNameMapping[nodeName]; diff --git a/src/Engine/Rendering/RenderQueueFactory.cpp b/src/Engine/Rendering/RenderQueueFactory.cpp index 9a7d89a1..aec304ed 100644 --- a/src/Engine/Rendering/RenderQueueFactory.cpp +++ b/src/Engine/Rendering/RenderQueueFactory.cpp @@ -36,12 +36,15 @@ glm::vec3 GetAbsolutePosition(World* world, ComponentWrapper transformComponent) void RenderQueueFactory::FillModels(World* world, RenderQueue* renderQueue) { for(auto& modelC : world->GetComponents("Model")) { - ModelJob job; std::string resource = modelC["Resource"]; + if (resource.empty()) { + continue; + } glm::vec4 color = modelC["Color"]; Model* model = ResourceManager::Load(resource); for (auto texGroup : model->TextureGroups) { + ModelJob job; job.TextureID = (texGroup.Texture) ? texGroup.Texture->ResourceID : 0; job.DiffuseTexture = texGroup.Texture.get(); job.NormalTexture = texGroup.NormalMap.get(); From 3085ccdfbf13f767db7b24a1311846cc43374434 Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Wed, 9 Dec 2015 14:23:49 +0100 Subject: [PATCH 09/17] Added temporary Release function to resource manager to be able to reload a resource --- include/Engine/Core/ResourceManager.h | 2 ++ src/Engine/Core/ResourceManager.cpp | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/include/Engine/Core/ResourceManager.h b/include/Engine/Core/ResourceManager.h index d408f5af..86ed6254 100644 --- a/include/Engine/Core/ResourceManager.h +++ b/include/Engine/Core/ResourceManager.h @@ -81,6 +81,8 @@ public: @param resourceName Fully qualified name of the resource to reload. */ static void Reload(std::string resourceName); + + static void Release(std::string resourceType, std::string resourceName); static void Update(); diff --git a/src/Engine/Core/ResourceManager.cpp b/src/Engine/Core/ResourceManager.cpp index 325bfab8..81823dbf 100644 --- a/src/Engine/Core/ResourceManager.cpp +++ b/src/Engine/Core/ResourceManager.cpp @@ -35,6 +35,20 @@ void ResourceManager::Reload(std::string resourceName) } } + +void ResourceManager::Release(std::string resourceType, std::string resourceName) +{ + auto key = std::make_pair(resourceType, resourceName); + if (m_ResourceCache.find(key) == m_ResourceCache.end()) { + return; + } + auto resource = m_ResourceCache.at(key); + m_ResourceCache.erase(key); + m_ResourceFromName.erase(resourceName); + m_ResourceParents.erase(resource); + delete resource; +} + unsigned int ResourceManager::GetNewResourceID(unsigned int typeID) { return m_ResourceCount[typeID]++; From 58d827f7d08431df982864dd1de8a92e998fae97 Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Wed, 9 Dec 2015 14:25:41 +0100 Subject: [PATCH 10/17] Moved world definition to Schema/Entities/Test.xml and removed HardcodedTestWorld --- assets | 2 +- include/Engine/Core/World.h | 2 +- include/Game/Game.h | 8 ++++ include/Game/HardcodedTestWorld.h | 47 ------------------- resources/Schema/Entities/Test.xml | 44 ++++++++++++++---- resources/Schema/Types/Entity.xsd | 2 +- src/Engine/Core/World.cpp | 5 +- src/Engine/Rendering/RenderQueueFactory.cpp | 51 +++++++++++---------- src/Game/Game.cpp | 32 +++++++++++-- 9 files changed, 105 insertions(+), 88 deletions(-) delete mode 100644 include/Game/HardcodedTestWorld.h diff --git a/assets b/assets index 4bd902b6..5a207bbb 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 4bd902b697b8eef063da800102e6e9c3b29353eb +Subproject commit 5a207bbb3ee4dcc620a9d2dfe8bfa0190db21a63 diff --git a/include/Engine/Core/World.h b/include/Engine/Core/World.h index 1ac10df1..932d2a17 100644 --- a/include/Engine/Core/World.h +++ b/include/Engine/Core/World.h @@ -22,7 +22,7 @@ public: // Get a component of an entity ComponentWrapper GetComponent(EntityID entity, std::string componentType); // Get all components of the specified type - const ComponentPool& GetComponents(std::string componentType); + const ComponentPool* GetComponents(std::string componentType); private: EntityID m_CurrentEntityID = 1; diff --git a/include/Game/Game.h b/include/Game/Game.h index cd16a3dd..b561119a 100644 --- a/include/Game/Game.h +++ b/include/Game/Game.h @@ -9,6 +9,8 @@ #include "GUI/Frame.h" #include "Core/World.h" #include "Rendering/RenderQueueFactory.h" +#include "Core/EKeyDown.h" +#include "Core/EntityXMLFile.h" class Game { @@ -28,6 +30,12 @@ private: GUI::Frame* m_FrameStack; World* m_World; RenderQueueFactory* m_RenderQueueFactory; + + EventRelay m_EKeyUp; + bool testOnKeyUp(const Events::KeyUp& e); + + void testIntialize(); + void testTick(double dt); }; #endif diff --git a/include/Game/HardcodedTestWorld.h b/include/Game/HardcodedTestWorld.h deleted file mode 100644 index ec7e3267..00000000 --- a/include/Game/HardcodedTestWorld.h +++ /dev/null @@ -1,47 +0,0 @@ -#include -#include -#include -#include "GLM.h" -#include "Core/World.h" -#include "Core/Util/Any.h" -#include "Core/EntityXMLFile.h" - -class HardcodedTestWorld : public World -{ -public: - HardcodedTestWorld() - : World() - { - ResourceManager::RegisterType("EntityXMLFile"); - ResourceManager::Load("Schema/Entities/Test.xml")->PopulateWorld(this); - - createTestEntities(); - } - -private: - void createTestEntities() - { - //Create some test widgets - { - EntityID entityScaleWidget = CreateEntity(); - ComponentWrapper transform = AttachComponent(entityScaleWidget, "Transform"); - transform["Position"] = glm::vec3(-1.5f, 0.f, 0.f); - ComponentWrapper model = AttachComponent(entityScaleWidget, "Model"); - model["Resource"] = "Models/ScaleWidget.obj"; - } - { - EntityID entityRotationWidget = CreateEntity(); - ComponentWrapper transform = AttachComponent(entityRotationWidget, "Transform"); - transform["Position"] = glm::vec3(1.5f, 0.f, 0.f); - ComponentWrapper model = AttachComponent(entityRotationWidget, "Model"); - model["Resource"] = "Models/RotationWidget.obj"; - } - { - EntityID entityDummyScene = CreateEntity(); - ComponentWrapper transform = AttachComponent(entityDummyScene, "Transform"); - transform["Position"] = glm::vec3(0, 0.f, 0.f); - ComponentWrapper model = AttachComponent(entityDummyScene, "Model"); - model["Resource"] = "Models/DummyScene.obj"; - } - } -}; \ No newline at end of file diff --git a/resources/Schema/Entities/Test.xml b/resources/Schema/Entities/Test.xml index 9b379495..2b003aea 100644 --- a/resources/Schema/Entities/Test.xml +++ b/resources/Schema/Entities/Test.xml @@ -2,19 +2,43 @@ - - - - + - Models/Core/UnitSphere.obj + Models/DummyScene.obj - - 12 - 11.11 - Hello World - + + + + + + + + Models/ScaleWidget.obj + + + + + + + + + + Models/RotationWidget.obj + + + + + + + + + + + Models/Core/UnitRaptor.obj + + + \ No newline at end of file diff --git a/resources/Schema/Types/Entity.xsd b/resources/Schema/Types/Entity.xsd index bd7de5a3..49d0f895 100644 --- a/resources/Schema/Types/Entity.xsd +++ b/resources/Schema/Types/Entity.xsd @@ -7,7 +7,7 @@ - + diff --git a/src/Engine/Core/World.cpp b/src/Engine/Core/World.cpp index 26d3f1e4..4ebf733e 100644 --- a/src/Engine/Core/World.cpp +++ b/src/Engine/Core/World.cpp @@ -41,9 +41,10 @@ ComponentWrapper World::GetComponent(EntityID entity, std::string componentType) return pool->GetByEntity(entity); } -const ComponentPool& World::GetComponents(std::string componentType) +const ComponentPool* World::GetComponents(std::string componentType) { - return *m_ComponentPools.at(componentType); + auto it = m_ComponentPools.find(componentType); + return (it != m_ComponentPools.end()) ? it->second : nullptr; } EntityID World::generateEntityID() diff --git a/src/Engine/Rendering/RenderQueueFactory.cpp b/src/Engine/Rendering/RenderQueueFactory.cpp index aec304ed..9d001b96 100644 --- a/src/Engine/Rendering/RenderQueueFactory.cpp +++ b/src/Engine/Rendering/RenderQueueFactory.cpp @@ -35,32 +35,37 @@ glm::vec3 GetAbsolutePosition(World* world, ComponentWrapper transformComponent) void RenderQueueFactory::FillModels(World* world, RenderQueue* renderQueue) { - for(auto& modelC : world->GetComponents("Model")) { - std::string resource = modelC["Resource"]; - if (resource.empty()) { - continue; - } - glm::vec4 color = modelC["Color"]; - Model* model = ResourceManager::Load(resource); + auto models = world->GetComponents("Model"); + if (models == nullptr) { + return; + } - for (auto texGroup : model->TextureGroups) { - ModelJob job; - job.TextureID = (texGroup.Texture) ? texGroup.Texture->ResourceID : 0; - job.DiffuseTexture = texGroup.Texture.get(); - job.NormalTexture = texGroup.NormalMap.get(); - job.SpecularTexture = texGroup.SpecularMap.get(); - job.Model = model; - job.StartIndex = texGroup.StartIndex; - job.EndIndex = texGroup.EndIndex; - job.ModelMatrix = model->m_Matrix * ModelMatrix(world, modelC.EntityID); - job.Color = color; + for (auto& modelC : *models) { + std::string resource = modelC["Resource"]; + if (resource.empty()) { + continue; + } + glm::vec4 color = modelC["Color"]; + Model* model = ResourceManager::Load(resource); - //TODO: RENDERER: Not sure if the best solution for pickingColor to entity link is this - job.Entity = modelC.EntityID; + for (auto texGroup : model->TextureGroups) { + ModelJob job; + job.TextureID = (texGroup.Texture) ? texGroup.Texture->ResourceID : 0; + job.DiffuseTexture = texGroup.Texture.get(); + job.NormalTexture = texGroup.NormalMap.get(); + job.SpecularTexture = texGroup.SpecularMap.get(); + job.Model = model; + job.StartIndex = texGroup.StartIndex; + job.EndIndex = texGroup.EndIndex; + job.ModelMatrix = model->m_Matrix * ModelMatrix(world, modelC.EntityID); + job.Color = color; - renderQueue->Add(job); - } - } + //TODO: RENDERER: Not sure if the best solution for pickingColor to entity link is this + job.Entity = modelC.EntityID; + + renderQueue->Add(job); + } + } } void RenderQueueFactory::FillLights(World* world, RenderQueue* renderQueue) diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index 416b054e..4dcf0416 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -1,11 +1,11 @@ #include "Game.h" -#include "HardcodedTestWorld.h" Game::Game(int argc, char* argv[]) { ResourceManager::RegisterType("ConfigFile"); ResourceManager::RegisterType("Model"); ResourceManager::RegisterType("Texture"); + ResourceManager::RegisterType("EntityXMLFile"); m_Config = ResourceManager::Load("Config.ini"); LOG_LEVEL = static_cast<_LOG_LEVEL>(m_Config->Get("Debug.LogLevel", 1)); @@ -35,10 +35,12 @@ Game::Game(int argc, char* argv[]) m_FrameStack->Width = m_Renderer->Resolution().Width; m_FrameStack->Height = m_Renderer->Resolution().Height; - // Create a TEST WORLD - m_World = new HardcodedTestWorld(); + // Create a world + m_World = new World(); m_LastTime = glfwGetTime(); + + testIntialize(); } Game::~Game() @@ -58,6 +60,7 @@ void Game::Tick() m_Renderer->Update(dt); m_EventBroker->Swap(); + testTick(dt); m_RenderQueueFactory->Update(m_World); m_Renderer->Draw(m_RenderQueueFactory->RenderQueues()); @@ -67,3 +70,26 @@ void Game::Tick() glfwPollEvents(); } + + +bool Game::testOnKeyUp(const Events::KeyUp& e) +{ + if (e.KeyCode == GLFW_KEY_R) { + delete m_World; + m_World = new World(); + ResourceManager::Release("EntityXMLFile", "Schema/Entities/Test.xml"); + ResourceManager::Load("Schema/Entities/Test.xml")->PopulateWorld(m_World); + } + + return false; +} + +void Game::testIntialize() +{ + EVENT_SUBSCRIBE_MEMBER(m_EKeyUp, &Game::testOnKeyUp); +} + +void Game::testTick(double dt) +{ + m_EventBroker->Process(); +} From 578018607aecfa3e21ec9d05a7ec6e28b9d5cc1c Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Wed, 9 Dec 2015 14:32:34 +0100 Subject: [PATCH 11/17] Moved decision of which map to load to Config.ini --- resources/DefaultConfig.ini | 1 + src/Game/Game.cpp | 15 +++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/resources/DefaultConfig.ini b/resources/DefaultConfig.ini index ac7e9ec2..535e109b 100644 --- a/resources/DefaultConfig.ini +++ b/resources/DefaultConfig.ini @@ -1,5 +1,6 @@ [Debug] LogLevel=1 +LoadMap= [Video] Fullscreen=false diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index 4dcf0416..38660e73 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -37,6 +37,10 @@ Game::Game(int argc, char* argv[]) // Create a world m_World = new World(); + std::string mapToLoad = m_Config->Get("Debug.LoadMap", ""); + if (!mapToLoad.empty()) { + ResourceManager::Load(mapToLoad)->PopulateWorld(m_World); + } m_LastTime = glfwGetTime(); @@ -75,10 +79,13 @@ void Game::Tick() bool Game::testOnKeyUp(const Events::KeyUp& e) { if (e.KeyCode == GLFW_KEY_R) { - delete m_World; - m_World = new World(); - ResourceManager::Release("EntityXMLFile", "Schema/Entities/Test.xml"); - ResourceManager::Load("Schema/Entities/Test.xml")->PopulateWorld(m_World); + std::string mapToLoad = m_Config->Get("Debug.LoadMap", ""); + if (!mapToLoad.empty()) { + delete m_World; + m_World = new World(); + ResourceManager::Release("EntityXMLFile", mapToLoad); + ResourceManager::Load(mapToLoad)->PopulateWorld(m_World); + } } return false; From 90a79c702fb237ebc246427528fafed4b8b3b386 Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Wed, 9 Dec 2015 15:26:49 +0100 Subject: [PATCH 12/17] Added crude absolute positioning when rendering --- assets | 2 +- include/Engine/Core/World.h | 2 + include/Engine/Rendering/RenderQueueFactory.h | 1 - resources/Schema/Components/Transform.xsd | 2 +- resources/Schema/Entities/Test.xml | 55 ++++++++++++++++++- src/Engine/Core/World.cpp | 6 ++ src/Engine/Rendering/RenderQueueFactory.cpp | 17 +++--- src/Game/Game.cpp | 2 +- 8 files changed, 73 insertions(+), 14 deletions(-) diff --git a/assets b/assets index 5a207bbb..8a7ecf53 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 5a207bbb3ee4dcc620a9d2dfe8bfa0190db21a63 +Subproject commit 8a7ecf53f7ad7b8c36d778d0927fd77f7c6f6db0 diff --git a/include/Engine/Core/World.h b/include/Engine/Core/World.h index 932d2a17..65dc3be7 100644 --- a/include/Engine/Core/World.h +++ b/include/Engine/Core/World.h @@ -23,6 +23,8 @@ public: ComponentWrapper GetComponent(EntityID entity, std::string componentType); // Get all components of the specified type const ComponentPool* GetComponents(std::string componentType); + // Get entity parent + EntityID GetParent(EntityID entity); private: EntityID m_CurrentEntityID = 1; diff --git a/include/Engine/Rendering/RenderQueueFactory.h b/include/Engine/Rendering/RenderQueueFactory.h index 918692ac..f1535cdb 100644 --- a/include/Engine/Rendering/RenderQueueFactory.h +++ b/include/Engine/Rendering/RenderQueueFactory.h @@ -22,7 +22,6 @@ private: void FillLights(World* world, RenderQueue* renderQueue); glm::mat4 ModelMatrix(World* world, EntityID entity); - glm::vec3 GetAbsolutePosition(World* world, ComponentWrapper transformComponent); }; #endif \ No newline at end of file diff --git a/resources/Schema/Components/Transform.xsd b/resources/Schema/Components/Transform.xsd index d28ff601..b8d24777 100644 --- a/resources/Schema/Components/Transform.xsd +++ b/resources/Schema/Components/Transform.xsd @@ -12,7 +12,7 @@ The position vector - + diff --git a/resources/Schema/Entities/Test.xml b/resources/Schema/Entities/Test.xml index 2b003aea..4e7eafcf 100644 --- a/resources/Schema/Entities/Test.xml +++ b/resources/Schema/Entities/Test.xml @@ -2,7 +2,9 @@ - + + + Models/DummyScene.obj @@ -37,8 +39,59 @@ Models/Core/UnitRaptor.obj + + + + + + + + + + + + + + + + + + Models/Core/UnitCube.obj + + + + + + + + + + + + + Models/Core/UnitCube.obj + + + + + + + + + + + + + Models/Core/UnitCube.obj + + + + + + + \ No newline at end of file diff --git a/src/Engine/Core/World.cpp b/src/Engine/Core/World.cpp index 4ebf733e..dfab23cd 100644 --- a/src/Engine/Core/World.cpp +++ b/src/Engine/Core/World.cpp @@ -47,6 +47,12 @@ const ComponentPool* World::GetComponents(std::string componentType) return (it != m_ComponentPools.end()) ? it->second : nullptr; } + +EntityID World::GetParent(EntityID entity) +{ + return m_EntityParents.at(entity); +} + EntityID World::generateEntityID() { // TODO: Make EntityID generation smarter diff --git a/src/Engine/Rendering/RenderQueueFactory.cpp b/src/Engine/Rendering/RenderQueueFactory.cpp index 9d001b96..0ada02af 100644 --- a/src/Engine/Rendering/RenderQueueFactory.cpp +++ b/src/Engine/Rendering/RenderQueueFactory.cpp @@ -21,16 +21,15 @@ glm::mat4 RenderQueueFactory::ModelMatrix(World* world, EntityID entity) ComponentWrapper transformComponent = world->GetComponent(entity, "Transform"); glm::vec3 position = transformComponent["Position"]; glm::vec3 scale = transformComponent["Scale"]; - glm::quat oritentation = transformComponent["Orientation"]; + glm::vec3 oritentation = transformComponent["Orientation"]; - glm::mat4 modelMatrix = glm::translate(glm::mat4(), position) * glm::toMat4(oritentation) * glm::scale(scale); - return modelMatrix; -} - -glm::vec3 GetAbsolutePosition(World* world, ComponentWrapper transformComponent) -{ - // positionComponent.EntityID - return glm::vec3(); + glm::mat4 modelMatrix = glm::translate(glm::mat4(), position) * glm::toMat4(glm::quat(oritentation)) * glm::scale(scale); + EntityID parent = world->GetParent(entity); + if (parent != 0) { + return ModelMatrix(world, parent) * modelMatrix; + } else { + return modelMatrix; + } } void RenderQueueFactory::FillModels(World* world, RenderQueue* renderQueue) diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index 38660e73..eb62587e 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -65,8 +65,8 @@ void Game::Tick() m_EventBroker->Swap(); testTick(dt); - m_RenderQueueFactory->Update(m_World); + m_RenderQueueFactory->Update(m_World); m_Renderer->Draw(m_RenderQueueFactory->RenderQueues()); m_EventBroker->Swap(); From 4de613814b1fe31239e17d3ef074690d61138409 Mon Sep 17 00:00:00 2001 From: stiffly Date: Wed, 9 Dec 2015 17:43:36 +0100 Subject: [PATCH 13/17] WIP Packet loss identification. Put packetID in message --- include/Engine/Network/Client.h | 5 ++++ include/Engine/Network/NetworkDefinitions.h | 1 + include/Engine/Network/Server.h | 5 ++++ include/Game/Game.h | 3 +-- src/Engine/Network/Client.cpp | 26 ++++++++++++++++++--- src/Engine/Network/Server.cpp | 12 ++++++++++ src/Game/Game.cpp | 6 +++-- 7 files changed, 51 insertions(+), 7 deletions(-) diff --git a/include/Engine/Network/Client.h b/include/Engine/Network/Client.h index 5b2070d6..3485736b 100644 --- a/include/Engine/Network/Client.h +++ b/include/Engine/Network/Client.h @@ -42,12 +42,17 @@ private: void ParseServerPing(); void ParseSnapshot(char* data, size_t length); void CreateNewPlayer(int i); + void IdentifyPacketLoss(); // udp stuff boost::asio::ip::udp::endpoint m_ReceiverEndpoint; boost::asio::io_service m_IOService; boost::asio::ip::udp::socket m_Socket; + // Packet loss logic + unsigned int m_PacketID = 0; + unsigned int m_PreviousPacketID = 0; + World* m_World; int m_PlayerID = -1; glm::vec2 m_PlayerPositions[MAXCONNECTIONS]; diff --git a/include/Engine/Network/NetworkDefinitions.h b/include/Engine/Network/NetworkDefinitions.h index e9da132f..b9d36226 100644 --- a/include/Engine/Network/NetworkDefinitions.h +++ b/include/Engine/Network/NetworkDefinitions.h @@ -7,6 +7,7 @@ #define BOARDSIZE 16 #define MAXCONNECTIONS 8 #define INPUTSIZE 128 +#define PACKETMODULUS 1000 // How many packets before the number resets typedef boost::shared_ptr socket_ptr; typedef boost::shared_ptr string_ptr; diff --git a/include/Engine/Network/Server.h b/include/Engine/Network/Server.h index 381759d7..3b476d2a 100644 --- a/include/Engine/Network/Server.h +++ b/include/Engine/Network/Server.h @@ -32,6 +32,11 @@ private: std::clock_t m_StopTimes[8]; // Game logic World* m_World; + // Packet loss logic + unsigned int m_PacketCounter = 0; + unsigned int m_PacketID = 0; + const unsigned int m_PacketModolus = 1000; + // Close logic bool m_ThreadIsRunning = true; // Threaded diff --git a/include/Game/Game.h b/include/Game/Game.h index 2763b4dd..8ec4a6d8 100644 --- a/include/Game/Game.h +++ b/include/Game/Game.h @@ -36,8 +36,7 @@ private: RenderQueueFactory* m_RenderQueueFactory; // Network variables boost::thread m_NetworkThread; - Server m_Server; - Client m_Client; + // Network methods void NetworkFunction(); // Network events diff --git a/src/Engine/Network/Client.cpp b/src/Engine/Network/Client.cpp index df418e06..5e9b1fb3 100644 --- a/src/Engine/Network/Client.cpp +++ b/src/Engine/Network/Client.cpp @@ -7,6 +7,8 @@ Client::Client() : m_Socket(m_IOService) { // Set up network stream m_ReceiverEndpoint = udp::endpoint(boost::asio::ip::address::from_string("192.168.1.6"), 13); + m_NextSnapshot.inputForward = ""; + m_NextSnapshot.inputRight = ""; } Client::~Client() @@ -72,7 +74,7 @@ void Client::ReadFromServer() void Client::SendToServer() { - if (m_NextSnapshot.inputForward != "") { + if (m_NextSnapshot.inputForward != "" && m_NextSnapshot.inputForward[0] != '\0') { char* dataPackage = new char[INPUTSIZE]; // The package that will be sent to the server, when filled int len = CreateMessage(MessageType::Event, m_NextSnapshot.inputForward, dataPackage); m_Socket.send_to(boost::asio::buffer( @@ -81,7 +83,7 @@ void Client::SendToServer() m_ReceiverEndpoint, 0); delete[] dataPackage; } - if (m_NextSnapshot.inputRight != "") { + if (m_NextSnapshot.inputRight != "" && m_NextSnapshot.inputRight[0] != '\0') { char* dataPackage = new char[INPUTSIZE]; // The package that will be sent to the server, when filled int len = CreateMessage(MessageType::Event, m_NextSnapshot.inputRight, dataPackage); m_Socket.send_to(boost::asio::buffer( @@ -98,6 +100,12 @@ void Client::ParseMessageType(char* data, size_t length) memcpy(&messageType, data, sizeof(int)); // Read what type off message was sent from server MoveMessageHead(data, length, sizeof(int)); // Move the message head to know where to read from + // Read packet ID + m_PreviousPacketID = m_PacketID; + memcpy(&m_PacketID, data, sizeof(int)); + MoveMessageHead(data, length, sizeof(int)); + IdentifyPacketLoss(); + switch (static_cast(messageType)) { case MessageType::Connect: ParseConnect(data, length); @@ -323,4 +331,16 @@ void Client::CreateNewPlayer(int i) ComponentWrapper transform = m_World->AttachComponent(m_PlayerDefinitions[i].EntityID, "Transform"); ComponentWrapper model = m_World->AttachComponent(m_PlayerDefinitions[i].EntityID, "Model"); model["Resource"] = "Models/Core/UnitSphere.obj"; -} \ No newline at end of file +} + +void Client::IdentifyPacketLoss() +{ + // if no packets lost, difference should be equal to 1 + int difference = m_PacketID - m_PreviousPacketID; + if (difference != 1) { + for (int i = m_PreviousPacketID + 1; i < m_PacketID; i++) + { + LOG_INFO("Packet %i was lost...", i); + } + } +} diff --git a/src/Engine/Network/Server.cpp b/src/Engine/Network/Server.cpp index 344054f6..235b26ec 100644 --- a/src/Engine/Network/Server.cpp +++ b/src/Engine/Network/Server.cpp @@ -162,10 +162,15 @@ int Server::CreateMessage(MessageType type, std::string message, char * data) // Message type memcpy(data + offset, &type, sizeof(int)); offset += sizeof(int); + // Packet ID + m_PacketID = m_PacketCounter % 10; + memcpy(data + offset, &m_PacketID, sizeof(int)); + offset += sizeof(int); // Message, add one extra byte for null terminator memcpy(data + offset, message.data(), (lengthOfMessage + 1) * sizeof(char)); offset += (lengthOfMessage + 1) * sizeof(char); + m_PacketCounter++; return offset; } @@ -273,6 +278,9 @@ int Server::CreateHeader(MessageType type, char * data) int offset = 0; memcpy(data, &messageType, sizeof(int)); offset += sizeof(int); + m_PacketID = m_PacketCounter % 10; + memcpy(data + offset, &m_PacketID, sizeof(int)); + offset += sizeof(int); return offset; } @@ -361,6 +369,10 @@ void Server::ParseConnect(char * data, size_t length) offset += sizeof(int); memcpy(temp + offset, &i, sizeof(int)); + memcpy(temp, &m_PacketID, sizeof(int)); + offset += sizeof(int); + m_PacketCounter++; + m_Socket.send_to( boost::asio::buffer(temp, sizeof(int) * 2), m_PlayerDefinitions[i].Endpoint, diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index 5722eaf2..affaaa66 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -48,8 +48,8 @@ Game::Game(int argc, char* argv[]) Game::~Game() { // Call before to ensure that thread closes correctly. - m_Client.Close(); - m_Server.Close(); + //m_Client.Close(); + //m_Server.Close(); delete m_FrameStack; delete m_EventBroker; @@ -84,9 +84,11 @@ void Game::NetworkFunction() std::cout << "Start client or server? (c/s)" << std::endl; std::cin >> inputMessage; if (inputMessage == "c" || inputMessage == "C") { + Client m_Client; m_Client.Start(m_World, m_EventBroker); } if (inputMessage == "s" || inputMessage == "S") { + Server m_Server; m_Server.Start(m_World); } } \ No newline at end of file From 53ef7497360936d7d37702753e43087f745c0c3c Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Thu, 10 Dec 2015 10:15:14 +0100 Subject: [PATCH 14/17] Fixed absoute positioning, I think... --- include/Engine/Rendering/RenderQueueFactory.h | 4 ++ src/Engine/Rendering/RenderQueueFactory.cpp | 49 +++++++++++++++---- 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/include/Engine/Rendering/RenderQueueFactory.h b/include/Engine/Rendering/RenderQueueFactory.h index f1535cdb..b273b672 100644 --- a/include/Engine/Rendering/RenderQueueFactory.h +++ b/include/Engine/Rendering/RenderQueueFactory.h @@ -22,6 +22,10 @@ private: void FillLights(World* world, RenderQueue* renderQueue); glm::mat4 ModelMatrix(World* world, EntityID entity); + + glm::vec3 AbsolutePosition(World* world, EntityID entity); + glm::quat AbsoluteOrientation(World* world, EntityID entity); + glm::vec3 AbsoluteScale(World* world, EntityID entity); }; #endif \ No newline at end of file diff --git a/src/Engine/Rendering/RenderQueueFactory.cpp b/src/Engine/Rendering/RenderQueueFactory.cpp index 0ada02af..81d7391e 100644 --- a/src/Engine/Rendering/RenderQueueFactory.cpp +++ b/src/Engine/Rendering/RenderQueueFactory.cpp @@ -15,20 +15,51 @@ void RenderQueueFactory::Update(World* world) glm::mat4 RenderQueueFactory::ModelMatrix(World* world, EntityID entity) { - //should really return absolute model matrix based on parents position, scale and orientation - //GetAbsolutePosition(World* world, ComponentWrapper transformComponent) + glm::vec3 position = AbsolutePosition(world, entity); + glm::quat orientation = AbsoluteOrientation(world, entity); + glm::vec3 scale = AbsoluteScale(world, entity); - ComponentWrapper transformComponent = world->GetComponent(entity, "Transform"); - glm::vec3 position = transformComponent["Position"]; - glm::vec3 scale = transformComponent["Scale"]; - glm::vec3 oritentation = transformComponent["Orientation"]; + glm::mat4 modelMatrix = glm::translate(glm::mat4(), position) * glm::toMat4(orientation) * glm::scale(scale); + return modelMatrix; +} + + +glm::vec3 RenderQueueFactory::AbsolutePosition(World* world, EntityID entity) +{ + glm::vec3 position; + + do { + ComponentWrapper transform = world->GetComponent(entity, "Transform"); + position += AbsoluteOrientation(world, entity) * (glm::vec3)transform["Position"]; + entity = world->GetParent(entity); + } while (entity != 0); + + return position; +} + +glm::quat RenderQueueFactory::AbsoluteOrientation(World* world, EntityID entity) +{ + glm::quat orientation; + + do { + ComponentWrapper transform = world->GetComponent(entity, "Transform"); + orientation = glm::quat((glm::vec3)transform["Orientation"]) * orientation; + entity = world->GetParent(entity); + } while (entity != 0); + + return orientation; +} + +glm::vec3 RenderQueueFactory::AbsoluteScale(World* world, EntityID entity) +{ + ComponentWrapper transform = world->GetComponent(entity, "Transform"); + glm::vec3 scale = (glm::vec3)transform["Scale"]; - glm::mat4 modelMatrix = glm::translate(glm::mat4(), position) * glm::toMat4(glm::quat(oritentation)) * glm::scale(scale); EntityID parent = world->GetParent(entity); if (parent != 0) { - return ModelMatrix(world, parent) * modelMatrix; + return AbsoluteScale(world, parent) * scale; } else { - return modelMatrix; + return scale; } } From 352074da04bf27c7e72020166c17c9f1c692fcb7 Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Thu, 10 Dec 2015 10:17:08 +0100 Subject: [PATCH 15/17] Created base for systems --- include/Engine/Core/System.h | 25 ++++++++++++ include/Engine/Core/SystemPipeline.h | 58 ++++++++++++++++++++++++++++ include/Game/Game.h | 2 + src/Game/Game.cpp | 5 +++ 4 files changed, 90 insertions(+) create mode 100644 include/Engine/Core/System.h create mode 100644 include/Engine/Core/SystemPipeline.h diff --git a/include/Engine/Core/System.h b/include/Engine/Core/System.h new file mode 100644 index 00000000..8e8c71b9 --- /dev/null +++ b/include/Engine/Core/System.h @@ -0,0 +1,25 @@ +#ifndef System_h__ +#define System_h__ + +#include "EventBroker.h" +#include "World.h" +#include "ComponentWrapper.h" + +class System +{ + friend class SystemPipeline; + +public: + System(const EventBroker* eventBroker, std::string componentType) + : m_EventBroker(eventBroker) + , m_ComponentType(componentType) + { } + + virtual void Update(World* world, ComponentWrapper& component, double dt) = 0; + +private: + const EventBroker* m_EventBroker; + std::string m_ComponentType; +}; + +#endif \ No newline at end of file diff --git a/include/Engine/Core/SystemPipeline.h b/include/Engine/Core/SystemPipeline.h new file mode 100644 index 00000000..24f98121 --- /dev/null +++ b/include/Engine/Core/SystemPipeline.h @@ -0,0 +1,58 @@ +#ifndef SystemPipeline_h__ +#define SystemPipeline_h__ + +#include "../Common.h" +#include "EventBroker.h" +#include "System.h" +#include "World.h" + +class SystemPipeline +{ +public: + SystemPipeline(const EventBroker* eventBroker) + : m_EventBroker(eventBroker) + { } + ~SystemPipeline() + { + for (auto& pair : m_Systems) { + for (auto& system : pair.second) { + delete system; + } + } + } + + template + void AddSystem(Arguments... args) + { + System* system = new T(m_EventBroker, args...); + if (!system->m_ComponentType.empty()) { + m_Systems[system->m_ComponentType].push_back(system); + } else { + LOG_ERROR("Failed to add system \"%s\": Missing component type!", typeid(T).name()); + delete system; + } + } + + void Update(World* world, double dt) + { + for (auto& pair : m_Systems) { + const std::string& componentName = pair.first; + auto& systems = pair.second; + const ComponentPool* pool = world->GetComponents(componentName); + if (pool == nullptr) { + continue; + } + for (auto& component : *pool) { + for (auto& system : systems) { + system->Update(world, component, dt); + } + } + } + } + +private: + const EventBroker* m_EventBroker; + std::unordered_map> m_Systems; +}; + +#endif \ No newline at end of file diff --git a/include/Game/Game.h b/include/Game/Game.h index b561119a..d52bc8cb 100644 --- a/include/Game/Game.h +++ b/include/Game/Game.h @@ -11,6 +11,7 @@ #include "Rendering/RenderQueueFactory.h" #include "Core/EKeyDown.h" #include "Core/EntityXMLFile.h" +#include "Core/SystemPipeline.h" class Game { @@ -29,6 +30,7 @@ private: InputManager* m_InputManager; GUI::Frame* m_FrameStack; World* m_World; + SystemPipeline* m_SystemPipeline; RenderQueueFactory* m_RenderQueueFactory; EventRelay m_EKeyUp; diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index eb62587e..efa8c4b7 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -41,6 +41,9 @@ Game::Game(int argc, char* argv[]) if (!mapToLoad.empty()) { ResourceManager::Load(mapToLoad)->PopulateWorld(m_World); } + + // Create system pipeline + m_SystemPipeline = new SystemPipeline(m_EventBroker); m_LastTime = glfwGetTime(); @@ -64,6 +67,8 @@ void Game::Tick() m_Renderer->Update(dt); m_EventBroker->Swap(); + // Iterate through systems and update world! + m_SystemPipeline->Update(m_World, dt); testTick(dt); m_RenderQueueFactory->Update(m_World); From 0367826f1666c7b34e597d86a60bef3b12a71eef Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Thu, 10 Dec 2015 10:17:18 +0100 Subject: [PATCH 16/17] Added RaptorCopter example system --- assets | 2 +- include/Game/Game.h | 1 + include/Game/RaptorCopterSystem.h | 16 ++++ resources/Schema/Components.xsd | 1 + resources/Schema/Components/RaptorCopter.xml | 4 + resources/Schema/Components/RaptorCopter.xsd | 14 +++ resources/Schema/Entities/Test.xml | 93 ++++++++++++-------- resources/Schema/Types/Entity.xsd | 1 + src/Game/Game.cpp | 1 + 9 files changed, 95 insertions(+), 38 deletions(-) create mode 100644 include/Game/RaptorCopterSystem.h create mode 100644 resources/Schema/Components/RaptorCopter.xml create mode 100644 resources/Schema/Components/RaptorCopter.xsd diff --git a/assets b/assets index 8a7ecf53..b3746822 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 8a7ecf53f7ad7b8c36d778d0927fd77f7c6f6db0 +Subproject commit b37468222e45ec0b2116f1543c578cb9784d43f2 diff --git a/include/Game/Game.h b/include/Game/Game.h index d52bc8cb..500ecf3a 100644 --- a/include/Game/Game.h +++ b/include/Game/Game.h @@ -12,6 +12,7 @@ #include "Core/EKeyDown.h" #include "Core/EntityXMLFile.h" #include "Core/SystemPipeline.h" +#include "RaptorCopterSystem.h" class Game { diff --git a/include/Game/RaptorCopterSystem.h b/include/Game/RaptorCopterSystem.h new file mode 100644 index 00000000..55647004 --- /dev/null +++ b/include/Game/RaptorCopterSystem.h @@ -0,0 +1,16 @@ +#include "Common.h" +#include "Core/System.h" + +class RaptorCopterSystem : public System +{ +public: + RaptorCopterSystem(const EventBroker* eventBroker) + : System(eventBroker, "RaptorCopter") + { } + + virtual void Update(World* world, ComponentWrapper& raptorCopter, double dt) override + { + ComponentWrapper& transform = world->GetComponent(raptorCopter.EntityID, "Transform"); + (glm::vec3&)transform["Orientation"] += (float)(double)raptorCopter["Speed"] * (float)dt * (glm::vec3)raptorCopter["Axis"]; + } +}; \ No newline at end of file diff --git a/resources/Schema/Components.xsd b/resources/Schema/Components.xsd index 54896b69..d4160700 100644 --- a/resources/Schema/Components.xsd +++ b/resources/Schema/Components.xsd @@ -4,4 +4,5 @@ + \ No newline at end of file diff --git a/resources/Schema/Components/RaptorCopter.xml b/resources/Schema/Components/RaptorCopter.xml new file mode 100644 index 00000000..cc1ece52 --- /dev/null +++ b/resources/Schema/Components/RaptorCopter.xml @@ -0,0 +1,4 @@ + + 0 + + \ No newline at end of file diff --git a/resources/Schema/Components/RaptorCopter.xsd b/resources/Schema/Components/RaptorCopter.xsd new file mode 100644 index 00000000..23ee8a96 --- /dev/null +++ b/resources/Schema/Components/RaptorCopter.xsd @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/Schema/Entities/Test.xml b/resources/Schema/Entities/Test.xml index 4e7eafcf..2c3ea18e 100644 --- a/resources/Schema/Entities/Test.xml +++ b/resources/Schema/Entities/Test.xml @@ -37,57 +37,76 @@ - - Models/Core/UnitRaptor.obj - - + - - + + + + Models/Core/UnitRaptor.obj + + - - - - - Models/Core/UnitCube.obj - - - - - - - - - + - - Models/Core/UnitCube.obj - - - - - - - - - - - - - Models/Core/UnitCube.obj - - + + 20 + + + + + + + + + + + Models/Core/UnitCylinder.obj + + + + + + + + + + + + + Models/Core/UnitCube.obj + + + + + + + + + + + + + Models/Core/UnitCube.obj + + + + + diff --git a/resources/Schema/Types/Entity.xsd b/resources/Schema/Types/Entity.xsd index 49d0f895..695ae7d1 100644 --- a/resources/Schema/Types/Entity.xsd +++ b/resources/Schema/Types/Entity.xsd @@ -13,6 +13,7 @@ + diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index efa8c4b7..15dde3a0 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -44,6 +44,7 @@ Game::Game(int argc, char* argv[]) // Create system pipeline m_SystemPipeline = new SystemPipeline(m_EventBroker); + m_SystemPipeline->AddSystem(); m_LastTime = glfwGetTime(); From 9a8f5293afc0b546fd09cd28686f59bc0a22ab4c Mon Sep 17 00:00:00 2001 From: stiffly Date: Thu, 10 Dec 2015 12:55:28 +0100 Subject: [PATCH 17/17] Can now Identify Packet Loss. Enumerated messages that loops around 0-1000. --- include/Engine/Network/NetworkDefinitions.h | 2 +- src/Engine/Network/Client.cpp | 12 ++-- src/Engine/Network/Server.cpp | 62 +++++++++++---------- 3 files changed, 40 insertions(+), 36 deletions(-) diff --git a/include/Engine/Network/NetworkDefinitions.h b/include/Engine/Network/NetworkDefinitions.h index b9d36226..4ad32e26 100644 --- a/include/Engine/Network/NetworkDefinitions.h +++ b/include/Engine/Network/NetworkDefinitions.h @@ -7,7 +7,7 @@ #define BOARDSIZE 16 #define MAXCONNECTIONS 8 #define INPUTSIZE 128 -#define PACKETMODULUS 1000 // How many packets before the number resets +#define PACKETMODULUS 1000 // How many packets to send before the number resets typedef boost::shared_ptr socket_ptr; typedef boost::shared_ptr string_ptr; diff --git a/src/Engine/Network/Client.cpp b/src/Engine/Network/Client.cpp index 5e9b1fb3..4f397b5b 100644 --- a/src/Engine/Network/Client.cpp +++ b/src/Engine/Network/Client.cpp @@ -6,7 +6,7 @@ using namespace boost::asio::ip; Client::Client() : m_Socket(m_IOService) { // Set up network stream - m_ReceiverEndpoint = udp::endpoint(boost::asio::ip::address::from_string("192.168.1.6"), 13); + m_ReceiverEndpoint = udp::endpoint(boost::asio::ip::address::from_string("192.168.1.2"), 13); m_NextSnapshot.inputForward = ""; m_NextSnapshot.inputRight = ""; } @@ -133,14 +133,15 @@ void Client::ParseMessageType(char* data, size_t length) void Client::ParseConnect(char* data, size_t len) { - memcpy(&m_PlayerID, data, sizeof(int)); - std::cout << "I am player: " << m_PlayerID << std::endl; + memcpy(&m_PacketID, data, sizeof(int)); + m_PreviousPacketID = m_PacketID; + std::cout << m_PacketID << ": I am player: " << m_PlayerID << std::endl; } void Client::ParsePing() { m_DurationOfPingTime = 1000 * (std::clock() - m_StartPingTime) / static_cast(CLOCKS_PER_SEC); - std::cout << "response time with ctime(ms): " << m_DurationOfPingTime << std::endl; + std::cout << m_PacketID << ": response time with ctime(ms): " << m_DurationOfPingTime << std::endl; } void Client::ParseServerPing() @@ -169,7 +170,7 @@ void Client::ParseEventMessage(char* data, size_t length) m_PlayerDefinitions[Id].Name = command.erase(0, 7); } else { - std::cout << "Event message: " << std::string(data) << std::endl; + std::cout << m_PacketID << ": Event message: " << std::string(data) << std::endl; } MoveMessageHead(data, length, std::string(data).size() + 1); @@ -177,6 +178,7 @@ void Client::ParseEventMessage(char* data, size_t length) void Client::ParseSnapshot(char* data, size_t length) { + std::cout << m_PacketID << ": Parsing incoming snapshot." << std::endl; std::string tempName; for (size_t i = 0; i < MAXCONNECTIONS; i++) { // We're checking for empty name for now. This might not be the best way, diff --git a/src/Engine/Network/Server.cpp b/src/Engine/Network/Server.cpp index 235b26ec..2dea57f5 100644 --- a/src/Engine/Network/Server.cpp +++ b/src/Engine/Network/Server.cpp @@ -53,6 +53,8 @@ void Server::ReadFromClients() // m_ThreadIsRunning might be unnecessary but the // program crashed if it executed m_Socket.available() // when closing the program. + + // If available message -> Socket.available() = true if (m_ThreadIsRunning && m_Socket.available()) { try { bytesRead = Receive(readBuf, INPUTSIZE); @@ -60,30 +62,29 @@ void Server::ReadFromClients() } catch (const std::exception& err) { // To not spam "socket closed messages" //if (std::string(err.what()).find("forcefully closed") != std::string::npos) { - std::cout << "Read from client crashed: " << err.what(); + std::cout << m_PacketID << ": Read from client crashed: " << err.what(); //} } - - std::clock_t currentTime = std::clock(); - // int tempTestRemovePlz = (1000 * (currentTime - previousSnapshotMessage) / (double)CLOCKS_PER_SEC); - // Send snapshot - if (snapshotInterval < (1000 * (currentTime - previousSnapshotMessage) / (double)CLOCKS_PER_SEC)) { - SendSnapshot(); - previousSnapshotMessage = currentTime; - } - - // Send pings each - if (intervallMs < (1000 * (currentTime - previousePingMessage) / (double)CLOCKS_PER_SEC)) { - SendPing(); - previousePingMessage = currentTime; - } - - // Time out logic - if (timeToCheckTimeOutTime < (1000 * (currentTime - timOutTimer) / (double)CLOCKS_PER_SEC)) { - CheckForTimeOuts(); - timOutTimer = currentTime; - } } + std::clock_t currentTime = std::clock(); + // int tempTestRemovePlz = (1000 * (currentTime - previousSnapshotMessage) / (double)CLOCKS_PER_SEC); + // Send snapshot + if (snapshotInterval < (1000 * (currentTime - previousSnapshotMessage) / (double)CLOCKS_PER_SEC)) { + SendSnapshot(); + previousSnapshotMessage = currentTime; + } + + // Send pings each + if (intervallMs < (1000 * (currentTime - previousePingMessage) / (double)CLOCKS_PER_SEC)) { + SendPing(); + previousePingMessage = currentTime; + } + + // Time out logic + if (timeToCheckTimeOutTime < (1000 * (currentTime - timOutTimer) / (double)CLOCKS_PER_SEC)) { + CheckForTimeOuts(); + timOutTimer = currentTime; + } } } @@ -102,7 +103,7 @@ void Server::InputLoop() Broadcast(inputMessage); } catch (const std::exception& err) { - std::cout << "Read from WriteLoop crashed: " << err.what(); + std::cout << m_PacketID << ": Read from WriteLoop crashed: " << err.what(); } } if (inputMessage.find("exit") != std::string::npos) @@ -163,7 +164,7 @@ int Server::CreateMessage(MessageType type, std::string message, char * data) memcpy(data + offset, &type, sizeof(int)); offset += sizeof(int); // Packet ID - m_PacketID = m_PacketCounter % 10; + m_PacketID = m_PacketCounter % PACKETMODULUS; memcpy(data + offset, &m_PacketID, sizeof(int)); offset += sizeof(int); // Message, add one extra byte for null terminator @@ -182,7 +183,7 @@ void Server::MoveMessageHead(char *& data, size_t & length, size_t stepSize) void Server::Broadcast(std::string message) { - std::cout << "Broadcast: " << message << std::endl; + std::cout << m_PacketID << ": Broadcast: " << message << std::endl; char* data = new char[128]; int offset = CreateMessage(MessageType::Event, message, data); for (int i = 0; i < MAXCONNECTIONS; i++) { @@ -238,7 +239,7 @@ void Server::SendPing() // Prints connected players ping for (size_t i = 0; i < MAXCONNECTIONS; i++) { if (m_PlayerDefinitions[i].Endpoint.address() != boost::asio::ip::address()) - std::cout << "Player " << i << "'s ping: " << 1000 * (m_StopTimes[i] - m_StartPingTime) + std::cout << m_PacketID << ": Player " << i << "'s ping: " << 1000 * (m_StopTimes[i] - m_StartPingTime) / static_cast(CLOCKS_PER_SEC) << std::endl; } @@ -278,9 +279,10 @@ int Server::CreateHeader(MessageType type, char * data) int offset = 0; memcpy(data, &messageType, sizeof(int)); offset += sizeof(int); - m_PacketID = m_PacketCounter % 10; + m_PacketID = m_PacketCounter % PACKETMODULUS; memcpy(data + offset, &m_PacketID, sizeof(int)); offset += sizeof(int); + m_PacketCounter++; return offset; } @@ -358,7 +360,7 @@ void Server::ParseConnect(char * data, size_t length) m_PlayerDefinitions[i].Name = std::string(data); m_StopTimes[i] = std::clock(); - std::cout << "Player \"" << m_PlayerDefinitions[i].Name << "\" connected on IP: " << + std::cout << m_PacketID << ": Player \"" << m_PlayerDefinitions[i].Name << "\" connected on IP: " << m_PlayerDefinitions[i].Endpoint.address().to_string() << std::endl; int offset = 0; @@ -379,7 +381,7 @@ void Server::ParseConnect(char * data, size_t length) 0); // Send notification that a player has connected - std::string str = "Player " + m_PlayerDefinitions[i].Name + " connected on: " + std::string str = m_PacketID + "Player " + m_PlayerDefinitions[i].Name + " connected on: " + m_PlayerDefinitions[i].Endpoint.address().to_string(); Broadcast(str); // +1 is the null terminator @@ -392,7 +394,7 @@ void Server::ParseConnect(char * data, size_t length) void Server::ParseDisconnect() { - std::cout << "Parsing disconnect. \n"; + std::cout << m_PacketID << ":Parsing disconnect. \n"; for (int i = 0; i < MAXCONNECTIONS; i++) { if (m_PlayerDefinitions[i].Endpoint.address() == m_ReceiverEndpoint.address()) { @@ -407,7 +409,7 @@ void Server::ParseClientPing() char* testMesssage = new char[128]; int testOffset = CreateMessage(MessageType::ClientPing, "Ping recieved", testMesssage); - std::cout << "Parsing ping." << std::endl; + std::cout << m_PacketID << ":Parsing ping." << std::endl; // Return ping m_Socket.send_to( boost::asio::buffer(