From 03bbe25a1e119c21cd0c938c2b7498477caca5f3 Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Tue, 8 Dec 2015 17:42:59 +0100 Subject: [PATCH 01/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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 e580540143b7827795f113f8aaaf54bef38ac114 Mon Sep 17 00:00:00 2001 From: William Moberg Date: Wed, 9 Dec 2015 17:16:11 +0100 Subject: [PATCH 13/19] Made some optimizations in OctTree and added a unit test for BoxesInSameRegion. --- include/Engine/Core/OctTree.h | 9 +++--- src/Engine/Core/OctTree.cpp | 55 ++++++++++++++++++++++------------- src/Tests/OctTreeTest.cpp | 20 +++++++++++++ 3 files changed, 58 insertions(+), 26 deletions(-) diff --git a/include/Engine/Core/OctTree.h b/include/Engine/Core/OctTree.h index e5d5a83a..27fbcba7 100644 --- a/include/Engine/Core/OctTree.h +++ b/include/Engine/Core/OctTree.h @@ -25,9 +25,6 @@ public: OctTree(const OctTree&& other) = delete; OctTree& operator= (const OctTree& other) = delete; - //Collision test function. WTODO: Probably remove or relocate elsewhere, Collision system? - void Update(float dt, World* world, Camera* cam); - void AddDynamicObject(const AABB& box); void AddStaticObject(const AABB& box); @@ -36,10 +33,13 @@ public: void ClearObjects(); void ClearDynamicObjects(); + //Collision test function. WTODO: Probably remove or relocate elsewhere, Collision system? + void Update(float dt, World* world, Camera* cam); //Returns true if the ray collides with something in the tree. Result is written to [data]. bool RayCollides(const Ray& ray, Output& data) const; //Returns true if the box collides with something in the tree. //On collision with a box, that box is written to [outBoxIntersected]. + //Note: More efficient than calling BoxesInSameRegion from outside and testing there. bool BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const; private: @@ -47,11 +47,10 @@ private: //WTODO: Do -derived class from AABB- struct containing AABB, with a bool Tested, falsify at //start of Collision test, set on check, don't check if set already. Solves duplicate boxes in tree. //Store indices in the struct, pointing to grand ancestor list of boxes, need the same AABB not copies to save Tested. - //WTODO: Boxes collide with themselves? Fix somehow, maybe float epsilon stuff. std::vector m_StaticObjects; std::vector m_DynamicObjects; AABB m_Box; - + bool m_UpdatedOnce; unsigned int m_BoxID; glm::vec3 m_PrevPos; diff --git a/src/Engine/Core/OctTree.cpp b/src/Engine/Core/OctTree.cpp index 82c1b554..5fab6f04 100644 --- a/src/Engine/Core/OctTree.cpp +++ b/src/Engine/Core/OctTree.cpp @@ -21,6 +21,16 @@ bool isFirstLower(const ChildInfo& first, const ChildInfo& second) return first.Distance < second.Distance; } +bool isSameBoxProbably(const AABB& first, const AABB& second) +{ + const float EPS = 0.0001f; + const auto& ma = first.MaxCorner(); + const auto& mi = first.MinCorner(); + return (std::abs(ma.x - mi.x) < EPS) && + (std::abs(ma.z - mi.z) < EPS) && + (std::abs(ma.y - mi.y) < EPS); +} + } OctTree::OctTree() @@ -131,16 +141,18 @@ bool OctTree::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const return true; } } else { - std::vector> objVectors = { - m_StaticObjects, - m_DynamicObjects - }; - for (const auto& objVector : objVectors) { - for (const auto& obj : objVector) { - if (Collision::AABBVsAABB(boxToTest, obj)) { - outBoxIntersected = obj; - return true; - } + for (const auto& obj : m_StaticObjects) { + if (Collision::AABBVsAABB(boxToTest, obj)) { + outBoxIntersected = obj; + return true; + } + } + for (const auto& obj : m_DynamicObjects) { + //If there is a collision and it is not testing against itself. + if (!isSameBoxProbably(boxToTest, obj) && + Collision::AABBVsAABB(boxToTest, obj)) { + outBoxIntersected = obj; + return true; } } } @@ -170,17 +182,18 @@ bool OctTree::RayCollides(const Ray& ray, Output& data) const //Check against boxes in the node. float minDist = INFINITY; bool intersected = false; - std::vector> objVectors = { - m_StaticObjects, - m_DynamicObjects - }; - for (const auto& objVector : objVectors) { - for (const auto& obj : objVector) { - float dist; - if (Collision::RayVsAABB(ray, obj, dist)) { - minDist = std::min(dist, minDist); - intersected = true; - } + for (const auto& obj : m_StaticObjects) { + float dist; + if (Collision::RayVsAABB(ray, obj, dist)) { + minDist = std::min(dist, minDist); + intersected = true; + } + } + for (const auto& obj : m_DynamicObjects) { + float dist; + if (Collision::RayVsAABB(ray, obj, dist)) { + minDist = std::min(dist, minDist); + intersected = true; } } diff --git a/src/Tests/OctTreeTest.cpp b/src/Tests/OctTreeTest.cpp index 5392e63c..47036485 100644 --- a/src/Tests/OctTreeTest.cpp +++ b/src/Tests/OctTreeTest.cpp @@ -16,5 +16,25 @@ BOOST_AUTO_TEST_CASE(octTreeTest2) } +BOOST_AUTO_TEST_CASE(octSameRegionTest) +{ + glm::vec3 mini = glm::vec3(-1, -1, -1); + glm::vec3 maxi = glm::vec3(1, 1, 1); + OctTree tree(AABB(mini, maxi), 2); + AABB firstQuadrant(mini, 0.8f*mini); + tree.AddStaticObject(firstQuadrant); + AABB testBox(0.9f*mini, 0.8f*mini); + std::vector region; + tree.BoxesInSameRegion(testBox, region); + BOOST_REQUIRE(region.size() == 1); + AABB& box = region[0]; + BOOST_CHECK_CLOSE_FRACTION(box.Center().x, firstQuadrant.Center().x, 0.00001f); + BOOST_CHECK_CLOSE_FRACTION(box.Center().y, firstQuadrant.Center().y, 0.00001f); + BOOST_CHECK_CLOSE_FRACTION(box.Center().z, firstQuadrant.Center().z, 0.00001f); + BOOST_CHECK_CLOSE_FRACTION(box.HalfSize().x, firstQuadrant.HalfSize().x, 0.00001f); + BOOST_CHECK_CLOSE_FRACTION(box.HalfSize().y, firstQuadrant.HalfSize().y, 0.00001f); + BOOST_CHECK_CLOSE_FRACTION(box.HalfSize().z, firstQuadrant.HalfSize().z, 0.00001f); +} + BOOST_AUTO_TEST_SUITE_END() From 53ef7497360936d7d37702753e43087f745c0c3c Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Thu, 10 Dec 2015 10:15:14 +0100 Subject: [PATCH 14/19] 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/19] 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/19] 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 0d8f7acb7e229507e5c924c85eb59a8978232f6f Mon Sep 17 00:00:00 2001 From: William Moberg Date: Thu, 10 Dec 2015 16:04:55 +0100 Subject: [PATCH 17/19] OctTree doesn't check the same object multiple times if it exists in multiple places in the tree. --- include/Engine/Core/OctTree.h | 80 +++++++++--- include/Game/HardcodedTestWorld.h | 5 +- src/Engine/Core/OctTree.cpp | 201 +++++++++++++++++++++++------- 3 files changed, 222 insertions(+), 64 deletions(-) diff --git a/include/Engine/Core/OctTree.h b/include/Engine/Core/OctTree.h index 27fbcba7..2a3b87b2 100644 --- a/include/Engine/Core/OctTree.h +++ b/include/Engine/Core/OctTree.h @@ -13,7 +13,21 @@ public: struct Output { float CollideDistance; - }; + }; + struct ContainedObject + { + ContainedObject() + : Box(AABB()) + , Checked(false) + {} + ContainedObject(AABB box) + : Box(box) + , Checked(false) + {} + AABB Box; + bool Checked; + }; + OctTree(); ~OctTree(); //For the root OctTree, [octTreeBounds] should be a box containing the entire level. @@ -24,41 +38,71 @@ public: OctTree(const OctTree& other) = delete; OctTree(const OctTree&& other) = delete; OctTree& operator= (const OctTree& other) = delete; - + //Add a dynamic object (one that moves around) into the tree. void AddDynamicObject(const AABB& box); + //Add a static object (that does not move) into the tree. void AddStaticObject(const AABB& box); - - void BoxesInSameRegion(const AABB& box, std::vector& outBoxes) const; - + //Get the boxes that are in the same area as the input [box], the boxes are put in [outBoxes]. + void BoxesInSameRegion(const AABB& box, std::vector& outBoxes); + //Empty the tree of all objects, static and dynamic. void ClearObjects(); + //Empty the tree of all dynamic objects. Static objects remain in the tree. void ClearDynamicObjects(); //Collision test function. WTODO: Probably remove or relocate elsewhere, Collision system? void Update(float dt, World* world, Camera* cam); //Returns true if the ray collides with something in the tree. Result is written to [data]. - bool RayCollides(const Ray& ray, Output& data) const; + bool RayCollides(const Ray& ray, Output& data); //Returns true if the box collides with something in the tree. //On collision with a box, that box is written to [outBoxIntersected]. //Note: More efficient than calling BoxesInSameRegion from outside and testing there. - bool BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const; + bool BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected); private: - OctTree* m_Children[8]; - //WTODO: Do -derived class from AABB- struct containing AABB, with a bool Tested, falsify at - //start of Collision test, set on check, don't check if set already. Solves duplicate boxes in tree. - //Store indices in the struct, pointing to grand ancestor list of boxes, need the same AABB not copies to save Tested. - std::vector m_StaticObjects; - std::vector m_DynamicObjects; - AABB m_Box; - + struct OctChild; + OctChild* m_Root; + std::vector m_StaticObjects; + std::vector m_DynamicObjects; + bool m_UpdatedOnce; unsigned int m_BoxID; glm::vec3 m_PrevPos; glm::quat m_PrevOri; - inline bool hasChildren() const; - int childIndexContainingPoint(const glm::vec3& point) const; - std::vector childIndicesContainingBox(const AABB& box) const; + void falsifyObjectChecks(); + + struct OctChild + { + ~OctChild(); + OctChild(const AABB& octTreeBounds, + int subDivisions, + std::vector& staticObjects, + std::vector& dynamicObjects); + OctChild(const OctChild& other) = delete; + OctChild(const OctChild&& other) = delete; + OctChild& operator= (const OctChild& other) = delete; + void AddDynamicObject(const AABB& box); + void AddStaticObject(const AABB& box); + void BoxesInSameRegion(const AABB& box, std::vector& outBoxes) const; + void ClearObjects(); + void ClearDynamicObjects(); + bool RayCollides(const Ray& ray, Output& data) const; + bool BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const; + + OctChild* m_Children[8]; + //Indices into the lists in OctTree. + std::vector m_StaticObjIndices; + std::vector m_DynamicObjIndices; + AABB m_Box; + //Reference to the lists in OctTree. + std::vector& m_StaticObjectsRef; + std::vector& m_DynamicObjectsRef; + + inline bool hasChildren() const; + int childIndexContainingPoint(const glm::vec3& point) const; + std::vector childIndicesContainingBox(const AABB& box) const; + }; }; + #endif \ No newline at end of file diff --git a/include/Game/HardcodedTestWorld.h b/include/Game/HardcodedTestWorld.h index 5f7cc5f6..dd132971 100644 --- a/include/Game/HardcodedTestWorld.h +++ b/include/Game/HardcodedTestWorld.h @@ -108,12 +108,15 @@ private: ComponentWrapper model = world.AttachComponent(entityDummyScene, "Model"); model["Resource"] = "Models/DummyScene.obj"; } + for (int i = 0; i < 16; ++i) { EntityID entityCollisionBox = world.CreateEntity(); ComponentWrapper transform = world.AttachComponent(entityCollisionBox, "Transform"); - transform["Position"] = glm::vec3(0.f, 2.f, 0.f); + transform["Position"] = glm::vec3(rand()%11-5, rand() % 11 - 5, rand() % 11 - 5); ComponentWrapper model = world.AttachComponent(entityCollisionBox, "Model"); model["Resource"] = "Models/Core/UnitBox.obj"; + float sc = 0.20f; + transform["Scale"] = glm::vec3(sc, sc, sc); ComponentWrapper collision = world.AttachComponent(entityCollisionBox, "Collision"); glm::vec3 pos = transform["Position"]; diff --git a/src/Engine/Core/OctTree.cpp b/src/Engine/Core/OctTree.cpp index 5fab6f04..63eba63e 100644 --- a/src/Engine/Core/OctTree.cpp +++ b/src/Engine/Core/OctTree.cpp @@ -38,11 +38,79 @@ OctTree::OctTree() {} OctTree::OctTree(const AABB& octTreeBounds, int subDivisions) - : m_Box(octTreeBounds) + : m_Root(new OctChild(octTreeBounds, subDivisions, m_StaticObjects, m_DynamicObjects)) , m_UpdatedOnce(false) +{} + +OctTree::~OctTree() +{ + delete m_Root; +} + +void OctTree::AddDynamicObject(const AABB& box) +{ + m_Root->AddDynamicObject(box); + m_DynamicObjects.push_back(box); +} + +void OctTree::AddStaticObject(const AABB& box) +{ + m_Root->AddStaticObject(box); + m_StaticObjects.push_back(box); +} + +void OctTree::BoxesInSameRegion(const AABB& box, std::vector& outBoxes) +{ + falsifyObjectChecks(); + m_Root->BoxesInSameRegion(box, outBoxes); +} + +void OctTree::ClearObjects() +{ + m_StaticObjects.clear(); + m_DynamicObjects.clear(); + m_Root->ClearObjects(); +} + +void OctTree::ClearDynamicObjects() +{ + m_DynamicObjects.clear(); + m_Root->ClearDynamicObjects(); +} + +bool OctTree::RayCollides(const Ray& ray, Output& data) +{ + falsifyObjectChecks(); + data.CollideDistance = -1; + return m_Root->RayCollides(ray, data); +} + +bool OctTree::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) +{ + falsifyObjectChecks(); + return m_Root->BoxCollides(boxToTest, outBoxIntersected); +} + +void OctTree::falsifyObjectChecks() +{ + for (auto& obj : m_StaticObjects) { + obj.Checked = false; + } + for (auto& obj : m_DynamicObjects) { + obj.Checked = false; + } +} + +OctTree::OctChild::OctChild(const AABB& octTreeBounds, + int subDivisions, + std::vector& staticObjects, + std::vector& dynamicObjects) + : m_Box(octTreeBounds) + , m_StaticObjectsRef(staticObjects) + , m_DynamicObjectsRef(dynamicObjects) { if (subDivisions == 0) { - for (OctTree*& c : m_Children) { + for (OctChild*& c : m_Children) { c = nullptr; } } else { @@ -78,14 +146,14 @@ OctTree::OctTree(const AABB& octTreeBounds, int subDivisions) minPos.z = parentMin.z; maxPos.z = parentCenter.z; } - m_Children[i] = new OctTree(AABB(minPos, maxPos), subDivisions); + m_Children[i] = new OctChild(AABB(minPos, maxPos), subDivisions, m_StaticObjectsRef, m_DynamicObjectsRef); } } } -OctTree::~OctTree() +OctTree::OctChild::~OctChild() { - for (OctTree*& c : m_Children) { + for (OctChild*& c : m_Children) { if (c != nullptr) { delete c; c = nullptr; @@ -95,19 +163,22 @@ OctTree::~OctTree() void OctTree::Update(float dt, World* world, Camera* cam) { - AABB aabb; for (ComponentWrapper& c : world->GetComponents("Collision")) { + AABB aabb; aabb.CreateFromCenter(c["BoxCenter"], c["BoxSize"]); - AddStaticObject(aabb); + AddDynamicObject(aabb); } const glm::vec4 redCol = glm::vec4(1, 0.2f, 0, 1); const glm::vec4 greenCol = glm::vec4(0.1f, 1.0f, 0.25f, 1); - const glm::vec3 boxSize = 0.1f*glm::vec3(1.0f, 1.0f, 1.0f); + const glm::vec4 blueCol = glm::vec4(0.1f, 0.05f, 0.95f, 1); + const glm::vec4 cyanCol = glm::vec4(0.1f, 0.9f, 0.85f, 1); + const glm::vec3 boxSize = 0.05f*glm::vec3(1.0f, 1.0f, 1.0f); if (!m_UpdatedOnce) { m_BoxID = world->CreateEntity(); ComponentWrapper transform = world->AttachComponent(m_BoxID, "Transform"); transform["Scale"] = boxSize; + ComponentWrapper model = world->AttachComponent(m_BoxID, "Model"); model["Resource"] = "Models/Core/UnitBox.obj"; m_UpdatedOnce = true; @@ -119,21 +190,24 @@ void OctTree::Update(float dt, World* world, Camera* cam) ComponentWrapper transform = world->GetComponent(m_BoxID, "Transform"); transform["Position"] = boxPos; ComponentWrapper model = world->GetComponent(m_BoxID, "Model"); - //if (BoxCollides(box, AABB())) { - if (Collision::AABBVsAABB(box, aabb)) { + bool collBox = BoxCollides(box, AABB()); + if (collBox) { cam->SetPosition(m_PrevPos); cam->SetOrientation(m_PrevOri); - model["Color"] = greenCol; + bool collRay = RayCollides({ cam->Position(), cam->Forward() }, Output()); + model["Color"] = collRay ? cyanCol : greenCol; + } else if (RayCollides({ cam->Position(), cam->Forward() }, Output())) { + model["Color"] = blueCol; } else { model["Color"] = redCol; } m_PrevPos = cam->Position(); m_PrevOri = cam->Orientation(); - ClearObjects(); + ClearDynamicObjects(); } -bool OctTree::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const +bool OctTree::OctChild::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const { if (hasChildren()) { for (int i : childIndicesContainingBox(boxToTest)) { @@ -141,25 +215,32 @@ bool OctTree::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const return true; } } else { - for (const auto& obj : m_StaticObjects) { - if (Collision::AABBVsAABB(boxToTest, obj)) { - outBoxIntersected = obj; - return true; + for (int i : m_StaticObjIndices) { + if (!m_StaticObjectsRef[i].Checked) { + const AABB& objBox = m_StaticObjectsRef[i].Box; + if (Collision::AABBVsAABB(boxToTest, objBox)) { + outBoxIntersected = objBox; + return true; + } + m_StaticObjectsRef[i].Checked = true; } } - for (const auto& obj : m_DynamicObjects) { - //If there is a collision and it is not testing against itself. - if (!isSameBoxProbably(boxToTest, obj) && - Collision::AABBVsAABB(boxToTest, obj)) { - outBoxIntersected = obj; - return true; + for (int i : m_DynamicObjIndices) { + if (!m_DynamicObjectsRef[i].Checked) { + const AABB& objBox = m_DynamicObjectsRef[i].Box; + if (!isSameBoxProbably(boxToTest, objBox) && + Collision::AABBVsAABB(boxToTest, objBox)) { + outBoxIntersected = objBox; + return true; + } + m_DynamicObjectsRef[i].Checked = true; } } } return false; } -bool OctTree::RayCollides(const Ray& ray, Output& data) const +bool OctTree::OctChild::RayCollides(const Ray& ray, Output& data) const { //If the node AABB is missed, everything it contains is missed. if (Collision::RayAABBIntr(ray, m_Box)) { @@ -182,19 +263,25 @@ bool OctTree::RayCollides(const Ray& ray, Output& data) const //Check against boxes in the node. float minDist = INFINITY; bool intersected = false; - for (const auto& obj : m_StaticObjects) { + for (int i : m_StaticObjIndices) { float dist; - if (Collision::RayVsAABB(ray, obj, dist)) { + //If we haven't tested against this object before, and the ray hits. + if (!m_StaticObjectsRef[i].Checked && + Collision::RayVsAABB(ray, m_StaticObjectsRef[i].Box, dist)) { minDist = std::min(dist, minDist); intersected = true; } + m_StaticObjectsRef[i].Checked = true; } - for (const auto& obj : m_DynamicObjects) { + for (int i : m_DynamicObjIndices) { float dist; - if (Collision::RayVsAABB(ray, obj, dist)) { + //If we haven't tested against this object before, and the ray hits. + if (!m_DynamicObjectsRef[i].Checked && + Collision::RayVsAABB(ray, m_DynamicObjectsRef[i].Box, dist)) { minDist = std::min(dist, minDist); intersected = true; } + m_DynamicObjectsRef[i].Checked = true; } data.CollideDistance = minDist; @@ -205,60 +292,84 @@ bool OctTree::RayCollides(const Ray& ray, Output& data) const } -void OctTree::AddDynamicObject(const AABB& box) +void OctTree::OctChild::AddDynamicObject(const AABB& box) { if (hasChildren()) { for (auto i : childIndicesContainingBox(box)) { m_Children[i]->AddDynamicObject(box); } } else { - m_DynamicObjects.push_back(box); + //Since it hasn't been added yet to the real object list, the index is after the last =size. + m_DynamicObjIndices.push_back(m_DynamicObjectsRef.size()); } } -void OctTree::AddStaticObject(const AABB& box) +void OctTree::OctChild::AddStaticObject(const AABB& box) { if (hasChildren()) { for (auto i : childIndicesContainingBox(box)) { m_Children[i]->AddStaticObject(box); } } else { - m_StaticObjects.push_back(box); + //Since it hasn't been added yet to the real object list, the index is after the last =size. + m_StaticObjIndices.push_back(m_StaticObjectsRef.size()); } } -void OctTree::BoxesInSameRegion(const AABB& box, std::vector& outBoxes) const +void OctTree::OctChild::BoxesInSameRegion(const AABB& box, std::vector& outBoxes) const { if (hasChildren()) { for (auto i : childIndicesContainingBox(box)) { m_Children[i]->BoxesInSameRegion(box, outBoxes); } } else { - outBoxes.insert(outBoxes.end(), m_StaticObjects.begin(), m_StaticObjects.end()); - outBoxes.insert(outBoxes.end(), m_DynamicObjects.begin(), m_DynamicObjects.end()); + int startIndex = outBoxes.size(); + int numDuplicates = 0; + outBoxes.resize(outBoxes.size() + m_StaticObjIndices.size() + m_DynamicObjIndices.size()); + for (size_t i = 0; i < m_StaticObjIndices.size(); ++i){ + ContainedObject& obj = m_StaticObjectsRef[m_StaticObjIndices[i]]; + if (obj.Checked) { + ++numDuplicates; + } else { + obj.Checked = true; + outBoxes[startIndex + i - numDuplicates] = obj.Box; + } + } + for (size_t i = 0; i < m_DynamicObjIndices.size(); ++i) { + ContainedObject& obj = m_DynamicObjectsRef[m_DynamicObjIndices[i]]; + if (obj.Checked) { + ++numDuplicates; + } else { + obj.Checked = true; + outBoxes[startIndex + i - numDuplicates] = obj.Box; + } + } + for (size_t i = 0; i < numDuplicates; ++i) { + outBoxes.pop_back(); + } } } -void OctTree::ClearObjects() +void OctTree::OctChild::ClearObjects() { if (hasChildren()) { - for (OctTree*& c : m_Children) { + for (OctChild*& c : m_Children) { c->ClearObjects(); } } else { - m_DynamicObjects.clear(); - m_StaticObjects.clear(); + m_DynamicObjIndices.clear(); + m_StaticObjIndices.clear(); } } -void OctTree::ClearDynamicObjects() +void OctTree::OctChild::ClearDynamicObjects() { if (hasChildren()) { - for (OctTree*& c : m_Children) { + for (OctChild*& c : m_Children) { c->ClearObjects(); } } else { - m_DynamicObjects.clear(); + m_DynamicObjIndices.clear(); } } @@ -274,13 +385,13 @@ void OctTree::ClearDynamicObjects() // x : - - - - + + + + // y : - - + + - - + + // z : - + - + - + - + -int OctTree::childIndexContainingPoint(const glm::vec3& point) const +int OctTree::OctChild::childIndexContainingPoint(const glm::vec3& point) const { const glm::vec3& c = m_Box.Center(); return (1 << 2) * (point.x >= c.x) | (1 << 1) * (point.y >= c.y) | (point.z >= c.z); } -std::vector OctTree::childIndicesContainingBox(const AABB& box) const +std::vector OctTree::OctChild::childIndicesContainingBox(const AABB& box) const { int minInd = childIndexContainingPoint(box.MinCorner()); int maxInd = childIndexContainingPoint(box.MaxCorner()); @@ -318,7 +429,7 @@ std::vector OctTree::childIndicesContainingBox(const AABB& box) const } } -inline bool OctTree::hasChildren() const +inline bool OctTree::OctChild::hasChildren() const { return m_Children[0] != nullptr; } \ No newline at end of file From 37f9ab232223a9aefa31c720d07f0dfd07740246 Mon Sep 17 00:00:00 2001 From: William Moberg Date: Thu, 10 Dec 2015 17:53:33 +0100 Subject: [PATCH 18/19] Quick fix for unit test compilation. --- src/Tests/WorldTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tests/WorldTest.cpp b/src/Tests/WorldTest.cpp index 4fd4ceed..8d92a328 100644 --- a/src/Tests/WorldTest.cpp +++ b/src/Tests/WorldTest.cpp @@ -64,7 +64,7 @@ BOOST_AUTO_TEST_CASE(WorldTestMultipleAllocations, * utf::tolerance(0.00001)) // Loop through them and check data int i = 0; - for (auto& c : w.GetComponents("Test")) { + for (auto& c : *w.GetComponents("Test")) { BOOST_TEST((int)c["TestInteger"] == i); i++; } From 4195baa5dca6a31eca4d83ce7df6a9cfc7eba022 Mon Sep 17 00:00:00 2001 From: William Moberg Date: Thu, 10 Dec 2015 17:57:09 +0100 Subject: [PATCH 19/19] ContainedObject in OctTree made private. --- include/Engine/Core/OctTree.h | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/include/Engine/Core/OctTree.h b/include/Engine/Core/OctTree.h index 2a3b87b2..a3715480 100644 --- a/include/Engine/Core/OctTree.h +++ b/include/Engine/Core/OctTree.h @@ -14,19 +14,6 @@ public: { float CollideDistance; }; - struct ContainedObject - { - ContainedObject() - : Box(AABB()) - , Checked(false) - {} - ContainedObject(AABB box) - : Box(box) - , Checked(false) - {} - AABB Box; - bool Checked; - }; OctTree(); ~OctTree(); @@ -59,7 +46,20 @@ public: bool BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected); private: - struct OctChild; + struct OctChild; //Fwd declaration; + struct ContainedObject + { + ContainedObject() + : Box(AABB()) + , Checked(false) + {} + ContainedObject(AABB box) + : Box(box) + , Checked(false) + {} + AABB Box; + bool Checked; + }; OctChild* m_Root; std::vector m_StaticObjects; std::vector m_DynamicObjects;