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

# Conflicts:
#	include/Engine/Core/ComponentWrapper.h
#	include/Game/PlayerSystem.h
#	include/Game/Systems/HealthSystem.h
#	resources/Schema/Components.xsd
#	resources/Schema/Components/Player.xml
#	resources/Schema/Types/Entity.xsd
#	src/Game/PlayerSystem.cpp
#	src/Tests/HealthSystemTest.cpp
#	src/Tests/OctTreeTestAnders.cpp
#	src/Tests/OctTreeTestGameClass.cpp
#	src/Tests/OctTreeTestGameClass.h
#	src/Tests/OctTreeTestHardCodedTestWorld.h
This commit is contained in:
verysecrethero
2016-01-20 17:53:33 +01:00
212 changed files with 7248 additions and 2556 deletions
+3 -3
View File
@@ -11,18 +11,18 @@ public:
AABB(const glm::vec3& minPos, const glm::vec3& maxPos);
AABB(const glm::vec4& minPos, const glm::vec4& maxPos);
//No checks are made. Size must consist of non-negative numbers.
virtual void CreateFromCenter(const glm::vec3& center, const glm::vec3& size);
static AABB FromOriginSize(const glm::vec3& origin, const glm::vec3& size);
virtual ~AABB();
const glm::vec3& MinCorner() const { return m_MinCorner; }
const glm::vec3& MaxCorner() const { return m_MaxCorner; }
const glm::vec3& Center() const { return m_Center; }
const glm::vec3& Origin() const { return m_Origin; }
const glm::vec3 Size() const { return 2.0f * m_HalfSize; }
const glm::vec3& HalfSize() const { return m_HalfSize; }
private:
glm::vec3 m_MinCorner;
glm::vec3 m_MaxCorner;
glm::vec3 m_Center;
glm::vec3 m_Origin;
glm::vec3 m_HalfSize;
};
+6 -3
View File
@@ -9,11 +9,13 @@ struct ComponentInfo
{
std::string Annotation;
unsigned int Allocation = 0;
unsigned int Stride = 0;
std::map<std::string, std::string> FieldAnnotations;
std::map<std::string, std::map<std::string, int>> FieldEnumDefinitions;
};
struct Field_t
{
std::string Name;
std::string Type;
unsigned int Offset;
unsigned int Stride;
@@ -21,9 +23,10 @@ struct ComponentInfo
std::string Name;
std::unordered_map<std::string, Field_t> Fields;
std::vector<const Field_t*> FieldsInOrder;
Meta_t Meta;
std::vector<std::string> FieldsInOrder;
unsigned int Stride = 0;
std::shared_ptr<char> Defaults = nullptr;
std::shared_ptr<Meta_t> Meta = nullptr;
};
template<>
+2 -1
View File
@@ -43,7 +43,7 @@ public:
ComponentPool(const ::ComponentInfo& ci)
: m_ComponentInfo(ci)
, m_Pool(ci.Meta.Allocation, sizeof(EntityID) + ci.Meta.Stride)
, m_Pool(ci.Meta->Allocation, sizeof(EntityID) + ci.Stride)
{ }
ComponentPool(const ComponentPool& other) = delete;
ComponentPool(const ComponentPool&& other) = delete;
@@ -61,6 +61,7 @@ public:
iterator begin() const;
iterator end() const;
size_t size() 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<<)
+31 -18
View File
@@ -18,22 +18,32 @@ struct ComponentWrapper
const ::EntityID EntityID;
char* Data;
template <typename T>
T& Property(std::string name)
int Enum(const char* fieldName, const char* enumKey)
{
unsigned int offset = Info.Fields.at(name).Offset;
return *reinterpret_cast<T*>(&Data[offset]);
return Info.Meta->FieldEnumDefinitions.at(fieldName).at(enumKey);
}
template <typename T>
void SetProperty(std::string name, const T value) { Property<T>(name) = value; }
T& Field(std::string name)
{
const ComponentInfo::Field_t& field = Info.Fields.at(name);
if (sizeof(T) > field.Stride) {
std::stringstream message;
message << "Type size of \"" << typeid(T).name() << "\" doesn't match size of component field \"" << Info.Name << "." << name << "\"!";
throw new std::runtime_error(message.str().c_str());
}
return *reinterpret_cast<T*>(&Data[field.Offset]);
}
template <typename T>
void SetField(std::string name, const T value) { Field<T>(name) = value; }
//template <typename T>
//void SetProperty(std::string name, T& value) { Property<T>(name) = value; }
//void SetField(std::string name, T& value) { Field<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); }
void SetField(std::string name, const char(&value)[N]) { Field<std::string>(name) = std::string(value); }
struct SubscriptProxy
{
friend struct ComponentWrapper;
@@ -47,18 +57,21 @@ struct ComponentWrapper
std::string m_PropertyName;
public:
template <typename T>
operator T&() { return m_Component->Property<T>(m_PropertyName); }
// Return the integer value of an enum type key for this field
int Enum(const char* enumKey) { return m_Component->Enum(m_PropertyName.c_str(), enumKey); }
template <typename T>
void operator=(const T val) { m_Component->SetProperty<T>(m_PropertyName, val); }
operator T&() { return m_Component->Field<T>(m_PropertyName); }
template <typename T>
void operator=(const T val) { m_Component->SetField<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); }
//void operator=(T& val) { m_Component->SetField<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); }
template <std::size_t N>
void operator=(const char(&val)[N]) { m_Component->SetField<N>(m_PropertyName, val); }
};
SubscriptProxy operator[](std::string propertyName) { return SubscriptProxy(this, propertyName); }
};
@@ -71,7 +84,7 @@ public:
ComponentWrapperFactory(std::string componentTypeName, std::size_t allocation = 0)
{
m_ComponentInfo.Name = componentTypeName;
m_ComponentInfo.Meta.Allocation = allocation;
m_ComponentInfo.Meta->Allocation = allocation;
}
template <typename T>
@@ -79,14 +92,14 @@ public:
{
m_DefaultValues.push_back(defaultValue);
m_ComponentInfo.Fields[fieldName].Type = typeid(T).name();
m_ComponentInfo.Fields[fieldName].Offset = m_ComponentInfo.Meta.Stride;
m_ComponentInfo.Fields[fieldName].Offset = m_ComponentInfo.Stride;
m_ComponentInfo.Fields[fieldName].Stride = sizeof(T);
m_ComponentInfo.Meta.Stride += sizeof(T);
m_ComponentInfo.Stride += sizeof(T);
}
ComponentInfo& Finalize()
{
m_ComponentInfo.Defaults = std::shared_ptr<char>(new char[m_ComponentInfo.Meta.Stride]);
m_ComponentInfo.Defaults = std::shared_ptr<char>(new char[m_ComponentInfo.Stride]);
std::size_t offset = 0;
for (auto& val : m_DefaultValues) {
memcpy(m_ComponentInfo.Defaults.get() + offset, val.Data.get(), val.Size);
+20
View File
@@ -0,0 +1,20 @@
#ifndef ECaptured_h__
#define ECaptured_h__
#include "EventBroker.h"
#include "../Core/Entity.h"
#include "Engine/GLM.h"
namespace Events
{
//triggers when a capturePoint has been taken over
struct Captured : Event
{
int TeamNumberThatCapturedCapturePoint;
EntityID CapturePointID;
};
}
#endif
+20
View File
@@ -0,0 +1,20 @@
#ifndef EComponentAttached_h__
#define EComponentAttached_h__
#include "EventBroker.h"
#include "World.h"
#include "Entity.h"
#include "ComponentWrapper.h"
namespace Events
{
struct ComponentAttached : Event
{
EntityWrapper Entity;
ComponentWrapper Component;
};
}
#endif
+20
View File
@@ -0,0 +1,20 @@
#ifndef EWin_h__
#define EWin_h__
#include "EventBroker.h"
#include "../Core/Entity.h"
#include "Engine/GLM.h"
namespace Events
{
//triggers when a team has captured all capturePoints
struct Win : Event
{
//can be 0 = none, 1,2
int TeamThatWon;
};
}
#endif
+1
View File
@@ -4,4 +4,5 @@
typedef unsigned int EntityID;
const static unsigned int EntityID_Invalid = -1;
#endif
+8 -8
View File
@@ -285,7 +285,7 @@ private:
XSValue::Status status;
XSValue* val = XSValue::getActualValue(child->getNodeValue(), XSValue::dt_integer, status);
compInfo.Meta.Allocation += val->fData.fValue.f_int;
compInfo.Meta->Allocation += val->fData.fValue.f_int;
}
// Save documentation string
@@ -293,11 +293,11 @@ private:
if (documentationTags->getLength() != 0) {
auto child = documentationTags->item(0)->getFirstChild();
if (child != nullptr) {
compInfo.Meta.Annotation = XSTR(child->getNodeValue());
compInfo.Meta->Annotation = XSTR(child->getNodeValue());
}
}
// TODO: Parse annotation string XML
// compInfo.Meta.Allocation = ...
// compInfo.Meta->Allocation = ...
} else {
std::cout << "Warning: Component is missing an annotation!" << std::endl;
}
@@ -344,7 +344,7 @@ private:
fieldOffset += getTypeStride(type);
}
compInfo.Meta.Stride = fieldOffset;
compInfo.Stride = fieldOffset;
m_ComponentInfo[compInfo.Name] = compInfo;
}
}
@@ -367,14 +367,14 @@ private:
std::string componentName = XSTR(component->getLocalName());
auto& compInfo = m_ComponentInfo.at(componentName);
compInfo.Meta.Allocation += 1;
compInfo.Meta->Allocation += 1;
}
std::cout << "COMPONENT INFO" << std::endl;
for (auto& pair : m_ComponentInfo) {
ComponentInfo& ci = pair.second;
std::cout << "Component: " << ci.Name << " (" << ci.Meta.Annotation << ")" << std::endl;
std::cout << " Allocation: " << ci.Meta.Allocation << std::endl;
std::cout << "Component: " << ci.Name << " (" << ci.Meta->Annotation << ")" << std::endl;
std::cout << " Allocation: " << ci.Meta->Allocation << std::endl;
std::cout << " Fields:" << std::endl;
// Calculate component size
@@ -393,7 +393,7 @@ private:
cs.ComponentName = ci.Name;
cs.Stride = stride;
cs.Info = ci;
cs.Data = new char[stride*ci.Meta.Allocation];
cs.Data = new char[stride*ci.Meta->Allocation];
m_ComponentStore[cs.ComponentName] = cs;
}
}
+18 -147
View File
@@ -73,88 +73,15 @@ public:
ComponentField
};
EntityFileSAXHandler(const EntityFileHandler* handler, xercesc::SAX2XMLReader* reader)
: m_Handler(handler)
, m_Reader(reader)
{
// 0 is imaginary world entity
m_EntityStack.push(0);
m_StateStack.push(State::Unknown);
}
EntityFileSAXHandler(const EntityFileHandler* handler, xercesc::SAX2XMLReader* reader);
void startElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname, const xercesc::Attributes& attrs) override
{
std::string name = XS::ToString(_localName);
void startElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname, const xercesc::Attributes& attrs) override;
void characters(const XMLCh* const chars, const XMLSize_t length) override;
void endElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname) override;
if (m_StateStack.top() == State::Unknown || m_StateStack.top() == State::Entity) {
if (name == "Entity") {
m_StateStack.push(State::Entity);
onStartEntity(attrs);
return;
}
if (name == "EntityRef") {
onStartEntityRef(attrs);
return;
}
}
std::string uri = XS::ToString(_uri);
if (m_StateStack.top() == State::Entity) {
if (uri == "components") {
m_StateStack.push(State::Component);
onStartComponent(name);
return;
}
}
if (m_StateStack.top() == State::Component) {
m_StateStack.push(State::ComponentField);
onStartComponentField(name, attrs);
return;
}
}
void characters(const XMLCh* const chars, const XMLSize_t length) override
{
if (m_StateStack.top() == State::ComponentField) {
char* transcoded = xercesc::XMLString::transcode(chars);
onFieldData(transcoded);
}
}
void endElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname) override
{
std::string name = XS::ToString(_localName);
if (m_StateStack.top() == State::Entity) {
if (name == "Entity") {
m_StateStack.pop();
onEndEntity();
return;
}
}
std::string uri = XS::ToString(_uri);
if (m_StateStack.top() == State::Component) {
//if (uri == "components") {
m_StateStack.pop();
onEndComponent(name);
return;
//}
}
if (m_StateStack.top() == State::ComponentField) {
m_StateStack.pop();
onEndComponentField(name);
return;
}
}
void fatalError(const xercesc::SAXParseException& e)
{
XS::ToString s(e.getMessage());
LOG_ERROR("SAXParseException: %s", ((std::string)s).c_str());
//throw e;
}
void warning(const xercesc::SAXParseException& e);
void error(const xercesc::SAXParseException& e);
void fatalError(const xercesc::SAXParseException& e);
private:
const EntityFileHandler* m_Handler;
@@ -168,73 +95,14 @@ private:
std::string m_CurrentField;
std::map<std::string, std::string> m_CurrentAttributes;
void onStartEntity(const xercesc::Attributes& attrs)
{
EntityID parent = m_EntityStack.top();
if (m_Handler->m_OnStartEntityCallback) {
std::string name;
auto xName = attrs.getValue(XS::ToXMLCh("name"));
if (xName != nullptr) {
name = XS::ToString(xName);
}
m_Handler->m_OnStartEntityCallback(m_NextEntityID, parent, name);
}
m_EntityStack.push(m_NextEntityID);
m_NextEntityID++;
}
void onEndEntity()
{
m_EntityStack.pop();
}
void onStartEntityRef(const xercesc::Attributes& attrs)
{
std::string path = XS::ToString(attrs.getValue(XS::ToXMLCh("file")));
xercesc::SAX2XMLReader* parser = xercesc::XMLReaderFactory::createXMLReader();
parser->setContentHandler(this);
parser->setErrorHandler(this);
parser->parse(path.c_str());
delete parser;
}
void onStartComponent(const std::string& name)
{
//LOG_DEBUG(" Component: %s", name.c_str());
m_CurrentComponent = name;
if (m_Handler->m_OnStartComponentCallback) {
m_Handler->m_OnStartComponentCallback(m_EntityStack.top(), name);
}
}
void onEndComponent(const std::string& name) { }
void onStartComponentField(const std::string& field, const xercesc::Attributes& attrs)
{
//LOG_DEBUG(" Field: %s", field.c_str());
m_CurrentField = field;
m_CurrentAttributes.clear();
for (int i = 0; i < attrs.getLength(); i++) {
auto name = attrs.getQName(i);
auto value = attrs.getValue(name);
//LOG_DEBUG(" %s = %s", (char*)XS::ToString(name), (char*)XS::ToString(value));
m_CurrentAttributes[XS::ToString(name).operator std::string()] = XS::ToString(value).operator std::string();
}
if (m_Handler->m_OnStartFieldCallback) {
m_Handler->m_OnStartFieldCallback(m_EntityStack.top(), m_CurrentComponent, field, m_CurrentAttributes);
}
}
void onEndComponentField(const std::string& field) { }
void onFieldData(char* data)
{
//LOG_DEBUG(" Data: %s", data);
if (m_Handler->m_OnStartFieldDataCallback) {
m_Handler->m_OnStartFieldDataCallback(m_EntityStack.top(), m_CurrentComponent, m_CurrentField, data);
}
xercesc::XMLString::release(&data);
}
void onStartEntity(const xercesc::Attributes& attrs);
void onEndEntity();
void onStartEntityRef(const xercesc::Attributes& attrs);
void onStartComponent(const std::string& name);
void onEndComponent(const std::string& name);
void onStartComponentField(const std::string& field, const xercesc::Attributes& attrs);
void onEndComponentField(const std::string& field);
void onFieldData(char* data);
};
class EntityFileXMLErrorHandler : public xercesc::ErrorHandler
@@ -269,6 +137,7 @@ private:
class EntityFile : public Resource
{
friend class ResourceManager;
friend class EntityFileSAXHandler;
private:
EntityFile(boost::filesystem::path path);
~EntityFile();
@@ -288,6 +157,8 @@ private:
xercesc::SAX2XMLReader* m_SAX2XMLReader;
//std::map<std::string, ::ComponentInfo> m_ComponentInfo;
//std::vector<std::string> m_EntityReferences;
static void setReaderFeatures(xercesc::SAX2XMLReader* reader);
};
#endif
+2 -1
View File
@@ -9,12 +9,13 @@ class EntityFileParser
public:
EntityFileParser(const EntityFile* entityFile);
void MergeEntities(World* world);
EntityID MergeEntities(World* world, EntityID baseParent = EntityID_Invalid);
private:
const EntityFile* m_EntityFile;
EntityFileHandler m_Handler;
World* m_World = nullptr;
EntityID m_FirstEntity = EntityID_Invalid;
// Maps EntityIDs local to the file to real IDs in the world after they've been
// created in order to resolve parent-child relationships.
std::map<EntityID, EntityID> m_EntityIDMapper;
@@ -5,6 +5,7 @@
#include <xercesc/framework/psvi/XSComplexTypeDefinition.hpp>
#include <xercesc/framework/psvi/XSParticle.hpp>
#include <xercesc/framework/psvi/XSModelGroup.hpp>
#include <xercesc/framework/psvi/XSModelGroupDefinition.hpp>
#include <xercesc/framework/psvi/XSAnnotation.hpp>
#include <xercesc/framework/psvi/XSValue.hpp>
#include <xercesc/framework/MemBufFormatTarget.hpp>
@@ -31,6 +32,7 @@ private:
void onStartComponent(EntityID entity, std::string type);
void parseComponentInfo();
void parseDefaults();
std::string parseAnnotationXML(const XMLCh* xml);
};
#endif
+32
View File
@@ -0,0 +1,32 @@
#ifndef EntityWrapper_h__
#define EntityWrapper_h__
#include <boost/optional.hpp>
#include "ComponentWrapper.h"
class World;
struct EntityWrapper
{
EntityWrapper()
: World(nullptr)
, ID(EntityID_Invalid)
{ }
EntityWrapper(::World* world, EntityID id)
: World(world)
, ID(id)
{ }
::World* World;
EntityID ID;
static const EntityWrapper Invalid;
bool HasComponent(const std::string& componentName);
ComponentWrapper operator[](const std::string& componentName);
bool operator==(const EntityWrapper& e);
explicit operator EntityID();
};
#endif
+2 -2
View File
@@ -43,7 +43,7 @@ template <typename ContextType, typename EventType>
class EventRelay : public BaseEventRelay
{
public:
typedef std::function<bool(const EventType&)> CallbackType;
typedef std::function<bool(EventType&)> CallbackType;
EventRelay()
: m_Callback(nullptr)
@@ -65,7 +65,7 @@ template <typename ContextType, typename EventType>
bool EventRelay<ContextType, EventType>::Receive(const std::shared_ptr<Event> event)
{
if (m_Callback != nullptr) {
return m_Callback(*static_cast<const EventType*>(event.get()));
return m_Callback(*static_cast<EventType*>(event.get()));
} else {
return false;
}
+14 -4
View File
@@ -5,6 +5,14 @@
template <typename T>
class MemoryPoolForwardIterator;
namespace DisableMemoryPool
{
//if true -> Pool allocation is not used when calling Allocate/Free, just use regular dynamic allocation.
//if false -> Use pool allocation.
//Should default to false, unless the DisableMemoryPool is true in the Config.ini files.
extern bool Value;
}
//This is the class to use if you want to allocate blocks (slots) of raw memory, with a fixed maximum size (stride).
//Additionally, if you know that every memory-block will contain one object of a specific type, (i.e. the stride for the slot
//will the size of the object type) you should use ObjectPool<T> instead, your life will become easier.
@@ -80,8 +88,8 @@ public:
//If element cannot be allocated in the pool, because the memory ran out, memory is allocated dynamically with malloc() "outside the pool".
char* Allocate()
{
for (; m_CurrentAllocSlot < m_NumSlots && m_SlotIsAllocated[m_CurrentAllocSlot]; ++m_CurrentAllocSlot);
if (m_CurrentAllocSlot < m_NumSlots) {
for (; m_CurrentAllocSlot < m_NumSlots && m_SlotIsAllocated[m_CurrentAllocSlot] && !DisableMemoryPool::Value; ++m_CurrentAllocSlot);
if (m_CurrentAllocSlot < m_NumSlots && !DisableMemoryPool::Value) {
if (m_LowestAllocatedSlot > m_CurrentAllocSlot)
m_LowestAllocatedSlot = m_CurrentAllocSlot;
//Mark the slot as allocated.
@@ -93,7 +101,9 @@ public:
else {
m_ExtraMemory.push_back((char*)malloc(m_Stride));
//We should preferably not enter here to avoid performance issues. Set more numMaxElements in constructor instead.
LOG_WARNING("Allocated slots exceed Pool size, extra memory allocated dynamically. Pool size: %u, dynamic size: %u.", m_NumSlots, m_ExtraMemory.size());
if (!DisableMemoryPool::Value) {
LOG_WARNING("Allocated slots exceed Pool size, extra memory allocated dynamically. Pool size: %u, dynamic size: %u.", m_NumSlots, m_ExtraMemory.size());
}
return m_ExtraMemory.back();
}
}
@@ -108,7 +118,7 @@ public:
//(i.e. IsAllocatedInPool may give false positives)
//if it was malloc():ed
//so, we may enter here even if we shouldn't.
if (IsAllocatedInPool(obj)) {
if (!DisableMemoryPool::Value && IsAllocatedInPool(obj)) {
--m_NumAllocatedSlots;
const size_t freeSlot = (obj - m_StartAddress) / m_Stride;
m_SlotIsAllocated[freeSlot] = false;
@@ -1,11 +1,12 @@
#ifndef OctTree_h__
#define OctTree_h__
#ifndef Octree_h__
#define Octree_h__
#include "Core/AABB.h"
#include "../Common.h"
#include "AABB.h"
class Ray;
class OctTree
class Octree
{
public:
struct Output
@@ -13,16 +14,16 @@ public:
float CollideDistance;
};
OctTree();
~OctTree();
//For the root OctTree, [octTreeBounds] should be a box containing the entire level.
OctTree(const AABB& octTreeBounds, int subDivisions);
Octree() = delete;
~Octree();
//For the root Octree, [octreeBounds] should be a box containing the entire level.
Octree(const AABB& octreeBounds, int subDivisions);
//We cannot copy the OctTree as of now, because of the recursive dynamic allocation.
//Define these if the OctTree suddenly needs to be copied, think of the children OctChild* ptrs.
OctTree(const OctTree& other) = delete;
OctTree(const OctTree&& other) = delete;
OctTree& operator= (const OctTree& other) = delete;
//We cannot copy the Octree as of now, because of the recursive dynamic allocation.
//Define these if the Octree suddenly needs to be copied, think of the children Child* ptrs.
Octree(const Octree& other) = delete;
Octree(const Octree&& other) = delete;
Octree& operator= (const Octree& 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.
@@ -42,7 +43,7 @@ public:
bool BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected);
private:
struct OctChild; //Fwd declaration;
struct Child; //Fwd declaration;
struct ContainedObject
{
ContainedObject()
@@ -56,7 +57,7 @@ private:
AABB Box;
bool Checked;
};
OctChild* m_Root;
Child* m_Root;
std::vector<ContainedObject> m_StaticObjects;
std::vector<ContainedObject> m_DynamicObjects;
@@ -67,16 +68,16 @@ private:
void falsifyObjectChecks();
struct OctChild
struct Child
{
~OctChild();
OctChild(const AABB& octTreeBounds,
~Child();
Child(const AABB& octTreeBounds,
int subDivisions,
std::vector<OctTree::ContainedObject>& staticObjects,
std::vector<OctTree::ContainedObject>& dynamicObjects);
OctChild(const OctChild& other) = delete;
OctChild(const OctChild&& other) = delete;
OctChild& operator= (const OctChild& other) = delete;
std::vector<Octree::ContainedObject>& staticObjects,
std::vector<Octree::ContainedObject>& dynamicObjects);
Child(const Child& other) = delete;
Child(const Child&& other) = delete;
Child& operator= (const Child& other) = delete;
void AddDynamicObject(const AABB& box);
void AddStaticObject(const AABB& box);
void BoxesInSameRegion(const AABB& box, std::vector<AABB>& outBoxes) const;
@@ -85,14 +86,14 @@ private:
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.
Child* m_Children[8];
//Indices into the lists in Octree.
std::vector<int> m_StaticObjIndices;
std::vector<int> m_DynamicObjIndices;
AABB m_Box;
//Reference to the lists in OctTree.
std::vector<OctTree::ContainedObject>& m_StaticObjectsRef;
std::vector<OctTree::ContainedObject>& m_DynamicObjectsRef;
//Reference to the lists in Octree.
std::vector<Octree::ContainedObject>& m_StaticObjectsRef;
std::vector<Octree::ContainedObject>& m_DynamicObjectsRef;
inline bool hasChildren() const;
int childIndexContainingPoint(const glm::vec3& point) const;
+1 -1
View File
@@ -2,7 +2,7 @@
#define Ray_h__
#include "../GLM.h"
#include "Common.h"
#include "../Common.h"
class Ray
{
+132 -39
View File
@@ -12,7 +12,6 @@
/** Base Resource class.
Implement this class for every resource to be handled by the resource manager.
Implement Create() to return a new object of that type.
*/
class Resource
{
@@ -22,6 +21,23 @@ protected:
Resource() { }
public:
//Should be thrown in a Resource's constructor if it cannot complete because another resource is still loading.
//Not actually an error, just a message to the ResourceManager.
struct StillLoadingException : public std::exception
{
virtual const char* what() const throw()
{
return "Resource is still loading.";
}
};
struct FailedLoadingException : public std::exception
{
virtual const char* what() const throw()
{
return "Resource is failed to load.";
}
};
// Pretend that this is a pure virtual function that you have to implement
// FIXME: Why did we do this again instead of just using the constructor?
// static Resource* Create(std::string resourceName);
@@ -33,6 +49,15 @@ public:
unsigned int ResourceID;
};
//Any class inheriting from this class will always be loaded on the master thread, not on a parallel worker thread.
//This is important in case some instructions must be executed on the main thread, e.g. OpenGL commands, like glBindBuffer.
//This resource can still be loaded asyncronously, but it will not be loaded in a thread, instead it's constructor will
//be called once on every ResourceManager::Load, just throw StillLoadingException in the constructor if it is not done yet.
class ThreadUnsafeResource : public Resource
{
friend class ResourceManager;
};
/** Singleton resource manager to keep track of and cache any external engine assets */
class ResourceManager
{
@@ -40,6 +65,7 @@ private:
ResourceManager();
public:
static bool UseThreading;
/*static ResourceManager& Instance()
{
static ResourceManager s;
@@ -49,15 +75,6 @@ public:
template <typename T>
static void RegisterType(std::string typeName);
/** Preloads a resource and caches it for future use
@tparam T Resource type.
@param resourceName Fully qualified name of the resource to preload.
*/
template <typename T>
static void Preload(std::string resourceName);
static void Preload(std::string resourceType, std::string resourceName);
/** Checks if a resource is in cache
@param resourceType Resource type as string.
@@ -65,15 +82,20 @@ public:
*/
// TODO: Templateify
static bool IsResourceLoaded(std::string resourceType, std::string resourceName);
/** Return value should always be a valid pointer, will throw an exception on error.
If the resource has been loaded already, returns a pointer to it.
/** Hot-loads a resource and caches it for future use
If Async is false: Hot-loads a resource, caches it for future use, and returns a pointer to it.
If Async is true: If the resource is not loaded yet, starts loading the resource
in the background and throws Resource::StillLoadingException immediately.
@tparam T Resource type.
@tparam async Set this to true if the resource should be loaded asyncronously.
@param resourceName Fully qualified name of the resource to load.
*/
template <typename T>
static T* Load(std::string resourceName, Resource* parent = nullptr);
static Resource* Load(std::string resourceType, std::string resourceName, Resource* parent = nullptr);
template <typename T, bool async = false>
static T* Load(const std::string& resourceName, Resource* parent = nullptr);
/** Reloads an already loaded resource, keeping its resource ID intact.
@@ -87,19 +109,31 @@ public:
static void Update();
private:
//This is a haxy way to make sure that IsMainThread is run when the program starts, so the master thread id is set.
struct MasterThreadChecker
{
MasterThreadChecker()
{
ResourceManager::IsMainThread();
}
};
const static MasterThreadChecker m_Checker;
static std::unordered_map<std::string, std::string> m_CompilerTypenameToResourceType;
static std::unordered_map<std::string, std::function<Resource*(std::string)>> m_FactoryFunctions; // type -> factory function
static std::unordered_map<std::pair<std::string, std::string>, Resource*> m_ResourceCache; // (type, name) -> resource
static std::unordered_map<std::string, Resource*> m_ResourceFromName; // name -> resource
static std::unordered_map<Resource*, Resource*> m_ResourceParents; // resource -> parent resource
static std::unordered_map<std::pair<std::string, std::string>, boost::thread> m_LoadingThreads; // (type, name) -> loading thread
static std::unordered_map<std::pair<std::string, std::string>, std::exception_ptr> m_LoadingThreadExceptions; // (type, name) -> exceptions
static boost::recursive_mutex m_Mutex;
// TODO: Getters for IDs
static unsigned int m_CurrentResourceTypeID;
static std::unordered_map<std::string, unsigned int> m_ResourceTypeIDs;
// Number of resources of a type. Doubles as local ID.
static std::unordered_map<unsigned int, unsigned int> m_ResourceCount;
// Flag to suppress hot-load warnings when a preloading resource chain loads another resource
static bool m_Preloading;
static FileWatcher m_FileWatcher;
static void fileWatcherCallback(std::string path, FileWatcher::FileEventFlags flags);
@@ -108,22 +142,13 @@ private:
static unsigned int GetNewResourceID(unsigned int typeID);
// Internal: Create a resource and cache it
static Resource* CreateResource(std::string resourceType, std::string resourceName, Resource* parent);
static Resource* createResourceThrowing(const std::string& resourceType, const std::string& resourceName, Resource* parent);
static Resource* createResource(const std::string& resourceType, const std::string& resourceName, Resource* parent, std::exception_ptr& exception);
static Resource* cacheResource(Resource* resource, const std::string& resourceType, const std::string& resourceName, Resource* parent);
static bool IsMainThread();
};
template <typename T>
T* ResourceManager::Load(std::string resourceName, Resource* parent /* = nullptr */)
{
auto resourceTypename = typeid(T).name();
auto it = m_CompilerTypenameToResourceType.find(resourceTypename);
if (it == m_CompilerTypenameToResourceType.end()) {
LOG_ERROR("Failed to load resource \"%s\" of type \"%s\": type not registered", resourceName.c_str(), resourceTypename);
return nullptr;
}
return static_cast<T*>(Load(it->second, resourceName, parent));
}
template <typename T>
void ResourceManager::RegisterType(std::string typeName)
{
@@ -131,17 +156,85 @@ void ResourceManager::RegisterType(std::string typeName)
m_FactoryFunctions[typeName] = [](std::string resourceName) { return new T(resourceName); };
}
template <typename T>
void ResourceManager::Preload(std::string resourceName)
template <typename T, bool async>
static T* ResourceManager::Load(const std::string& resourceName, Resource* parent /* = nullptr */)
{
auto resourceTypename = typeid(T).name();
auto it = m_CompilerTypenameToResourceType.find(resourceTypename);
if (it == m_CompilerTypenameToResourceType.end()) {
LOG_ERROR("Failed to load resource \"%s\" of type \"%s\": type not registered", resourceName.c_str(), resourceTypename);
return;
}
auto resourceTypename = typeid(T).name();
auto iter = m_CompilerTypenameToResourceType.find(resourceTypename);
if (iter == m_CompilerTypenameToResourceType.end()) {
LOG_ERROR("Failed to load resource \"%s\" of type \"%s\": type not registered", resourceName.c_str(), resourceTypename);
throw Resource::FailedLoadingException();
}
Preload(it->second, resourceName);
std::string resourceType = iter->second;
constexpr bool mustNotLoadInThread = std::is_base_of<ThreadUnsafeResource, T>::value;
if (mustNotLoadInThread && !IsMainThread()) {
LOG_ERROR("Failed to Load \"%s\": ThreadUnsafeResource type \"%s\" load in the constructor of another resource that is loaded asyncronously.", resourceName.c_str(), iter->second.c_str());
throw Resource::FailedLoadingException();
}
auto cacheKey = std::make_pair(resourceType, resourceName);
decltype(m_ResourceCache)::iterator it;
//If a thread has already been launched to load this resource.
auto tIt = m_LoadingThreads.find(cacheKey);
if (UseThreading && tIt != m_LoadingThreads.end()) {
if (async) {
//Throw StillLoadingException if the thread is still working.
if (!tIt->second.try_join_for(boost::chrono::nanoseconds(1))) {
throw Resource::StillLoadingException();
}
//Else we know the thread has completed.
} else {
//Wait for the thread to finish loading.
tIt->second.join();
}
//When the thread is done, delete the thread.
m_LoadingThreads.erase(tIt);
//Rethrow the thread exception if it threw any.
auto excIt = m_LoadingThreadExceptions.find(cacheKey);
std::exception_ptr exception = excIt->second;
m_LoadingThreadExceptions.erase(excIt);
if (exception) {
std::rethrow_exception(exception);
}
}
//If resource has already been cached and completely loaded.
it = m_ResourceCache.find(cacheKey);
if (it != m_ResourceCache.end()) {
if (it->second != nullptr) {
return static_cast<T*>(it->second);
} else {
//Don't return null on failure, exception instead.
throw Resource::FailedLoadingException();
}
}
//If resource is not cached..
if (UseThreading && async) {
if (mustNotLoadInThread) {
try {
return static_cast<T*>(createResourceThrowing(resourceType, resourceName, parent));
} catch (const Resource::StillLoadingException&) {
throw;
}
} else {
//Create a thread that loads the resource into cache.
m_LoadingThreads[cacheKey] = boost::thread(createResource, resourceType, resourceName, parent, m_LoadingThreadExceptions[cacheKey]);
throw Resource::StillLoadingException();
}
} else {
//load and return the resource.
while (true) {
try {
return static_cast<T*>(createResourceThrowing(resourceType, resourceName, parent));
} catch (const Resource::StillLoadingException&) {
continue;
} catch (const std::exception&) {
throw;
}
}
}
}
#endif
+10 -9
View File
@@ -3,6 +3,7 @@
#include "EventBroker.h"
#include "World.h"
#include "EntityWrapper.h"
#include "ComponentWrapper.h"
class System
@@ -10,6 +11,9 @@ class System
friend class SystemPipeline;
protected:
System()
: m_EventBroker(nullptr)
{ }
System(EventBroker* eventBroker)
: m_EventBroker(eventBroker)
{ }
@@ -18,30 +22,27 @@ protected:
EventBroker* m_EventBroker;
};
class PureSystem : public System
class PureSystem : public virtual System
{
friend class SystemPipeline;
protected:
PureSystem(EventBroker* eventBroker, std::string componentType)
: System(eventBroker)
, m_ComponentType(componentType)
PureSystem(std::string componentType)
: m_ComponentType(componentType)
{ }
virtual ~PureSystem() = default;
const std::string m_ComponentType;
virtual void UpdateComponent(World* world, ComponentWrapper& component, double dt) = 0;
virtual void UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) = 0;
};
class ImpureSystem : public System
class ImpureSystem : public virtual System
{
friend class SystemPipeline;
protected:
ImpureSystem(EventBroker* eventBroker)
: System(eventBroker)
{ }
ImpureSystem() = default;
virtual ~ImpureSystem() = default;
virtual void Update(World* world, double dt) = 0;
+8 -8
View File
@@ -32,8 +32,8 @@ public:
System* system = new T(m_EventBroker, args...);
group.Systems[typeid(T).name()] = system;
if (std::is_base_of<PureSystem, T>::value) {
PureSystem* pureSystem = static_cast<PureSystem*>(system);
PureSystem* pureSystem = dynamic_cast<PureSystem*>(system);
if (pureSystem != nullptr) {
if (!pureSystem->m_ComponentType.empty()) {
group.PureSystems[pureSystem->m_ComponentType].push_back(pureSystem);
} else {
@@ -41,8 +41,8 @@ public:
}
}
if (std::is_base_of<ImpureSystem, T>::value) {
ImpureSystem* impureSystem = static_cast<ImpureSystem*>(system);
ImpureSystem* impureSystem = dynamic_cast<ImpureSystem*>(system);
if (impureSystem != nullptr) {
group.ImpureSystems.push_back(impureSystem);
}
}
@@ -56,6 +56,9 @@ public:
}
// Update
for (auto& system : group.ImpureSystems) {
system->Update(world, dt);
}
for (auto& pair : group.PureSystems) {
const std::string& componentName = pair.first;
auto& systems = pair.second;
@@ -65,13 +68,10 @@ public:
}
for (auto& component : *pool) {
for (auto& system : systems) {
system->UpdateComponent(world, component, dt);
system->UpdateComponent(world, EntityWrapper(world, component.EntityID), component, dt);
}
}
}
for (auto& system : group.ImpureSystems) {
system->Update(world, dt);
}
}
}
+17
View File
@@ -0,0 +1,17 @@
#ifndef Transform_h__
#define Transform_h__
#include "../GLM.h"
#include "World.h"
namespace Transform
{
glm::vec3 AbsolutePosition(World* world, EntityID entity);
glm::quat AbsoluteOrientation(World* world, EntityID entity);
glm::vec3 AbsoluteScale(World* world, EntityID entity);
glm::mat4 ModelMatrix(EntityID entity, World* world);
}
#endif
+7 -5
View File
@@ -21,19 +21,21 @@ public:
// 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);
ComponentWrapper AttachComponent(EntityID entity, const std::string& componentType);
// Check if an entity has a component
bool HasComponent(EntityID entity, std::string componentType) const;
bool HasComponent(EntityID entity, const std::string& componentType) const;
// Get a component of an entity
ComponentWrapper GetComponent(EntityID entity, std::string componentType);
ComponentWrapper GetComponent(EntityID entity, const std::string& componentType);
// Delete a component off an entity
void DeleteComponent(EntityID entity, std::string componentType);
void DeleteComponent(EntityID entity, const std::string& componentType);
// Get all components of the specified type
const ComponentPool* GetComponents(std::string componentType);
const ComponentPool* GetComponents(const std::string& componentType);
// Get entity parent
EntityID GetParent(EntityID entity);
// Change the parent of an entity
void SetParent(EntityID entity, EntityID parent);
// Get children of an entity
const std::pair<std::unordered_multimap<EntityID, EntityID>::const_iterator, std::unordered_multimap<EntityID, EntityID>::const_iterator> GetChildren(EntityID entity);
// Get all component pools
const std::unordered_map<std::string, ComponentPool*>& GetComponentPools() const { return m_ComponentPools; }
// Get the entity children map