Compare commits

...

33 Commits

Author SHA1 Message Date
William Moberg d1b6fb1259 Tiny logic alteration so we don't get false warnings in debug. 2016-01-19 16:59:02 +01:00
William Moberg 017ad96bbe Fixed some errors in Tests. 2016-01-19 15:20:29 +01:00
William Moberg 713ebbe18c Can add any objects that inherit from AABB into the Octree. 2016-01-19 14:50:46 +01:00
William Moberg 621d935d7a Octree returns correct boxes when testing along an axis by searching through the correct child subtrees. 2016-01-18 18:24:11 +01:00
William Moberg b2358a1854 Added bool in Physics to toggle gravity for entities. 2016-01-18 18:16:24 +01:00
William Moberg bf3f8aea89 Merge pull request #36 from teamfisk/PlayerMovement
Player movement
2016-01-18 13:32:42 +01:00
William Moberg 0669d91767 CollisionSystem loops over Collidable components. 2016-01-18 13:29:10 +01:00
William Moberg 942064c450 Removed class PlayerSystem and associated files. 2016-01-18 13:07:04 +01:00
Jace fb7e0498a8 Merge pull request #35 from teamfisk/DisableMemoryPool
Possible to disable the MemoryPool allocation in Config files.
2016-01-18 10:46:53 +01:00
Jace f281d220de Working Spawner, SpawnPoint, PlayerSpawn and Team components, along with their systems. 2016-01-17 01:00:48 +01:00
Jace 6385a98eca Added runtime type size check to ComponentWrapper to avoid corruption when types don't match 2016-01-17 00:59:26 +01:00
Jace d8a24bbfde Renamed all instances of "Property" to "Field" in ComponentWrapper to maintain consistent naming with ComponentInfo 2016-01-17 00:38:25 +01:00
Jace 9ec32464bc Added enum support to entity file format, see "Team" component for an example. Use ComponentInfo::Enum to convert enum string keys to its corresponding integer representation at runtime. 2016-01-16 23:12:24 +01:00
Jace f65ac65e30 Updated component defaults files to match component schema and made schema validation strict. 2016-01-16 17:03:57 +01:00
Jace b2213dbe9a Merge remote-tracking branch 'origin/master' into PlayerMovement
# Conflicts:
#	include/Engine/Collision/Collision.h
#	include/Engine/Collision/CollisionSystem.h
#	include/Engine/Collision/TriggerSystem.h
#	resources/Schema/Components.xsd
#	resources/Schema/Entities/CollisionTestLevel.xml
#	resources/Schema/Types/Entity.xsd
#	src/Engine/Collision/Collision.cpp
#	src/Game/Game.cpp
2016-01-15 20:28:43 +01:00
Jace bbabc84127 Fixed default values for CPlayerSpawn 2016-01-15 20:26:30 +01:00
Jace 8bd5a428b9 EntityFileParser now ignores component fields not present in component definition instead of crashing. 2016-01-15 20:25:48 +01:00
Jace db1b972cd1 Spawner, SpawnPoint and PlayerSpawn components, and base work on their systems 2016-01-15 18:32:47 +01:00
Jace 97e12ff550 Made EntityFileParser::MergeEntities return the base entity that was created, and also take an optional parent entity to create it under. 2016-01-15 18:31:32 +01:00
Jace 0469460029 Input binding format changed to allow custom values for bindings. Relevant code must clamp input values to prevent speedhaxx! 2016-01-15 16:32:04 +01:00
Jace 567173c565 Merge branch 'master' into PlayerMovement
# Conflicts:
#	src/Engine/Rendering/RenderSystem.cpp
#	src/Game/Game.cpp
2016-01-14 18:24:34 +01:00
Jace 5e721325a4 Merge fixes 2016-01-14 18:20:51 +01:00
Jace 3a4f378ac5 Merge remote-tracking branch 'origin/master' into PlayerMovement
# Conflicts:
#	src/Game/Game.cpp
2016-01-14 17:07:39 +01:00
Jace 6ad1839def Initial work on PlayerMovementSystem 2016-01-14 17:03:48 +01:00
Jace 986af01091 Fixed editor component fields with the same name across components being treated as the same value 2016-01-14 17:02:13 +01:00
Jace 99406c32cf Better error handling for EntityFilePreprocessor 2016-01-14 17:01:39 +01:00
Jace d34470256b EntityWrapper to uniquely identify entities and make using them a little easier 2016-01-14 15:43:19 +01:00
Jace 28392def79 Made string passing in World a little more effective 2016-01-14 15:42:55 +01:00
Jace 71d936f8d1 Start of a movement system with collisions against AABBs 2016-01-14 14:54:12 +01:00
Jace d6ef527f25 Basic collisions using Octree. Seems buggy over octree boundaries. 2016-01-13 15:34:43 +01:00
Jace 8ed4ba1219 Added missing include for Octree 2016-01-13 12:16:35 +01:00
Jace 311475cbb6 Renamed all OctTree to Octree (More OCD) 2016-01-13 12:15:36 +01:00
Jace 8164a955d6 Renamed OctTree files to Octree (OCD to the max) 2016-01-13 12:15:09 +01:00
102 changed files with 1818 additions and 817 deletions
@@ -0,0 +1,24 @@
#ifndef CollidableOctreeSystem_h__
#define CollidableOctreeSystem_h__
#include "../Core/System.h"
#include "../Core/Octree.h"
#include "Collision.h"
class CollidableOctreeSystem : public ImpureSystem, public PureSystem
{
public:
CollidableOctreeSystem(EventBroker* eventBroker, Octree<AABB>* octree)
: System(eventBroker)
, PureSystem("Collidable")
, m_Octree(octree)
{ }
virtual void Update(World* world, double dt) override;
virtual void UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) override;
private:
Octree<AABB>* m_Octree;
};
#endif
+11 -3
View File
@@ -6,11 +6,14 @@
//or you will get "fatal error C1189: #error: gl.h included before glew.h" //or you will get "fatal error C1189: #error: gl.h included before glew.h"
#include <vector> #include <vector>
#include <boost/optional.hpp>
#include "../Core/Ray.h" #include "../Core/Ray.h"
#include "../Core/AABB.h" #include "../Core/AABB.h"
#include "../Rendering/RawModel.h" #include "../Rendering/RawModel.h"
#include "../Core/Transform.h"
#include "../Core/Entity.h" #include "../Core/Entity.h"
#include "../Core/EntityWrapper.h"
class World; class World;
struct ComponentWrapper; struct ComponentWrapper;
@@ -43,6 +46,12 @@ bool RayVsModel(const Ray& ray,
float& outUCoord, float& outUCoord,
float& outVCoord); float& outVCoord);
bool AABBvsTriangles(const AABB& box,
const std::vector<RawModel::Vertex>& modelVertices,
const std::vector<unsigned int>& modelIndices,
const glm::mat4& modelMatrix,
glm::vec3& outResolutionVector);
//Return true if the boxes are intersecting. //Return true if the boxes are intersecting.
bool AABBVsAABB(const AABB& a, const AABB& b); bool AABBVsAABB(const AABB& a, const AABB& b);
//Return true if the boxes are intersecting. //Return true if the boxes are intersecting.
@@ -50,9 +59,8 @@ bool AABBVsAABB(const AABB& a, const AABB& b);
bool AABBVsAABB(const AABB& a, const AABB& b, glm::vec3& minimumTranslation); bool AABBVsAABB(const AABB& a, const AABB& b, glm::vec3& minimumTranslation);
bool IsSameBoxProbably(const AABB& first, const AABB& second, const float epsilon = 0.0001f); bool IsSameBoxProbably(const AABB& first, const AABB& second, const float epsilon = 0.0001f);
//Returns true if the entity has a boundingbox. Outputs the aabb in [outBox]. // Calculates an absolute AABB from an entity AABB component
bool GetEntityBox(World* world, EntityID entity, AABB& outBox, bool forceBoxFromModel = false); boost::optional<AABB> EntityAbsoluteAABB(EntityWrapper& entity);
bool GetEntityBox(World* world, ComponentWrapper& AABBComponent, AABB& outBox);
} }
+8 -3
View File
@@ -8,22 +8,27 @@
#include "../Core/System.h" #include "../Core/System.h"
#include "../Core/EventBroker.h" #include "../Core/EventBroker.h"
#include "../Core/EKeyUp.h" #include "../Core/EKeyUp.h"
#include "../Core/Octree.h"
class CollisionSystem : public PureSystem class CollisionSystem : public PureSystem
{ {
public: public:
CollisionSystem(EventBroker* eventBroker) CollisionSystem(EventBroker* eventBroker, Octree<AABB>* octree)
: PureSystem(eventBroker, "AABB") : System(eventBroker)
, PureSystem("Collidable")
, m_Octree(octree)
, zPress(false) , zPress(false)
{ {
//TODO: Debug stuff, remove later. //TODO: Debug stuff, remove later.
EVENT_SUBSCRIBE_MEMBER(m_EKeyUp, &CollisionSystem::OnKeyUp); EVENT_SUBSCRIBE_MEMBER(m_EKeyUp, &CollisionSystem::OnKeyUp);
} }
virtual void UpdateComponent(World* world, ComponentWrapper& cAABB, double dt) override; virtual void UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) override;
private: private:
Octree<AABB>* m_Octree;
bool zPress; bool zPress;
EventRelay<CollisionSystem, Events::KeyUp> m_EKeyUp; EventRelay<CollisionSystem, Events::KeyUp> m_EKeyUp;
bool OnKeyUp(const Events::KeyUp &event); bool OnKeyUp(const Events::KeyUp &event);
}; };
+20 -4
View File
@@ -6,6 +6,7 @@
#include "../Core/System.h" #include "../Core/System.h"
#include "../Core/EventBroker.h" #include "../Core/EventBroker.h"
#include "../Core/Octree.h"
#include "ETrigger.h" #include "ETrigger.h"
class AABB; class AABB;
@@ -13,16 +14,31 @@ class AABB;
class TriggerSystem : public PureSystem class TriggerSystem : public PureSystem
{ {
public: public:
TriggerSystem(EventBroker* eventBroker) TriggerSystem(EventBroker* eventBroker, Octree<AABB>* octree)
: PureSystem(eventBroker, "Trigger") : System(eventBroker)
{} , PureSystem("Trigger")
, m_Octree(octree)
{
EVENT_SUBSCRIBE_MEMBER(m_ETouch, &TriggerSystem::OnTouch);
EVENT_SUBSCRIBE_MEMBER(m_EEnter, &TriggerSystem::OnEnter);
EVENT_SUBSCRIBE_MEMBER(m_ELeave, &TriggerSystem::OnLeave);
}
virtual void UpdateComponent(World* world, ComponentWrapper& collision, double dt) override; virtual void UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) override;
private: private:
Octree<AABB>* m_Octree;
std::unordered_map<EntityID, std::unordered_set<EntityID>> m_EntitiesTouchingTrigger; std::unordered_map<EntityID, std::unordered_set<EntityID>> m_EntitiesTouchingTrigger;
std::unordered_map<EntityID, std::unordered_set<EntityID>> m_EntitiesCompletelyInTrigger; std::unordered_map<EntityID, std::unordered_set<EntityID>> m_EntitiesCompletelyInTrigger;
//TODO: Only exists for debug purposes, remove later.
EventRelay<TriggerSystem, Events::TriggerEnter> m_EEnter;
bool OnEnter(const Events::TriggerEnter &event);
EventRelay<TriggerSystem, Events::TriggerTouch> m_ETouch;
bool OnTouch(const Events::TriggerTouch &event);
EventRelay<TriggerSystem, Events::TriggerLeave> m_ELeave;
bool OnLeave(const Events::TriggerLeave &event);
//True if leave event was thrown. //True if leave event was thrown.
bool throwLeaveIfWasInTrigger(std::unordered_set<EntityID>& triggerSet, EntityID pId, EntityID tId); bool throwLeaveIfWasInTrigger(std::unordered_set<EntityID>& triggerSet, EntityID pId, EntityID tId);
template<typename Event> template<typename Event>
+1
View File
@@ -1,5 +1,6 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <sstream>
#include <vector> #include <vector>
#include <map> #include <map>
#include <unordered_map> #include <unordered_map>
+3 -3
View File
@@ -11,18 +11,18 @@ public:
AABB(const glm::vec3& minPos, const glm::vec3& maxPos); AABB(const glm::vec3& minPos, const glm::vec3& maxPos);
AABB(const glm::vec4& minPos, const glm::vec4& maxPos); AABB(const glm::vec4& minPos, const glm::vec4& maxPos);
//No checks are made. Size must consist of non-negative numbers. //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(); virtual ~AABB();
const glm::vec3& MinCorner() const { return m_MinCorner; } const glm::vec3& MinCorner() const { return m_MinCorner; }
const glm::vec3& MaxCorner() const { return m_MaxCorner; } 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 Size() const { return 2.0f * m_HalfSize; }
const glm::vec3& HalfSize() const { return m_HalfSize; } const glm::vec3& HalfSize() const { return m_HalfSize; }
private: private:
glm::vec3 m_MinCorner; glm::vec3 m_MinCorner;
glm::vec3 m_MaxCorner; glm::vec3 m_MaxCorner;
glm::vec3 m_Center; glm::vec3 m_Origin;
glm::vec3 m_HalfSize; glm::vec3 m_HalfSize;
}; };
+4 -2
View File
@@ -9,7 +9,8 @@ struct ComponentInfo
{ {
std::string Annotation; std::string Annotation;
unsigned int Allocation = 0; 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 struct Field_t
@@ -23,8 +24,9 @@ struct ComponentInfo
std::string Name; std::string Name;
std::unordered_map<std::string, Field_t> Fields; std::unordered_map<std::string, Field_t> Fields;
std::vector<std::string> FieldsInOrder; std::vector<std::string> FieldsInOrder;
Meta_t Meta; unsigned int Stride = 0;
std::shared_ptr<char> Defaults = nullptr; std::shared_ptr<char> Defaults = nullptr;
std::shared_ptr<Meta_t> Meta = nullptr;
}; };
template<> template<>
+1 -1
View File
@@ -43,7 +43,7 @@ public:
ComponentPool(const ::ComponentInfo& ci) ComponentPool(const ::ComponentInfo& ci)
: m_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;
ComponentPool(const ComponentPool&& other) = delete; ComponentPool(const ComponentPool&& other) = delete;
+30 -17
View File
@@ -18,21 +18,31 @@ struct ComponentWrapper
const ::EntityID EntityID; const ::EntityID EntityID;
char* Data; char* Data;
template <typename T> int Enum(const char* fieldName, const char* enumKey)
T& Property(std::string name)
{ {
unsigned int offset = Info.Fields.at(name).Offset; return Info.Meta->FieldEnumDefinitions.at(fieldName).at(enumKey);
return *reinterpret_cast<T*>(&Data[offset]);
} }
template <typename T> 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> //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 // Specialization for string literals
template <std::size_t N> 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 struct SubscriptProxy
{ {
@@ -47,18 +57,21 @@ struct ComponentWrapper
std::string m_PropertyName; std::string m_PropertyName;
public: public:
template <typename T> // Return the integer value of an enum type key for this field
operator T&() { return m_Component->Property<T>(m_PropertyName); } int Enum(const char* enumKey) { return m_Component->Enum(m_PropertyName.c_str(), enumKey); }
template <typename T> 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?) // TODO: Pass by reference and rvalue (universal reference?)
//template <typename T> //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 // Specialization for string literals
template<std::size_t N> template <std::size_t N>
void operator=(const char(&val)[N]) { m_Component->SetProperty<N>(m_PropertyName, val); } void operator=(const char(&val)[N]) { m_Component->SetField<N>(m_PropertyName, val); }
}; };
SubscriptProxy operator[](std::string propertyName) { return SubscriptProxy(this, propertyName); } SubscriptProxy operator[](std::string propertyName) { return SubscriptProxy(this, propertyName); }
}; };
@@ -71,7 +84,7 @@ public:
ComponentWrapperFactory(std::string componentTypeName, std::size_t allocation = 0) ComponentWrapperFactory(std::string componentTypeName, std::size_t allocation = 0)
{ {
m_ComponentInfo.Name = componentTypeName; m_ComponentInfo.Name = componentTypeName;
m_ComponentInfo.Meta.Allocation = allocation; m_ComponentInfo.Meta->Allocation = allocation;
} }
template <typename T> template <typename T>
@@ -79,14 +92,14 @@ public:
{ {
m_DefaultValues.push_back(defaultValue); m_DefaultValues.push_back(defaultValue);
m_ComponentInfo.Fields[fieldName].Name = typeid(T).name(); m_ComponentInfo.Fields[fieldName].Name = 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.Fields[fieldName].Stride = sizeof(T);
m_ComponentInfo.Meta.Stride += sizeof(T); m_ComponentInfo.Stride += sizeof(T);
} }
ComponentInfo& Finalize() 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; std::size_t offset = 0;
for (auto& val : m_DefaultValues) { for (auto& val : m_DefaultValues) {
memcpy(m_ComponentInfo.Defaults.get() + offset, val.Data.get(), val.Size); memcpy(m_ComponentInfo.Defaults.get() + offset, val.Data.get(), val.Size);
+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
+1
View File
@@ -4,4 +4,5 @@
typedef unsigned int EntityID; typedef unsigned int EntityID;
const static unsigned int EntityID_Invalid = -1; const static unsigned int EntityID_Invalid = -1;
#endif #endif
+8 -8
View File
@@ -285,7 +285,7 @@ private:
XSValue::Status status; XSValue::Status status;
XSValue* val = XSValue::getActualValue(child->getNodeValue(), XSValue::dt_integer, 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 // Save documentation string
@@ -293,11 +293,11 @@ private:
if (documentationTags->getLength() != 0) { if (documentationTags->getLength() != 0) {
auto child = documentationTags->item(0)->getFirstChild(); auto child = documentationTags->item(0)->getFirstChild();
if (child != nullptr) { if (child != nullptr) {
compInfo.Meta.Annotation = XSTR(child->getNodeValue()); compInfo.Meta->Annotation = XSTR(child->getNodeValue());
} }
} }
// TODO: Parse annotation string XML // TODO: Parse annotation string XML
// compInfo.Meta.Allocation = ... // compInfo.Meta->Allocation = ...
} else { } else {
std::cout << "Warning: Component is missing an annotation!" << std::endl; std::cout << "Warning: Component is missing an annotation!" << std::endl;
} }
@@ -344,7 +344,7 @@ private:
fieldOffset += getTypeStride(type); fieldOffset += getTypeStride(type);
} }
compInfo.Meta.Stride = fieldOffset; compInfo.Stride = fieldOffset;
m_ComponentInfo[compInfo.Name] = compInfo; m_ComponentInfo[compInfo.Name] = compInfo;
} }
} }
@@ -367,14 +367,14 @@ private:
std::string componentName = XSTR(component->getLocalName()); std::string componentName = XSTR(component->getLocalName());
auto& compInfo = m_ComponentInfo.at(componentName); auto& compInfo = m_ComponentInfo.at(componentName);
compInfo.Meta.Allocation += 1; compInfo.Meta->Allocation += 1;
} }
std::cout << "COMPONENT INFO" << std::endl; std::cout << "COMPONENT INFO" << std::endl;
for (auto& pair : m_ComponentInfo) { for (auto& pair : m_ComponentInfo) {
ComponentInfo& ci = pair.second; ComponentInfo& ci = pair.second;
std::cout << "Component: " << ci.Name << " (" << ci.Meta.Annotation << ")" << std::endl; std::cout << "Component: " << ci.Name << " (" << ci.Meta->Annotation << ")" << std::endl;
std::cout << " Allocation: " << ci.Meta.Allocation << std::endl; std::cout << " Allocation: " << ci.Meta->Allocation << std::endl;
std::cout << " Fields:" << std::endl; std::cout << " Fields:" << std::endl;
// Calculate component size // Calculate component size
@@ -393,7 +393,7 @@ private:
cs.ComponentName = ci.Name; cs.ComponentName = ci.Name;
cs.Stride = stride; cs.Stride = stride;
cs.Info = ci; cs.Info = ci;
cs.Data = new char[stride*ci.Meta.Allocation]; cs.Data = new char[stride*ci.Meta->Allocation];
m_ComponentStore[cs.ComponentName] = cs; m_ComponentStore[cs.ComponentName] = cs;
} }
} }
+18 -147
View File
@@ -73,88 +73,15 @@ public:
ComponentField ComponentField
}; };
EntityFileSAXHandler(const EntityFileHandler* handler, xercesc::SAX2XMLReader* reader) 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);
}
void startElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname, const xercesc::Attributes& attrs) override 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;
std::string name = XS::ToString(_localName); 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) { void warning(const xercesc::SAXParseException& e);
if (name == "Entity") { void error(const xercesc::SAXParseException& e);
m_StateStack.push(State::Entity); void fatalError(const xercesc::SAXParseException& e);
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;
}
private: private:
const EntityFileHandler* m_Handler; const EntityFileHandler* m_Handler;
@@ -168,73 +95,14 @@ private:
std::string m_CurrentField; std::string m_CurrentField;
std::map<std::string, std::string> m_CurrentAttributes; std::map<std::string, std::string> m_CurrentAttributes;
void onStartEntity(const xercesc::Attributes& attrs) void onStartEntity(const xercesc::Attributes& attrs);
{ void onEndEntity();
EntityID parent = m_EntityStack.top(); void onStartEntityRef(const xercesc::Attributes& attrs);
void onStartComponent(const std::string& name);
if (m_Handler->m_OnStartEntityCallback) { void onEndComponent(const std::string& name);
std::string name; void onStartComponentField(const std::string& field, const xercesc::Attributes& attrs);
auto xName = attrs.getValue(XS::ToXMLCh("name")); void onEndComponentField(const std::string& field);
if (xName != nullptr) { void onFieldData(char* data);
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);
}
}; };
class EntityFileXMLErrorHandler : public xercesc::ErrorHandler class EntityFileXMLErrorHandler : public xercesc::ErrorHandler
@@ -269,6 +137,7 @@ private:
class EntityFile : public Resource class EntityFile : public Resource
{ {
friend class ResourceManager; friend class ResourceManager;
friend class EntityFileSAXHandler;
private: private:
EntityFile(boost::filesystem::path path); EntityFile(boost::filesystem::path path);
~EntityFile(); ~EntityFile();
@@ -288,6 +157,8 @@ private:
xercesc::SAX2XMLReader* m_SAX2XMLReader; xercesc::SAX2XMLReader* m_SAX2XMLReader;
//std::map<std::string, ::ComponentInfo> m_ComponentInfo; //std::map<std::string, ::ComponentInfo> m_ComponentInfo;
//std::vector<std::string> m_EntityReferences; //std::vector<std::string> m_EntityReferences;
static void setReaderFeatures(xercesc::SAX2XMLReader* reader);
}; };
#endif #endif
+2 -1
View File
@@ -9,12 +9,13 @@ class EntityFileParser
public: public:
EntityFileParser(const EntityFile* entityFile); EntityFileParser(const EntityFile* entityFile);
void MergeEntities(World* world); EntityID MergeEntities(World* world, EntityID baseParent = EntityID_Invalid);
private: private:
const EntityFile* m_EntityFile; const EntityFile* m_EntityFile;
EntityFileHandler m_Handler; EntityFileHandler m_Handler;
World* m_World = nullptr; 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 // Maps EntityIDs local to the file to real IDs in the world after they've been
// created in order to resolve parent-child relationships. // created in order to resolve parent-child relationships.
std::map<EntityID, EntityID> m_EntityIDMapper; std::map<EntityID, EntityID> m_EntityIDMapper;
@@ -5,6 +5,7 @@
#include <xercesc/framework/psvi/XSComplexTypeDefinition.hpp> #include <xercesc/framework/psvi/XSComplexTypeDefinition.hpp>
#include <xercesc/framework/psvi/XSParticle.hpp> #include <xercesc/framework/psvi/XSParticle.hpp>
#include <xercesc/framework/psvi/XSModelGroup.hpp> #include <xercesc/framework/psvi/XSModelGroup.hpp>
#include <xercesc/framework/psvi/XSModelGroupDefinition.hpp>
#include <xercesc/framework/psvi/XSAnnotation.hpp> #include <xercesc/framework/psvi/XSAnnotation.hpp>
#include <xercesc/framework/psvi/XSValue.hpp> #include <xercesc/framework/psvi/XSValue.hpp>
#include <xercesc/framework/MemBufFormatTarget.hpp> #include <xercesc/framework/MemBufFormatTarget.hpp>
@@ -31,6 +32,7 @@ private:
void onStartComponent(EntityID entity, std::string type); void onStartComponent(EntityID entity, std::string type);
void parseComponentInfo(); void parseComponentInfo();
void parseDefaults(); void parseDefaults();
std::string parseAnnotationXML(const XMLCh* xml);
}; };
#endif #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 class EventRelay : public BaseEventRelay
{ {
public: public:
typedef std::function<bool(const EventType&)> CallbackType; typedef std::function<bool(EventType&)> CallbackType;
EventRelay() EventRelay()
: m_Callback(nullptr) : m_Callback(nullptr)
@@ -65,7 +65,7 @@ template <typename ContextType, typename EventType>
bool EventRelay<ContextType, EventType>::Receive(const std::shared_ptr<Event> event) bool EventRelay<ContextType, EventType>::Receive(const std::shared_ptr<Event> event)
{ {
if (m_Callback != nullptr) { if (m_Callback != nullptr) {
return m_Callback(*static_cast<const EventType*>(event.get())); return m_Callback(*static_cast<EventType*>(event.get()));
} else { } else {
return false; return false;
} }
-104
View File
@@ -1,104 +0,0 @@
#ifndef OctTree_h__
#define OctTree_h__
#include "Core/AABB.h"
class Ray;
class OctTree
{
public:
struct Output
{
float CollideDistance;
};
OctTree();
~OctTree();
//For the root OctTree, [octTreeBounds] should be a box containing the entire level.
OctTree(const AABB& octTreeBounds, 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;
//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);
//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<AABB>& 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();
//Returns true if the ray collides with something in the tree. Result is written to [data].
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);
private:
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<ContainedObject> m_StaticObjects;
std::vector<ContainedObject> m_DynamicObjects;
bool m_UpdatedOnce;
unsigned int m_BoxID;
glm::vec3 m_PrevPos;
glm::quat m_PrevOri;
void falsifyObjectChecks();
struct OctChild
{
~OctChild();
OctChild(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;
void AddDynamicObject(const AABB& box);
void AddStaticObject(const AABB& box);
void BoxesInSameRegion(const AABB& box, std::vector<AABB>& 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<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;
inline bool hasChildren() const;
int childIndexContainingPoint(const glm::vec3& point) const;
std::vector<int> childIndicesContainingBox(const AABB& box) const;
};
};
#endif
+233
View File
@@ -0,0 +1,233 @@
#ifndef Octree_h__
#define Octree_h__
#include <type_traits>
#include "../Common.h"
#include "AABB.h"
//Fwd declarations.
class Ray;
namespace OctSpace
{
struct Output;
struct ContainedObject;
struct Child;
}
//T needs to be AABB, or inherit from AABB.
//T also needs to have a default constructor.
template<typename T>
class Octree
{
public:
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 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 T& object);
//Add a static object (that does not move) into the tree.
void AddStaticObject(const T& object);
//Get the objects that are in the same area as the input [box], the objects are put in [outObjects].
//The type Box must be AABB, or inherit from AABB.
template<typename Box>
void ObjectsInSameRegion(const Box& box, std::vector<T>& outObjects);
//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();
//Returns true if the ray collides with something in the tree. Result is written to [data].
bool RayCollides(const Ray& ray, OctSpace::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 ObjectsInSameRegion from outside and testing there.
bool BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected);
private:
OctSpace::Child* m_Root;
std::vector<OctSpace::ContainedObject> m_StaticObjects;
std::vector<OctSpace::ContainedObject> m_DynamicObjects;
void falsifyObjectChecks();
};
namespace OctSpace
{
struct Output
{
float CollideDistance;
};
struct ContainedObject
{
ContainedObject()
: Box(nullptr)
, Checked(false)
{}
template<typename BoxlikeObject>
ContainedObject(const BoxlikeObject& box)
: Box(new BoxlikeObject(box))
, Checked(false)
{}
std::unique_ptr<AABB> Box;
bool Checked;
};
struct Child
{
~Child();
Child(const AABB& octTreeBounds,
int subDivisions,
std::vector<ContainedObject>& staticObjects,
std::vector<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);
template<typename T, typename Box>
void ObjectsInSameRegion(const Box& box, std::vector<T>& outObjects) const;
void ClearObjects();
void ClearDynamicObjects();
bool RayCollides(const Ray& ray, Output& data) const;
bool BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const;
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 Octree.
std::vector<ContainedObject>& m_StaticObjectsRef;
std::vector<ContainedObject>& m_DynamicObjectsRef;
inline bool hasChildren() const;
int childIndexContainingPoint(const glm::vec3& point) const;
std::vector<int> childIndicesContainingBox(const AABB& box) const;
};
}
template<typename T>
Octree<T>::Octree(const AABB& octTreeBounds, int subDivisions)
: m_Root(new OctSpace::Child(octTreeBounds, subDivisions, m_StaticObjects, m_DynamicObjects))
{
static_assert(std::is_base_of<AABB, T>::value, "template argument type T in Octree must be a subclass of AABB.");
}
template<typename T>
Octree<T>::~Octree()
{
delete m_Root;
}
template<typename T>
void Octree<T>::AddDynamicObject(const T& object)
{
m_Root->AddDynamicObject(object);
m_DynamicObjects.emplace_back(object);
}
template<typename T>
void Octree<T>::AddStaticObject(const T& object)
{
m_Root->AddStaticObject(object);
m_StaticObjects.emplace_back(object);
}
template<typename T>
template<typename Box>
void Octree<T>::ObjectsInSameRegion(const Box& box, std::vector<T>& outObjects)
{
static_assert(std::is_base_of<AABB, Box>::value, "template argument type Box in Octree<T>::ObjectsInSameRegion must be a subclass of AABB.");
falsifyObjectChecks();
m_Root->ObjectsInSameRegion(box, outObjects);
}
template<typename T>
void Octree<T>::ClearObjects()
{
m_StaticObjects.clear();
m_DynamicObjects.clear();
m_Root->ClearObjects();
}
template<typename T>
void Octree<T>::ClearDynamicObjects()
{
m_DynamicObjects.clear();
m_Root->ClearDynamicObjects();
}
template<typename T>
bool Octree<T>::RayCollides(const Ray& ray, OctSpace::Output& data)
{
falsifyObjectChecks();
data.CollideDistance = -1;
return m_Root->RayCollides(ray, data);
}
template<typename T>
bool Octree<T>::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected)
{
falsifyObjectChecks();
return m_Root->BoxCollides(boxToTest, outBoxIntersected);
}
template<typename T>
void Octree<T>::falsifyObjectChecks()
{
for (auto& obj : m_StaticObjects) {
obj.Checked = false;
}
for (auto& obj : m_DynamicObjects) {
obj.Checked = false;
}
}
template<typename T, typename Box>
void OctSpace::Child::ObjectsInSameRegion(const Box& box, std::vector<T>& outObjects) const
{
if (hasChildren()) {
for (auto i : childIndicesContainingBox(box)) {
m_Children[i]->ObjectsInSameRegion(box, outObjects);
}
} else {
size_t startIndex = outObjects.size();
int numDuplicates = 0;
outObjects.resize(outObjects.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;
outObjects[startIndex + i - numDuplicates] = *static_cast<T*>(obj.Box.get());
}
}
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;
outObjects[startIndex + i - numDuplicates] = *static_cast<T*>(obj.Box.get());
}
}
for (size_t i = 0; i < numDuplicates; ++i) {
outObjects.pop_back();
}
}
}
#endif
+10 -9
View File
@@ -3,6 +3,7 @@
#include "EventBroker.h" #include "EventBroker.h"
#include "World.h" #include "World.h"
#include "EntityWrapper.h"
#include "ComponentWrapper.h" #include "ComponentWrapper.h"
class System class System
@@ -10,6 +11,9 @@ class System
friend class SystemPipeline; friend class SystemPipeline;
protected: protected:
System()
: m_EventBroker(nullptr)
{ }
System(EventBroker* eventBroker) System(EventBroker* eventBroker)
: m_EventBroker(eventBroker) : m_EventBroker(eventBroker)
{ } { }
@@ -18,30 +22,27 @@ protected:
EventBroker* m_EventBroker; EventBroker* m_EventBroker;
}; };
class PureSystem : public System class PureSystem : public virtual System
{ {
friend class SystemPipeline; friend class SystemPipeline;
protected: protected:
PureSystem(EventBroker* eventBroker, std::string componentType) PureSystem(std::string componentType)
: System(eventBroker) : m_ComponentType(componentType)
, m_ComponentType(componentType)
{ } { }
virtual ~PureSystem() = default; virtual ~PureSystem() = default;
const std::string m_ComponentType; 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; friend class SystemPipeline;
protected: protected:
ImpureSystem(EventBroker* eventBroker) ImpureSystem() = default;
: System(eventBroker)
{ }
virtual ~ImpureSystem() = default; virtual ~ImpureSystem() = default;
virtual void Update(World* world, double dt) = 0; virtual void Update(World* world, double dt) = 0;
+8 -8
View File
@@ -32,8 +32,8 @@ public:
System* system = new T(m_EventBroker, args...); System* system = new T(m_EventBroker, args...);
group.Systems[typeid(T).name()] = system; group.Systems[typeid(T).name()] = system;
if (std::is_base_of<PureSystem, T>::value) { PureSystem* pureSystem = dynamic_cast<PureSystem*>(system);
PureSystem* pureSystem = static_cast<PureSystem*>(system); if (pureSystem != nullptr) {
if (!pureSystem->m_ComponentType.empty()) { if (!pureSystem->m_ComponentType.empty()) {
group.PureSystems[pureSystem->m_ComponentType].push_back(pureSystem); group.PureSystems[pureSystem->m_ComponentType].push_back(pureSystem);
} else { } else {
@@ -41,8 +41,8 @@ public:
} }
} }
if (std::is_base_of<ImpureSystem, T>::value) { ImpureSystem* impureSystem = dynamic_cast<ImpureSystem*>(system);
ImpureSystem* impureSystem = static_cast<ImpureSystem*>(system); if (impureSystem != nullptr) {
group.ImpureSystems.push_back(impureSystem); group.ImpureSystems.push_back(impureSystem);
} }
} }
@@ -56,6 +56,9 @@ public:
} }
// Update // Update
for (auto& system : group.ImpureSystems) {
system->Update(world, dt);
}
for (auto& pair : group.PureSystems) { for (auto& pair : group.PureSystems) {
const std::string& componentName = pair.first; const std::string& componentName = pair.first;
auto& systems = pair.second; auto& systems = pair.second;
@@ -65,13 +68,10 @@ public:
} }
for (auto& component : *pool) { for (auto& component : *pool) {
for (auto& system : systems) { 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);
}
} }
} }
+7 -5
View File
@@ -21,19 +21,21 @@ public:
// Register a component type and allocate space for it // Register a component type and allocate space for it
void RegisterComponent(ComponentInfo& ci); void RegisterComponent(ComponentInfo& ci);
// Attach a component to an entity and fill it with default values // 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 // 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 // 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 // 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 // Get all components of the specified type
const ComponentPool* GetComponents(std::string componentType); const ComponentPool* GetComponents(const std::string& componentType);
// Get entity parent // Get entity parent
EntityID GetParent(EntityID entity); EntityID GetParent(EntityID entity);
// Change the parent of an entity // Change the parent of an entity
void SetParent(EntityID entity, EntityID parent); 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 // Get all component pools
const std::unordered_map<std::string, ComponentPool*>& GetComponentPools() const { return m_ComponentPools; } const std::unordered_map<std::string, ComponentPool*>& GetComponentPools() const { return m_ComponentPools; }
// Get the entity children map // Get the entity children map
+1
View File
@@ -1,6 +1,7 @@
#ifndef InputProxy_h__ #ifndef InputProxy_h__
#define InputProxy_h__ #define InputProxy_h__
#include <boost/tokenizer.hpp>
#include "../Common.h" #include "../Common.h"
#include "../Core/ResourceManager.h" #include "../Core/ResourceManager.h"
#include "../Core/ConfigFile.h" #include "../Core/ConfigFile.h"
+18
View File
@@ -0,0 +1,18 @@
#ifndef ESpawnerSpawn_h__
#define ESpawnerSpawn_h__
#include "Core/Event.h"
#include "Core/EntityWrapper.h"
namespace Events
{
struct SpawnerSpawn : Event
{
EntityWrapper Spawner;
EntityWrapper Parent;
};
}
#endif
+3 -2
View File
@@ -14,12 +14,11 @@
#include "Core/EKeyDown.h" #include "Core/EKeyDown.h"
#include "Core/EntityFilePreprocessor.h" #include "Core/EntityFilePreprocessor.h"
#include "Core/SystemPipeline.h" #include "Core/SystemPipeline.h"
#include "RaptorCopterSystem.h"
#include "PlayerSystem.h"
#include "Editor/EditorSystem.h" #include "Editor/EditorSystem.h"
#include "Core/EntityFile.h" #include "Core/EntityFile.h"
#include "Rendering/RenderSystem.h" #include "Rendering/RenderSystem.h"
#include "Core/EntityFileParser.h" #include "Core/EntityFileParser.h"
#include "Core/Octree.h"
// Network // Network
#include <boost/thread.hpp> #include <boost/thread.hpp>
@@ -48,6 +47,8 @@ private:
InputProxy* m_InputProxy; InputProxy* m_InputProxy;
GUI::Frame* m_FrameStack; GUI::Frame* m_FrameStack;
World* m_World; World* m_World;
Octree<AABB>* m_OctreeCollision;
Octree<AABB>* m_OctreeFrustrumCulling;
SystemPipeline* m_SystemPipeline; SystemPipeline* m_SystemPipeline;
RenderFrame* m_RenderFrame; RenderFrame* m_RenderFrame;
// Network variables // Network variables
-33
View File
@@ -1,33 +0,0 @@
#ifndef PlayerSystem_h__
#define PlayerSystem_h__
#include <GLFW/glfw3.h>
#include <glm/common.hpp>
#include "Common.h"
#include "Core/System.h"
#include "Collision/ETrigger.h"
class PlayerSystem : public PureSystem
{
public:
PlayerSystem(EventBroker* eventBroker)
: PureSystem(eventBroker, "Player")
{
EVENT_SUBSCRIBE_MEMBER(m_ETouch, &PlayerSystem::OnTouch);
EVENT_SUBSCRIBE_MEMBER(m_EEnter, &PlayerSystem::OnEnter);
EVENT_SUBSCRIBE_MEMBER(m_ELeave, &PlayerSystem::OnLeave);
}
virtual void UpdateComponent(World* world, ComponentWrapper& player, double dt) override;
private:
float m_Speed = 5;
EventRelay<PlayerSystem, Events::TriggerEnter> m_EEnter;
bool OnEnter(const Events::TriggerEnter &event);
EventRelay<PlayerSystem, Events::TriggerTouch> m_ETouch;
bool PlayerSystem::OnTouch(const Events::TriggerTouch &event);
EventRelay<PlayerSystem, Events::TriggerLeave> m_ELeave;
bool PlayerSystem::OnLeave(const Events::TriggerLeave &event);
};
#endif
-16
View File
@@ -1,16 +0,0 @@
#include "Common.h"
#include "Core/System.h"
class RaptorCopterSystem : public PureSystem
{
public:
RaptorCopterSystem(EventBroker* eventBroker)
: PureSystem(eventBroker, "RaptorCopter")
{ }
virtual void UpdateComponent(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"];
}
};
@@ -6,9 +6,9 @@
#include "Common.h" #include "Common.h"
#include "Core/System.h" #include "Core/System.h"
#include "Core\EPlayerDamage.h"; #include "Core/EPlayerDamage.h"
#include "Core\EPlayerHealthPickup.h"; #include "Core/EPlayerHealthPickup.h"
#include "Core\EPlayerDeath.h"; #include "Core/EPlayerDeath.h"
#include <tuple> #include <tuple>
#include <vector> #include <vector>
@@ -19,7 +19,7 @@ public:
HealthSystem(EventBroker* eventBroker); HealthSystem(EventBroker* eventBroker);
//updatecomponent //updatecomponent
virtual void UpdateComponent(World* world, ComponentWrapper& health, double dt) override; virtual void UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) override;
private: private:
//methods which will take care of specific events //methods which will take care of specific events
@@ -0,0 +1,14 @@
#include "Common.h"
#include "GLM.h"
#include "Core/System.h"
class PlayerMovementSystem : public PureSystem
{
public:
PlayerMovementSystem(EventBroker* eventBroker)
: System(eventBroker)
, PureSystem("Player")
{ }
virtual void UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt);
};
+18
View File
@@ -0,0 +1,18 @@
#include "Core/System.h"
#include "Input/EInputCommand.h"
#include "Systems/SpawnerSystem.h"
#include "Events/ESpawnerSpawn.h"
class PlayerSpawnSystem : public ImpureSystem
{
public:
PlayerSpawnSystem(EventBroker* eventBroker);
virtual void Update(World* world, double dt) override;
private:
EventRelay<PlayerSpawnSystem, Events::InputCommand> m_OnInputCommand;
bool OnInputCommand(const Events::InputCommand& e);
std::vector<int> m_SpawnRequests;
};
+17
View File
@@ -0,0 +1,17 @@
#include "Common.h"
#include "Core/System.h"
class RaptorCopterSystem : public PureSystem
{
public:
RaptorCopterSystem(EventBroker* eventBroker)
: System(eventBroker)
, PureSystem("RaptorCopter")
{ }
virtual void UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) override
{
ComponentWrapper& transform = world->GetComponent(component.EntityID, "Transform");
(glm::vec3&)transform["Orientation"] += (float)(double)component["Speed"] * (float)dt * (glm::vec3)component["Axis"];
}
};
+25
View File
@@ -0,0 +1,25 @@
#ifndef SpawnerSystem_h__
#define SpawnerSystem_h__
#include <random>
#include "Common.h"
#include "GLM.h"
#include "Core/System.h"
#include "Events/ESpawnerSpawn.h"
#include "Core/Transform.h"
#include "Core/ResourceManager.h"
#include "Core/EntityFileParser.h"
class SpawnerSystem : public System
{
public:
SpawnerSystem(EventBroker* eventBroker);
static EntityWrapper Spawn(EntityWrapper spawner, EntityWrapper parent = EntityWrapper::Invalid);
private:
EventRelay<SpawnerSystem, Events::SpawnerSpawn> m_OnSpawnerSpawn;
bool OnSpawnerSpawn(Events::SpawnerSpawn& e);
};
#endif
+4 -4
View File
@@ -6,10 +6,10 @@ InvertPitch=false
MouseLeft=PrimaryFire MouseLeft=PrimaryFire
MouseX=Yaw MouseX=Yaw
MouseY=Pitch MouseY=Pitch
W=+Forward W=Forward,1
S=-Forward S=Forward,-1
D=+Right D=Right,1
A=-Right A=Right,-1
R=Reload R=Reload
Space=Jump Space=Jump
LeftControl=Crouch LeftControl=Crouch
+6 -1
View File
@@ -2,8 +2,8 @@
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="components" elementFormDefault="qualified"> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="components" elementFormDefault="qualified">
<xs:include schemaLocation="Components/Transform.xsd"/> <xs:include schemaLocation="Components/Transform.xsd"/>
<xs:include schemaLocation="Components/Physics.xsd"/>
<xs:include schemaLocation="Components/Model.xsd"/> <xs:include schemaLocation="Components/Model.xsd"/>
<xs:include schemaLocation="Components/Test.xsd"/>
<xs:include schemaLocation="Components/RaptorCopter.xsd"/> <xs:include schemaLocation="Components/RaptorCopter.xsd"/>
<xs:include schemaLocation="Components/Player.xsd"/> <xs:include schemaLocation="Components/Player.xsd"/>
<xs:include schemaLocation="Components/Camera.xsd"/> <xs:include schemaLocation="Components/Camera.xsd"/>
@@ -13,4 +13,9 @@
<xs:include schemaLocation="Components/Health.xsd"/> <xs:include schemaLocation="Components/Health.xsd"/>
<xs:include schemaLocation="Components/Listener.xsd"/> <xs:include schemaLocation="Components/Listener.xsd"/>
<xs:include schemaLocation="Components/SoundEmitter.xsd"/> <xs:include schemaLocation="Components/SoundEmitter.xsd"/>
<xs:include schemaLocation="Components/Collidable.xsd"/>
<xs:include schemaLocation="Components/Spawner.xsd"/>
<xs:include schemaLocation="Components/SpawnPoint.xsd"/>
<xs:include schemaLocation="Components/PlayerSpawn.xsd"/>
<xs:include schemaLocation="Components/Team.xsd"/>
</xs:schema> </xs:schema>
+5 -4
View File
@@ -1,4 +1,5 @@
<c:AABB> <?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<BoxCenter X="0" Y="0" Z="0"/> <AABB xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="AABB.xsd">
<BoxSize X="1" Y="1" Z="1"/> <Origin X="0" Y="0" Z="0"/>
</c:AABB> <Size X="1" Y="1" Z="1"/>
</AABB>
+6 -2
View File
@@ -6,8 +6,12 @@
<xs:element name="AABB"> <xs:element name="AABB">
<xs:complexType> <xs:complexType>
<xs:all> <xs:all>
<xs:element name="BoxCenter" type="t:Vector" minOccurs="0"/> <xs:element name="Origin" type="t:Vector" minOccurs="0">
<xs:element name="BoxSize" type="t:Vector" minOccurs="0"/> <xs:annotation><xs:documentation>Middle point of the bounding box</xs:documentation></xs:annotation>
</xs:element>
<xs:element name="Size" type="t:Vector" minOccurs="0">
<xs:annotation><xs:documentation>Size of the bounding box</xs:documentation></xs:annotation>
</xs:element>
</xs:all> </xs:all>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
+4 -3
View File
@@ -1,6 +1,7 @@
<c:Camera> <?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<Camera xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Camera.xsd">
<Name>cam</Name> <Name>cam</Name>
<FOV>60.0</FOV> <FOV>45</FOV>
<NearClip>0.01</NearClip> <NearClip>0.01</NearClip>
<FarClip>5000</FarClip> <FarClip>5000</FarClip>
</c:Camera> </Camera>
+3 -1
View File
@@ -10,7 +10,9 @@
<xs:complexType> <xs:complexType>
<xs:all> <xs:all>
<xs:element name="Name" type="t:string" minOccurs="0"/> <xs:element name="Name" type="t:string" minOccurs="0"/>
<xs:element name="FOV" type="t:double" minOccurs="0"/> <xs:element name="FOV" type="t:double" minOccurs="0">
<xs:annotation><xs:documentation>Vertical Field of View in degrees</xs:documentation></xs:annotation>
</xs:element>
<xs:element name="NearClip" type="t:double" minOccurs="0"/> <xs:element name="NearClip" type="t:double" minOccurs="0"/>
<xs:element name="FarClip" type="t:double" minOccurs="0"/> <xs:element name="FarClip" type="t:double" minOccurs="0"/>
</xs:all> </xs:all>
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<Collidable xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Collidable.xsd">
</Collidable>
@@ -0,0 +1,8 @@
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:t="types">
<xs:import schemaLocation="../Types.xsd" namespace="types"/>
<xs:element name="Collidable">
</xs:element>
</xs:schema>
+3 -2
View File
@@ -1,4 +1,5 @@
<c:Health> <?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<Health xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Health.xsd">
<Health>100</Health> <Health>100</Health>
<MaxHealth>100</MaxHealth> <MaxHealth>100</MaxHealth>
</c:Health> </Health>
+2 -3
View File
@@ -1,3 +1,2 @@
<c:Listener> <?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<Listener xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Listener.xsd"/>
</c:Listener>
+3 -2
View File
@@ -1,5 +1,6 @@
<c:Model> <?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<Model xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Model.xsd">
<Resource></Resource> <Resource></Resource>
<Color R="1" G="1" B="1" A="1"/> <Color R="1" G="1" B="1" A="1"/>
<Visible>true</Visible> <Visible>true</Visible>
</c:Model> </Model>
+5
View File
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<Physics xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Physics.xsd">
<Velocity X="0" Y="0" Z="0"/>
<Gravity>true</Gravity>
</Physics>
+17
View File
@@ -0,0 +1,17 @@
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:t="types">
<xs:import schemaLocation="../Types.xsd" namespace="types"/>
<xs:element name="Physics">
<xs:annotation>
<xs:documentation>Physics stuff</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:all>
<xs:element name="Velocity" type="t:Vector" minOccurs="0"/>
<xs:element name="Gravity" type="t:bool" minOccurs="0"/>
</xs:all>
</xs:complexType>
</xs:element>
</xs:schema>
+3 -2
View File
@@ -1,7 +1,8 @@
<c:Player> <?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<Player xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Player.xsd">
<Velocity X="0" Y="0" Z="0"/> <Velocity X="0" Y="0" Z="0"/>
<Forward>false</Forward> <Forward>false</Forward>
<Left>false</Left> <Left>false</Left>
<Back>false</Back> <Back>false</Back>
<Right>false</Right> <Right>false</Right>
</c:Player> </Player>
@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<PlayerSpawn xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="PlayerSpawn.xsd"/>
@@ -0,0 +1,11 @@
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:t="types">
<xs:import schemaLocation="../Types.xsd" namespace="types"/>
<xs:element name="PlayerSpawn">
<xs:annotation>
<xs:documentation>Combined with a Spawner and a Team component, defines a spawn point for a player team.</xs:documentation>
</xs:annotation>
</xs:element>
</xs:schema>
+3 -2
View File
@@ -1,7 +1,8 @@
<c:PointLight> <?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<PointLight xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="PointLight.xsd">
<Color R="1" G="1" B="1" A="1"/> <Color R="1" G="1" B="1" A="1"/>
<Radius>1.0</Radius> <Radius>1.0</Radius>
<Intensity>0.8</Intensity> <Intensity>0.8</Intensity>
<Falloff>0.3</Falloff> <Falloff>0.3</Falloff>
<Visible>true</Visible> <Visible>true</Visible>
</c:PointLight> </PointLight>
+8 -1
View File
@@ -12,7 +12,14 @@
<xs:element name="Color" type="t:Color" minOccurs="0"/> <xs:element name="Color" type="t:Color" minOccurs="0"/>
<xs:element name="Radius" type="t:double" minOccurs="0"/> <xs:element name="Radius" type="t:double" minOccurs="0"/>
<xs:element name="Intensity" type="t:double" minOccurs="0"/> <xs:element name="Intensity" type="t:double" minOccurs="0"/>
<xs:element name="Falloff" type="t:double" minOccurs="0" minInclusive="0" maxInclusive="1"/> <xs:element name="Falloff">
<xs:simpleType>
<xs:restriction base="t:double">
<xs:minInclusive value="0"/>
<xs:maxInclusive value="1"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="Visible" type="t:bool" minOccurs="0"/> <xs:element name="Visible" type="t:bool" minOccurs="0"/>
</xs:all> </xs:all>
</xs:complexType> </xs:complexType>
+3 -2
View File
@@ -1,4 +1,5 @@
<c:RaptorCopter> <?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<RaptorCopter xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="RaptorCopter.xsd">
<Speed>0</Speed> <Speed>0</Speed>
<Axis X="0" Y="0" Z="0"/> <Axis X="0" Y="0" Z="0"/>
</c:RaptorCopter> </RaptorCopter>
+3 -2
View File
@@ -1,4 +1,5 @@
<c:SoundEmitter> <?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<SoundEmitter xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="SoundEmitter.xsd">
<FilePath></FilePath> <FilePath></FilePath>
<Gain>1.0</Gain> <Gain>1.0</Gain>
<Pitch>1.0</Pitch> <Pitch>1.0</Pitch>
@@ -6,4 +7,4 @@
<MaxDistance>20.0</MaxDistance> <MaxDistance>20.0</MaxDistance>
<RollOffFactor>1.0</RollOffFactor> <RollOffFactor>1.0</RollOffFactor>
<ReferenceDistance>1.0</ReferenceDistance> <ReferenceDistance>1.0</ReferenceDistance>
</c:SoundEmitter> </SoundEmitter>
+12 -6
View File
@@ -7,18 +7,24 @@
<xs:complexType> <xs:complexType>
<xs:all> <xs:all>
<xs:element name="FilePath" type="t:string" minOccurs="0"/> <xs:element name="FilePath" type="t:string" minOccurs="0"/>
<xs:element name="Gain" type="t:double" minOccurs="0"/> <xs:element name="Gain" type="t:double" minOccurs="0">
<xs:annotation><xs:documentation>The "volume" of the emitter. A value betweeen 0-1</xs:documentation></xs:annotation> <xs:annotation><xs:documentation>The "volume" of the emitter. A value betweeen 0-1</xs:documentation></xs:annotation>
<xs:element name="Pitch" type="t:double" minOccurs="0"/> </xs:element>
<xs:element name="Pitch" type="t:double" minOccurs="0">
<xs:annotation><xs:documentation>The pitch of the emitter. A value betweeen 0-1</xs:documentation></xs:annotation> <xs:annotation><xs:documentation>The pitch of the emitter. A value betweeen 0-1</xs:documentation></xs:annotation>
<xs:element name="Loop" type="t:bool" minOccurs="0"/> </xs:element>
<xs:element name="Loop" type="t:bool" minOccurs="0">
<xs:annotation><xs:documentation>If the sound should loop or not.</xs:documentation></xs:annotation> <xs:annotation><xs:documentation>If the sound should loop or not.</xs:documentation></xs:annotation>
<xs:element name="MaxDistance" type="t:double" minOccurs="0"/> </xs:element>
<xs:element name="MaxDistance" type="t:double" minOccurs="0">
<xs:annotation><xs:documentation>The distance where there will no longer be any attenuation.</xs:documentation></xs:annotation> <xs:annotation><xs:documentation>The distance where there will no longer be any attenuation.</xs:documentation></xs:annotation>
<xs:element name="RollOffFactor" type="t:double" minOccurs="0"/> </xs:element>
<xs:element name="RollOffFactor" type="t:double" minOccurs="0">
<xs:annotation><xs:documentation>The rolloff rate of the source.</xs:documentation></xs:annotation> <xs:annotation><xs:documentation>The rolloff rate of the source.</xs:documentation></xs:annotation>
<xs:element name="ReferenceDistance" type="t:double" minOccurs="0"/> </xs:element>
<xs:element name="ReferenceDistance" type="t:double" minOccurs="0">
<xs:annotation><xs:documentation>The distance that the source will be the loudest.</xs:documentation></xs:annotation> <xs:annotation><xs:documentation>The distance that the source will be the loudest.</xs:documentation></xs:annotation>
</xs:element>
</xs:all> </xs:all>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<SpawnPoint xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="SpawnPoint.xsd"/>
@@ -0,0 +1,11 @@
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:t="types">
<xs:import schemaLocation="../Types.xsd" namespace="types"/>
<xs:element name="SpawnPoint">
<xs:annotation>
<xs:documentation>Defines this entity as a spawn point for a parent Spawner</xs:documentation>
</xs:annotation>
</xs:element>
</xs:schema>
+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<Spawner xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Spawner.xsd">
<EntityFile></EntityFile>
</Spawner>
+18
View File
@@ -0,0 +1,18 @@
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:t="types">
<xs:import schemaLocation="../Types.xsd" namespace="types"/>
<xs:element name="Spawner">
<xs:annotation>
<xs:documentation>Randomly selects a child SpawnPoint component and spawns a copy of an entity template when receiving a SpawnerSpawn event. If no SpawnPoint is found it spawns from its own position.</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:all>
<xs:element name="EntityFile" type="t:string" minOccurs="0">
<xs:annotation><xs:documentation>The entity template to spawn</xs:documentation></xs:annotation>
</xs:element>
</xs:all>
</xs:complexType>
</xs:element>
</xs:schema>
+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<Team xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Team.xsd">
<Team><Spectator/></Team>
</Team>
+28
View File
@@ -0,0 +1,28 @@
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:t="types">
<xs:import schemaLocation="../Types.xsd" namespace="types"/>
<xs:complexType name="TeamEnum" mixed="true">
<xs:complexContent>
<xs:extension base="t:enum">
<xs:choice>
<xs:element name="Spectator" type="xs:integer" fixed="1" minOccurs="0"/>
<xs:element name="Red" type="xs:integer" fixed="2" minOccurs="0"/>
<xs:element name="Blue" type="xs:integer" fixed="3" minOccurs="0"/>
</xs:choice>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="Team">
<xs:annotation>
<xs:documentation>Represents entity team affiliation</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:all>
<xs:element name="Team" type="TeamEnum" minOccurs="0"/>
</xs:all>
</xs:complexType>
</xs:element>
</xs:schema>
+3 -2
View File
@@ -1,5 +1,6 @@
<c:Transform> <?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<Transform xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Transform.xsd">
<Position X="0" Y="0" Z="0"/> <Position X="0" Y="0" Z="0"/>
<Orientation X="0" Y="0" Z="0"/> <Orientation X="0" Y="0" Z="0"/>
<Scale X="1" Y="1" Z="1"/> <Scale X="1" Y="1" Z="1"/>
</c:Transform> </Transform>
+3 -2
View File
@@ -1,2 +1,3 @@
<c:Trigger> <?xml version="1.0" encoding="UTF-8" standalone="no" ?>
</c:Trigger> <Trigger xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Trigger.xsd">
</Trigger>
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<Entity xmlns:c="components" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../Types/Entity.xsd">
<Components>
<c:Transform/>
</Components>
<Children>
<Entity>
<Components>
<c:AABB/>
<c:Collidable>
<Static>false</Static>
</c:Collidable>
<c:Transform>
<Position X="1.5" Y="0" Z="-7"/>
</c:Transform>
</Components>
<Children/>
</Entity>
<Entity>
<Components>
<c:Collidable>
<Static>false</Static>
</c:Collidable>
<c:Model>
<Resource>Models/Core/UnitCube.obj</Resource>
<Color A="1" B="0" G="1" R="0"/>
</c:Model>
<c:Transform>
<Position X="2" Y="0" Z="-7"/>
</c:Transform>
</Components>
<Children/>
</Entity>
</Children>
</Entity>
+5 -1
View File
@@ -1,6 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?> <?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<Entity xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../Types/Entity.xsd" xmlns:c="components"> <Entity xmlns:c="components" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../Types/Entity.xsd">
<Components> <Components>
<c:Transform/> <c:Transform/>
</Components> </Components>
<Children/>
</Entity> </Entity>
@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<Entity xmlns:c="components" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../Types/Entity.xsd">
<Components>
<c:Transform/>
</Components>
<Children>
<Entity>
<Components>
<c:Camera/>
<c:Transform/>
</Components>
<Children/>
</Entity>
<Entity>
<Components>
<c:AABB/>
<c:Collidable/>
<c:Model>
<Resource>Models/Core/UnitCube.obj</Resource>
<Color A="1" B="0.513725519" G="0" R="1"/>
</c:Model>
<c:Transform>
<Position X="0" Y="2" Z="0"/>
<Scale X="5" Y="1" Z="5"/>
</c:Transform>
</Components>
<Children/>
</Entity>
<Entity name="Player">
<Components>
<c:AABB>
<Origin X="0" Y="0.773000062" Z="0"/>
<Size X="1" Y="1.60000002" Z="1"/>
</c:AABB>
<c:Collidable/>
<c:Physics/>
<c:Model>
<Resource>Models/Assault.obj</Resource>
<Color A="1" B="1" G="0" R="0"/>
</c:Model>
<c:Player/>
<c:Transform>
<Position X="0" Y="2.52699995" Z="0.0542778969"/>
</c:Transform>
</Components>
<Children/>
</Entity>
<Entity>
<Components>
<c:AABB/>
<c:Collidable/>
<c:Physics>
<Velocity X="0" Y="-0.0934068039" Z="0"/>
</c:Physics>
<c:Model>
<Resource>Models/Core/UnitCube.obj</Resource>
<Color A="1" B="0" G="1" R="1"/>
</c:Model>
<c:Player/>
<c:Transform>
<Position X="0" Y="4.15580511" Z="0"/>
<Scale X="0.704558551" Y="0.115156889" Z="1"/>
</c:Transform>
</Components>
<Children/>
</Entity>
</Children>
</Entity>
+56
View File
@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<Entity xmlns:c="components" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../Types/Entity.xsd">
<Components>
<c:Transform/>
</Components>
<Children>
<Entity>
<Components>
<c:AABB/>
<c:Collidable/>
<c:Model>
<Resource>Models/Core/UnitCube.obj</Resource>
<Color A="1" B="1" G="0" R="0"/>
</c:Model>
<c:Transform>
<Position X="-2" Y="0" Z="-7"/>
</c:Transform>
</Components>
<Children/>
</Entity>
<Entity>
<Components>
<c:AABB/>
<c:Collidable>
<Static>false</Static>
</c:Collidable>
<c:Model>
<Resource>Models/Core/UnitCube.obj</Resource>
<Color A="1" B="0" G="0" R="1"/>
</c:Model>
<c:Transform>
<Position X="1.5" Y="0" Z="-7"/>
</c:Transform>
</Components>
<Children/>
</Entity>
<Entity>
<Components>
<c:Collidable>
<Static>false</Static>
</c:Collidable>
<c:Model>
<Resource>Models/Core/UnitCube.obj</Resource>
<Color A="1" B="0" G="1" R="0"/>
</c:Model>
<c:Transform>
<Position X="2" Y="0" Z="-7"/>
</c:Transform>
</Components>
<Children/>
</Entity>
</Children>
</Entity>
+18
View File
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<Entity name="Player" xmlns:c="components" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../Types/Entity.xsd">
<Components>
<c:AABB/>
<c:Physics/>
<c:Collidable/>
<c:Model>
<Resource>Models/Core/UnitSphere.obj</Resource>
<Color A="1" B="1" G="0" R="0"/>
</c:Model>
<c:Player/>
<c:Transform/>
</Components>
<Children/>
</Entity>
+64
View File
@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<Entity xmlns:c="components" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../Types/Entity.xsd">
<Components>
<c:Transform/>
</Components>
<Children>
<Entity>
<Components>
<c:PlayerSpawn/>
<c:Spawner>
<EntityFile>Schema/Entities/Player.xml</EntityFile>
</c:Spawner>
<c:Team>
<Team>2</Team>
</c:Team>
<c:Transform>
<Position X="11.2723322" Y="1.28011799" Z="3.66820574"/>
</c:Transform>
</Components>
<Children>
<Entity>
<Components>
<c:SpawnPoint/>
<c:Model>
<Resource>Models/Core/UnitSphere.obj</Resource>
</c:Model>
<c:Transform>
<Position X="0" Y="0" Z="1.26689196"/>
<Scale X="0.300000012" Y="0.300000012" Z="0.300000012"/>
</c:Transform>
</Components>
<Children/>
</Entity>
<Entity>
<Components>
<c:SpawnPoint/>
<c:Model>
<Resource>Models/Core/UnitSphere.obj</Resource>
</c:Model>
<c:Transform>
<Position X="0" Y="0" Z="-1.14786315"/>
<Scale X="0.300000012" Y="0.300000012" Z="0.300000012"/>
</c:Transform>
</Components>
<Children/>
</Entity>
</Children>
</Entity>
<Entity>
<Components>
<c:Camera/>
<c:Listener/>
<c:Transform>
<Position X="-0.123331964" Y="7.64918661" Z="6.59480286"/>
<Orientation X="-0.500915647" Y="-1.35800648" Z="-7.76194497e-07"/>
</c:Transform>
</Components>
<Children/>
</Entity>
</Children>
</Entity>
+13
View File
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<Entity xmlns:c="components" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../Types/Entity.xsd">
<Components>
<c:Team>
<Team>3</Team>
</c:Team>
<c:Transform/>
</Components>
<Children/>
</Entity>
+3
View File
@@ -4,6 +4,9 @@
<xs:include schemaLocation="Types/Quaternion.xsd"/> <xs:include schemaLocation="Types/Quaternion.xsd"/>
<xs:include schemaLocation="Types/Vector.xsd"/> <xs:include schemaLocation="Types/Vector.xsd"/>
<xs:include schemaLocation="Types/Color.xsd"/> <xs:include schemaLocation="Types/Color.xsd"/>
<xs:complexType name="enum" mixed="true">
<xs:choice></xs:choice>
</xs:complexType>
<xs:simpleType name="bool"> <xs:simpleType name="bool">
<xs:restriction base="xs:boolean"></xs:restriction> <xs:restriction base="xs:boolean"></xs:restriction>
</xs:simpleType> </xs:simpleType>
+9 -1
View File
@@ -11,14 +11,22 @@
<xs:complexType> <xs:complexType>
<xs:all> <xs:all>
<xs:element ref="c:Transform" minOccurs="0"/> <xs:element ref="c:Transform" minOccurs="0"/>
<xs:element ref="c:Physics" minOccurs="0"/>
<xs:element ref="c:Model" minOccurs="0"/> <xs:element ref="c:Model" minOccurs="0"/>
<xs:element ref="c:Test" minOccurs="0"/>
<xs:element ref="c:RaptorCopter" minOccurs="0"/> <xs:element ref="c:RaptorCopter" minOccurs="0"/>
<xs:element ref="c:Player" minOccurs="0"/> <xs:element ref="c:Player" minOccurs="0"/>
<xs:element ref="c:Camera" minOccurs="0"/>
<xs:element ref="c:AABB" minOccurs="0"/>
<xs:element ref="c:Trigger" minOccurs="0"/>
<xs:element ref="c:Health" minOccurs="0"/> <xs:element ref="c:Health" minOccurs="0"/>
<xs:element ref="c:PointLight" minOccurs="0"/> <xs:element ref="c:PointLight" minOccurs="0"/>
<xs:element ref="c:Listener" minOccurs="0"/> <xs:element ref="c:Listener" minOccurs="0"/>
<xs:element ref="c:SoundEmitter" minOccurs="0"/> <xs:element ref="c:SoundEmitter" minOccurs="0"/>
<xs:element ref="c:Collidable" minOccurs="0"/>
<xs:element ref="c:Spawner" minOccurs="0"/>
<xs:element ref="c:SpawnPoint" minOccurs="0"/>
<xs:element ref="c:PlayerSpawn" minOccurs="0"/>
<xs:element ref="c:Team" minOccurs="0"/>
</xs:all> </xs:all>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
@@ -0,0 +1,18 @@
#include "Collision/CollidableOctreeSystem.h"
void CollidableOctreeSystem::Update(World* world, double dt)
{
m_Octree->ClearDynamicObjects();
}
void CollidableOctreeSystem::UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt)
{
if (entity.HasComponent("AABB")) {
boost::optional<AABB> absoluteAABB = Collision::EntityAbsoluteAABB(entity);
if (absoluteAABB) {
m_Octree->AddDynamicObject(*absoluteAABB);
}
} else if (entity.HasComponent("Model")) {
// TODO: Derive AABB from model
}
}
+56 -38
View File
@@ -13,7 +13,7 @@ bool RayAABBIntr(const Ray& ray, const AABB& box)
{ {
glm::vec3 w = 75.0f * ray.Direction(); glm::vec3 w = 75.0f * ray.Direction();
glm::vec3 v = glm::abs(w); glm::vec3 v = glm::abs(w);
glm::vec3 c = ray.Origin() - box.Center() + w; glm::vec3 c = ray.Origin() - box.Origin() + w;
glm::vec3 half = box.HalfSize(); glm::vec3 half = box.HalfSize();
if (abs(c.x) > v.x + half.x) { if (abs(c.x) > v.x + half.x) {
@@ -68,8 +68,8 @@ bool RayVsAABB(const Ray& ray, const AABB& box, float& outDistance)
bool AABBVsAABB(const AABB& a, const AABB& b) bool AABBVsAABB(const AABB& a, const AABB& b)
{ {
const glm::vec3& aCenter = a.Center(); const glm::vec3& aCenter = a.Origin();
const glm::vec3& bCenter = b.Center(); const glm::vec3& bCenter = b.Origin();
const glm::vec3& aHSize = a.HalfSize(); const glm::vec3& aHSize = a.HalfSize();
const glm::vec3& bHSize = b.HalfSize(); const glm::vec3& bHSize = b.HalfSize();
//Test will probably exit because of the X and Z axes more often, so test them first. //Test will probably exit because of the X and Z axes more often, so test them first.
@@ -199,11 +199,51 @@ bool RayVsModel(const Ray& ray,
return hit; return hit;
} }
bool AABBvsTriangles(const AABB& box, const std::vector<RawModel::Vertex>& modelVertices, const std::vector<unsigned int>& modelIndices, const glm::mat4& modelMatrix, glm::vec3& outResolutionVector)
{
bool hit = false;
const glm::vec3& origin = box.Origin();
const glm::vec3& min = box.MinCorner();
const glm::vec3& max = box.MaxCorner();
outResolutionVector.x = INFINITY;
for (int i = 0; i < modelIndices.size(); ++i) {
glm::vec3 p = modelVertices[i].Position;
p = glm::vec3(modelMatrix * glm::vec4(p.x, p.y, p.z, 1));
float distFromOrigin = glm::abs(origin.x - p.x);
float penetration = box.HalfSize().x - distFromOrigin;
if (penetration > 0 && penetration < glm::abs(outResolutionVector.x)) {
if (p.x > origin.x) {
outResolutionVector.x = -penetration;
} else {
outResolutionVector.x = penetration;
}
hit = true;
}
//glm::vec3 pLocal = origin - p;
//for (int axis = 0; axis < 3; ++axis) {
// if (p[axis] < min[axis] || p[axis] > max[axis]) {
// continue;
// }
// if (glm::abs(pLocal[axis]) < box.HalfSize()[axis]) {
// outResolutionVector[axis] = (glm::sign(pLocal[axis]) * box.HalfSize()[axis]) - pLocal[axis];
// hit = true;
// }
//}
}
return hit;
}
bool IsSameBoxProbably(const AABB& first, const AABB& second, const float epsilon) bool IsSameBoxProbably(const AABB& first, const AABB& second, const float epsilon)
{ {
const glm::vec3& ma1 = first.MaxCorner(); const glm::vec3& ma1 = first.MaxCorner();
const glm::vec3& ma2 = first.MaxCorner(); const glm::vec3& ma2 = second.MaxCorner();
const glm::vec3& mi1 = second.MinCorner(); const glm::vec3& mi1 = first.MinCorner();
const glm::vec3& mi2 = second.MinCorner(); const glm::vec3& mi2 = second.MinCorner();
return (std::abs(ma1.x - ma2.x) < epsilon) && return (std::abs(ma1.x - ma2.x) < epsilon) &&
(std::abs(mi1.x - mi2.x) < epsilon) && (std::abs(mi1.x - mi2.x) < epsilon) &&
@@ -238,45 +278,23 @@ bool attachAABBComponentFromModel(World* world, EntityID id)
mini.y = std::min(wPos.y, mini.y); mini.y = std::min(wPos.y, mini.y);
mini.z = std::min(wPos.z, mini.z); mini.z = std::min(wPos.z, mini.z);
} }
collision["BoxCenter"] = 0.5f * (maxi + mini); collision["Origin"] = 0.5f * (maxi + mini);
collision["BoxSize"] = maxi - mini; collision["Size"] = maxi - mini;
return true; return true;
} }
bool GetEntityBox(World* world, ComponentWrapper& AABBComponent, AABB& outBox) boost::optional<AABB> EntityAbsoluteAABB(EntityWrapper& entity)
{ {
ComponentWrapper& cTrans = world->GetComponent(AABBComponent.EntityID, "Transform"); if (!entity.HasComponent("AABB")) {
ComponentWrapper model = world->GetComponent(AABBComponent.EntityID, "Model"); return boost::none;
Model* modelRes = ResourceManager::Load<Model>(model["Resource"]);
outBox.CreateFromCenter(AABBComponent["BoxCenter"], AABBComponent["BoxSize"]);
glm::vec3 mini = outBox.MinCorner();
glm::vec3 maxi = outBox.MaxCorner();
if (modelRes == nullptr) {
return false;
}
glm::mat4 modelMatrix = modelRes->Matrix() *
glm::translate(glm::mat4(), (glm::vec3)cTrans["Position"]) *
glm::scale((glm::vec3)cTrans["Scale"]);
outBox = AABB(modelMatrix * glm::vec4(mini.x, mini.y, mini.z, 1),
modelMatrix * glm::vec4(maxi.x, maxi.y, maxi.z, 1));
return true;
}
bool GetEntityBox(World* world, EntityID entity, AABB& outBox, bool forceBoxFromModel)
{
if (!world->HasComponent(entity, "AABB")) {
if (forceBoxFromModel) {
if (!attachAABBComponentFromModel(world, entity))
return false;
} else {
return false;
}
} }
ComponentWrapper& cBox = world->GetComponent(entity, "AABB"); ComponentWrapper& cAABB = entity["AABB"];
return GetEntityBox(world, cBox, outBox); glm::vec3 absPosition = Transform::AbsolutePosition(entity.World, entity.ID);
glm::vec3 absScale = Transform::AbsoluteScale(entity.World, entity.ID);
glm::vec3 origin = absPosition + (glm::vec3)cAABB["Origin"];
glm::vec3 size = (glm::vec3)cAABB["Size"] * absScale;
return AABB::FromOriginSize(origin, size);
} }
} }
+43 -16
View File
@@ -2,33 +2,60 @@
#include "Collision/CollisionSystem.h" #include "Collision/CollisionSystem.h"
#include "Core/AABB.h" #include "Core/AABB.h"
void CollisionSystem::UpdateComponent(World * world, ComponentWrapper & cAABB, double dt) void CollisionSystem::UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt)
{ {
//Right now, cAABB is a component attached to any entity that should be collideable. if (!entity.HasComponent("Physics")) {
AABB thisBox;
if (!Collision::GetEntityBox(world, cAABB, thisBox)) {
return; return;
} }
ComponentWrapper& cPhysics = entity["Physics"];
boost::optional<AABB> boundingBox = Collision::EntityAbsoluteAABB(entity);
if (!boundingBox) {
return;
}
ComponentWrapper& cTransform = entity["Transform"];
AABB& boxA = *boundingBox;
//Press 'Z' to enable/disable collision. //Press 'Z' to enable/disable collision.
if (zPress) { if (zPress) {
return; return;
} }
//Here, mover should be an object that moves, currently only players.
for (auto& mover : *world->GetComponents("Player")) { // Collide against octree
if (cAABB.EntityID == mover.EntityID) { std::vector<AABB> octreeResult;
m_Octree->ObjectsInSameRegion(*boundingBox, octreeResult);
for (auto& boxB : octreeResult) {
glm::vec3 resolutionVector;
if (Collision::IsSameBoxProbably(boxA, boxB)) {
continue; continue;
} }
AABB otherBox; if (Collision::AABBVsAABB(boxA, boxB, resolutionVector)) {
if (!Collision::GetEntityBox(world, mover.EntityID, otherBox)) { (glm::vec3&)cTransform["Position"] += resolutionVector;
continue; cPhysics["Velocity"] = glm::vec3(0, 0, 0);
}
glm::vec3 resolveTranslation;
if (Collision::AABBVsAABB(otherBox, thisBox, resolveTranslation)) {
ComponentWrapper& trans = world->GetComponent(mover.EntityID, "Transform");
//TODO: Special treatment if both are movers.
trans["Position"] = (glm::vec3)trans["Position"] + resolveTranslation;
} }
} }
// HACK: Temporarily collide against all collidable models since they're not in the octree yet
//auto otherCollidables = world->GetComponents("Model");
//for (auto& cModel : *otherCollidables) {
// if (cModel.EntityID == entity) {
// continue;
// }
// if (!world->HasComponent(cModel.EntityID, "Collidable")) {
// continue;
// }
// auto absPosition = RenderQueueFactory::AbsolutePosition(world, cModel.EntityID);
// auto absOrientation = RenderQueueFactory::AbsoluteOrientation(world, cModel.EntityID);
// auto absScale = RenderQueueFactory::AbsoluteScale(world, cModel.EntityID);
// glm::mat4 modelMatrix = glm::translate(absPosition); // *glm::toMat4(absOrientation) * glm::scale(absScale);
// auto model = ResourceManager::Load<Model>(cModel["Resource"]);
// glm::vec3 resolutionVector;
// if (Collision::AABBvsTriangles(boxA, model->m_Vertices, model->m_Indices, modelMatrix, resolutionVector)) {
// (glm::vec3&)cTransform["Position"] += resolutionVector;
// }
//}
} }
bool CollisionSystem::OnKeyUp(const Events::KeyUp & event) bool CollisionSystem::OnKeyUp(const Events::KeyUp & event)
+29 -10
View File
@@ -3,27 +3,27 @@
#include "Core/AABB.h" #include "Core/AABB.h"
#include "Rendering/Model.h" #include "Rendering/Model.h"
void TriggerSystem::UpdateComponent(World* world, ComponentWrapper& trigger, double dt) void TriggerSystem::UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt)
{ {
//Currently only players can trigger things. //Currently only players can trigger things.
auto players = world->GetComponents("Player"); auto players = world->GetComponents("Player");
if (players == nullptr) { if (players == nullptr) {
return; return;
} }
EntityID tId = trigger.EntityID; EntityID tId = component.EntityID;
AABB triggerBox; boost::optional<AABB> triggerBox = Collision::EntityAbsoluteAABB(entity);
//The trigger *should* have a bounding box, or something, to test against so it can be triggered. //The trigger *should* have a bounding box, or something, to test against so it can be triggered.
if (!Collision::GetEntityBox(world, tId, triggerBox, true)) { if (!triggerBox) {
return; return;
} }
for (auto& pc : *players) { for (auto& pc : *players) {
EntityID pId = pc.EntityID; EntityID pId = pc.EntityID;
AABB playerBox; boost::optional<AABB> playerBox = Collision::EntityAbsoluteAABB(EntityWrapper(world, pId));
//The player can't trigger anything without an AABB. //The player can't trigger anything without an AABB.
if (!Collision::GetEntityBox(world, pId, playerBox, true)) { if (!playerBox) {
continue; continue;
} }
if (!Collision::AABBVsAABB(triggerBox, playerBox)) { if (!Collision::AABBVsAABB(*triggerBox, *playerBox)) {
//Entity is not touching the trigger, //Entity is not touching the trigger,
//Throw event if it was previously. //Throw event if it was previously.
if (throwLeaveIfWasInTrigger(m_EntitiesTouchingTrigger[tId], pId, tId)) { if (throwLeaveIfWasInTrigger(m_EntitiesTouchingTrigger[tId], pId, tId)) {
@@ -35,9 +35,11 @@ void TriggerSystem::UpdateComponent(World* world, ComponentWrapper& trigger, dou
} else { } else {
//Entity is at least touching the trigger. //Entity is at least touching the trigger.
AABB completelyInsideBox; AABB completelyInsideBox;
completelyInsideBox.CreateFromCenter(triggerBox.Center(), triggerBox.Size() - 2.0f * playerBox.Size()); bool playerFitsInTrigger = glm::all(glm::greaterThan((*triggerBox).Size(), (*playerBox).Size()));
if (Collision::AABBVsAABB(completelyInsideBox, playerBox) && if (playerFitsInTrigger) {
glm::all(glm::greaterThan(triggerBox.Size(), playerBox.Size()))) { completelyInsideBox = AABB::FromOriginSize((*triggerBox).Origin(), (*triggerBox).Size() - 2.0f * (*playerBox).Size());
}
if (playerFitsInTrigger && Collision::AABBVsAABB(completelyInsideBox, *playerBox)) {
//Entity is completely inside the trigger. //Entity is completely inside the trigger.
//If it was only touching before, it is erased. //If it was only touching before, it is erased.
m_EntitiesTouchingTrigger[tId].erase(pId); m_EntitiesTouchingTrigger[tId].erase(pId);
@@ -79,3 +81,20 @@ bool TriggerSystem::throwLeaveIfWasInTrigger(std::unordered_set<EntityID>& trigg
return false; return false;
} }
bool TriggerSystem::OnTouch(const Events::TriggerTouch &event)
{
LOG_INFO("Player entity %i touched trigger entity %i.", event.Entity, event.Trigger);
return true;
}
bool TriggerSystem::OnEnter(const Events::TriggerEnter &event)
{
LOG_INFO("Player entity %i entered trigger entity %i.", event.Entity, event.Trigger);
return true;
}
bool TriggerSystem::OnLeave(const Events::TriggerLeave &event)
{
LOG_INFO("Player entity %i left trigger entity %i.", event.Entity, event.Trigger);
return true;
}
+7 -8
View File
@@ -4,7 +4,7 @@
AABB::AABB(const glm::vec3& minPos, const glm::vec3& maxPos) AABB::AABB(const glm::vec3& minPos, const glm::vec3& maxPos)
: m_MinCorner(minPos) : m_MinCorner(minPos)
, m_MaxCorner(maxPos) , m_MaxCorner(maxPos)
, m_Center(0.5f * (maxPos + minPos)) , m_Origin(0.5f * (maxPos + minPos))
, m_HalfSize(0.5f * (maxPos - minPos)) , m_HalfSize(0.5f * (maxPos - minPos))
{ {
DEBUG_IF(glm::any(glm::lessThan(m_MaxCorner, m_MinCorner))) { DEBUG_IF(glm::any(glm::lessThan(m_MaxCorner, m_MinCorner))) {
@@ -15,20 +15,19 @@ AABB::AABB(const glm::vec3& minPos, const glm::vec3& maxPos)
m_MinCorner.y = glm::min(m_MaxCorner.y, m_MinCorner.y); m_MinCorner.y = glm::min(m_MaxCorner.y, m_MinCorner.y);
m_MaxCorner.z = glm::max(m_MaxCorner.z, m_MinCorner.z); m_MaxCorner.z = glm::max(m_MaxCorner.z, m_MinCorner.z);
m_MinCorner.z = glm::min(m_MaxCorner.z, m_MinCorner.z); m_MinCorner.z = glm::min(m_MaxCorner.z, m_MinCorner.z);
m_Origin = 0.5f * (m_MaxCorner + m_MinCorner);
m_HalfSize = 0.5f * (m_MaxCorner - m_MinCorner);
} }
} }
AABB::AABB(const glm::vec4& minPos, const glm::vec4& maxPos) AABB::AABB(const glm::vec4& minPos, const glm::vec4& maxPos)
: AABB(glm::vec3(minPos), glm::vec3(maxPos)) : AABB(glm::vec3(minPos), glm::vec3(maxPos))
{} { }
void AABB::CreateFromCenter(const glm::vec3& center, const glm::vec3& size) AABB AABB::FromOriginSize(const glm::vec3& origin, const glm::vec3& size)
{ {
m_Center = center; return AABB(origin - (size/2.f), origin + (size/2.f));
m_HalfSize = 0.5f * size;
m_MinCorner = m_Center - m_HalfSize;
m_MaxCorner = m_Center + m_HalfSize;
} }
AABB::~AABB() AABB::~AABB()
{} { }
+182 -3
View File
@@ -21,14 +21,24 @@ void EntityFile::Parse(const EntityFileHandler* handler) const
using namespace xercesc; using namespace xercesc;
EntityFileSAXHandler saxHandler(handler, nullptr); EntityFileSAXHandler saxHandler(handler, nullptr);
m_SAX2XMLReader->setFeature(XMLUni::fgXercesCacheGrammarFromParse, true); setReaderFeatures(m_SAX2XMLReader);
m_SAX2XMLReader->setFeature(XMLUni::fgXercesUseCachedGrammarInParse, true);
m_SAX2XMLReader->setContentHandler(&saxHandler); m_SAX2XMLReader->setContentHandler(&saxHandler);
m_SAX2XMLReader->setErrorHandler(&saxHandler); m_SAX2XMLReader->setErrorHandler(&saxHandler);
m_SAX2XMLReader->setDeclarationHandler(&saxHandler); m_SAX2XMLReader->setDeclarationHandler(&saxHandler);
m_SAX2XMLReader->parse(m_FilePath.string().c_str()); m_SAX2XMLReader->parse(m_FilePath.string().c_str());
} }
void EntityFile::setReaderFeatures(xercesc::SAX2XMLReader* reader)
{
using namespace xercesc;
reader->setFeature(XMLUni::fgXercesCacheGrammarFromParse, true);
reader->setFeature(XMLUni::fgXercesUseCachedGrammarInParse, true);
reader->setFeature(XMLUni::fgSAX2CoreValidation, true);
reader->setFeature(XMLUni::fgSAX2CoreNameSpaces, true);
reader->setFeature(XMLUni::fgXercesSchema, true);
reader->setFeature(XMLUni::fgXercesSchemaFullChecking, true);
}
std::size_t EntityFile::GetTypeStride(std::string typeName) std::size_t EntityFile::GetTypeStride(std::string typeName)
{ {
std::map<std::string, size_t> typeStrides{ std::map<std::string, size_t> typeStrides{
@@ -37,6 +47,7 @@ std::size_t EntityFile::GetTypeStride(std::string typeName)
{ "float", sizeof(float) }, { "float", sizeof(float) },
{ "double", sizeof(double) }, { "double", sizeof(double) },
{ "string", sizeof(std::string) }, { "string", sizeof(std::string) },
{ "enum", sizeof(int) },
{ "Vector", sizeof(glm::vec3) }, { "Vector", sizeof(glm::vec3) },
{ "Quaternion", sizeof(glm::quat) }, { "Quaternion", sizeof(glm::quat) },
{ "Color", sizeof(glm::vec4) } { "Color", sizeof(glm::vec4) }
@@ -75,7 +86,7 @@ void EntityFile::WriteAttributeData(char* outData, const ComponentInfo::Field_t&
void EntityFile::WriteValueData(char* outData, const ComponentInfo::Field_t& field, const char* valueData) void EntityFile::WriteValueData(char* outData, const ComponentInfo::Field_t& field, const char* valueData)
{ {
if (field.Type == "int") { if (field.Type == "int" || field.Type == "enum") {
int value = boost::lexical_cast<int>(valueData); int value = boost::lexical_cast<int>(valueData);
memcpy(outData, reinterpret_cast<char*>(&value), field.Stride); memcpy(outData, reinterpret_cast<char*>(&value), field.Stride);
} else if (field.Type == "float") { } else if (field.Type == "float") {
@@ -93,3 +104,171 @@ void EntityFile::WriteValueData(char* outData, const ComponentInfo::Field_t& fie
LOG_WARNING("Unknown value data type: %s", field.Type.c_str()); LOG_WARNING("Unknown value data type: %s", field.Type.c_str());
} }
} }
EntityFileSAXHandler::EntityFileSAXHandler(const EntityFileHandler* handler, xercesc::SAX2XMLReader* reader) : m_Handler(handler)
, m_Reader(reader)
{
// 0 is imaginary base parent
m_EntityStack.push(0);
m_StateStack.push(State::Unknown);
}
void EntityFileSAXHandler::startElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname, const xercesc::Attributes& attrs)
{
std::string name = XS::ToString(_localName);
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 EntityFileSAXHandler::endElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname)
{
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 EntityFileSAXHandler::characters(const XMLCh* const chars, const XMLSize_t length)
{
if (m_StateStack.top() == State::ComponentField) {
char* transcoded = xercesc::XMLString::transcode(chars);
onFieldData(transcoded);
}
}
void EntityFileSAXHandler::fatalError(const xercesc::SAXParseException& e)
{
XS::ToString s(e.getMessage());
LOG_ERROR("SAXParseException: %s", ((std::string)s).c_str());
//throw e;
}
void EntityFileSAXHandler::error(const xercesc::SAXParseException& e)
{
XS::ToString s(e.getMessage());
LOG_ERROR("SAXParseException: %s", ((std::string)s).c_str());
}
void EntityFileSAXHandler::warning(const xercesc::SAXParseException& e)
{
XS::ToString s(e.getMessage());
LOG_ERROR("SAXParseException: %s", ((std::string)s).c_str());
}
void EntityFileSAXHandler::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 EntityFileSAXHandler::onEndEntity()
{
m_EntityStack.pop();
}
void EntityFileSAXHandler::onStartEntityRef(const xercesc::Attributes& attrs)
{
std::string path = XS::ToString(attrs.getValue(XS::ToXMLCh("file")));
xercesc::SAX2XMLReader* reader = xercesc::XMLReaderFactory::createXMLReader();
EntityFile::setReaderFeatures(reader);
reader->setContentHandler(this);
reader->setErrorHandler(this);
reader->parse(path.c_str());
delete reader;
}
void EntityFileSAXHandler::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 EntityFileSAXHandler::onEndComponent(const std::string& name) { }
void EntityFileSAXHandler::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 EntityFileSAXHandler::onEndComponentField(const std::string& field) { }
void EntityFileSAXHandler::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);
}
+17 -4
View File
@@ -9,17 +9,21 @@ EntityFileParser::EntityFileParser(const EntityFile* entityFile)
m_Handler.SetStartFieldDataCallback(std::bind(&EntityFileParser::onFieldData, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); m_Handler.SetStartFieldDataCallback(std::bind(&EntityFileParser::onFieldData, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
} }
void EntityFileParser::MergeEntities(World* world) EntityID EntityFileParser::MergeEntities(World* world, EntityID baseParent /*= EntityID_Invalid */)
{ {
m_World = world; m_World = world;
m_EntityIDMapper[0] = 0; m_EntityIDMapper[0] = baseParent;
m_EntityFile->Parse(&m_Handler); m_EntityFile->Parse(&m_Handler);
return m_FirstEntity;
} }
void EntityFileParser::onStartEntity(EntityID entity, EntityID parent, const std::string& name) void EntityFileParser::onStartEntity(EntityID entity, EntityID parent, const std::string& name)
{ {
EntityID realParent = m_EntityIDMapper.at(parent); EntityID realParent = m_EntityIDMapper.at(parent);
EntityID realEntity = m_World->CreateEntity(realParent); EntityID realEntity = m_World->CreateEntity(realParent);
if (m_FirstEntity == EntityID_Invalid) {
m_FirstEntity = realEntity;
}
if (!name.empty()) { if (!name.empty()) {
m_World->SetName(realEntity, name); m_World->SetName(realEntity, name);
} }
@@ -38,7 +42,12 @@ void EntityFileParser::onStartComponentField(EntityID entity, const std::string&
{ {
EntityID realEntity = m_EntityIDMapper.at(entity); EntityID realEntity = m_EntityIDMapper.at(entity);
ComponentWrapper component = m_World->GetComponent(realEntity, componentType); ComponentWrapper component = m_World->GetComponent(realEntity, componentType);
auto& field = component.Info.Fields.at(fieldName); auto fieldIt = component.Info.Fields.find(fieldName);
if (fieldIt == component.Info.Fields.end()) {
LOG_ERROR("Tried to set unknown field \"%s\" of component type \"%s\"! Ignoring.", fieldName.c_str(), componentType.c_str());
return;
}
auto& field = fieldIt->second;
LOG_DEBUG("Field \"%s\" type \"%s\"", fieldName.c_str(), field.Type.c_str()); LOG_DEBUG("Field \"%s\" type \"%s\"", fieldName.c_str(), field.Type.c_str());
LOG_DEBUG("Attributes:"); LOG_DEBUG("Attributes:");
@@ -54,7 +63,11 @@ void EntityFileParser::onFieldData(EntityID entity, const std::string& component
{ {
EntityID realEntity = m_EntityIDMapper.at(entity); EntityID realEntity = m_EntityIDMapper.at(entity);
ComponentWrapper component = m_World->GetComponent(realEntity, componentType); ComponentWrapper component = m_World->GetComponent(realEntity, componentType);
auto& field = component.Info.Fields.at(fieldName); auto fieldIt = component.Info.Fields.find(fieldName);
if (fieldIt == component.Info.Fields.end()) {
return;
}
auto& field = fieldIt->second;
char* data = component.Data + field.Offset; char* data = component.Data + field.Offset;
EntityFile::WriteValueData(data, field, fieldData); EntityFile::WriteValueData(data, field, fieldData);
+105 -54
View File
@@ -16,12 +16,12 @@ EntityFilePreprocessor::EntityFilePreprocessor(const EntityFile* entityFile)
for (auto& kv : m_ComponentInfo) { for (auto& kv : m_ComponentInfo) {
auto& info = kv.second; auto& info = kv.second;
LOG_DEBUG("Component: %s (%s)", info.Name.c_str(), info.Meta.Annotation.c_str()); LOG_DEBUG("Component: %s (%s)", info.Name.c_str(), info.Meta->Annotation.c_str());
LOG_DEBUG("Stride: %i", info.Meta.Stride); LOG_DEBUG("Stride: %i", info.Stride);
LOG_DEBUG("Allocation: %i", info.Meta.Allocation); LOG_DEBUG("Allocation: %i", info.Meta->Allocation);
for (auto& kv : info.Fields) { for (auto& kv : info.Fields) {
auto& field = kv.second; auto& field = kv.second;
LOG_DEBUG("\t%i\t%s %s", field.Offset, field.Type, kv.first.c_str()); LOG_DEBUG("\t%i\t%s %s", field.Offset, field.Type.c_str(), kv.first.c_str());
} }
} }
@@ -62,62 +62,36 @@ void EntityFilePreprocessor::parseComponentInfo()
} }
ComponentInfo compInfo; ComponentInfo compInfo;
compInfo.Meta = std::make_shared<ComponentInfo::Meta_t>();
// Name // Name
compInfo.Name = XS::ToString(element->getName()); compInfo.Name = XS::ToString(element->getName());
// Known allocation // Known allocation
compInfo.Meta.Allocation = m_ComponentCounts[compInfo.Name]; compInfo.Meta->Allocation = m_ComponentCounts[compInfo.Name];
// Annotation // Annotation
auto componentAnnotation = element->getAnnotation(); auto componentAnnotation = element->getAnnotation();
if (componentAnnotation != nullptr) { if (componentAnnotation != nullptr) {
// Parse annotation XML compInfo.Meta->Annotation = parseAnnotationXML(componentAnnotation->getAnnotationString());
char* annotationString = XMLString::transcode(componentAnnotation->getAnnotationString());
MemBufInputSource annotationInput(reinterpret_cast<const XMLByte*>(annotationString), strlen(annotationString), "MemBuf: Annotation String");
XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager, grammarPool);
parser.setErrorHandler(&errorHandler);
parser.parse(annotationInput);
XMLString::release(&annotationString);
auto doc = parser.getDocument();
// TODO: Add allocation estimations from external file on map-to-map basis
// Add allocation estimation(s)
//auto allocationTags = doc->getElementsByTagName(XSTR("meta:allocation"));
//for (int i = 0; i < allocationTags->getLength(); ++i) {
// auto allocation = dynamic_cast<DOMElement*>(allocationTags->item(i));
// auto child = allocation->getFirstChild();
// if (child == nullptr) {
// continue;
// }
// XSValue::Status status;
// XSValue* val = XSValue::getActualValue(child->getNodeValue(), XSValue::dt_integer, status);
// compInfo.Meta.Allocation += val->fData.fValue.f_int;
//}
// Save documentation string
auto documentationTags = doc->getElementsByTagName(XS::ToXMLCh("xs:documentation"));
if (documentationTags->getLength() != 0) {
auto child = documentationTags->item(0)->getFirstChild();
if (child != nullptr) {
compInfo.Meta.Annotation = XS::ToString(child->getNodeValue());
}
}
} else { } else {
LOG_WARNING("Component is missing an annotation!"); LOG_WARNING("Component \"%s\" is missing an annotation!", compInfo.Name.c_str());
} }
// <xs:complexType> // <xs:complexType>
auto typeDefinition = element->getTypeDefinition(); auto typeDefinition = element->getTypeDefinition();
// Allow empty components
if (typeDefinition == nullptr) {
continue;
}
if (typeDefinition->getTypeCategory() != XSTypeDefinition::COMPLEX_TYPE) { if (typeDefinition->getTypeCategory() != XSTypeDefinition::COMPLEX_TYPE) {
LOG_ERROR("Type definition wasn't COMPLEX_TYPE! Skipping."); LOG_ERROR("Failed to parse component definition for \"%s\": Type definition wasn't COMPLEX_TYPE!", compInfo.Name.c_str());
continue; continue;
} }
auto complexTypeDefinition = dynamic_cast<XSComplexTypeDefinition*>(typeDefinition); auto complexTypeDefinition = dynamic_cast<XSComplexTypeDefinition*>(typeDefinition);
// <xs:all> // <xs:all>
auto modelGroupParticle = complexTypeDefinition->getParticle(); auto modelGroupParticle = complexTypeDefinition->getParticle();
if (modelGroupParticle->getTermType() != XSParticle::TERM_MODELGROUP) { if (modelGroupParticle == nullptr || modelGroupParticle->getTermType() != XSParticle::TERM_MODELGROUP) {
LOG_ERROR("Model group particle wasn't TERM_MODELGROUP! Skipping."); LOG_ERROR("Failed to parse component definition for \"%s\": Model group particle was null or wasn't TERM_MODELGROUP!", compInfo.Name.c_str());
continue; continue;
} }
auto modelGroup = modelGroupParticle->getModelGroupTerm(); auto modelGroup = modelGroupParticle->getModelGroupTerm();
@@ -129,31 +103,65 @@ void EntityFilePreprocessor::parseComponentInfo()
for (unsigned int i = 0; i < particles->size(); ++i) { for (unsigned int i = 0; i < particles->size(); ++i) {
auto particle = particles->elementAt(i); auto particle = particles->elementAt(i);
if (particle->getTermType() != XSParticle::TERM_ELEMENT) { if (particle->getTermType() != XSParticle::TERM_ELEMENT) {
LOG_ERROR("Particle wasn't TERM_ELEMENT! Skipping."); LOG_ERROR("Failed to parse a field definition in component \"%s\": Particle wasn't TERM_ELEMENT! Skipping.", compInfo.Name.c_str());
continue; continue;
} }
auto elementDeclaration = particle->getElementTerm(); auto elementDeclaration = particle->getElementTerm();
std::string name = XS::ToString(elementDeclaration->getName()); std::string name = XS::ToString(elementDeclaration->getName());
std::string type = XS::ToString(elementDeclaration->getTypeDefinition()->getName()); std::string type = XS::ToString(elementDeclaration->getTypeDefinition()->getName());
std::string typeNamespace = XS::ToString(elementDeclaration->getTypeDefinition()->getNamespace());
std::string baseType = XS::ToString(elementDeclaration->getTypeDefinition()->getBaseType()->getName());
std::string effectiveType = type;
size_t stride = EntityFile::GetTypeStride(type); size_t stride = EntityFile::GetTypeStride(type);
if (stride == 0) { if (stride == 0) {
std::cout << "Warning: Field \"" << name << "\" in component \"" << compInfo.Name << "\" uses unexpected field type \"" << type << "\". Skipping." << std::endl; stride = EntityFile::GetTypeStride(baseType);
if (stride == 0) {
LOG_WARNING("Field \"%s\" in component \"%s\" uses unexpected field type \"%s\" with base type \"%s\". Skipping.", name.c_str(), compInfo.Name.c_str(), type.c_str(), baseType.c_str());
continue; continue;
} }
effectiveType = baseType;
}
// Annotation
auto fieldAnnotation = elementDeclaration->getAnnotation();
if (fieldAnnotation != nullptr) {
compInfo.Meta->FieldAnnotations[name] = parseAnnotationXML(fieldAnnotation->getAnnotationString());
} else {
LOG_WARNING("Component field \"%s.%s\" is missing an annotation!", compInfo.Name.c_str(), name.c_str());
}
if (effectiveType == "enum") {
// Parse potential enum type definition for field type
if (compInfo.Meta->FieldEnumDefinitions.count(name) == 0) {
auto enumTypeDefinition = xsModel->getTypeDefinition(XS::ToXMLCh(type), XS::ToXMLCh("components"));
auto xsComplexType = dynamic_cast<XSComplexTypeDefinition*>(enumTypeDefinition);
auto xsComplexContent = xsComplexType->getParticle();
auto xsExtension = xsComplexContent->getModelGroupTerm();
auto xsExtensionParticles = xsExtension->getParticles();
auto xsChoice = xsExtensionParticles->elementAt(0)->getModelGroupTerm();
auto xsChoiceParticles = xsChoice->getParticles();
for (int i = 0; i < xsChoiceParticles->size(); ++i) {
auto enumElement = xsChoiceParticles->elementAt(i)->getElementTerm();
std::string enumName = XS::ToString(enumElement->getName());
std::string enumValue = XS::ToString(enumElement->getConstraintValue());
compInfo.Meta->FieldEnumDefinitions[name][enumName] = boost::lexical_cast<int>(enumValue);
LOG_DEBUG("ENUM %s = %s", enumName.c_str(), enumValue.c_str());
}
}
}
auto& field = compInfo.Fields[name]; auto& field = compInfo.Fields[name];
field.Name = name; field.Name = name;
field.Type = type; field.Type = effectiveType;
field.Offset = fieldOffset; field.Offset = fieldOffset;
field.Stride = stride; field.Stride = stride;
compInfo.FieldsInOrder.push_back(name); compInfo.FieldsInOrder.push_back(name);
fieldOffset += stride; fieldOffset += stride;
} }
compInfo.Meta.Stride = fieldOffset; compInfo.Stride = fieldOffset;
m_ComponentInfo[compInfo.Name] = compInfo; m_ComponentInfo[compInfo.Name] = compInfo;
} }
} }
@@ -166,13 +174,22 @@ void EntityFilePreprocessor::parseDefaults()
for (auto& ci : m_ComponentInfo) { for (auto& ci : m_ComponentInfo) {
// Allocate memory for default values // Allocate memory for default values
ci.second.Defaults = std::shared_ptr<char>(new char[ci.second.Meta.Stride]); ci.second.Defaults = std::shared_ptr<char>(new char[ci.second.Stride]);
memset(ci.second.Defaults.get(), 0, ci.second.Meta.Stride); memset(ci.second.Defaults.get(), 0, ci.second.Stride);
XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager);
parser.setErrorHandler(&errorHandler);
std::string componentName = ci.first; std::string componentName = ci.first;
XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager);
parser.setDoSchema(true);
parser.setDoNamespaces(true);
parser.setErrorHandler(&errorHandler);
parser.setValidationScheme(XercesDOMParser::Val_Always);
parser.setValidationSchemaFullChecking(true);
//parser.setDoNamespaces(true);
//boost::filesystem::path schemaLocation = "Schema/Components/" + componentName + ".xsd";
//std::string namespaceSchema = schemaLocation.string();
//parser.setExternalNoNamespaceSchemaLocation("Teamasdasdasdasd.xsd");
LOG_DEBUG("Parsing defaults for component %s", componentName.c_str()); LOG_DEBUG("Parsing defaults for component %s", componentName.c_str());
boost::filesystem::path defaultsFile = "Schema/Components/" + componentName + ".xml"; boost::filesystem::path defaultsFile = "Schema/Components/" + componentName + ".xml";
@@ -184,7 +201,7 @@ void EntityFilePreprocessor::parseDefaults()
} }
// Find the node in the components namespace matching the component name // Find the node in the components namespace matching the component name
std::string tagName = "c:" + componentName; std::string tagName = componentName;
auto rootNodes = doc->getElementsByTagName(XS::ToXMLCh(tagName)); auto rootNodes = doc->getElementsByTagName(XS::ToXMLCh(tagName));
if (rootNodes->getLength() == 0) { if (rootNodes->getLength() == 0) {
LOG_ERROR("Couldn't find defaults for component \"%s\"! Skipping.", componentName.c_str()); LOG_ERROR("Couldn't find defaults for component \"%s\"! Skipping.", componentName.c_str());
@@ -217,9 +234,19 @@ void EntityFilePreprocessor::parseDefaults()
EntityFile::WriteAttributeData(data, field, attributes); EntityFile::WriteAttributeData(data, field, attributes);
} }
// Handle potential field values
auto childNode = fieldElement->getFirstChild(); auto childNode = fieldElement->getFirstChild();
if (childNode != nullptr && childNode->getNodeType() == DOMNode::TEXT_NODE) { if (childNode == nullptr) {
continue;
}
// An enum will either have an element node with a text node inside,
// or contain a text node directly.
if (childNode->getNodeType() == DOMNode::ELEMENT_NODE) {
childNode = childNode->getFirstChild();
}
// Handle potential field values
if (childNode->getNodeType() == DOMNode::TEXT_NODE) {
char* cstrValue = XMLString::transcode(childNode->getNodeValue()); char* cstrValue = XMLString::transcode(childNode->getNodeValue());
EntityFile::WriteValueData(data, field, cstrValue); EntityFile::WriteValueData(data, field, cstrValue);
XMLString::release(&cstrValue); XMLString::release(&cstrValue);
@@ -228,3 +255,27 @@ void EntityFilePreprocessor::parseDefaults()
} }
} }
std::string EntityFilePreprocessor::parseAnnotationXML(const XMLCh* xml)
{
using namespace xercesc;
// Parse annotation XML
char* annotationString = XMLString::transcode(xml);
MemBufInputSource annotationInput(reinterpret_cast<const XMLByte*>(annotationString), strlen(annotationString), "MemBuf: Annotation String");
XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager);
//parser.setErrorHandler(&errorHandler);
parser.parse(annotationInput);
XMLString::release(&annotationString);
auto doc = parser.getDocument();
// Save documentation string
auto documentationTags = doc->getElementsByTagName(XS::ToXMLCh("xs:documentation"));
if (documentationTags->getLength() != 0) {
auto child = documentationTags->item(0)->getFirstChild();
if (child != nullptr) {
return XS::ToString(child->getNodeValue());
}
}
return std::string();
}
+1 -1
View File
@@ -114,7 +114,7 @@ void EntityFileWriter::appentEntityComponents(xercesc::DOMElement* parentElement
fieldElement->setAttribute(X("Y"), X(boost::lexical_cast<std::string>(q.y))); fieldElement->setAttribute(X("Y"), X(boost::lexical_cast<std::string>(q.y)));
fieldElement->setAttribute(X("Z"), X(boost::lexical_cast<std::string>(q.z))); fieldElement->setAttribute(X("Z"), X(boost::lexical_cast<std::string>(q.z)));
fieldElement->setAttribute(X("W"), X(boost::lexical_cast<std::string>(q.w))); fieldElement->setAttribute(X("W"), X(boost::lexical_cast<std::string>(q.w)));
} else if (field.Type == "int") { } else if (field.Type == "int" || field.Type == "enum") {
const int& value = c[fieldName]; const int& value = c[fieldName];
fieldElement->appendChild(doc->createTextNode(X(boost::lexical_cast<std::string>(value)))); fieldElement->appendChild(doc->createTextNode(X(boost::lexical_cast<std::string>(value))));
} else if (field.Type == "float") { } else if (field.Type == "float") {
+30
View File
@@ -0,0 +1,30 @@
#include "Core/EntityWrapper.h"
#include "Core/World.h"
const EntityWrapper EntityWrapper::Invalid = EntityWrapper(nullptr, EntityID_Invalid);
bool EntityWrapper::operator==(const EntityWrapper& e)
{
return (this->World == e.World) && (this->ID == e.ID);
}
bool EntityWrapper::HasComponent(const std::string& componentName)
{
return World->HasComponent(ID, componentName);
}
ComponentWrapper EntityWrapper::operator[](const std::string& componentName)
{
if (World->HasComponent(ID, componentName)) {
return World->GetComponent(ID, componentName);
} else {
LOG_WARNING("EntityWrapper implicitly attached \"%s\" component to #%i as a result of a fetch request!", componentName.c_str(), ID);
return World->AttachComponent(ID, componentName);
}
}
EntityWrapper::operator EntityID()
{
return this->ID;
}
@@ -2,7 +2,7 @@
#include <algorithm> #include <algorithm>
#include <bitset> #include <bitset>
#include "Core/OctTree.h" #include "Core/Octree.h"
#include "Collision/Collision.h" #include "Collision/Collision.h"
namespace namespace
@@ -21,75 +21,10 @@ bool isFirstLower(const ChildInfo& first, const ChildInfo& second)
} }
OctTree::OctTree() namespace OctSpace
: OctTree(AABB(), 0)
{}
OctTree::OctTree(const AABB& octTreeBounds, int subDivisions)
: m_Root(new OctChild(octTreeBounds, subDivisions, m_StaticObjects, m_DynamicObjects))
, m_UpdatedOnce(false)
{}
OctTree::~OctTree()
{ {
delete m_Root;
}
void OctTree::AddDynamicObject(const AABB& box) Child::Child(const AABB& octTreeBounds,
{
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<AABB>& 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, int subDivisions,
std::vector<ContainedObject>& staticObjects, std::vector<ContainedObject>& staticObjects,
std::vector<ContainedObject>& dynamicObjects) std::vector<ContainedObject>& dynamicObjects)
@@ -98,7 +33,7 @@ OctTree::OctChild::OctChild(const AABB& octTreeBounds,
, m_DynamicObjectsRef(dynamicObjects) , m_DynamicObjectsRef(dynamicObjects)
{ {
if (subDivisions == 0) { if (subDivisions == 0) {
for (OctChild*& c : m_Children) { for (Child*& c : m_Children) {
c = nullptr; c = nullptr;
} }
} else { } else {
@@ -107,7 +42,7 @@ OctTree::OctChild::OctChild(const AABB& octTreeBounds,
glm::vec3 minPos, maxPos; glm::vec3 minPos, maxPos;
const glm::vec3& parentMin = m_Box.MinCorner(); const glm::vec3& parentMin = m_Box.MinCorner();
const glm::vec3& parentMax = m_Box.MaxCorner(); const glm::vec3& parentMax = m_Box.MaxCorner();
const glm::vec3& parentCenter = m_Box.Center(); const glm::vec3& parentCenter = m_Box.Origin();
std::bitset<3> bits(i); std::bitset<3> bits(i);
//If child is 4,5,6,7. //If child is 4,5,6,7.
if (bits.test(2)) { if (bits.test(2)) {
@@ -134,14 +69,14 @@ OctTree::OctChild::OctChild(const AABB& octTreeBounds,
minPos.z = parentMin.z; minPos.z = parentMin.z;
maxPos.z = parentCenter.z; maxPos.z = parentCenter.z;
} }
m_Children[i] = new OctChild(AABB(minPos, maxPos), subDivisions, m_StaticObjectsRef, m_DynamicObjectsRef); m_Children[i] = new Child(AABB(minPos, maxPos), subDivisions, m_StaticObjectsRef, m_DynamicObjectsRef);
} }
} }
} }
OctTree::OctChild::~OctChild() Child::~Child()
{ {
for (OctChild*& c : m_Children) { for (Child*& c : m_Children) {
if (c != nullptr) { if (c != nullptr) {
delete c; delete c;
c = nullptr; c = nullptr;
@@ -149,7 +84,7 @@ OctTree::OctChild::~OctChild()
} }
} }
bool OctTree::OctChild::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const bool Child::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const
{ {
if (hasChildren()) { if (hasChildren()) {
for (int i : childIndicesContainingBox(boxToTest)) { for (int i : childIndicesContainingBox(boxToTest)) {
@@ -159,7 +94,7 @@ bool OctTree::OctChild::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersect
} else { } else {
for (int i : m_StaticObjIndices) { for (int i : m_StaticObjIndices) {
if (!m_StaticObjectsRef[i].Checked) { if (!m_StaticObjectsRef[i].Checked) {
const AABB& objBox = m_StaticObjectsRef[i].Box; const AABB& objBox = *m_StaticObjectsRef[i].Box;
if (Collision::AABBVsAABB(boxToTest, objBox)) { if (Collision::AABBVsAABB(boxToTest, objBox)) {
outBoxIntersected = objBox; outBoxIntersected = objBox;
return true; return true;
@@ -169,7 +104,7 @@ bool OctTree::OctChild::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersect
} }
for (int i : m_DynamicObjIndices) { for (int i : m_DynamicObjIndices) {
if (!m_DynamicObjectsRef[i].Checked) { if (!m_DynamicObjectsRef[i].Checked) {
const AABB& objBox = m_DynamicObjectsRef[i].Box; const AABB& objBox = *m_DynamicObjectsRef[i].Box;
if (!Collision::IsSameBoxProbably(boxToTest, objBox) && if (!Collision::IsSameBoxProbably(boxToTest, objBox) &&
Collision::AABBVsAABB(boxToTest, objBox)) { Collision::AABBVsAABB(boxToTest, objBox)) {
outBoxIntersected = objBox; outBoxIntersected = objBox;
@@ -182,7 +117,7 @@ bool OctTree::OctChild::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersect
return false; return false;
} }
bool OctTree::OctChild::RayCollides(const Ray& ray, Output& data) const bool Child::RayCollides(const Ray& ray, OctSpace::Output& data) const
{ {
//If the node AABB is missed, everything it contains is missed. //If the node AABB is missed, everything it contains is missed.
if (Collision::RayAABBIntr(ray, m_Box)) { if (Collision::RayAABBIntr(ray, m_Box)) {
@@ -192,7 +127,7 @@ bool OctTree::OctChild::RayCollides(const Ray& ray, Output& data) const
std::vector<ChildInfo> childInfos; std::vector<ChildInfo> childInfos;
childInfos.reserve(8); childInfos.reserve(8);
for (int i = 0; i < 8; ++i) { for (int i = 0; i < 8; ++i) {
childInfos.push_back({ i, glm::distance(ray.Origin(), m_Children[i]->m_Box.Center()) }); childInfos.push_back({ i, glm::distance(ray.Origin(), m_Children[i]->m_Box.Origin()) });
} }
std::sort(childInfos.begin(), childInfos.end(), isFirstLower); std::sort(childInfos.begin(), childInfos.end(), isFirstLower);
//Loop through the children, starting with the one closest to the ray origin. I.e the first to be hit. //Loop through the children, starting with the one closest to the ray origin. I.e the first to be hit.
@@ -209,7 +144,7 @@ bool OctTree::OctChild::RayCollides(const Ray& ray, Output& data) const
float dist; float dist;
//If we haven't tested against this object before, and the ray hits. //If we haven't tested against this object before, and the ray hits.
if (!m_StaticObjectsRef[i].Checked && if (!m_StaticObjectsRef[i].Checked &&
Collision::RayVsAABB(ray, m_StaticObjectsRef[i].Box, dist)) { Collision::RayVsAABB(ray, *m_StaticObjectsRef[i].Box, dist)) {
minDist = std::min(dist, minDist); minDist = std::min(dist, minDist);
intersected = true; intersected = true;
} }
@@ -219,7 +154,7 @@ bool OctTree::OctChild::RayCollides(const Ray& ray, Output& data) const
float dist; float dist;
//If we haven't tested against this object before, and the ray hits. //If we haven't tested against this object before, and the ray hits.
if (!m_DynamicObjectsRef[i].Checked && if (!m_DynamicObjectsRef[i].Checked &&
Collision::RayVsAABB(ray, m_DynamicObjectsRef[i].Box, dist)) { Collision::RayVsAABB(ray, *m_DynamicObjectsRef[i].Box, dist)) {
minDist = std::min(dist, minDist); minDist = std::min(dist, minDist);
intersected = true; intersected = true;
} }
@@ -234,7 +169,7 @@ bool OctTree::OctChild::RayCollides(const Ray& ray, Output& data) const
} }
void OctTree::OctChild::AddDynamicObject(const AABB& box) void Child::AddDynamicObject(const AABB& box)
{ {
if (hasChildren()) { if (hasChildren()) {
for (auto i : childIndicesContainingBox(box)) { for (auto i : childIndicesContainingBox(box)) {
@@ -246,7 +181,7 @@ void OctTree::OctChild::AddDynamicObject(const AABB& box)
} }
} }
void OctTree::OctChild::AddStaticObject(const AABB& box) void Child::AddStaticObject(const AABB& box)
{ {
if (hasChildren()) { if (hasChildren()) {
for (auto i : childIndicesContainingBox(box)) { for (auto i : childIndicesContainingBox(box)) {
@@ -258,44 +193,10 @@ void OctTree::OctChild::AddStaticObject(const AABB& box)
} }
} }
void OctTree::OctChild::BoxesInSameRegion(const AABB& box, std::vector<AABB>& outBoxes) const void Child::ClearObjects()
{ {
if (hasChildren()) { if (hasChildren()) {
for (auto i : childIndicesContainingBox(box)) { for (Child*& c : m_Children) {
m_Children[i]->BoxesInSameRegion(box, outBoxes);
}
} else {
size_t 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::OctChild::ClearObjects()
{
if (hasChildren()) {
for (OctChild*& c : m_Children) {
c->ClearObjects(); c->ClearObjects();
} }
} else { } else {
@@ -304,11 +205,11 @@ void OctTree::OctChild::ClearObjects()
} }
} }
void OctTree::OctChild::ClearDynamicObjects() void Child::ClearDynamicObjects()
{ {
if (hasChildren()) { if (hasChildren()) {
for (OctChild*& c : m_Children) { for (Child*& c : m_Children) {
c->ClearObjects(); c->ClearDynamicObjects();
} }
} else { } else {
m_DynamicObjIndices.clear(); m_DynamicObjIndices.clear();
@@ -327,13 +228,13 @@ void OctTree::OctChild::ClearDynamicObjects()
// x : - - - - + + + + // x : - - - - + + + +
// y : - - + + - - + + // y : - - + + - - + +
// z : - + - + - + - + // z : - + - + - + - +
int OctTree::OctChild::childIndexContainingPoint(const glm::vec3& point) const int Child::childIndexContainingPoint(const glm::vec3& point) const
{ {
const glm::vec3& c = m_Box.Center(); const glm::vec3& c = m_Box.Origin();
return (1 << 2) * (point.x >= c.x) | (1 << 1) * (point.y >= c.y) | (point.z >= c.z); return (1 << 2) * (point.x >= c.x) | (1 << 1) * (point.y >= c.y) | (point.z >= c.z);
} }
std::vector<int> OctTree::OctChild::childIndicesContainingBox(const AABB& box) const std::vector<int> Child::childIndicesContainingBox(const AABB& box) const
{ {
int minInd = childIndexContainingPoint(box.MinCorner()); int minInd = childIndexContainingPoint(box.MinCorner());
int maxInd = childIndexContainingPoint(box.MaxCorner()); int maxInd = childIndexContainingPoint(box.MaxCorner());
@@ -356,9 +257,13 @@ std::vector<int> OctTree::OctChild::childIndicesContainingBox(const AABB& box) c
//the dimensions they are responsible for (which octant). //the dimensions they are responsible for (which octant).
bits.flip(); bits.flip();
//At this point the bits necessarily have exactly one bit set. //At this point the bits necessarily have exactly one bit set.
//Check the same bit in the minInd as the one set in bits.
int setOrUnset = (bits.to_ulong() & minInd);
for (int c = 0; c < 8; ++c) { for (int c = 0; c < 8; ++c) {
//If the child index have the same bit set as the bits, add box to it. //Check the same bit in the child index as the one set in bits.
if (bits.to_ulong() & c) { //Enter here if both c and minInd have the bit set, or if neither have it set.
//I.e, if they are on the same side (+ or -) in the dimension marked by the bit in bits.
if (!((bits.to_ulong() & c) ^ setOrUnset)) {
ret.push_back(c); ret.push_back(c);
} }
} }
@@ -371,7 +276,9 @@ std::vector<int> OctTree::OctChild::childIndicesContainingBox(const AABB& box) c
} }
} }
inline bool OctTree::OctChild::hasChildren() const inline bool Child::hasChildren() const
{ {
return m_Children[0] != nullptr; return m_Children[0] != nullptr;
} }
}
+11 -6
View File
@@ -66,7 +66,7 @@ void World::RegisterComponent(ComponentInfo& ci)
} }
} }
ComponentWrapper World::AttachComponent(EntityID entity, std::string componentType) ComponentWrapper World::AttachComponent(EntityID entity, const std::string& componentType)
{ {
// TODO: Allocate dynamic pool if component isn't registered // TODO: Allocate dynamic pool if component isn't registered
ComponentPool* pool = m_ComponentPools.at(componentType); ComponentPool* pool = m_ComponentPools.at(componentType);
@@ -75,31 +75,31 @@ ComponentWrapper World::AttachComponent(EntityID entity, std::string componentTy
// Allocate space for the component // Allocate space for the component
ComponentWrapper c = pool->Allocate(entity); ComponentWrapper c = pool->Allocate(entity);
// Write default values // Write default values
memcpy(c.Data, ci.Defaults.get(), ci.Meta.Stride); memcpy(c.Data, ci.Defaults.get(), ci.Stride);
return c; return c;
} }
bool World::HasComponent(EntityID entity, std::string componentType) const bool World::HasComponent(EntityID entity, const std::string& componentType) const
{ {
ComponentPool* pool = m_ComponentPools.at(componentType); ComponentPool* pool = m_ComponentPools.at(componentType);
return pool->KnowsEntity(entity); return pool->KnowsEntity(entity);
} }
ComponentWrapper World::GetComponent(EntityID entity, std::string componentType) ComponentWrapper World::GetComponent(EntityID entity, const std::string& componentType)
{ {
ComponentPool* pool = m_ComponentPools.at(componentType); ComponentPool* pool = m_ComponentPools.at(componentType);
return pool->GetByEntity(entity); return pool->GetByEntity(entity);
} }
void World::DeleteComponent(EntityID entity, std::string componentType) void World::DeleteComponent(EntityID entity, const std::string& componentType)
{ {
ComponentPool* pool = m_ComponentPools.at(componentType); ComponentPool* pool = m_ComponentPools.at(componentType);
ComponentWrapper c = pool->GetByEntity(entity); ComponentWrapper c = pool->GetByEntity(entity);
return pool->Delete(c); return pool->Delete(c);
} }
const ComponentPool* World::GetComponents(std::string componentType) const ComponentPool* World::GetComponents(const std::string& componentType)
{ {
auto it = m_ComponentPools.find(componentType); auto it = m_ComponentPools.find(componentType);
return (it != m_ComponentPools.end()) ? it->second : nullptr; return (it != m_ComponentPools.end()) ? it->second : nullptr;
@@ -125,6 +125,11 @@ void World::SetParent(EntityID entity, EntityID parent)
m_EntityChildren.insert(std::make_pair(parent, entity)); m_EntityChildren.insert(std::make_pair(parent, entity));
} }
const std::pair<std::unordered_multimap<EntityID, EntityID>::const_iterator, std::unordered_multimap<EntityID, EntityID>::const_iterator> World::GetChildren(EntityID entity)
{
return m_EntityChildren.equal_range(entity);
}
void World::SetName(EntityID entity, const std::string& name) void World::SetName(EntityID entity, const std::string& name)
{ {
m_EntityNames[entity] = name; m_EntityNames[entity] = name;
+32 -10
View File
@@ -3,7 +3,8 @@
#include <imgui/imgui_internal.h> #include <imgui/imgui_internal.h>
EditorSystem::EditorSystem(EventBroker* eventBroker, IRenderer* renderer) EditorSystem::EditorSystem(EventBroker* eventBroker, IRenderer* renderer)
: ImpureSystem(eventBroker) : System(eventBroker)
, ImpureSystem()
, m_Renderer(renderer) , m_Renderer(renderer)
{ {
auto config = ResourceManager::Load<ConfigFile>("Config.ini"); auto config = ResourceManager::Load<ConfigFile>("Config.ini");
@@ -483,8 +484,8 @@ void EditorSystem::drawUI(World* world, double dt)
} }
if (ImGui::CollapsingHeader(componentType.c_str())) { if (ImGui::CollapsingHeader(componentType.c_str())) {
if (!ci.Meta.Annotation.empty()) { if (!ci.Meta->Annotation.empty()) {
ImGui::Text(ci.Meta.Annotation.c_str()); ImGui::Text(ci.Meta->Annotation.c_str());
} }
auto& component = world->GetComponent(m_Selection, componentType); auto& component = world->GetComponent(m_Selection, componentType);
@@ -492,9 +493,10 @@ void EditorSystem::drawUI(World* world, double dt)
const std::string& fieldName = kv.first; const std::string& fieldName = kv.first;
auto& field = kv.second; auto& field = kv.second;
ImGui::PushID(fieldName.c_str()); std::string uniqueID = componentType + fieldName;
ImGui::PushID(uniqueID.c_str());
if (field.Type == "Vector") { if (field.Type == "Vector") {
auto& val = component.Property<glm::vec3>(fieldName); auto& val = component.Field<glm::vec3>(fieldName);
if (fieldName == "Scale") { if (fieldName == "Scale") {
ImGui::DragFloat3("", glm::value_ptr(val), 0.1f, 0.f, std::numeric_limits<float>::max()); ImGui::DragFloat3("", glm::value_ptr(val), 0.1f, 0.f, std::numeric_limits<float>::max());
} else if (fieldName == "Orientation") { } else if (fieldName == "Orientation") {
@@ -506,10 +508,10 @@ void EditorSystem::drawUI(World* world, double dt)
ImGui::DragFloat3("", glm::value_ptr(val), 0.1f, std::numeric_limits<float>::lowest(), std::numeric_limits<float>::max()); ImGui::DragFloat3("", glm::value_ptr(val), 0.1f, std::numeric_limits<float>::lowest(), std::numeric_limits<float>::max());
} }
} else if (field.Type == "Color") { } else if (field.Type == "Color") {
auto& val = component.Property<glm::vec4>(fieldName); auto& val = component.Field<glm::vec4>(fieldName);
ImGui::ColorEdit4("", glm::value_ptr(val), true); ImGui::ColorEdit4("", glm::value_ptr(val), true);
} else if (field.Type == "string") { } else if (field.Type == "string") {
std::string& val = component.Property<std::string>(fieldName); std::string& val = component.Field<std::string>(fieldName);
char tempString[1024]; char tempString[1024];
memcpy(tempString, val.c_str(), std::min(val.length() + 1, sizeof(tempString))); memcpy(tempString, val.c_str(), std::min(val.length() + 1, sizeof(tempString)));
if (ImGui::InputText("", tempString, sizeof(tempString))) { if (ImGui::InputText("", tempString, sizeof(tempString))) {
@@ -523,12 +525,32 @@ void EditorSystem::drawUI(World* world, double dt)
} }
} else if (field.Type == "double") { } else if (field.Type == "double") {
float tempVal = static_cast<float>(component.Property<double>(fieldName)); float tempVal = static_cast<float>(component.Field<double>(fieldName));
if (ImGui::InputFloat("", &tempVal, 0.01f, 1.f)) { if (ImGui::InputFloat("", &tempVal, 0.01f, 1.f)) {
component.SetProperty(fieldName, static_cast<double>(tempVal)); component.SetField(fieldName, static_cast<double>(tempVal));
}
} else if (field.Type == "int") {
int val = component.Field<int>(fieldName);
ImGui::InputInt("", &val);
} else if (field.Type == "enum") {
int currentValue = component.Field<int>(fieldName);
int item = -1;
std::stringstream enumKeys;
std::vector<int> enumValues;
int i = 0;
for (auto& kv : ci.Meta->FieldEnumDefinitions.at(fieldName)) {
enumKeys << kv.first << " (" << kv.second << ")" << '\0';
enumValues.push_back(kv.second);
if (currentValue == kv.second) {
item = i;
}
i++;
}
if (ImGui::Combo("", &item, enumKeys.str().c_str())) {
component.SetField(fieldName, enumValues.at(item));
} }
} else if (field.Type == "bool") { } else if (field.Type == "bool") {
auto& val = component.Property<bool>(fieldName); auto& val = component.Field<bool>(fieldName);
ImGui::Checkbox("", &val); ImGui::Checkbox("", &val);
} else { } else {
ImGui::TextDisabled(field.Type.c_str()); ImGui::TextDisabled(field.Type.c_str());
+9 -8
View File
@@ -20,15 +20,16 @@ void InputProxy::LoadBindings(std::string file)
for (auto& origin : config->GetAll<std::string>("Bindings")) { for (auto& origin : config->GetAll<std::string>("Bindings")) {
Events::BindOrigin e; Events::BindOrigin e;
e.Origin = origin.first; e.Origin = origin.first;
e.Command = origin.second; const std::string& command = origin.second;
if (!command.empty()) {
boost::char_separator<char> separator(", ");
boost::tokenizer<decltype(separator)> tokenizer(command, separator);
auto token = tokenizer.begin();
e.Command = *token;
if (++token != tokenizer.end()) {
e.Value = boost::lexical_cast<float>(*token);
} else {
e.Value = 1.f; e.Value = 1.f;
if (!e.Command.empty()) {
char prefix = e.Command.at(0);
if (prefix == '+' || prefix == '-') {
e.Command = e.Command.substr(1);
if (prefix == '-') {
e.Value *= -1.f;
}
} }
OnBindOrigin(e); OnBindOrigin(e);
} }
+5 -4
View File
@@ -1,14 +1,15 @@
#include "Rendering/RenderSystem.h" #include "Rendering/RenderSystem.h"
RenderSystem::RenderSystem(EventBroker* eventBrokerer, const IRenderer* renderer, RenderFrame* renderFrame) :ImpureSystem(eventBrokerer) RenderSystem::RenderSystem(EventBroker* eventBroker, const IRenderer* renderer, RenderFrame* renderFrame)
: System(eventBroker)
, m_Renderer(renderer)
, m_RenderFrame(renderFrame)
{ {
m_Renderer = renderer;
m_RenderFrame = renderFrame;
EVENT_SUBSCRIBE_MEMBER(m_ESetCamera, &RenderSystem::OnSetCamera); EVENT_SUBSCRIBE_MEMBER(m_ESetCamera, &RenderSystem::OnSetCamera);
EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &RenderSystem::OnInputCommand); EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &RenderSystem::OnInputCommand);
m_Camera = new Camera((float)m_Renderer->Resolution().Width / m_Renderer->Resolution().Height, glm::radians(45.f), 0.01f, 5000.f); m_Camera = new Camera((float)m_Renderer->Resolution().Width / m_Renderer->Resolution().Height, glm::radians(45.f), 0.01f, 5000.f);
m_DebugCameraInputController = new DebugCameraInputController<RenderSystem>(eventBrokerer, -1); m_DebugCameraInputController = new DebugCameraInputController<RenderSystem>(eventBroker, -1);
} }
RenderSystem::~RenderSystem() RenderSystem::~RenderSystem()
+12 -6
View File
@@ -10,17 +10,23 @@ include_directories(
${Boost_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}
) )
file(GLOB SOURCE_FILES file(GLOB SOURCE_FILES_Systems
"${INCLUDE_PATH}/*.h" "${INCLUDE_PATH}/Systems/*.h"
#"*.cpp" "Systems/*.cpp"
) )
#source_group(Core FILES ${SOURCE_FILES}) source_group(Systems FILES ${SOURCE_FILES_Systems})
file(GLOB SOURCE_FILES_Events
"${INCLUDE_PATH}/Events/*.h"
"Events/*.cpp"
)
source_group(Events FILES ${SOURCE_FILES_Events})
set(SOURCE_FILES set(SOURCE_FILES
${SOURCE_FILES} ${SOURCE_FILES}
"Game.cpp" "Game.cpp"
"HealthSystem.cpp" ${SOURCE_FILES_Systems}
"PlayerSystem.cpp" ${SOURCE_FILES_Events}
) )
set(LIBRARIES set(LIBRARIES
+21 -8
View File
@@ -1,7 +1,12 @@
#include "Game.h" #include "Game.h"
#include "Collision/CollidableOctreeSystem.h"
#include "Collision/TriggerSystem.h" #include "Collision/TriggerSystem.h"
#include "Collision/CollisionSystem.h" #include "Collision/CollisionSystem.h"
#include "Game/HealthSystem.h" #include "Systems/RaptorCopterSystem.h"
#include "Systems/HealthSystem.h"
#include "Systems/PlayerMovementSystem.h"
#include "Systems/SpawnerSystem.h"
#include "Systems/PlayerSpawnSystem.h"
#include "Core/EntityFileWriter.h" #include "Core/EntityFileWriter.h"
Game::Game(int argc, char* argv[]) Game::Game(int argc, char* argv[])
@@ -62,21 +67,27 @@ Game::Game(int argc, char* argv[])
//SO MUCH TEMP PLEASE REMOVE ME OMFG VIKTOR HELP //SO MUCH TEMP PLEASE REMOVE ME OMFG VIKTOR HELP
m_Renderer->m_World = m_World; m_Renderer->m_World = m_World;
// Create Octrees
m_OctreeCollision = new Octree<AABB>(AABB(glm::vec3(-100), glm::vec3(100)), 4);
m_OctreeFrustrumCulling = new Octree<AABB>(AABB(glm::vec3(-100), glm::vec3(100)), 4);
// Create system pipeline // Create system pipeline
m_SystemPipeline = new SystemPipeline(m_EventBroker); m_SystemPipeline = new SystemPipeline(m_EventBroker);
// All systems with orderlevel 0 will be updated first.
//All systems with orderlevel 0 will be updated first.
unsigned int updateOrderLevel = 0; unsigned int updateOrderLevel = 0;
m_SystemPipeline->AddSystem<RaptorCopterSystem>(updateOrderLevel); m_SystemPipeline->AddSystem<RaptorCopterSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<PlayerSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<EditorSystem>(updateOrderLevel, m_Renderer); m_SystemPipeline->AddSystem<EditorSystem>(updateOrderLevel, m_Renderer);
m_SystemPipeline->AddSystem<HealthSystem>(updateOrderLevel); m_SystemPipeline->AddSystem<HealthSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<PlayerMovementSystem>(updateOrderLevel);
//Collision and TriggerSystem should update after player. m_SystemPipeline->AddSystem<SpawnerSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<PlayerSpawnSystem>(updateOrderLevel);
// Populate Octree with collidables
++updateOrderLevel; ++updateOrderLevel;
m_SystemPipeline->AddSystem<CollisionSystem>(updateOrderLevel); m_SystemPipeline->AddSystem<CollidableOctreeSystem>(updateOrderLevel, m_OctreeCollision);
m_SystemPipeline->AddSystem<TriggerSystem>(updateOrderLevel); // Collision and TriggerSystem should update after player.
++updateOrderLevel;
m_SystemPipeline->AddSystem<CollisionSystem>(updateOrderLevel, m_OctreeCollision);
m_SystemPipeline->AddSystem<TriggerSystem>(updateOrderLevel, m_OctreeCollision);
++updateOrderLevel; ++updateOrderLevel;
m_SystemPipeline->AddSystem<RenderSystem>(updateOrderLevel, m_Renderer, m_RenderFrame); m_SystemPipeline->AddSystem<RenderSystem>(updateOrderLevel, m_Renderer, m_RenderFrame);
@@ -96,6 +107,8 @@ Game::~Game()
{ {
delete m_SystemPipeline; delete m_SystemPipeline;
delete m_SoundSystem; delete m_SoundSystem;
delete m_OctreeFrustrumCulling;
delete m_OctreeCollision;
delete m_World; delete m_World;
delete m_FrameStack; delete m_FrameStack;
delete m_InputProxy; delete m_InputProxy;
-42
View File
@@ -1,42 +0,0 @@
#include "PlayerSystem.h"
void PlayerSystem::UpdateComponent(World * world, ComponentWrapper & player, double dt)
{
player["Velocity"] = glm::vec3(0.f, 0.f, 0.f);
if ((bool&)player["Forward"] == true) {
((glm::vec3&)player["Velocity"]).z = m_Speed * float(dt) * -1;
}
if ((bool&)player["Left"] == true) {
((glm::vec3&)player["Velocity"]).x = m_Speed * float(dt) * -1;
}
if ((bool&)player["Back"] == true) {
((glm::vec3&)player["Velocity"]).z = m_Speed * float(dt);
}
if ((bool&)player["Right"] == true) {
((glm::vec3&)player["Velocity"]).x = m_Speed * float(dt);
}
if ((glm::vec3)player["Velocity"] != glm::vec3(0.f)) {
ComponentWrapper& transform = world->GetComponent(player.EntityID, "Transform");
(glm::vec3&)transform["Position"] += (glm::vec3)player["Velocity"];
}
}
bool PlayerSystem::OnTouch(const Events::TriggerTouch &event)
{
LOG_INFO("Player entity %i touched widget (entity %i).", event.Entity, event.Trigger);
return false;
}
bool PlayerSystem::OnEnter(const Events::TriggerEnter &event)
{
LOG_INFO("Player entity %i entered widget (entity %i).", event.Entity, event.Trigger);
return false;
}
bool PlayerSystem::OnLeave(const Events::TriggerLeave &event)
{
LOG_INFO("Player entity %i left widget (entity %i).", event.Entity, event.Trigger);
return false;
}
@@ -1,32 +1,32 @@
#include "HealthSystem.h" #include "Systems/HealthSystem.h"
#include <algorithm>
HealthSystem::HealthSystem(EventBroker* eventBroker) HealthSystem::HealthSystem(EventBroker* eventBroker)
: PureSystem(eventBroker, "Health") : System(eventBroker)
, PureSystem("Health")
{ {
//subscribe/listenTo playerdamage,healthpickup events (using the eventBroker) //subscribe/listenTo playerdamage,healthpickup events (using the eventBroker)
EVENT_SUBSCRIBE_MEMBER(m_EPlayerDamage, &HealthSystem::OnPlayerDamaged); EVENT_SUBSCRIBE_MEMBER(m_EPlayerDamage, &HealthSystem::OnPlayerDamaged);
EVENT_SUBSCRIBE_MEMBER(m_EPlayerHealthPickup, &HealthSystem::OnPlayerHealthPickup); EVENT_SUBSCRIBE_MEMBER(m_EPlayerHealthPickup, &HealthSystem::OnPlayerHealthPickup);
} }
void HealthSystem::UpdateComponent(World *world, ComponentWrapper &health, double dt) void HealthSystem::UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt)
{ {
//if entityID of health is 9 then the players ID is also 9 (player,health are connected to the same entity) //if entityID of health is 9 then the players ID is also 9 (player,health are connected to the same entity)
ComponentWrapper player = world->GetComponent(health.EntityID, "Player"); ComponentWrapper player = world->GetComponent(component.EntityID, "Player");
double maxHealth = (double)health["MaxHealth"]; double maxHealth = (double)component["MaxHealth"];
//process the DeltaHealthVector and change the entitys health accordingly //process the DeltaHealthVector and change the entitys health accordingly
for (size_t i = m_DeltaHealthVector.size(); i > 0; i--) for (size_t i = m_DeltaHealthVector.size(); i > 0; i--)
{ {
auto deltaHP = m_DeltaHealthVector[i - 1]; auto deltaHP = m_DeltaHealthVector[i - 1];
//if we have a healthchange for the current player and health is greater than 0, then apply it //if we have a healthchange for the current player and health is greater than 0, then apply it
if (std::get<0>(deltaHP) == player.EntityID && (double)health["Health"] > 0.0f) { if (std::get<0>(deltaHP) == player.EntityID && (double)component["Health"] > 0.0f) {
//get the deltaHP value from the tuple and make sure you dont get more than maxHealth //get the deltaHP value from the tuple and make sure you dont get more than maxHealth
double newHealth = std::min((double)health["Health"] + (double)std::get<1>(deltaHP), maxHealth); double newHealth = std::min((double)component["Health"] + (double)std::get<1>(deltaHP), maxHealth);
health["Health"] = newHealth; component["Health"] = newHealth;
m_DeltaHealthVector.erase(m_DeltaHealthVector.begin() + i - 1); m_DeltaHealthVector.erase(m_DeltaHealthVector.begin() + i - 1);
//check if health is <= 0 //check if health is <= 0
if ((double)health["Health"] <= 0.0f) { if ((double)component["Health"] <= 0.0f) {
//publish death event //publish death event
Events::PlayerDeath e; Events::PlayerDeath e;
e.PlayerID = player.EntityID; e.PlayerID = player.EntityID;
+18
View File
@@ -0,0 +1,18 @@
#include "Systems/PlayerMovementSystem.h"
void PlayerMovementSystem::UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt)
{
ComponentWrapper& cTransform = entity["Transform"];
if (!entity.HasComponent("Physics")) {
return;
}
ComponentWrapper& cPhysics = entity["Physics"];
glm::vec3& velocity = cPhysics["Velocity"];
if (cPhysics["Gravity"]) {
velocity.y -= 9.82 * dt;
}
glm::vec3& position = cTransform["Position"];
position += velocity * (float)dt;
}
+51
View File
@@ -0,0 +1,51 @@
#include "Systems/PlayerSpawnSystem.h"
PlayerSpawnSystem::PlayerSpawnSystem(EventBroker* eventBroker)
: System(eventBroker)
{
EVENT_SUBSCRIBE_MEMBER(m_OnInputCommand, &PlayerSpawnSystem::OnInputCommand);
}
void PlayerSpawnSystem::Update(World* world, double dt)
{
auto playerSpawns = world->GetComponents("PlayerSpawn");
if (playerSpawns == nullptr) {
return;
}
for (auto& team : m_SpawnRequests) {
for (auto& cPlayerSpawn : *playerSpawns) {
EntityWrapper spawner(world, cPlayerSpawn.EntityID);
if (!spawner.HasComponent("Spawner")) {
continue;
}
// If the spawner has a team affiliation, check it
if (spawner.HasComponent("Team")) {
if ((int)spawner["Team"]["Team"] != team) {
continue;
}
}
// Spawn the player!
EntityWrapper player = SpawnerSystem::Spawn(spawner);
// Set the player team affiliation
player["Team"]["Team"] = team;
}
}
m_SpawnRequests.clear();
}
bool PlayerSpawnSystem::OnInputCommand(const Events::InputCommand& e)
{
if (e.Command != "PickTeam") {
return false;
}
if (e.Value != 0) {
m_SpawnRequests.push_back((int)e.Value);
}
return true;
}
+61
View File
@@ -0,0 +1,61 @@
#include "Systems/SpawnerSystem.h"
SpawnerSystem::SpawnerSystem(EventBroker* eventBroker) : System(eventBroker)
{
EVENT_SUBSCRIBE_MEMBER(m_OnSpawnerSpawn, &SpawnerSystem::OnSpawnerSpawn);
}
EntityWrapper SpawnerSystem::Spawn(EntityWrapper spawner, EntityWrapper parent /*= EntityWrapper::Invalid*/)
{
// Spawn the entity in the parent's world if it exists, otherwise in the spawner's world
World* world = parent.World;
if (world == nullptr) {
world = spawner.World;
}
// Find any SpawnPoints existing as children of spawner
auto children = spawner.World->GetChildren(spawner.ID);
std::vector<EntityWrapper> spawnPoints;
for (auto kv = children.first; kv != children.second; ++kv) {
const EntityID& child = kv->second;
if (spawner.World->HasComponent(child, "SpawnPoint")) {
spawnPoints.push_back(EntityWrapper(spawner.World, child));
}
}
// Choose a random SpawnPoint
EntityWrapper spawnPoint = spawner;
if (!spawnPoints.empty()) {
if (spawnPoints.size() > 1) {
static std::random_device randomDevice;
static std::mt19937 randomGenerator(randomDevice());
std::uniform_int_distribution<> distribution(0, std::distance(spawnPoints.begin(), spawnPoints.end()) - 1);
auto randomSpawnPointIt = spawnPoints.begin();
std::advance(randomSpawnPointIt, distribution(randomGenerator));
spawnPoint = *randomSpawnPointIt;
} else {
spawnPoint = spawnPoints.front();
}
}
// Load the entity file and parse it
const std::string& entityFilePath = spawner["Spawner"]["EntityFile"];
auto entityFile = ResourceManager::Load<EntityFile>(entityFilePath);
if (entityFile == nullptr) {
return EntityWrapper::Invalid;
}
EntityFileParser parser(entityFile);
EntityWrapper spawnedEntity(world, parser.MergeEntities(world, parent.ID));
// Set its position and orientation to that of the SpawnPoint
spawnedEntity["Transform"]["Position"] = Transform::AbsolutePosition(spawnPoint.World, spawnPoint.ID);
spawnedEntity["Transform"]["Orientation"] = glm::eulerAngles(Transform::AbsoluteOrientation(spawnPoint.World, spawnPoint.ID));
return spawnedEntity;
}
bool SpawnerSystem::OnSpawnerSpawn(Events::SpawnerSpawn& e)
{
EntityWrapper spawnedEntity = Spawn(e.Spawner, e.Parent);
return true;
}
+3 -3
View File
@@ -7,7 +7,7 @@ using boost::unit_test_framework::test_case;
#include "Engine/Core/AABB.h" #include "Engine/Core/AABB.h"
#include "Engine/Core/Ray.h" #include "Engine/Core/Ray.h"
#include <stdlib.h>//srand #include <stdlib.h>//srand
#include "Engine/Core/OctTree.h" #include "Engine/Core/Octree.h"
//vs model //vs model
#include <sstream> #include <sstream>
#include <string> #include <string>
@@ -205,9 +205,9 @@ BOOST_AUTO_TEST_CASE(octTest)
{ {
glm::vec3 mini = glm::vec3(-1, -1, -1); glm::vec3 mini = glm::vec3(-1, -1, -1);
glm::vec3 maxi = glm::vec3(1, 1, 1); glm::vec3 maxi = glm::vec3(1, 1, 1);
OctTree tree(AABB(mini, maxi), 2); Octree<AABB> tree(AABB(mini, maxi), 2);
tree.AddDynamicObject(AABB(mini, -0.9f*maxi)); tree.AddDynamicObject(AABB(mini, -0.9f*maxi));
OctTree::Output data; OctSpace::Output data;
glm::vec3 origin = 3.0f * mini; glm::vec3 origin = 3.0f * mini;
bool rayIntersected = tree.RayCollides(Ray(origin , mini - origin), data); bool rayIntersected = tree.RayCollides(Ray(origin , mini - origin), data);
BOOST_CHECK(rayIntersected); BOOST_CHECK(rayIntersected);
+2 -2
View File
@@ -10,8 +10,8 @@ BOOST_AUTO_TEST_CASE(ComponentPoolTest)
//ci.Name = "Test"; //ci.Name = "Test";
//ci.FieldTypes["Field"] = "int"; //ci.FieldTypes["Field"] = "int";
//ci.FieldOffsets["Field"] = 0; //ci.FieldOffsets["Field"] = 0;
//ci.Meta.Allocation = 3; //ci.Meta->Allocation = 3;
//ci.Meta.Stride = sizeof(EntityID) + sizeof(int); //ci.Stride = sizeof(EntityID) + sizeof(int);
//std::vector<ComponentWrapper> wrappers; //std::vector<ComponentWrapper> wrappers;
//ComponentPool pool(ci); //ComponentPool pool(ci);
+24 -14
View File
@@ -3,7 +3,7 @@ using boost::unit_test_framework::test_suite;
using boost::unit_test_framework::test_case; using boost::unit_test_framework::test_case;
#include <stdlib.h>//srand #include <stdlib.h>//srand
#include "Engine/Core/OctTree.h" #include "Engine/Core/Octree.h"
#include "Engine/Core/Ray.h" #include "Engine/Core/Ray.h"
#include "OldOctTree.h" #include "OldOctTree.h"
@@ -13,17 +13,17 @@ BOOST_AUTO_TEST_CASE(octSameRegionTest)
{ {
glm::vec3 mini = glm::vec3(-1, -1, -1); glm::vec3 mini = glm::vec3(-1, -1, -1);
glm::vec3 maxi = glm::vec3(1, 1, 1); glm::vec3 maxi = glm::vec3(1, 1, 1);
OctTree tree(AABB(mini, maxi), 2); Octree<AABB> tree(AABB(mini, maxi), 2);
AABB firstQuadrant(mini, 0.8f*mini); AABB firstQuadrant(mini, 0.8f*mini);
tree.AddStaticObject(firstQuadrant); tree.AddStaticObject(firstQuadrant);
AABB testBox(0.9f*mini, 0.8f*mini); AABB testBox(0.9f*mini, 0.8f*mini);
std::vector<AABB> region; std::vector<AABB> region;
tree.BoxesInSameRegion(testBox, region); tree.ObjectsInSameRegion(testBox, region);
BOOST_REQUIRE(region.size() == 1); BOOST_REQUIRE(region.size() == 1);
AABB& box = region[0]; AABB& box = region[0];
BOOST_CHECK_CLOSE_FRACTION(box.Center().x, firstQuadrant.Center().x, 0.00001f); BOOST_CHECK_CLOSE_FRACTION(box.Origin().x, firstQuadrant.Origin().x, 0.00001f);
BOOST_CHECK_CLOSE_FRACTION(box.Center().y, firstQuadrant.Center().y, 0.00001f); BOOST_CHECK_CLOSE_FRACTION(box.Origin().y, firstQuadrant.Origin().y, 0.00001f);
BOOST_CHECK_CLOSE_FRACTION(box.Center().z, firstQuadrant.Center().z, 0.00001f); BOOST_CHECK_CLOSE_FRACTION(box.Origin().z, firstQuadrant.Origin().z, 0.00001f);
BOOST_CHECK_CLOSE_FRACTION(box.HalfSize().x, firstQuadrant.HalfSize().x, 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().y, firstQuadrant.HalfSize().y, 0.00001f);
BOOST_CHECK_CLOSE_FRACTION(box.HalfSize().z, firstQuadrant.HalfSize().z, 0.00001f); BOOST_CHECK_CLOSE_FRACTION(box.HalfSize().z, firstQuadrant.HalfSize().z, 0.00001f);
@@ -40,7 +40,7 @@ const int NUM_FUNCTION_LOOPS = 25;
const int TESTS = 0; //10 const int TESTS = 0; //10
template<typename Tree> template<typename Tree>
void RegionTest(Tree& tree) void RegionTestOld(Tree& tree)
{ {
AABB aabb; AABB aabb;
aabb.CreateFromCenter(glm::vec3(rand() % LEVEL_BOUNDS, rand() % LEVEL_BOUNDS, rand() % LEVEL_BOUNDS), aabb.CreateFromCenter(glm::vec3(rand() % LEVEL_BOUNDS, rand() % LEVEL_BOUNDS, rand() % LEVEL_BOUNDS),
@@ -50,9 +50,19 @@ void RegionTest(Tree& tree)
} }
template<typename Tree> template<typename Tree>
void RegionTest(Tree& tree)
{
AABB aabb;
aabb.CreateFromCenter(glm::vec3(rand() % LEVEL_BOUNDS, rand() % LEVEL_BOUNDS, rand() % LEVEL_BOUNDS),
glm::vec3(rand() % MAXSIZE, rand() % MAXSIZE, rand() % MAXSIZE));
std::vector<AABB> outVec;
tree.ObjectsInSameRegion(aabb, outVec);
}
template<typename Tree, typename Output>
void RayTest(Tree& tree) void RayTest(Tree& tree)
{ {
Tree::Output data; Output data;
glm::vec3 rayStart = glm::vec3(rand() % LEVEL_BOUNDS, rand() % LEVEL_BOUNDS, rand() % LEVEL_BOUNDS); glm::vec3 rayStart = glm::vec3(rand() % LEVEL_BOUNDS, rand() % LEVEL_BOUNDS, rand() % LEVEL_BOUNDS);
glm::vec3 rayEnd = glm::vec3(rand() % LEVEL_BOUNDS, rand() % LEVEL_BOUNDS, rand() % LEVEL_BOUNDS); glm::vec3 rayEnd = glm::vec3(rand() % LEVEL_BOUNDS, rand() % LEVEL_BOUNDS, rand() % LEVEL_BOUNDS);
tree.RayCollides({ rayStart , glm::normalize(rayEnd - rayStart) }, data); tree.RayCollides({ rayStart , glm::normalize(rayEnd - rayStart) }, data);
@@ -111,13 +121,13 @@ void TestLoop(TestFunction xTest)
BOOST_AUTO_TEST_CASE(octRegionPerfTestWithDuplicates) BOOST_AUTO_TEST_CASE(octRegionPerfTestWithDuplicates)
{ {
TestLoop<Old::OctTree>(RegionTest<Old::OctTree>); TestLoop<Old::OctTree>(RegionTestOld<Old::OctTree>);
BOOST_CHECK(true); BOOST_CHECK(true);
} }
BOOST_AUTO_TEST_CASE(octRegionPerfTestNoDuplicates) BOOST_AUTO_TEST_CASE(octRegionPerfTestNoDuplicates)
{ {
TestLoop<OctTree>(RegionTest<OctTree>); TestLoop<Octree<AABB>>(RegionTest<Octree<AABB>>);
BOOST_CHECK(true); BOOST_CHECK(true);
} }
@@ -129,19 +139,19 @@ BOOST_AUTO_TEST_CASE(octBoxPerfTestWithDuplicates)
BOOST_AUTO_TEST_CASE(octBoxPerfTestNoDuplicates) BOOST_AUTO_TEST_CASE(octBoxPerfTestNoDuplicates)
{ {
TestLoop<OctTree>(BoxTest<OctTree>); TestLoop<Octree<AABB>>(BoxTest<Octree<AABB>>);
BOOST_CHECK(true); BOOST_CHECK(true);
} }
BOOST_AUTO_TEST_CASE(octRayPerfTestWithDuplicates) BOOST_AUTO_TEST_CASE(octRayPerfTestWithDuplicates)
{ {
TestLoop<Old::OctTree>(RayTest<Old::OctTree>); TestLoop<Old::OctTree>(RayTest<Old::OctTree, Old::OctTree::Output>);
BOOST_CHECK(true); BOOST_CHECK(true);
} }
BOOST_AUTO_TEST_CASE(octRayPerfTestNoDuplicates) BOOST_AUTO_TEST_CASE(octRayPerfTestNoDuplicates)
{ {
TestLoop<OctTree>(RayTest<OctTree>); TestLoop<Octree<AABB>>(RayTest<Octree<AABB>, OctSpace::Output>);
BOOST_CHECK(true); BOOST_CHECK(true);
} }
@@ -153,7 +163,7 @@ BOOST_AUTO_TEST_CASE(octNopPerfTestWithDuplicates)
BOOST_AUTO_TEST_CASE(octNopPerfTestNoDuplicates) BOOST_AUTO_TEST_CASE(octNopPerfTestNoDuplicates)
{ {
TestLoop<OctTree>(NopTest<OctTree>); TestLoop<Octree<AABB>>(NopTest<Octree<AABB>>);
BOOST_CHECK(true); BOOST_CHECK(true);
} }
+2 -2
View File
@@ -91,7 +91,7 @@ void Game::Tick()
frameCounter = 0; frameCounter = 0;
} }
ComponentWrapper transform = m_World->GetComponent(m_World->anotherBoxTransformId, "Transform"); ComponentWrapper transform = m_World->GetComponent(m_World->anotherBoxTransformId, "Transform");
transform["Position"] = boxi.Center(); transform["Position"] = boxi.Origin();
//check all children again in the tree if they have a box in them or not, and colormark them if they do //check all children again in the tree if they have a box in them or not, and colormark them if they do
//contentboxarna får man ut - inte childboxarna! //contentboxarna får man ut - inte childboxarna!
@@ -110,7 +110,7 @@ void Game::Tick()
//REQUIRED: childIndicesContainingBox must be public to test this! //REQUIRED: childIndicesContainingBox must be public to test this!
for each (auto someBoxIndex in boxIndex) for each (auto someBoxIndex in boxIndex)
{ {
glm::vec3 pos = m_World->someOctTree.m_Root->m_Children[someBoxIndex]->m_Box.Center(); glm::vec3 pos = m_World->someOctTree.m_Root->m_Children[someBoxIndex]->m_Box.Origin();
if (abs(pos.x - oneLinkedObject.posxyz.x) < 0.005f && if (abs(pos.x - oneLinkedObject.posxyz.x) < 0.005f &&
abs(pos.y - oneLinkedObject.posxyz.y) < 0.005f && abs(pos.y - oneLinkedObject.posxyz.y) < 0.005f &&
abs(pos.z - oneLinkedObject.posxyz.z) < 0.005f) { abs(pos.z - oneLinkedObject.posxyz.z) < 0.005f) {
+1 -1
View File
@@ -55,7 +55,7 @@ private:
glm::quat m_PrevOri; glm::quat m_PrevOri;
glm::vec3 worldSize = glm::vec3(50, 50, 50); glm::vec3 worldSize = glm::vec3(50, 50, 50);
OctTree someOctTree; Octree someOctTree;
}; };
+1 -1
View File
@@ -7,7 +7,7 @@ using boost::unit_test_framework::test_case;
#include "Engine/Core/AABB.h" #include "Engine/Core/AABB.h"
#include "Engine/Core/Ray.h" #include "Engine/Core/Ray.h"
#include <stdlib.h>//srand #include <stdlib.h>//srand
#include "Engine/Core/OctTree.h" #include "Engine/Core/Octree.h"
//vs memleaks //vs memleaks
//#define _CRTDBG_MAP_ALLOC //#define _CRTDBG_MAP_ALLOC
+8 -8
View File
@@ -16,9 +16,9 @@ class HardcodedTestWorld : public World
public: public:
struct LinkOctTreeAndModel { struct LinkOctTreeAndModel {
EntityID entId; EntityID entId;
OctTree::OctChild* child; Octree::Child* child;
glm::vec3 posxyz; glm::vec3 posxyz;
LinkOctTreeAndModel(EntityID eId, OctTree::OctChild* ch, glm::vec3 pos) LinkOctTreeAndModel(EntityID eId, Octree::Child* ch, glm::vec3 pos)
{ {
entId = eId; entId = eId;
child = ch; child = ch;
@@ -27,7 +27,7 @@ public:
}; };
EntityID anotherBoxTransformId; EntityID anotherBoxTransformId;
std::vector<LinkOctTreeAndModel> linkOM; std::vector<LinkOctTreeAndModel> linkOM;
OctTree someOctTree; Octree someOctTree;
//constructor //constructor
HardcodedTestWorld() HardcodedTestWorld()
@@ -77,7 +77,7 @@ private:
auto someAABB = AABB(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(1.0f, 1.0f, 1.0f)); auto someAABB = AABB(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(1.0f, 1.0f, 1.0f));
//draw main box first //draw main box first
AddBoxModel(someAABB.Center(), someAABB.HalfSize().x, someOctTree.m_Root, tempId); AddBoxModel(someAABB.Origin(), someAABB.HalfSize().x, someOctTree.m_Root, tempId);
//add anotherbox in octTree //add anotherbox in octTree
auto anotherBox = AABB(glm::vec3(0.1f, 0.1f, 0.1f), glm::vec3(0.2f, 0.2f, 0.2f)); auto anotherBox = AABB(glm::vec3(0.1f, 0.1f, 0.1f), glm::vec3(0.2f, 0.2f, 0.2f));
@@ -85,19 +85,19 @@ private:
someOctTree.AddDynamicObject(anotherBox); someOctTree.AddDynamicObject(anotherBox);
//draw anotherbox and save it in anotherBoxTransformId //draw anotherbox and save it in anotherBoxTransformId
AddBoxModel(anotherBox.Center(), anotherBox.HalfSize().x, someOctTree.m_Root, anotherBoxTransformId); AddBoxModel(anotherBox.Origin(), anotherBox.HalfSize().x, someOctTree.m_Root, anotherBoxTransformId);
//draw the octTree //draw the octTree
for (size_t j = 0; j < 8; j++) for (size_t j = 0; j < 8; j++)
{ {
AddBoxModel(someOctTree.m_Root->m_Children[j]->m_Box.Center(), AddBoxModel(someOctTree.m_Root->m_Children[j]->m_Box.Origin(),
someOctTree.m_Root->m_Children[j]->m_Box.HalfSize().x, someOctTree.m_Root->m_Children[j], tempId); someOctTree.m_Root->m_Children[j]->m_Box.HalfSize().x, someOctTree.m_Root->m_Children[j], tempId);
auto someChild = someOctTree.m_Root->m_Children[j]; auto someChild = someOctTree.m_Root->m_Children[j];
for (size_t i = 0; i < 8; i++) for (size_t i = 0; i < 8; i++)
{ {
AddBoxModel(someChild->m_Children[i]->m_Box.Center(), AddBoxModel(someChild->m_Children[i]->m_Box.Origin(),
someChild->m_Children[i]->m_Box.HalfSize().x, someChild->m_Children[i], tempId); someChild->m_Children[i]->m_Box.HalfSize().x, someChild->m_Children[i], tempId);
} }
} }
@@ -115,7 +115,7 @@ private:
model["Resource"] = "Models/Core/UnitBox.obj"; model["Resource"] = "Models/Core/UnitBox.obj";
} }
void AddBoxModel(const glm::vec3 &center, const float &halfSize, OctTree::OctChild* child, EntityID &outEntityId) { void AddBoxModel(const glm::vec3 &center, const float &halfSize, Octree::Child* child, EntityID &outEntityId) {
World& world = *this; World& world = *this;
EntityID entityDummyScene = world.CreateEntity(); EntityID entityDummyScene = world.CreateEntity();
+3 -3
View File
@@ -54,7 +54,7 @@ OctTree::OctTree(const AABB& octTreeBounds, int subDivisions)
glm::vec3 minPos, maxPos; glm::vec3 minPos, maxPos;
const glm::vec3& parentMin = m_Box.MinCorner(); const glm::vec3& parentMin = m_Box.MinCorner();
const glm::vec3& parentMax = m_Box.MaxCorner(); const glm::vec3& parentMax = m_Box.MaxCorner();
const glm::vec3& parentCenter = m_Box.Center(); const glm::vec3& parentCenter = m_Box.Origin();
std::bitset<3> bits(i); std::bitset<3> bits(i);
//If child is 4,5,6,7. //If child is 4,5,6,7.
if (bits.test(2)) { if (bits.test(2)) {
@@ -172,7 +172,7 @@ bool OctTree::RayCollides(const Ray& ray, Output& data) const
std::vector<ChildInfo> childInfos; std::vector<ChildInfo> childInfos;
childInfos.reserve(8); childInfos.reserve(8);
for (int i = 0; i < 8; ++i) { for (int i = 0; i < 8; ++i) {
childInfos.push_back({ i, glm::distance(ray.Origin(), m_Children[i]->m_Box.Center()) }); childInfos.push_back({ i, glm::distance(ray.Origin(), m_Children[i]->m_Box.Origin()) });
} }
std::sort(childInfos.begin(), childInfos.end(), isFirstLower); std::sort(childInfos.begin(), childInfos.end(), isFirstLower);
//Loop through the children, starting with the one closest to the ray origin. I.e the first to be hit. //Loop through the children, starting with the one closest to the ray origin. I.e the first to be hit.
@@ -279,7 +279,7 @@ void OctTree::ClearDynamicObjects()
// z : - + - + - + - + // z : - + - + - + - +
int OctTree::childIndexContainingPoint(const glm::vec3& point) const int OctTree::childIndexContainingPoint(const glm::vec3& point) const
{ {
const glm::vec3& c = m_Box.Center(); const glm::vec3& c = m_Box.Origin();
return (1 << 2) * (point.x >= c.x) | (1 << 1) * (point.y >= c.y) | (point.z >= c.z); return (1 << 2) * (point.x >= c.x) | (1 << 1) * (point.y >= c.y) | (point.z >= c.z);
} }

Some files were not shown because too many files have changed in this diff Show More