Merge remote-tracking branch 'origin/master' into Rendering

This commit is contained in:
Tleety
2015-12-03 18:15:56 +01:00
19 changed files with 1087 additions and 4 deletions
+1
View File
@@ -9,6 +9,7 @@ Libraries bundled along with binaries for Windows (MSVC14), available as a submo
| **[Assimp](http://assimp.sourceforge.net)** | 3.1.1 | [BSD 3-Clause License](http://assimp.sourceforge.net/main_license.html) |
| **[zlib](http://www.zlib.net)** | 1.28 | [zlib License](http://www.zlib.net/zlib_license.html) |
| **[libpng](http://www.libpng.org/pub/png/libpng.html)** | 1.6.19 | [libpng License](http://www.libpng.org/pub/png/src/libpng-LICENSE.txt) |
| **[Xerces-C++](https://xerces.apache.org/xerces-c)** | 3.1.2 | [Apache License Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) |
#### External libraries
Libraries that are too big to be bundled with the project.
+23
View File
@@ -0,0 +1,23 @@
# XERCES_FOUND
# XERCES_INCLUDE_DIRS
# XERCES_LIBRARIES
find_path(XERCES_INCLUDE_DIR xercesc/dom/dom.hpp
/usr/local/include
/usr/include
)
find_library(XERCES_LIBRARY
NAMES
xerces-c_3
xerces-c_3D
PATHS
/usr/local/lib
/usr/lib
)
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)
+1 -1
Submodule deps updated: 65d3f3bc31...1b478d3159
+31
View File
@@ -0,0 +1,31 @@
#ifndef ComponentInfo_h__
#define ComponentInfo_h__
#include "../Common.h"
struct ComponentInfo
{
struct Meta_t
{
std::string Annotation;
unsigned int Allocation = 0;
unsigned int Stride = 0;
};
std::string Name;
std::unordered_map<std::string, std::string> FieldTypes;
std::unordered_map<std::string, unsigned int> FieldOffsets;
Meta_t Meta;
std::shared_ptr<char> Defaults = nullptr;
};
template<>
struct std::hash<ComponentInfo>
{
inline std::size_t operator()(const ComponentInfo& v) const
{
return std::hash<std::string>()(v.Name);
}
};
#endif
+80
View File
@@ -0,0 +1,80 @@
#ifndef ComponentPool_h__
#define ComponentPool_h__
#include "MemoryPool.h"
#include "ComponentInfo.h"
#include "ComponentWrapper.h"
class ComponentPoolForwardIterator
: public std::iterator<std::forward_iterator_tag, ComponentWrapper>
{
public:
ComponentPoolForwardIterator(const ComponentInfo& componentInfo, const MemoryPool<char>::iterator begin, const MemoryPool<char>::iterator end)
: m_ComponentInfo(componentInfo)
, m_MemoryPoolIterator(begin)
, m_MemoryPoolEnd(end)
{ }
ComponentPoolForwardIterator(const ComponentPoolForwardIterator& other) = default;
ComponentPoolForwardIterator(ComponentPoolForwardIterator&& other) = default;
~ComponentPoolForwardIterator() = default;
ComponentPoolForwardIterator& operator=(const ComponentPoolForwardIterator& other) = default;
ComponentPoolForwardIterator& operator++();
ComponentPoolForwardIterator& operator++(int);
bool operator!=(const ComponentPoolForwardIterator& other) const;
bool operator==(const ComponentPoolForwardIterator& other) const;
ComponentWrapper operator*() const;
private:
const ComponentInfo& m_ComponentInfo;
MemoryPool<char>::iterator m_MemoryPoolIterator;
const MemoryPool<char>::iterator m_MemoryPoolEnd;
};
class ComponentPool
{
public:
typedef ComponentPoolForwardIterator iterator;
typedef ptrdiff_t difference_type;
typedef size_t size_type;
typedef ComponentWrapper value_type;
typedef ComponentWrapper* pointer;
typedef ComponentWrapper& reference;
ComponentPool(const ::ComponentInfo& ci)
: m_ComponentInfo(ci)
, m_Pool(ci.Meta.Allocation, sizeof(EntityID) + ci.Meta.Stride)
{ }
ComponentPool(const ComponentPool& other) = delete;
ComponentPool(const ComponentPool&& other) = delete;
const ::ComponentInfo& ComponentInfo() const { return m_ComponentInfo; }
// Allocate space for a component and store which entity it belongs to in internal structure
ComponentWrapper Allocate(EntityID entity);
// Get the component belonging to a specific entity
ComponentWrapper GetByEntity(EntityID ent);
// Delete a component and free its memory
void Delete(ComponentWrapper& wrapper);
iterator begin() const;
iterator end() const;
//Dumps information about what the pool memory looks like right now
//into an output stream (e.g. file/std::cout, anything that has an operator<<)
//Interpret the data in the memory as InterpretType.
template <typename InterpretType = char, typename OutStream>
void Dump(OutStream& out) const;
//Dumps information about what the pool memory looks like right now
//into std::cout. Interpret the data in the memory as InterpretType.
template <typename InterpretType = char>
void Dump() const;
private:
::ComponentInfo m_ComponentInfo;
MemoryPool<char> m_Pool;
std::unordered_map<EntityID, char*> m_EntityToComponent;
};
#endif
+65
View File
@@ -0,0 +1,65 @@
#ifndef ComponentWrapper_h__
#define ComponentWrapper_h__
#include "../Common.h"
#include "EntityWrapper.h"
#include "ComponentInfo.h"
struct ComponentWrapper
{
ComponentWrapper(const ComponentInfo& componentInfo, char* data)
: Info(componentInfo)
, EntityID(*reinterpret_cast<::EntityID*>(data))
, Data(data + sizeof(EntityID))
{ }
const ComponentInfo& Info;
const ::EntityID EntityID;
char* Data;
template <typename T>
T& Property(std::string name)
{
unsigned int offset = Info.FieldOffsets.at(name);
return *reinterpret_cast<T*>(&Data[offset]);
}
template <typename T>
void SetProperty(std::string name, const T value) { Property<T>(name) = value; }
//template <typename T>
//void SetProperty(std::string name, T& value) { Property<T>(name) = value; }
// Specialization for string literals
template <std::size_t N>
void SetProperty(std::string name, const char(&value)[N]) { Property<std::string>(name) = std::string(value); }
struct SubscriptProxy
{
friend struct ComponentWrapper;
private:
SubscriptProxy(ComponentWrapper* component, std::string propertyName)
: m_Component(component)
, m_PropertyName(propertyName)
{ }
ComponentWrapper* m_Component;
std::string m_PropertyName;
public:
template <typename T>
operator T&() { return m_Component->Property<T>(m_PropertyName); }
template <typename T>
void operator=(const T val) { m_Component->SetProperty<T>(m_PropertyName, val); }
// TODO: Pass by reference and rvalue (universal reference?)
//template <typename T>
//void operator=(T& val) { m_Component->SetProperty<T>(m_PropertyName, val); }
// Specialization for string literals
template<std::size_t N>
void operator=(const char(&val)[N]) { m_Component->SetProperty<N>(m_PropertyName, val); }
};
SubscriptProxy operator[](std::string propertyName) { return SubscriptProxy(this, propertyName); }
};
#endif
+480
View File
@@ -0,0 +1,480 @@
#include "../Common.h"
#include <sstream>
#include "../GLM.h"
#include <boost/filesystem.hpp>
#include <boost/utility/string_ref.hpp>
#include <xercesc/dom/DOM.hpp>
#include <xercesc/dom/DOMLSInput.hpp>
#include <xercesc/dom/DOMElement.hpp>
#include <xercesc/framework/Wrapper4InputSource.hpp>
#include <xercesc/framework/LocalFileInputSource.hpp>
#include <xercesc/framework/LocalFileFormatTarget.hpp>
#include <xercesc/framework/MemBufFormatTarget.hpp>
#include <xercesc/framework/MemBufInputSource.hpp>
#include <xercesc/sax/HandlerBase.hpp>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/util/XMLFloat.hpp>
#include <xercesc/framework/XMLGrammarPoolImpl.hpp>
#include <xercesc/parsers/XercesDOMParser.hpp>
#include <xercesc/framework/psvi/XSElementDeclaration.hpp>
#include <xercesc/framework/psvi/XSComplexTypeDefinition.hpp>
#include <xercesc/framework/psvi/XSParticle.hpp>
#include <xercesc/framework/psvi/XSModelGroup.hpp>
#include <xercesc/framework/psvi/XSAnnotation.hpp>
#include <xercesc/framework/psvi/XSValue.hpp>
#include <xercesc/framework/XMLValidator.hpp>
#include "EntityWrapper.h"
#include "ComponentWrapper.h"
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;
};
struct ComponentPool
{
std::string ComponentName;
unsigned int Size = 0;
unsigned int Stride = 0;
ComponentInfo Info;
char* Data = nullptr;
// TODO: Iterators
ComponentWrapper at(unsigned int index)
{
// TODO: EntityID
return ComponentWrapper(0, &Info, Data + (index*Stride));
}
};
class EntityFactory
{
public:
EntityFactory(std::string entityFile)
: m_EntityFile(entityFile)
{
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);
}
~EntityFactory()
{
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 Preprocess(boost::filesystem::path inPath, boost::filesystem::path outPath)
{
using namespace xercesc;
static const XMLCh gLS[] = { 'L', 'S', '\0' };
DOMImplementationLS* di = static_cast<DOMImplementationLS*>(DOMImplementationRegistry::getDOMImplementation(gLS));
// Parse the file
DOMLSParser* parser = di->createLSParser(DOMImplementationLS::MODE_SYNCHRONOUS, nullptr);
DOMConfiguration* config = parser->getDomConfig();
config->setParameter(XMLUni::fgDOMNamespaces, true);
config->setParameter(XMLUni::fgXercesSchema, true);
config->setParameter(XMLUni::fgXercesHandleMultipleImports, true);
config->setParameter(XMLUni::fgXercesSchemaFullChecking, true);
config->setParameter(XMLUni::fgXercesDoXInclude, true);
auto errHandler = new EntityPreprocessorXMLErrorHandler();
config->setParameter(XMLUni::fgDOMErrorHandler, errHandler);
auto source = new LocalFileInputSource(XSTR(inPath.string().c_str()));
Wrapper4InputSource* domSourceWrapper = new Wrapper4InputSource(source);
DOMDocument* doc = parser->parse(dynamic_cast<DOMLSInput*>(domSourceWrapper));
// Serialize and output the new XML
DOMLSSerializer* writer = di->createLSSerializer();
DOMLSOutput* output = di->createLSOutput();
XMLFormatTarget* formatTarget = new LocalFileFormatTarget(outPath.string().c_str());
// TODO: MemBufFormatTarget* formatTarget = new MemBufFormatTarget()
output->setByteStream(formatTarget);
writer->write(doc, output);
delete formatTarget;
output->release();
writer->release();
parser->release();
}
void Parse()
{
// HACK: Use Sax2 parser instead so the whole 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
AllocateComponentStore();
// 4. Parse entity hierarchy
ParseEntityGraph();
}
private:
static unsigned int InstanceCount;
std::string m_EntityFile;
xercesc::XMLGrammarPool* m_GrammarPool = nullptr;
EntityParserXMLErrorHandler* m_ErrorHandler = nullptr;
xercesc::XercesDOMParser* m_DOMParser = nullptr;
xercesc::DOMDocument* m_DOMDocument = nullptr;
std::map<std::string, ComponentInfo> m_ComponentInfo;
public:
std::map<std::string, ComponentPool> m_ComponentStore;
std::vector<EntityWrapper*> m_Entities;
private:
/*
Preprocess an XML file and output a new one
where xsi:includes are processed, since apparently
Xerces can't handle processing includes before validating schema.
*/
void ParseComponentInfo()
{
using namespace xercesc;
bool wasChanged;
XSModel* xsModel = m_GrammarPool->getXSModel(wasChanged);
// Find component xsd element declarations
std::cout << "Enumerating components..." << std::endl;
// <xs:element name="ComponentName">
auto topLevelElements = xsModel->getComponents(XSConstants::ELEMENT_DECLARATION);
for (unsigned int i = 0; i < topLevelElements->getLength(); ++i) {
auto element = static_cast<XSElementDeclaration*>(topLevelElements->item(i));
std::string nameSpace(XSTR(element->getNamespace()));
if (nameSpace != "components") {
continue;
}
ComponentInfo compInfo;
// Name
compInfo.Name = XSTR(element->getName());
// Annotation
auto componentAnnotation = element->getAnnotation();
if (componentAnnotation != nullptr) {
// Parse annotation XML
char* annotationString = XMLString::transcode(componentAnnotation->getAnnotationString());
MemBufInputSource annotationInput(reinterpret_cast<const XMLByte*>(annotationString), strlen(annotationString), "MemBuf: Annotation String");
XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager, m_GrammarPool);
parser.setErrorHandler(m_ErrorHandler);
parser.parse(annotationInput);
XMLString::release(&annotationString);
auto doc = parser.getDocument();
// Add allocation estimation(s)
auto allocationTags = doc->getElementsByTagName(XSTR("meta:allocation"));
for (int i = 0; i < allocationTags->getLength(); ++i) {
auto allocation = dynamic_cast<DOMElement*>(allocationTags->item(i));
auto child = allocation->getFirstChild();
if (child == nullptr) {
continue;
}
XSValue::Status status;
XSValue* val = XSValue::getActualValue(child->getNodeValue(), XSValue::dt_integer, status);
compInfo.Meta.Allocation += val->fData.fValue.f_int;
}
// Save documentation string
auto documentationTags = doc->getElementsByTagName(XSTR("xs:documentation"));
if (documentationTags->getLength() != 0) {
auto child = documentationTags->item(0)->getFirstChild();
if (child != nullptr) {
compInfo.Meta.Annotation = XSTR(child->getNodeValue());
}
}
// TODO: Parse annotation string XML
// compInfo.Meta.Allocation = ...
} else {
std::cout << "Warning: Component is missing an annotation!" << std::endl;
}
// <xs:complexType>
auto typeDefinition = element->getTypeDefinition();
if (typeDefinition->getTypeCategory() != XSTypeDefinition::COMPLEX_TYPE) {
std::cerr << "Error: Type definition wasn't COMPLEX_TYPE! Skipping." << std::endl;
continue;
}
auto complexTypeDefinition = dynamic_cast<XSComplexTypeDefinition*>(typeDefinition);
// <xs:all>
auto modelGroupParticle = complexTypeDefinition->getParticle();
if (modelGroupParticle->getTermType() != XSParticle::TERM_MODELGROUP) {
std::cerr << "Error: Model group particle wasn't TERM_MODELGROUP! Skipping." << std::endl;
continue;
}
auto modelGroup = modelGroupParticle->getModelGroupTerm();
// <xs:element...
// <xs:attribute...
unsigned int fieldOffset = 0;
auto particles = modelGroup->getParticles();
for (unsigned int i = 0; i < particles->size(); ++i) {
auto particle = particles->elementAt(i);
if (particle->getTermType() != XSParticle::TERM_ELEMENT) {
std::cerr << "Error: Particle wasn't TERM_ELEMENT! Skipping." << std::endl;
continue;
}
auto elementDeclaration = particle->getElementTerm();
std::string name = XSTR(elementDeclaration->getName());
std::string type = XSTR(elementDeclaration->getTypeDefinition()->getName());
size_t stride = getTypeStride(type);
if (stride == 0) {
std::cout << "Warning: Field \"" << name << "\" in component \"" << compInfo.Name << "\" uses unexpected field type \"" << type << "\". Skipping." << std::endl;
continue;
}
compInfo.FieldTypes[name] = type;
compInfo.FieldOffsets[name] = fieldOffset;
fieldOffset += getTypeStride(type);
}
compInfo.Meta.Stride = fieldOffset;
m_ComponentInfo[compInfo.Name] = compInfo;
}
}
void ParseDefaults()
{
}
void AllocateComponentStore()
{
using namespace xercesc;
auto root = m_DOMDocument->getDocumentElement();
// Count static instances of components present in entity hierarchy
auto components = m_DOMDocument->getElementsByTagNameNS(XSTR("components"), XSTR("*"));
for (int i = 0; i < components->getLength(); ++i) {
auto component = dynamic_cast<DOMElement*>(components->item(i));
std::string componentName = XSTR(component->getLocalName());
auto& compInfo = m_ComponentInfo.at(componentName);
compInfo.Meta.Allocation += 1;
}
std::cout << "COMPONENT INFO" << std::endl;
for (auto& pair : m_ComponentInfo) {
ComponentInfo& ci = pair.second;
std::cout << "Component: " << ci.Name << " (" << ci.Meta.Annotation << ")" << std::endl;
std::cout << " Allocation: " << ci.Meta.Allocation << std::endl;
std::cout << " Fields:" << std::endl;
// Calculate component size
unsigned int stride = 0;
// Reserve space for Entity pointer
stride += sizeof(EntityWrapper*);
std::cout << " Entity " << " (" << sizeof(EntityWrapper*) << " byte)" << std::endl;
// 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: " << stride << std::endl;
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 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<DOMElement*>(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<DOMElement*>(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<char*>(&standardString), getTypeStride(fieldType));
} else {
XSValue::Status status;
XSValue* val = XSValue::getActualValue(field->getTextContent(), dataType, status);
memcpy(&data[fieldOffset], reinterpret_cast<char*>(&val->fData.fValue), getTypeStride(fieldType));
}
}
}
auto entities = m_DOMDocument->getElementsByTagName(XSTR("Entity"));
for (int i = 0; i < entities->getLength(); ++i) {
auto entity = dynamic_cast<DOMElement*>(entities->item(i));
//entity->setIdAttribute()
std::cout << "ENTITY " << i + 1 << std::endl;
}
}
size_t getTypeStride(std::string typeName)
{
std::map<std::string, size_t> 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;
}
};
unsigned int EntityFactory::InstanceCount = 0;
+12
View File
@@ -0,0 +1,12 @@
#include "ResourceManager.h"
class EntityFile : public Resource
{
friend class ResourceManager;
private:
EntityFile(std::string path);
public:
};
+15
View File
@@ -0,0 +1,15 @@
#ifndef Entity_h__
#define Entity_h__
typedef unsigned int EntityID;
struct EntityWrapper
{
EntityWrapper(EntityID entityID)
: ID(entityID)
{ }
EntityID ID;
};
#endif
+1
View File
@@ -32,6 +32,7 @@ public:
typedef T value_type;
typedef T* pointer;
typedef T& reference;
MemoryPool()
: m_StartAddress(nullptr)
, m_SlotIsAllocated()
+36
View File
@@ -0,0 +1,36 @@
#ifndef World_h__
#define World_h__
#include "../Common.h"
#include "EntityWrapper.h"
#include "ObjectPool.h"
#include "ComponentPool.h"
class World
{
public:
World() = default;
~World();
EntityID CreateEntity(EntityID parent = 0);
// Register a component type and allocate space for it
void RegisterComponent(ComponentInfo& ci);
// Attach a component to an entity and fill it with default values
ComponentWrapper AttachComponent(EntityID entity, std::string componentType);
// 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);
private:
EntityID m_CurrentEntityID = 0;
std::unordered_map<EntityID, EntityID> m_EntityParents;
std::unordered_multimap<EntityID, EntityID> m_EntityChildren;
std::unordered_map<std::string, ComponentPool*> m_ComponentPools;
EntityID generateEntityID();
};
#endif
+3 -3
View File
@@ -3,12 +3,11 @@
#include "Core/ResourceManager.h"
#include "Core/ConfigFile.h"
#include "Core/EventBroker.h"
#include "Rendering/Renderer.h"
#include "Core/InputManager.h"
#include "GUI/Frame.h"
#include "Core/World.h"
class Game
{
@@ -26,6 +25,7 @@ private:
IRenderer* m_Renderer;
InputManager* m_InputManager;
GUI::Frame* m_FrameStack;
World* m_World;
};
#endif
#endif
+124
View File
@@ -0,0 +1,124 @@
#include <list>
#include <tuple>
#include <boost/any.hpp>
#include "GLM.h"
#include "Core/World.h"
struct any
{
any() { }
template <typename T>
any(const T& value)
{
Buffer = std::shared_ptr<char>(new char[sizeof(T)]);
memcpy(Buffer.get(), &value, sizeof(T));
}
template <typename T>
any(T&& value)
{
Buffer = std::shared_ptr<char>(new char[sizeof(T)]);
memcpy(Buffer.get(), &value, sizeof(T));
}
template <typename T>
any& operator=(const T& value)
{
return any(value);
}
template <typename T>
any& operator=(T&& value)
{
return any(value);
}
std::shared_ptr<char> Buffer = nullptr;
};
class HardcodedTestWorld : public World
{
public:
HardcodedTestWorld()
: World()
{
registerTestComponents();
createTestEntities();
}
private:
void registerTestComponents()
{
std::unordered_map<std::string, std::list<std::tuple<std::size_t, std::string, any>>> components
{
{
"Test",
{
std::make_tuple(sizeof(int), "TestInteger", 1337),
std::make_tuple(sizeof(float), "TestFloat", 13.37f)
}
},
{
"Debug",
{
std::make_tuple(sizeof(std::string), "Name", std::string("Unnamed")),
std::make_tuple(sizeof(glm::vec3), "PickingColor", glm::vec3(0.f))
}
},
{
"Transform",
{
std::make_tuple(sizeof(glm::vec3), "Position", glm::vec3(0.f, 0.f, 0.f)),
std::make_tuple(sizeof(glm::quat), "Orientation", glm::quat()),
std::make_tuple(sizeof(glm::vec3), "Scale", glm::vec3(1.f, 1.f, 1.f))
}
}
};
for (auto& c : components) {
ComponentInfo ci;
ci.Name = c.first;
// Fields
unsigned int stride = 0;
for (auto& f : c.second) {
stride += std::get<0>(f);
}
ci.Meta.Stride = stride;
ci.Defaults = std::shared_ptr<char>(new char[stride]);
unsigned int offset = 0;
for (auto& f : c.second) {
std::size_t size;
std::string fieldName;
any defaultValue;
std::tie(size, fieldName, defaultValue) = f;
ci.FieldOffsets[fieldName] = offset;
ci.FieldTypes[fieldName] = "undefined";
memcpy(ci.Defaults.get() + offset, defaultValue.Buffer.get(), size);
offset += size;
}
RegisterComponent(ci);
}
}
void createTestEntities()
{
EntityID e = CreateEntity();
AttachComponent(e, "Test");
AttachComponent(e, "Debug");
AttachComponent(e, "Transform");
ComponentWrapper testComponent = GetComponent(e, "Test");
int testValue = testComponent["TestInteger"];
float testFloat = testComponent["TestFloat"];
ComponentWrapper debugComponent = GetComponent(e, "Debug");
std::string name = debugComponent["Name"];
glm::vec3 pickingColor = debugComponent["PickingColor"];
ComponentWrapper testTransform = GetComponent(e, "Transform");
glm::vec3 pos = testTransform["Position"];
glm::quat ori = testTransform["Orientation"];
glm::vec3 scale = testTransform["Scale"];
}
};
+3
View File
@@ -7,6 +7,7 @@ find_package(Boost REQUIRED COMPONENTS system filesystem thread chrono)
find_package(assimp REQUIRED)
find_package(ZLIB REQUIRED)
find_package(PNG REQUIRED)
find_package(Xerces REQUIRED)
# Because FindOpenAL is retarded
#set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "${CMAKE_SOURCE_DIR}/deps/include/AL")
#find_package(OpenAL REQUIRED)
@@ -23,6 +24,7 @@ include_directories(
${Boost_INCLUDE_DIRS}
${assimp_INCLUDE_DIRS}
${PNG_INCLUDE_DIRS}
${Xerces_INCLUDE_DIRS}
${OPENAL_INCLUDE_DIR}
${X11_INCLUDE_DIRS}
)
@@ -78,6 +80,7 @@ set(LIBRARIES
${Boost_LIBRARIES}
${assimp_LIBRARIES}
${PNG_LIBRARIES}
${Xerces_LIBRARIES}
${OPENAL_LIBRARY}
${X11_LIBRARIES}
)
+79
View File
@@ -0,0 +1,79 @@
#include "Core/ComponentPool.h"
ComponentWrapper ComponentPoolForwardIterator::operator*() const
{
char* data = &(*m_MemoryPoolIterator);
ComponentWrapper wrapper(m_ComponentInfo, data);
return wrapper;
}
bool ComponentPoolForwardIterator::operator==(const ComponentPoolForwardIterator& other) const
{
return m_MemoryPoolIterator == other.m_MemoryPoolIterator;
}
bool ComponentPoolForwardIterator::operator!=(const ComponentPoolForwardIterator& other) const
{
return m_MemoryPoolIterator != other.m_MemoryPoolIterator;
}
ComponentPoolForwardIterator& ComponentPoolForwardIterator::operator++(int)
{
ComponentPoolForwardIterator copyIter(*this);
operator++();
return copyIter;
}
ComponentPoolForwardIterator& ComponentPoolForwardIterator::operator++()
{
++m_MemoryPoolIterator;
return *this;
}
//const ::ComponentInfo& ComponentPool::ComponentInfo() const
//{
// return m_ComponentInfo;
//}
ComponentWrapper ComponentPool::Allocate(EntityID entity)
{
char* data = m_Pool.Allocate();
memcpy(data, &entity, sizeof(EntityID));
m_EntityToComponent[entity] = data;
return ComponentWrapper(m_ComponentInfo, data);
}
ComponentWrapper ComponentPool::GetByEntity(EntityID ent)
{
return ComponentWrapper(m_ComponentInfo, m_EntityToComponent.at(ent));
}
void ComponentPool::Delete(ComponentWrapper& wrapper)
{
m_EntityToComponent.erase(wrapper.EntityID);
m_Pool.Free(wrapper.Data);
}
ComponentPool::iterator ComponentPool::begin() const
{
return iterator(m_ComponentInfo, m_Pool.begin(), m_Pool.end());
}
ComponentPool::iterator ComponentPool::end() const
{
return iterator(m_ComponentInfo, m_Pool.end(), m_Pool.end());
}
template <typename InterpretType /*= char*/>
void ComponentPool::Dump() const
{
m_Pool.Dump<InterpretType>();
}
template <typename InterpretType /*= char*/, typename OutStream>
void ComponentPool::Dump(OutStream& out) const
{
m_Pool.Dump<InterpretType>(out);
}
+54
View File
@@ -0,0 +1,54 @@
#include "Core/World.h"
World::~World()
{
for (auto& pool : m_ComponentPools) {
delete pool.second;
}
}
EntityID World::CreateEntity(EntityID parent /*= 0*/)
{
EntityID newEntity = generateEntityID();
m_EntityParents[newEntity] = parent;
if (parent != 0) {
m_EntityChildren.insert(std::make_pair(parent, newEntity));
}
return newEntity;
}
void World::RegisterComponent(ComponentInfo& ci)
{
m_ComponentPools[ci.Name] = new ComponentPool(ci);
}
ComponentWrapper World::AttachComponent(EntityID entity, std::string componentType)
{
ComponentPool* pool = m_ComponentPools.at(componentType);
const ComponentInfo& ci = pool->ComponentInfo();
// Allocate space for the component
ComponentWrapper c = pool->Allocate(entity);
// Write default values
memcpy(c.Data, ci.Defaults.get(), ci.Meta.Stride);
return c;
}
ComponentWrapper World::GetComponent(EntityID entity, std::string componentType)
{
ComponentPool* pool = m_ComponentPools.at(componentType);
return pool->GetByEntity(entity);
}
const ComponentPool& World::GetComponents(std::string componentType)
{
return *m_ComponentPools.at(componentType);
}
EntityID World::generateEntityID()
{
// TODO: Make EntityID generation smarter
return m_CurrentEntityID++;
}
+4
View File
@@ -1,4 +1,5 @@
#include "Game.h"
#include "HardcodedTestWorld.h"
Game::Game(int argc, char* argv[])
{
@@ -32,6 +33,9 @@ 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();
m_LastTime = glfwGetTime();
}
+34
View File
@@ -0,0 +1,34 @@
#include <boost/test/unit_test.hpp>
#include "Core/ComponentPool.h"
BOOST_AUTO_TEST_CASE(ComponentPoolTest)
{
// TODO: Write an updated test for component pool
BOOST_CHECK(false);
//ComponentInfo ci;
//ci.Name = "Test";
//ci.FieldTypes["Field"] = "int";
//ci.FieldOffsets["Field"] = 0;
//ci.Meta.Allocation = 3;
//ci.Meta.Stride = sizeof(EntityID) + sizeof(int);
//std::vector<ComponentWrapper> wrappers;
//ComponentPool pool(ci);
//for (int i = 0; i < 4; i++) {
// ComponentWrapper c = pool.New();
// c.EntityID = i;
// unsigned int offset = c.Info.FieldOffsets.at("Field");
// memcpy(&c.Data[offset], &i, sizeof(int));
// wrappers.push_back(c);
//}
//int i = 0;
//for (auto& c : pool) {
// BOOST_CHECK(c.EntityID == i);
// BOOST_CHECK((int)c["Field"] == i);
// i++;
//}
//pool.Delete(wrappers[1]);
}
+41
View File
@@ -0,0 +1,41 @@
#include <boost/test/unit_test.hpp>
#include "Common.h"
#include "Core/World.h"
BOOST_AUTO_TEST_CASE(WorldTest)
{
ComponentInfo ci;
ci.Name = "Test";
ci.FieldTypes["Field"] = "int";
ci.FieldOffsets["Field"] = 0;
ci.Meta.Stride = sizeof(int);
ci.Meta.Allocation = 3;
ci.Defaults = std::shared_ptr<char>(new char[ci.Meta.Stride]);
int default_Field = 1337;
memcpy(ci.Defaults.get(), &default_Field, ci.Meta.Stride);
World w;
w.RegisterComponent(ci);
std::vector<EntityID> ids;
for (int i = 0; i < 6; i++) {
EntityID e = w.CreateEntity();
ids.push_back(e);
w.AttachComponent(e, "Test");
ComponentWrapper c = w.GetComponent(e, "Test");
BOOST_CHECK(c.EntityID == e);
BOOST_CHECK((int)c["Field"] == 1337);
c.SetProperty("Field", i);
BOOST_CHECK((int)c["Field"] == i);
}
int i = 0;
for (auto& c : w.GetComponents("Test")) {
EntityID e = ids.at(i);
BOOST_CHECK(c.EntityID == e);
BOOST_CHECK((int)c["Field"] == i);
i++;
}
}