From 8164a955d6b24f387f244631abd1179923fa6ddf Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Wed, 13 Jan 2016 12:09:24 +0100 Subject: [PATCH 01/23] Renamed OctTree files to Octree (OCD to the max) --- include/Engine/Core/{OctTree.h => Octree.h} | 0 src/Engine/Core/{OctTree.cpp => Octree.cpp} | 2 +- src/Tests/CollisionTest.cpp | 2 +- src/Tests/OctTreeTest.cpp | 2 +- src/Tests/OctTreeTestGameMain.cpp | 2 +- 5 files changed, 4 insertions(+), 4 deletions(-) rename include/Engine/Core/{OctTree.h => Octree.h} (100%) rename src/Engine/Core/{OctTree.cpp => Octree.cpp} (99%) diff --git a/include/Engine/Core/OctTree.h b/include/Engine/Core/Octree.h similarity index 100% rename from include/Engine/Core/OctTree.h rename to include/Engine/Core/Octree.h diff --git a/src/Engine/Core/OctTree.cpp b/src/Engine/Core/Octree.cpp similarity index 99% rename from src/Engine/Core/OctTree.cpp rename to src/Engine/Core/Octree.cpp index c1d8c64e..f00a4a2a 100644 --- a/src/Engine/Core/OctTree.cpp +++ b/src/Engine/Core/Octree.cpp @@ -2,7 +2,7 @@ #include #include -#include "Core/OctTree.h" +#include "Core/Octree.h" #include "Collision/Collision.h" namespace diff --git a/src/Tests/CollisionTest.cpp b/src/Tests/CollisionTest.cpp index e6a29298..f83b4ee9 100644 --- a/src/Tests/CollisionTest.cpp +++ b/src/Tests/CollisionTest.cpp @@ -7,7 +7,7 @@ using boost::unit_test_framework::test_case; #include "Engine/Core/AABB.h" #include "Engine/Core/Ray.h" #include //srand -#include "Engine/Core/OctTree.h" +#include "Engine/Core/Octree.h" //vs model #include #include diff --git a/src/Tests/OctTreeTest.cpp b/src/Tests/OctTreeTest.cpp index 0206ce50..585bac6a 100644 --- a/src/Tests/OctTreeTest.cpp +++ b/src/Tests/OctTreeTest.cpp @@ -3,7 +3,7 @@ using boost::unit_test_framework::test_suite; using boost::unit_test_framework::test_case; #include //srand -#include "Engine/Core/OctTree.h" +#include "Engine/Core/Octree.h" #include "Engine/Core/Ray.h" #include "OldOctTree.h" diff --git a/src/Tests/OctTreeTestGameMain.cpp b/src/Tests/OctTreeTestGameMain.cpp index 43789cea..a248ac43 100644 --- a/src/Tests/OctTreeTestGameMain.cpp +++ b/src/Tests/OctTreeTestGameMain.cpp @@ -7,7 +7,7 @@ using boost::unit_test_framework::test_case; #include "Engine/Core/AABB.h" #include "Engine/Core/Ray.h" #include //srand -#include "Engine/Core/OctTree.h" +#include "Engine/Core/Octree.h" //vs memleaks //#define _CRTDBG_MAP_ALLOC From 311475cbb6d1a9b27c1bb0dccaa119b6e1599eaf Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Wed, 13 Jan 2016 12:15:36 +0100 Subject: [PATCH 02/23] Renamed all OctTree to Octree (More OCD) --- include/Engine/Core/Octree.h | 54 ++++++++++---------- src/Engine/Core/Octree.cpp | 60 +++++++++++------------ src/Tests/CollisionTest.cpp | 4 +- src/Tests/OctTreeTest.cpp | 10 ++-- src/Tests/OctTreeTestGameClass.h | 2 +- src/Tests/OctTreeTestHardCodedTestWorld.h | 8 +-- 6 files changed, 69 insertions(+), 69 deletions(-) diff --git a/include/Engine/Core/Octree.h b/include/Engine/Core/Octree.h index cdb21fbb..dc43343a 100644 --- a/include/Engine/Core/Octree.h +++ b/include/Engine/Core/Octree.h @@ -1,11 +1,11 @@ -#ifndef OctTree_h__ -#define OctTree_h__ +#ifndef Octree_h__ +#define Octree_h__ #include "Core/AABB.h" class Ray; -class OctTree +class Octree { public: struct Output @@ -13,16 +13,16 @@ public: float CollideDistance; }; - OctTree(); - ~OctTree(); - //For the root OctTree, [octTreeBounds] should be a box containing the entire level. - OctTree(const AABB& octTreeBounds, int subDivisions); + Octree(); + ~Octree(); + //For the root Octree, [octreeBounds] should be a box containing the entire level. + Octree(const AABB& octreeBounds, int subDivisions); - //We cannot copy the OctTree as of now, because of the recursive dynamic allocation. - //Define these if the OctTree suddenly needs to be copied, think of the children OctChild* ptrs. - OctTree(const OctTree& other) = delete; - OctTree(const OctTree&& other) = delete; - OctTree& operator= (const OctTree& other) = delete; + //We cannot copy the Octree as of now, because of the recursive dynamic allocation. + //Define these if the Octree suddenly needs to be copied, think of the children Child* ptrs. + Octree(const Octree& other) = delete; + Octree(const Octree&& other) = delete; + Octree& operator= (const Octree& other) = delete; //Add a dynamic object (one that moves around) into the tree. void AddDynamicObject(const AABB& box); //Add a static object (that does not move) into the tree. @@ -42,7 +42,7 @@ public: bool BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected); private: - struct OctChild; //Fwd declaration; + struct Child; //Fwd declaration; struct ContainedObject { ContainedObject() @@ -56,7 +56,7 @@ private: AABB Box; bool Checked; }; - OctChild* m_Root; + Child* m_Root; std::vector m_StaticObjects; std::vector m_DynamicObjects; @@ -67,16 +67,16 @@ private: void falsifyObjectChecks(); - struct OctChild + struct Child { - ~OctChild(); - OctChild(const AABB& octTreeBounds, + ~Child(); + Child(const AABB& octTreeBounds, int subDivisions, - std::vector& staticObjects, - std::vector& dynamicObjects); - OctChild(const OctChild& other) = delete; - OctChild(const OctChild&& other) = delete; - OctChild& operator= (const OctChild& other) = delete; + std::vector& staticObjects, + std::vector& dynamicObjects); + Child(const Child& other) = delete; + Child(const Child&& other) = delete; + Child& operator= (const Child& other) = delete; void AddDynamicObject(const AABB& box); void AddStaticObject(const AABB& box); void BoxesInSameRegion(const AABB& box, std::vector& outBoxes) const; @@ -85,14 +85,14 @@ private: bool RayCollides(const Ray& ray, Output& data) const; bool BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const; - OctChild* m_Children[8]; - //Indices into the lists in OctTree. + Child* m_Children[8]; + //Indices into the lists in Octree. std::vector m_StaticObjIndices; std::vector m_DynamicObjIndices; AABB m_Box; - //Reference to the lists in OctTree. - std::vector& m_StaticObjectsRef; - std::vector& m_DynamicObjectsRef; + //Reference to the lists in Octree. + std::vector& m_StaticObjectsRef; + std::vector& m_DynamicObjectsRef; inline bool hasChildren() const; int childIndexContainingPoint(const glm::vec3& point) const; diff --git a/src/Engine/Core/Octree.cpp b/src/Engine/Core/Octree.cpp index f00a4a2a..dca30cd7 100644 --- a/src/Engine/Core/Octree.cpp +++ b/src/Engine/Core/Octree.cpp @@ -21,65 +21,65 @@ bool isFirstLower(const ChildInfo& first, const ChildInfo& second) } -OctTree::OctTree() - : OctTree(AABB(), 0) +Octree::Octree() + : Octree(AABB(), 0) {} -OctTree::OctTree(const AABB& octTreeBounds, int subDivisions) - : m_Root(new OctChild(octTreeBounds, subDivisions, m_StaticObjects, m_DynamicObjects)) +Octree::Octree(const AABB& octTreeBounds, int subDivisions) + : m_Root(new Child(octTreeBounds, subDivisions, m_StaticObjects, m_DynamicObjects)) , m_UpdatedOnce(false) {} -OctTree::~OctTree() +Octree::~Octree() { delete m_Root; } -void OctTree::AddDynamicObject(const AABB& box) +void Octree::AddDynamicObject(const AABB& box) { m_Root->AddDynamicObject(box); m_DynamicObjects.push_back(box); } -void OctTree::AddStaticObject(const AABB& box) +void Octree::AddStaticObject(const AABB& box) { m_Root->AddStaticObject(box); m_StaticObjects.push_back(box); } -void OctTree::BoxesInSameRegion(const AABB& box, std::vector& outBoxes) +void Octree::BoxesInSameRegion(const AABB& box, std::vector& outBoxes) { falsifyObjectChecks(); m_Root->BoxesInSameRegion(box, outBoxes); } -void OctTree::ClearObjects() +void Octree::ClearObjects() { m_StaticObjects.clear(); m_DynamicObjects.clear(); m_Root->ClearObjects(); } -void OctTree::ClearDynamicObjects() +void Octree::ClearDynamicObjects() { m_DynamicObjects.clear(); m_Root->ClearDynamicObjects(); } -bool OctTree::RayCollides(const Ray& ray, Output& data) +bool Octree::RayCollides(const Ray& ray, Output& data) { falsifyObjectChecks(); data.CollideDistance = -1; return m_Root->RayCollides(ray, data); } -bool OctTree::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) +bool Octree::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) { falsifyObjectChecks(); return m_Root->BoxCollides(boxToTest, outBoxIntersected); } -void OctTree::falsifyObjectChecks() +void Octree::falsifyObjectChecks() { for (auto& obj : m_StaticObjects) { obj.Checked = false; @@ -89,7 +89,7 @@ void OctTree::falsifyObjectChecks() } } -OctTree::OctChild::OctChild(const AABB& octTreeBounds, +Octree::Child::Child(const AABB& octTreeBounds, int subDivisions, std::vector& staticObjects, std::vector& dynamicObjects) @@ -98,7 +98,7 @@ OctTree::OctChild::OctChild(const AABB& octTreeBounds, , m_DynamicObjectsRef(dynamicObjects) { if (subDivisions == 0) { - for (OctChild*& c : m_Children) { + for (Child*& c : m_Children) { c = nullptr; } } else { @@ -134,14 +134,14 @@ OctTree::OctChild::OctChild(const AABB& octTreeBounds, minPos.z = parentMin.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() +Octree::Child::~Child() { - for (OctChild*& c : m_Children) { + for (Child*& c : m_Children) { if (c != nullptr) { delete c; c = nullptr; @@ -149,7 +149,7 @@ OctTree::OctChild::~OctChild() } } -bool OctTree::OctChild::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const +bool Octree::Child::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const { if (hasChildren()) { for (int i : childIndicesContainingBox(boxToTest)) { @@ -182,7 +182,7 @@ bool OctTree::OctChild::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersect return false; } -bool OctTree::OctChild::RayCollides(const Ray& ray, Output& data) const +bool Octree::Child::RayCollides(const Ray& ray, Output& data) const { //If the node AABB is missed, everything it contains is missed. if (Collision::RayAABBIntr(ray, m_Box)) { @@ -234,7 +234,7 @@ bool OctTree::OctChild::RayCollides(const Ray& ray, Output& data) const } -void OctTree::OctChild::AddDynamicObject(const AABB& box) +void Octree::Child::AddDynamicObject(const AABB& box) { if (hasChildren()) { for (auto i : childIndicesContainingBox(box)) { @@ -246,7 +246,7 @@ void OctTree::OctChild::AddDynamicObject(const AABB& box) } } -void OctTree::OctChild::AddStaticObject(const AABB& box) +void Octree::Child::AddStaticObject(const AABB& box) { if (hasChildren()) { for (auto i : childIndicesContainingBox(box)) { @@ -258,7 +258,7 @@ void OctTree::OctChild::AddStaticObject(const AABB& box) } } -void OctTree::OctChild::BoxesInSameRegion(const AABB& box, std::vector& outBoxes) const +void Octree::Child::BoxesInSameRegion(const AABB& box, std::vector& outBoxes) const { if (hasChildren()) { for (auto i : childIndicesContainingBox(box)) { @@ -292,10 +292,10 @@ void OctTree::OctChild::BoxesInSameRegion(const AABB& box, std::vector& ou } } -void OctTree::OctChild::ClearObjects() +void Octree::Child::ClearObjects() { if (hasChildren()) { - for (OctChild*& c : m_Children) { + for (Child*& c : m_Children) { c->ClearObjects(); } } else { @@ -304,10 +304,10 @@ void OctTree::OctChild::ClearObjects() } } -void OctTree::OctChild::ClearDynamicObjects() +void Octree::Child::ClearDynamicObjects() { if (hasChildren()) { - for (OctChild*& c : m_Children) { + for (Child*& c : m_Children) { c->ClearObjects(); } } else { @@ -327,13 +327,13 @@ void OctTree::OctChild::ClearDynamicObjects() // x : - - - - + + + + // y : - - + + - - + + // z : - + - + - + - + -int OctTree::OctChild::childIndexContainingPoint(const glm::vec3& point) const +int Octree::Child::childIndexContainingPoint(const glm::vec3& point) const { const glm::vec3& c = m_Box.Center(); return (1 << 2) * (point.x >= c.x) | (1 << 1) * (point.y >= c.y) | (point.z >= c.z); } -std::vector OctTree::OctChild::childIndicesContainingBox(const AABB& box) const +std::vector Octree::Child::childIndicesContainingBox(const AABB& box) const { int minInd = childIndexContainingPoint(box.MinCorner()); int maxInd = childIndexContainingPoint(box.MaxCorner()); @@ -371,7 +371,7 @@ std::vector OctTree::OctChild::childIndicesContainingBox(const AABB& box) c } } -inline bool OctTree::OctChild::hasChildren() const +inline bool Octree::Child::hasChildren() const { return m_Children[0] != nullptr; } \ No newline at end of file diff --git a/src/Tests/CollisionTest.cpp b/src/Tests/CollisionTest.cpp index f83b4ee9..9f400330 100644 --- a/src/Tests/CollisionTest.cpp +++ b/src/Tests/CollisionTest.cpp @@ -205,9 +205,9 @@ BOOST_AUTO_TEST_CASE(octTest) { glm::vec3 mini = glm::vec3(-1, -1, -1); glm::vec3 maxi = glm::vec3(1, 1, 1); - OctTree tree(AABB(mini, maxi), 2); + Octree tree(AABB(mini, maxi), 2); tree.AddDynamicObject(AABB(mini, -0.9f*maxi)); - OctTree::Output data; + Octree::Output data; glm::vec3 origin = 3.0f * mini; bool rayIntersected = tree.RayCollides(Ray(origin , mini - origin), data); BOOST_CHECK(rayIntersected); diff --git a/src/Tests/OctTreeTest.cpp b/src/Tests/OctTreeTest.cpp index 585bac6a..f437bde0 100644 --- a/src/Tests/OctTreeTest.cpp +++ b/src/Tests/OctTreeTest.cpp @@ -13,7 +13,7 @@ BOOST_AUTO_TEST_CASE(octSameRegionTest) { glm::vec3 mini = glm::vec3(-1, -1, -1); glm::vec3 maxi = glm::vec3(1, 1, 1); - OctTree tree(AABB(mini, maxi), 2); + Octree tree(AABB(mini, maxi), 2); AABB firstQuadrant(mini, 0.8f*mini); tree.AddStaticObject(firstQuadrant); AABB testBox(0.9f*mini, 0.8f*mini); @@ -117,7 +117,7 @@ BOOST_AUTO_TEST_CASE(octRegionPerfTestWithDuplicates) BOOST_AUTO_TEST_CASE(octRegionPerfTestNoDuplicates) { - TestLoop(RegionTest); + TestLoop(RegionTest); BOOST_CHECK(true); } @@ -129,7 +129,7 @@ BOOST_AUTO_TEST_CASE(octBoxPerfTestWithDuplicates) BOOST_AUTO_TEST_CASE(octBoxPerfTestNoDuplicates) { - TestLoop(BoxTest); + TestLoop(BoxTest); BOOST_CHECK(true); } @@ -141,7 +141,7 @@ BOOST_AUTO_TEST_CASE(octRayPerfTestWithDuplicates) BOOST_AUTO_TEST_CASE(octRayPerfTestNoDuplicates) { - TestLoop(RayTest); + TestLoop(RayTest); BOOST_CHECK(true); } @@ -153,7 +153,7 @@ BOOST_AUTO_TEST_CASE(octNopPerfTestWithDuplicates) BOOST_AUTO_TEST_CASE(octNopPerfTestNoDuplicates) { - TestLoop(NopTest); + TestLoop(NopTest); BOOST_CHECK(true); } diff --git a/src/Tests/OctTreeTestGameClass.h b/src/Tests/OctTreeTestGameClass.h index 6dc9404e..4cce489f 100644 --- a/src/Tests/OctTreeTestGameClass.h +++ b/src/Tests/OctTreeTestGameClass.h @@ -55,7 +55,7 @@ private: glm::quat m_PrevOri; glm::vec3 worldSize = glm::vec3(50, 50, 50); - OctTree someOctTree; + Octree someOctTree; }; diff --git a/src/Tests/OctTreeTestHardCodedTestWorld.h b/src/Tests/OctTreeTestHardCodedTestWorld.h index 512716df..7fcae0b2 100644 --- a/src/Tests/OctTreeTestHardCodedTestWorld.h +++ b/src/Tests/OctTreeTestHardCodedTestWorld.h @@ -16,9 +16,9 @@ class HardcodedTestWorld : public World public: struct LinkOctTreeAndModel { EntityID entId; - OctTree::OctChild* child; + Octree::Child* child; glm::vec3 posxyz; - LinkOctTreeAndModel(EntityID eId, OctTree::OctChild* ch, glm::vec3 pos) + LinkOctTreeAndModel(EntityID eId, Octree::Child* ch, glm::vec3 pos) { entId = eId; child = ch; @@ -27,7 +27,7 @@ public: }; EntityID anotherBoxTransformId; std::vector linkOM; - OctTree someOctTree; + Octree someOctTree; //constructor HardcodedTestWorld() @@ -115,7 +115,7 @@ private: model["Resource"] = "Models/Core/UnitBox.obj"; } - void AddBoxModel(const glm::vec3 ¢er, const float &halfSize, OctTree::OctChild* child, EntityID &outEntityId) { + void AddBoxModel(const glm::vec3 ¢er, const float &halfSize, Octree::Child* child, EntityID &outEntityId) { World& world = *this; EntityID entityDummyScene = world.CreateEntity(); From 8ed4ba121930e777ed713d6beb05e73a726e097f Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Wed, 13 Jan 2016 12:16:35 +0100 Subject: [PATCH 03/23] Added missing include for Octree --- include/Engine/Core/Octree.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/Engine/Core/Octree.h b/include/Engine/Core/Octree.h index dc43343a..a2f358ae 100644 --- a/include/Engine/Core/Octree.h +++ b/include/Engine/Core/Octree.h @@ -1,6 +1,7 @@ #ifndef Octree_h__ #define Octree_h__ +#include "../Common.h" #include "Core/AABB.h" class Ray; From d6ef527f25ba86af726ae08944d504b8eb6c6a7a Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Wed, 13 Jan 2016 15:34:43 +0100 Subject: [PATCH 04/23] Basic collisions using Octree. Seems buggy over octree boundaries. --- .../Engine/Collision/CollidableOctreeSystem.h | 19 +++ include/Engine/Collision/Collision.h | 15 +- include/Engine/Collision/CollisionSystem.h | 17 ++- include/Engine/Collision/TriggerSystem.h | 14 +- include/Engine/Core/AABB.h | 6 +- include/Engine/Core/Octree.h | 4 +- include/Engine/Core/System.h | 16 +- include/Engine/Core/SystemPipeline.h | 14 +- include/Game/Game.h | 3 + include/Game/PlayerSystem.h | 3 +- include/Game/RaptorCopterSystem.h | 3 +- resources/Schema/Components.xsd | 1 + resources/Schema/Components/AABB.xml | 4 +- resources/Schema/Components/AABB.xsd | 8 +- resources/Schema/Components/Collidable.xml | 3 + resources/Schema/Components/Collidable.xsd | 13 ++ .../Schema/Entities/CollisionTestLevel.xml | 140 +++--------------- resources/Schema/Entities/Empty.xml | 8 +- resources/Schema/Entities/OctreeTest.xml | 64 ++++++++ resources/Schema/Types/Entity.xsd | 3 + .../Collision/CollidableOctreeSystem.cpp | 20 +++ src/Engine/Collision/Collision.cpp | 52 ++----- src/Engine/Collision/CollisionSystem.cpp | 31 ++-- src/Engine/Collision/TriggerSystem.cpp | 21 ++- src/Engine/Core/AABB.cpp | 13 +- src/Engine/Core/Octree.cpp | 12 +- src/Engine/Editor/EditorSystem.cpp | 3 +- src/Game/Game.cpp | 20 ++- src/Game/HealthSystem.cpp | 3 +- src/Tests/OctTreeTest.cpp | 6 +- src/Tests/OctTreeTestGameClass.cpp | 4 +- src/Tests/OctTreeTestHardCodedTestWorld.h | 8 +- src/Tests/OldOctTree.cpp | 6 +- 33 files changed, 290 insertions(+), 267 deletions(-) create mode 100644 include/Engine/Collision/CollidableOctreeSystem.h create mode 100644 resources/Schema/Components/Collidable.xml create mode 100644 resources/Schema/Components/Collidable.xsd create mode 100644 resources/Schema/Entities/OctreeTest.xml create mode 100644 src/Engine/Collision/CollidableOctreeSystem.cpp diff --git a/include/Engine/Collision/CollidableOctreeSystem.h b/include/Engine/Collision/CollidableOctreeSystem.h new file mode 100644 index 00000000..b7a77346 --- /dev/null +++ b/include/Engine/Collision/CollidableOctreeSystem.h @@ -0,0 +1,19 @@ +#include "../Core/System.h" +#include "../Core/Octree.h" +#include "Collision.h" + +class CollidableOctreeSystem : public ImpureSystem, public PureSystem +{ +public: + CollidableOctreeSystem(EventBroker* eventBroker, Octree* octree) + : System(eventBroker) + , PureSystem("Collidable") + , m_Octree(octree) + { } + + virtual void Update(World* world, double dt) override; + virtual void UpdateComponent(World* world, ComponentWrapper& component, double dt) override; + +private: + Octree* m_Octree; +}; \ No newline at end of file diff --git a/include/Engine/Collision/Collision.h b/include/Engine/Collision/Collision.h index 714cee3f..18520243 100644 --- a/include/Engine/Collision/Collision.h +++ b/include/Engine/Collision/Collision.h @@ -6,11 +6,13 @@ //or you will get "fatal error C1189: #error: gl.h included before glew.h" #include +#include -#include "Core/Ray.h" -#include "Core/AABB.h" -#include "Engine/Rendering/RawModel.h" -#include "Core/Entity.h" +#include "../Core/Ray.h" +#include "../Core/AABB.h" +#include "../Rendering/RawModel.h" +#include "../Rendering/RenderQueueFactory.h" +#include "../Core/Entity.h" class World; struct ComponentWrapper; @@ -50,9 +52,8 @@ bool AABBVsAABB(const AABB& a, const AABB& b); bool AABBVsAABB(const AABB& a, const AABB& b, glm::vec3& minimumTranslation); 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]. -bool GetEntityBox(World* world, EntityID entity, AABB& outBox, bool forceBoxFromModel = false); -bool GetEntityBox(World* world, ComponentWrapper& AABBComponent, AABB& outBox); +// Calculates an absolute AABB from an entity AABB component +boost::optional EntityAbsoluteAABB(World* world, EntityID entity); } diff --git a/include/Engine/Collision/CollisionSystem.h b/include/Engine/Collision/CollisionSystem.h index 254a2461..b4e25072 100644 --- a/include/Engine/Collision/CollisionSystem.h +++ b/include/Engine/Collision/CollisionSystem.h @@ -4,16 +4,19 @@ #include #include -#include "Common.h" -#include "Core/System.h" -#include "Core/EventBroker.h" -#include "Core/EKeyUp.h" +#include "../Common.h" +#include "../Core/System.h" +#include "../Core/EventBroker.h" +#include "../Core/EKeyUp.h" +#include "../Core/Octree.h" class CollisionSystem : public PureSystem { public: - CollisionSystem(EventBroker* eventBroker) - : PureSystem(eventBroker, "AABB") + CollisionSystem(EventBroker* eventBroker, Octree* octree) + : System(eventBroker) + , PureSystem("AABB") + , m_Octree(octree) , zPress(false) { //TODO: Debug stuff, remove later. @@ -23,7 +26,9 @@ public: virtual void UpdateComponent(World* world, ComponentWrapper& cAABB, double dt) override; private: + Octree* m_Octree; bool zPress; + EventRelay m_EKeyUp; bool OnKeyUp(const Events::KeyUp &event); }; diff --git a/include/Engine/Collision/TriggerSystem.h b/include/Engine/Collision/TriggerSystem.h index 7e6ef008..7856a09d 100644 --- a/include/Engine/Collision/TriggerSystem.h +++ b/include/Engine/Collision/TriggerSystem.h @@ -4,8 +4,9 @@ #include #include -#include "Core/System.h" -#include "Core/EventBroker.h" +#include "../Core/System.h" +#include "../Core/EventBroker.h" +#include "../Core/Octree.h" #include "ETrigger.h" class AABB; @@ -13,13 +14,16 @@ class AABB; class TriggerSystem : public PureSystem { public: - TriggerSystem(EventBroker* eventBroker) - : PureSystem(eventBroker, "Trigger") - {} + TriggerSystem(EventBroker* eventBroker, Octree* octree) + : System(eventBroker) + , PureSystem("Trigger") + , m_Octree(octree) + { } virtual void UpdateComponent(World* world, ComponentWrapper& collision, double dt) override; private: + Octree* m_Octree; std::unordered_map> m_EntitiesTouchingTrigger; std::unordered_map> m_EntitiesCompletelyInTrigger; diff --git a/include/Engine/Core/AABB.h b/include/Engine/Core/AABB.h index c8e05248..5b9c6485 100644 --- a/include/Engine/Core/AABB.h +++ b/include/Engine/Core/AABB.h @@ -11,18 +11,18 @@ public: AABB(const glm::vec3& minPos, const glm::vec3& maxPos); AABB(const glm::vec4& minPos, const glm::vec4& maxPos); //No checks are made. Size must consist of non-negative numbers. - virtual void CreateFromCenter(const glm::vec3& center, const glm::vec3& size); + static AABB FromOriginSize(const glm::vec3& origin, const glm::vec3& size); virtual ~AABB(); const glm::vec3& MinCorner() const { return m_MinCorner; } const glm::vec3& MaxCorner() const { return m_MaxCorner; } - const glm::vec3& Center() const { return m_Center; } + const glm::vec3& Origin() const { return m_Origin; } const glm::vec3 Size() const { return 2.0f * m_HalfSize; } const glm::vec3& HalfSize() const { return m_HalfSize; } private: glm::vec3 m_MinCorner; glm::vec3 m_MaxCorner; - glm::vec3 m_Center; + glm::vec3 m_Origin; glm::vec3 m_HalfSize; }; diff --git a/include/Engine/Core/Octree.h b/include/Engine/Core/Octree.h index a2f358ae..954dbcbc 100644 --- a/include/Engine/Core/Octree.h +++ b/include/Engine/Core/Octree.h @@ -2,7 +2,7 @@ #define Octree_h__ #include "../Common.h" -#include "Core/AABB.h" +#include "AABB.h" class Ray; @@ -14,7 +14,7 @@ public: float CollideDistance; }; - Octree(); + Octree() = delete; ~Octree(); //For the root Octree, [octreeBounds] should be a box containing the entire level. Octree(const AABB& octreeBounds, int subDivisions); diff --git a/include/Engine/Core/System.h b/include/Engine/Core/System.h index 75bd3882..cd8e9fc7 100644 --- a/include/Engine/Core/System.h +++ b/include/Engine/Core/System.h @@ -10,6 +10,9 @@ class System friend class SystemPipeline; protected: + System() + : m_EventBroker(nullptr) + { } System(EventBroker* eventBroker) : m_EventBroker(eventBroker) { } @@ -18,14 +21,13 @@ protected: EventBroker* m_EventBroker; }; -class PureSystem : public System +class PureSystem : public virtual System { friend class SystemPipeline; protected: - PureSystem(EventBroker* eventBroker, std::string componentType) - : System(eventBroker) - , m_ComponentType(componentType) + PureSystem(std::string componentType) + : m_ComponentType(componentType) { } virtual ~PureSystem() = default; @@ -34,14 +36,12 @@ protected: virtual void UpdateComponent(World* world, ComponentWrapper& component, double dt) = 0; }; -class ImpureSystem : public System +class ImpureSystem : public virtual System { friend class SystemPipeline; protected: - ImpureSystem(EventBroker* eventBroker) - : System(eventBroker) - { } + ImpureSystem() = default; virtual ~ImpureSystem() = default; virtual void Update(World* world, double dt) = 0; diff --git a/include/Engine/Core/SystemPipeline.h b/include/Engine/Core/SystemPipeline.h index d6a6b371..79d4ace4 100644 --- a/include/Engine/Core/SystemPipeline.h +++ b/include/Engine/Core/SystemPipeline.h @@ -32,8 +32,8 @@ public: System* system = new T(m_EventBroker, args...); group.Systems[typeid(T).name()] = system; - if (std::is_base_of::value) { - PureSystem* pureSystem = static_cast(system); + PureSystem* pureSystem = dynamic_cast(system); + if (pureSystem != nullptr) { if (!pureSystem->m_ComponentType.empty()) { group.PureSystems[pureSystem->m_ComponentType].push_back(pureSystem); } else { @@ -41,8 +41,8 @@ public: } } - if (std::is_base_of::value) { - ImpureSystem* impureSystem = static_cast(system); + ImpureSystem* impureSystem = dynamic_cast(system); + if (impureSystem != nullptr) { group.ImpureSystems.push_back(impureSystem); } } @@ -56,6 +56,9 @@ public: } // Update + for (auto& system : group.ImpureSystems) { + system->Update(world, dt); + } for (auto& pair : group.PureSystems) { const std::string& componentName = pair.first; auto& systems = pair.second; @@ -69,9 +72,6 @@ public: } } } - for (auto& system : group.ImpureSystems) { - system->Update(world, dt); - } } } diff --git a/include/Game/Game.h b/include/Game/Game.h index 1c19aac2..de45c558 100644 --- a/include/Game/Game.h +++ b/include/Game/Game.h @@ -20,6 +20,7 @@ #include "Editor/EditorSystem.h" #include "Core/EntityFile.h" #include "Core/EntityFileParser.h" +#include "Core/Octree.h" // Network #include @@ -46,6 +47,8 @@ private: InputProxy* m_InputProxy; GUI::Frame* m_FrameStack; World* m_World; + Octree* m_OctreeCollision; + Octree* m_OctreeFrustrumCulling; SystemPipeline* m_SystemPipeline; RenderQueueFactory* m_RenderQueueFactory; // Network variables diff --git a/include/Game/PlayerSystem.h b/include/Game/PlayerSystem.h index 577fbbb0..50492617 100644 --- a/include/Game/PlayerSystem.h +++ b/include/Game/PlayerSystem.h @@ -12,7 +12,8 @@ class PlayerSystem : public PureSystem { public: PlayerSystem(EventBroker* eventBroker) - : PureSystem(eventBroker, "Player") + : System(eventBroker) + , PureSystem("Player") { EVENT_SUBSCRIBE_MEMBER(m_ETouch, &PlayerSystem::OnTouch); EVENT_SUBSCRIBE_MEMBER(m_EEnter, &PlayerSystem::OnEnter); diff --git a/include/Game/RaptorCopterSystem.h b/include/Game/RaptorCopterSystem.h index 913efdb3..14b49f4d 100644 --- a/include/Game/RaptorCopterSystem.h +++ b/include/Game/RaptorCopterSystem.h @@ -5,7 +5,8 @@ class RaptorCopterSystem : public PureSystem { public: RaptorCopterSystem(EventBroker* eventBroker) - : PureSystem(eventBroker, "RaptorCopter") + : System(eventBroker) + , PureSystem("RaptorCopter") { } virtual void UpdateComponent(World* world, ComponentWrapper& raptorCopter, double dt) override diff --git a/resources/Schema/Components.xsd b/resources/Schema/Components.xsd index 7fcdd565..4f32b477 100644 --- a/resources/Schema/Components.xsd +++ b/resources/Schema/Components.xsd @@ -9,4 +9,5 @@ + \ No newline at end of file diff --git a/resources/Schema/Components/AABB.xml b/resources/Schema/Components/AABB.xml index 341d1d0d..6996b3dc 100644 --- a/resources/Schema/Components/AABB.xml +++ b/resources/Schema/Components/AABB.xml @@ -1,4 +1,4 @@ - - + + \ No newline at end of file diff --git a/resources/Schema/Components/AABB.xsd b/resources/Schema/Components/AABB.xsd index 8fac860e..daa633a6 100644 --- a/resources/Schema/Components/AABB.xsd +++ b/resources/Schema/Components/AABB.xsd @@ -6,8 +6,12 @@ - - + + Middle point of the bounding box + + + Size of the bounding box + diff --git a/resources/Schema/Components/Collidable.xml b/resources/Schema/Components/Collidable.xml new file mode 100644 index 00000000..0d1bb9b3 --- /dev/null +++ b/resources/Schema/Components/Collidable.xml @@ -0,0 +1,3 @@ + + true + \ No newline at end of file diff --git a/resources/Schema/Components/Collidable.xsd b/resources/Schema/Components/Collidable.xsd new file mode 100644 index 00000000..f835d9a6 --- /dev/null +++ b/resources/Schema/Components/Collidable.xsd @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/Schema/Entities/CollisionTestLevel.xml b/resources/Schema/Entities/CollisionTestLevel.xml index 99842b88..52420d14 100644 --- a/resources/Schema/Entities/CollisionTestLevel.xml +++ b/resources/Schema/Entities/CollisionTestLevel.xml @@ -1,122 +1,20 @@ - + + - - - - - - - Models/DummyScene.obj - - - - - - - - - - - Models/ScaleWidget.obj - - - - - - - - - - - Models/RotationWidgetX.obj - - - - - - - - - - - - - - - Models/Core/UnitCube.obj - - - - - - - - - - - - - - - - - - - - - - Models/Core/UnitRaptor.obj - - - - - - - - - - - - 20 - - - - - - - - - - - - - Models/Core/UnitCube.obj - - - - - - - - - - - - - Models/Core/UnitCube.obj - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + Models/Test/ObstacleCourse.obj + + + + + + + + diff --git a/resources/Schema/Entities/Empty.xml b/resources/Schema/Entities/Empty.xml index 70581847..6efd8318 100644 --- a/resources/Schema/Entities/Empty.xml +++ b/resources/Schema/Entities/Empty.xml @@ -1,6 +1,10 @@ - + + - \ No newline at end of file + + + + diff --git a/resources/Schema/Entities/OctreeTest.xml b/resources/Schema/Entities/OctreeTest.xml new file mode 100644 index 00000000..819159d0 --- /dev/null +++ b/resources/Schema/Entities/OctreeTest.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + Models/Core/UnitCube.obj + + + + + + + + + + + + + + Models/Core/UnitCube.obj + + + + + + + + + + + + + + Models/Core/UnitCube.obj + + + + + + + + + + + + Models/Core/UnitCube.obj + + + + + + + + + + diff --git a/resources/Schema/Types/Entity.xsd b/resources/Schema/Types/Entity.xsd index 6562f3ed..8790d8a9 100644 --- a/resources/Schema/Types/Entity.xsd +++ b/resources/Schema/Types/Entity.xsd @@ -15,7 +15,10 @@ + + + diff --git a/src/Engine/Collision/CollidableOctreeSystem.cpp b/src/Engine/Collision/CollidableOctreeSystem.cpp new file mode 100644 index 00000000..c7fed0a0 --- /dev/null +++ b/src/Engine/Collision/CollidableOctreeSystem.cpp @@ -0,0 +1,20 @@ +#include "Collision/CollidableOctreeSystem.h" + +void CollidableOctreeSystem::Update(World* world, double dt) +{ + m_Octree->ClearDynamicObjects(); +} + +void CollidableOctreeSystem::UpdateComponent(World* world, ComponentWrapper& cCollidable, double dt) +{ + EntityID entity = cCollidable.EntityID; + + if (world->HasComponent(entity, "AABB")) { + boost::optional absoluteAABB = Collision::EntityAbsoluteAABB(world, entity); + if (absoluteAABB) { + m_Octree->AddDynamicObject(*absoluteAABB); + } + } else if (world->HasComponent(entity, "Model")) { + // TODO: Derive AABB from model + } +} \ No newline at end of file diff --git a/src/Engine/Collision/Collision.cpp b/src/Engine/Collision/Collision.cpp index 620e9639..1af09382 100644 --- a/src/Engine/Collision/Collision.cpp +++ b/src/Engine/Collision/Collision.cpp @@ -13,7 +13,7 @@ bool RayAABBIntr(const Ray& ray, const AABB& box) { glm::vec3 w = 75.0f * ray.Direction(); 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(); 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) { - const glm::vec3& aCenter = a.Center(); - const glm::vec3& bCenter = b.Center(); + const glm::vec3& aCenter = a.Origin(); + const glm::vec3& bCenter = b.Origin(); const glm::vec3& aHSize = a.HalfSize(); const glm::vec3& bHSize = b.HalfSize(); //Test will probably exit because of the X and Z axes more often, so test them first. @@ -202,8 +202,8 @@ bool RayVsModel(const Ray& ray, bool IsSameBoxProbably(const AABB& first, const AABB& second, const float epsilon) { const glm::vec3& ma1 = first.MaxCorner(); - const glm::vec3& ma2 = first.MaxCorner(); - const glm::vec3& mi1 = second.MinCorner(); + const glm::vec3& ma2 = second.MaxCorner(); + const glm::vec3& mi1 = first.MinCorner(); const glm::vec3& mi2 = second.MinCorner(); return (std::abs(ma1.x - ma2.x) < epsilon) && (std::abs(mi1.x - mi2.x) < epsilon) && @@ -238,45 +238,23 @@ bool attachAABBComponentFromModel(World* world, EntityID id) mini.y = std::min(wPos.y, mini.y); mini.z = std::min(wPos.z, mini.z); } - collision["BoxCenter"] = 0.5f * (maxi + mini); - collision["BoxSize"] = maxi - mini; + collision["Origin"] = 0.5f * (maxi + mini); + collision["Size"] = maxi - mini; return true; } -bool GetEntityBox(World* world, ComponentWrapper& AABBComponent, AABB& outBox) -{ - ComponentWrapper& cTrans = world->GetComponent(AABBComponent.EntityID, "Transform"); - ComponentWrapper model = world->GetComponent(AABBComponent.EntityID, "Model"); - Model* modelRes = ResourceManager::Load(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->m_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) +boost::optional EntityAbsoluteAABB(World* world, EntityID entity) { if (!world->HasComponent(entity, "AABB")) { - if (forceBoxFromModel) { - if (!attachAABBComponentFromModel(world, entity)) - return false; - } else { - return false; - } + return boost::none; } - ComponentWrapper& cBox = world->GetComponent(entity, "AABB"); - return GetEntityBox(world, cBox, outBox); + ComponentWrapper& cAABB = world->GetComponent(entity, "AABB"); + glm::vec3 absPosition = RenderQueueFactory::AbsolutePosition(world, entity); + glm::vec3 absScale = RenderQueueFactory::AbsoluteScale(world, entity); + glm::vec3 origin = absPosition + (glm::vec3)cAABB["Origin"]; + glm::vec3 size = (glm::vec3)cAABB["Size"] * absScale; + return AABB::FromOriginSize(origin, size); } } diff --git a/src/Engine/Collision/CollisionSystem.cpp b/src/Engine/Collision/CollisionSystem.cpp index 69929c6d..4ce514da 100644 --- a/src/Engine/Collision/CollisionSystem.cpp +++ b/src/Engine/Collision/CollisionSystem.cpp @@ -2,31 +2,30 @@ #include "Collision/CollisionSystem.h" #include "Core/AABB.h" -void CollisionSystem::UpdateComponent(World * world, ComponentWrapper & cAABB, double dt) +void CollisionSystem::UpdateComponent(World* world, ComponentWrapper& cAABB, double dt) { - //Right now, cAABB is a component attached to any entity that should be collideable. - AABB thisBox; - if (!Collision::GetEntityBox(world, cAABB, thisBox)) { + EntityID entity = cAABB.EntityID; + boost::optional boundingBox = Collision::EntityAbsoluteAABB(world, entity); + if (!boundingBox) { return; } + ComponentWrapper& cTransform = world->GetComponent(entity, "Transform"); + AABB& boxA = *boundingBox; + //Press 'Z' to enable/disable collision. if (zPress) { return; } - //Here, mover should be an object that moves, currently only players. - for (auto& mover : *world->GetComponents("Player")) { - if (cAABB.EntityID == mover.EntityID) { + + std::vector octreeResult; + m_Octree->BoxesInSameRegion(*boundingBox, octreeResult); + for (auto& boxB : octreeResult) { + glm::vec3 resolutionVector; + if (Collision::IsSameBoxProbably(boxA, boxB)) { continue; } - AABB otherBox; - if (!Collision::GetEntityBox(world, mover.EntityID, otherBox)) { - continue; - } - 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; + if (Collision::AABBVsAABB(boxA, boxB, resolutionVector)) { + (glm::vec3&)cTransform["Position"] += resolutionVector; } } } diff --git a/src/Engine/Collision/TriggerSystem.cpp b/src/Engine/Collision/TriggerSystem.cpp index 09092461..2c8c7540 100644 --- a/src/Engine/Collision/TriggerSystem.cpp +++ b/src/Engine/Collision/TriggerSystem.cpp @@ -3,27 +3,27 @@ #include "Core/AABB.h" #include "Rendering/Model.h" -void TriggerSystem::UpdateComponent(World* world, ComponentWrapper& trigger, double dt) +void TriggerSystem::UpdateComponent(World* world, ComponentWrapper& cTrigger, double dt) { //Currently only players can trigger things. auto players = world->GetComponents("Player"); if (players == nullptr) { return; } - EntityID tId = trigger.EntityID; - AABB triggerBox; + EntityID tId = cTrigger.EntityID; + boost::optional triggerBox = Collision::EntityAbsoluteAABB(world, tId); //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; } for (auto& pc : *players) { EntityID pId = pc.EntityID; - AABB playerBox; + boost::optional playerBox = Collision::EntityAbsoluteAABB(world, pId); //The player can't trigger anything without an AABB. - if (!Collision::GetEntityBox(world, pId, playerBox, true)) { + if (!playerBox) { continue; } - if (!Collision::AABBVsAABB(triggerBox, playerBox)) { + if (!Collision::AABBVsAABB(*triggerBox, *playerBox)) { //Entity is not touching the trigger, //Throw event if it was previously. if (throwLeaveIfWasInTrigger(m_EntitiesTouchingTrigger[tId], pId, tId)) { @@ -34,10 +34,9 @@ void TriggerSystem::UpdateComponent(World* world, ComponentWrapper& trigger, dou throwLeaveIfWasInTrigger(m_EntitiesCompletelyInTrigger[tId], pId, tId); } else { //Entity is at least touching the trigger. - AABB completelyInsideBox; - completelyInsideBox.CreateFromCenter(triggerBox.Center(), triggerBox.Size() - 2.0f * playerBox.Size()); - if (Collision::AABBVsAABB(completelyInsideBox, playerBox) && - glm::all(glm::greaterThan(triggerBox.Size(), playerBox.Size()))) { + AABB completelyInsideBox = AABB::FromOriginSize((*triggerBox).Origin(), (*triggerBox).Size() - 2.0f * (*playerBox).Size()); + if (Collision::AABBVsAABB(completelyInsideBox, *playerBox) && + glm::all(glm::greaterThan((*triggerBox).Size(), (*playerBox).Size()))) { //Entity is completely inside the trigger. //If it was only touching before, it is erased. m_EntitiesTouchingTrigger[tId].erase(pId); diff --git a/src/Engine/Core/AABB.cpp b/src/Engine/Core/AABB.cpp index 0df56229..22272104 100644 --- a/src/Engine/Core/AABB.cpp +++ b/src/Engine/Core/AABB.cpp @@ -4,7 +4,7 @@ AABB::AABB(const glm::vec3& minPos, const glm::vec3& maxPos) : m_MinCorner(minPos) , m_MaxCorner(maxPos) - , m_Center(0.5f * (maxPos + minPos)) + , m_Origin(0.5f * (maxPos + minPos)) , m_HalfSize(0.5f * (maxPos - minPos)) { DEBUG_IF(glm::any(glm::lessThan(m_MaxCorner, m_MinCorner))) { @@ -20,15 +20,12 @@ AABB::AABB(const glm::vec3& minPos, const glm::vec3& maxPos) AABB::AABB(const glm::vec4& minPos, const glm::vec4& 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; - m_HalfSize = 0.5f * size; - m_MinCorner = m_Center - m_HalfSize; - m_MaxCorner = m_Center + m_HalfSize; + return AABB(origin - (size/2.f), origin + (size/2.f)); } AABB::~AABB() -{} +{ } diff --git a/src/Engine/Core/Octree.cpp b/src/Engine/Core/Octree.cpp index dca30cd7..47d06add 100644 --- a/src/Engine/Core/Octree.cpp +++ b/src/Engine/Core/Octree.cpp @@ -21,14 +21,10 @@ bool isFirstLower(const ChildInfo& first, const ChildInfo& second) } -Octree::Octree() - : Octree(AABB(), 0) -{} - Octree::Octree(const AABB& octTreeBounds, int subDivisions) : m_Root(new Child(octTreeBounds, subDivisions, m_StaticObjects, m_DynamicObjects)) , m_UpdatedOnce(false) -{} +{ } Octree::~Octree() { @@ -107,7 +103,7 @@ Octree::Child::Child(const AABB& octTreeBounds, glm::vec3 minPos, maxPos; const glm::vec3& parentMin = m_Box.MinCorner(); 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); //If child is 4,5,6,7. if (bits.test(2)) { @@ -192,7 +188,7 @@ bool Octree::Child::RayCollides(const Ray& ray, Output& data) const std::vector childInfos; childInfos.reserve(8); 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); //Loop through the children, starting with the one closest to the ray origin. I.e the first to be hit. @@ -329,7 +325,7 @@ void Octree::Child::ClearDynamicObjects() // z : - + - + - + - + int Octree::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); } diff --git a/src/Engine/Editor/EditorSystem.cpp b/src/Engine/Editor/EditorSystem.cpp index b49cf555..6d3dff3d 100644 --- a/src/Engine/Editor/EditorSystem.cpp +++ b/src/Engine/Editor/EditorSystem.cpp @@ -3,7 +3,8 @@ #include EditorSystem::EditorSystem(EventBroker* eventBroker, IRenderer* renderer) - : ImpureSystem(eventBroker) + : System(eventBroker) + , ImpureSystem() , m_Renderer(renderer) { auto config = ResourceManager::Load("Config.ini"); diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index c84c556b..1865dd6c 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -1,4 +1,5 @@ #include "Game.h" +#include "Collision/CollidableOctreeSystem.h" #include "Collision/TriggerSystem.h" #include "Collision/CollisionSystem.h" #include "Game/HealthSystem.h" @@ -56,20 +57,25 @@ Game::Game(int argc, char* argv[]) fp.MergeEntities(m_World); } + // Create Octrees + m_OctreeCollision = new Octree(AABB(glm::vec3(-100), glm::vec3(100)), 4); + m_OctreeFrustrumCulling = new Octree(AABB(glm::vec3(-100), glm::vec3(100)), 4); + // Create system pipeline 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; m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel, m_Renderer); m_SystemPipeline->AddSystem(updateOrderLevel); - - //Collision and TriggerSystem should update after player. + // Populate Octree with collidables ++updateOrderLevel; - m_SystemPipeline->AddSystem(updateOrderLevel); - m_SystemPipeline->AddSystem(updateOrderLevel); + m_SystemPipeline->AddSystem(updateOrderLevel, m_OctreeCollision); + // Collision and TriggerSystem should update after player. + ++updateOrderLevel; + m_SystemPipeline->AddSystem(updateOrderLevel, m_OctreeCollision); + m_SystemPipeline->AddSystem(updateOrderLevel, m_OctreeCollision); // Invoke network if (m_Config->Get("Networking.StartNetwork", false)) { @@ -82,6 +88,8 @@ Game::Game(int argc, char* argv[]) Game::~Game() { delete m_SystemPipeline; + delete m_OctreeFrustrumCulling; + delete m_OctreeCollision; delete m_World; delete m_FrameStack; delete m_InputProxy; diff --git a/src/Game/HealthSystem.cpp b/src/Game/HealthSystem.cpp index 7a1d5005..858355fc 100644 --- a/src/Game/HealthSystem.cpp +++ b/src/Game/HealthSystem.cpp @@ -2,7 +2,8 @@ #include HealthSystem::HealthSystem(EventBroker* eventBroker) - : PureSystem(eventBroker, "Health") + : System(eventBroker) + , PureSystem("Health") { //subscribe/listenTo playerdamage,healthpickup events (using the eventBroker) EVENT_SUBSCRIBE_MEMBER(m_EPlayerDamage, &HealthSystem::OnPlayerDamaged); diff --git a/src/Tests/OctTreeTest.cpp b/src/Tests/OctTreeTest.cpp index f437bde0..3a130354 100644 --- a/src/Tests/OctTreeTest.cpp +++ b/src/Tests/OctTreeTest.cpp @@ -21,9 +21,9 @@ BOOST_AUTO_TEST_CASE(octSameRegionTest) tree.BoxesInSameRegion(testBox, region); BOOST_REQUIRE(region.size() == 1); AABB& box = region[0]; - BOOST_CHECK_CLOSE_FRACTION(box.Center().x, firstQuadrant.Center().x, 0.00001f); - BOOST_CHECK_CLOSE_FRACTION(box.Center().y, firstQuadrant.Center().y, 0.00001f); - BOOST_CHECK_CLOSE_FRACTION(box.Center().z, firstQuadrant.Center().z, 0.00001f); + BOOST_CHECK_CLOSE_FRACTION(box.Origin().x, firstQuadrant.Origin().x, 0.00001f); + BOOST_CHECK_CLOSE_FRACTION(box.Origin().y, firstQuadrant.Origin().y, 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().y, firstQuadrant.HalfSize().y, 0.00001f); BOOST_CHECK_CLOSE_FRACTION(box.HalfSize().z, firstQuadrant.HalfSize().z, 0.00001f); diff --git a/src/Tests/OctTreeTestGameClass.cpp b/src/Tests/OctTreeTestGameClass.cpp index 10d4d6a5..2c45d897 100644 --- a/src/Tests/OctTreeTestGameClass.cpp +++ b/src/Tests/OctTreeTestGameClass.cpp @@ -91,7 +91,7 @@ void Game::Tick() frameCounter = 0; } 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 //contentboxarna får man ut - inte childboxarna! @@ -110,7 +110,7 @@ void Game::Tick() //REQUIRED: childIndicesContainingBox must be public to test this! 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 && abs(pos.y - oneLinkedObject.posxyz.y) < 0.005f && abs(pos.z - oneLinkedObject.posxyz.z) < 0.005f) { diff --git a/src/Tests/OctTreeTestHardCodedTestWorld.h b/src/Tests/OctTreeTestHardCodedTestWorld.h index 7fcae0b2..db0b3b3c 100644 --- a/src/Tests/OctTreeTestHardCodedTestWorld.h +++ b/src/Tests/OctTreeTestHardCodedTestWorld.h @@ -77,7 +77,7 @@ private: auto someAABB = AABB(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(1.0f, 1.0f, 1.0f)); //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 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); //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 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); auto someChild = someOctTree.m_Root->m_Children[j]; 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); } } diff --git a/src/Tests/OldOctTree.cpp b/src/Tests/OldOctTree.cpp index d3738ee6..0fb92e18 100644 --- a/src/Tests/OldOctTree.cpp +++ b/src/Tests/OldOctTree.cpp @@ -54,7 +54,7 @@ OctTree::OctTree(const AABB& octTreeBounds, int subDivisions) glm::vec3 minPos, maxPos; const glm::vec3& parentMin = m_Box.MinCorner(); 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); //If child is 4,5,6,7. if (bits.test(2)) { @@ -172,7 +172,7 @@ bool OctTree::RayCollides(const Ray& ray, Output& data) const std::vector childInfos; childInfos.reserve(8); 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); //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 : - + - + - + - + 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); } From 71d936f8d1fc86f0e43b4ec8272e60be95724612 Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Wed, 13 Jan 2016 17:53:54 +0100 Subject: [PATCH 05/23] Start of a movement system with collisions against AABBs --- .../Engine/Collision/CollidableOctreeSystem.h | 7 +++- include/Engine/Collision/Collision.h | 6 +++ include/Engine/Core/EComponentAttached.h | 20 ++++++++++ include/Engine/Core/Entity.h | 18 +++++++++ include/Game/PlayerMovementSystem.h | 12 ++++++ resources/Schema/Entities/CollisionTest1.xml | 38 ++++++++++++++++++ resources/Schema/Entities/OctreeTest.xml | 26 +++++------- src/Engine/Collision/Collision.cpp | 40 +++++++++++++++++++ src/Engine/Collision/CollisionSystem.cpp | 23 +++++++++++ src/Game/PlayerMovementSystem.cpp | 7 ++++ 10 files changed, 179 insertions(+), 18 deletions(-) create mode 100644 include/Engine/Core/EComponentAttached.h create mode 100644 include/Game/PlayerMovementSystem.h create mode 100644 resources/Schema/Entities/CollisionTest1.xml create mode 100644 src/Game/PlayerMovementSystem.cpp diff --git a/include/Engine/Collision/CollidableOctreeSystem.h b/include/Engine/Collision/CollidableOctreeSystem.h index b7a77346..760503e9 100644 --- a/include/Engine/Collision/CollidableOctreeSystem.h +++ b/include/Engine/Collision/CollidableOctreeSystem.h @@ -1,3 +1,6 @@ +#ifndef CollidableOctreeSystem_h__ +#define CollidableOctreeSystem_h__ + #include "../Core/System.h" #include "../Core/Octree.h" #include "Collision.h" @@ -16,4 +19,6 @@ public: private: Octree* m_Octree; -}; \ No newline at end of file +}; + +#endif \ No newline at end of file diff --git a/include/Engine/Collision/Collision.h b/include/Engine/Collision/Collision.h index 18520243..2854d07b 100644 --- a/include/Engine/Collision/Collision.h +++ b/include/Engine/Collision/Collision.h @@ -45,6 +45,12 @@ bool RayVsModel(const Ray& ray, float& outUCoord, float& outVCoord); +bool AABBvsTriangles(const AABB& box, + const std::vector& modelVertices, + const std::vector& modelIndices, + const glm::mat4& modelMatrix, + glm::vec3& outResolutionVector); + //Return true if the boxes are intersecting. bool AABBVsAABB(const AABB& a, const AABB& b); //Return true if the boxes are intersecting. diff --git a/include/Engine/Core/EComponentAttached.h b/include/Engine/Core/EComponentAttached.h new file mode 100644 index 00000000..b4ab9f78 --- /dev/null +++ b/include/Engine/Core/EComponentAttached.h @@ -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 \ No newline at end of file diff --git a/include/Engine/Core/Entity.h b/include/Engine/Core/Entity.h index 1f40b9b7..c6730924 100644 --- a/include/Engine/Core/Entity.h +++ b/include/Engine/Core/Entity.h @@ -4,4 +4,22 @@ typedef unsigned int EntityID; const static unsigned int EntityID_Invalid = -1; +class World; +struct EntityWrapper +{ + EntityWrapper(::World* world, EntityID id) + : World(world) + , ID(id) + { } + + ::World* World; + EntityID ID; + + bool operator==(const EntityWrapper& e) + { + return (this->World == e.World) && (this->ID == e.ID); + } + operator EntityID() { return this->ID; } +}; + #endif \ No newline at end of file diff --git a/include/Game/PlayerMovementSystem.h b/include/Game/PlayerMovementSystem.h new file mode 100644 index 00000000..aa40b5f6 --- /dev/null +++ b/include/Game/PlayerMovementSystem.h @@ -0,0 +1,12 @@ +#include "Common.h" +#include "Core/System.h" + +class PlayerMovementSystem : public PureSystem +{ +public: + PlayerMovementSystem(EventBroker* eventBroker) + : PureSystem(eventBroker, "Player") + { } + + virtual void UpdateComponent(World* world, ComponentWrapper& player, double dt); +}; \ No newline at end of file diff --git a/resources/Schema/Entities/CollisionTest1.xml b/resources/Schema/Entities/CollisionTest1.xml new file mode 100644 index 00000000..f0b310e1 --- /dev/null +++ b/resources/Schema/Entities/CollisionTest1.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + false + + + + + + + + + + + false + + + Models/Core/UnitCube.obj + + + + + + + + + + + diff --git a/resources/Schema/Entities/OctreeTest.xml b/resources/Schema/Entities/OctreeTest.xml index 819159d0..4d7fe709 100644 --- a/resources/Schema/Entities/OctreeTest.xml +++ b/resources/Schema/Entities/OctreeTest.xml @@ -15,7 +15,7 @@ - + @@ -23,38 +23,30 @@ - + + false + Models/Core/UnitCube.obj - + - - + + false + Models/Core/UnitCube.obj - - - - - - - - - Models/Core/UnitCube.obj - - - + diff --git a/src/Engine/Collision/Collision.cpp b/src/Engine/Collision/Collision.cpp index 1af09382..a1f24f59 100644 --- a/src/Engine/Collision/Collision.cpp +++ b/src/Engine/Collision/Collision.cpp @@ -199,6 +199,46 @@ bool RayVsModel(const Ray& ray, return hit; } +bool AABBvsTriangles(const AABB& box, const std::vector& modelVertices, const std::vector& 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) { const glm::vec3& ma1 = first.MaxCorner(); diff --git a/src/Engine/Collision/CollisionSystem.cpp b/src/Engine/Collision/CollisionSystem.cpp index 4ce514da..ec2f14a7 100644 --- a/src/Engine/Collision/CollisionSystem.cpp +++ b/src/Engine/Collision/CollisionSystem.cpp @@ -17,6 +17,7 @@ void CollisionSystem::UpdateComponent(World* world, ComponentWrapper& cAABB, dou return; } + // Collide against octree std::vector octreeResult; m_Octree->BoxesInSameRegion(*boundingBox, octreeResult); for (auto& boxB : octreeResult) { @@ -28,6 +29,28 @@ void CollisionSystem::UpdateComponent(World* world, ComponentWrapper& cAABB, dou (glm::vec3&)cTransform["Position"] += resolutionVector; } } + + // 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(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) diff --git a/src/Game/PlayerMovementSystem.cpp b/src/Game/PlayerMovementSystem.cpp new file mode 100644 index 00000000..f9ffac44 --- /dev/null +++ b/src/Game/PlayerMovementSystem.cpp @@ -0,0 +1,7 @@ +#include "RaptorCopterSystem.h" + +void PlayerMovementSystem::UpdateComponent(World* world, ComponentWrapper& player, double dt) +{ + +} + From 28392def793e12597cfcf7387fd0d44e203bbefe Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Thu, 14 Jan 2016 15:42:55 +0100 Subject: [PATCH 06/23] Made string passing in World a little more effective --- include/Engine/Core/World.h | 10 +++++----- src/Engine/Core/World.cpp | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/Engine/Core/World.h b/include/Engine/Core/World.h index 0a121728..3c666ceb 100644 --- a/include/Engine/Core/World.h +++ b/include/Engine/Core/World.h @@ -21,15 +21,15 @@ public: // Register a component type and allocate space for it void RegisterComponent(ComponentInfo& ci); // Attach a component to an entity and fill it with default values - ComponentWrapper AttachComponent(EntityID entity, std::string componentType); + ComponentWrapper AttachComponent(EntityID entity, const std::string& componentType); // Check if an entity has a component - bool HasComponent(EntityID entity, std::string componentType) const; + bool HasComponent(EntityID entity, const std::string& componentType) const; // Get a component of an entity - ComponentWrapper GetComponent(EntityID entity, std::string componentType); + ComponentWrapper GetComponent(EntityID entity, const std::string& componentType); // Delete a component off an entity - void DeleteComponent(EntityID entity, std::string componentType); + void DeleteComponent(EntityID entity, const std::string& componentType); // Get all components of the specified type - const ComponentPool* GetComponents(std::string componentType); + const ComponentPool* GetComponents(const std::string& componentType); // Get entity parent EntityID GetParent(EntityID entity); // Change the parent of an entity diff --git a/src/Engine/Core/World.cpp b/src/Engine/Core/World.cpp index c94cb8b3..811de45f 100644 --- a/src/Engine/Core/World.cpp +++ b/src/Engine/Core/World.cpp @@ -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 ComponentPool* pool = m_ComponentPools.at(componentType); @@ -80,26 +80,26 @@ ComponentWrapper World::AttachComponent(EntityID entity, std::string componentTy 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); 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); 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); ComponentWrapper c = pool->GetByEntity(entity); 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); return (it != m_ComponentPools.end()) ? it->second : nullptr; From d34470256b24273230bc32c9be63c567c197fe41 Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Thu, 14 Jan 2016 15:43:19 +0100 Subject: [PATCH 07/23] EntityWrapper to uniquely identify entities and make using them a little easier --- .../Engine/Collision/CollidableOctreeSystem.h | 2 +- include/Engine/Collision/Collision.h | 3 +- include/Engine/Collision/CollisionSystem.h | 2 +- include/Engine/Collision/TriggerSystem.h | 2 +- include/Engine/Core/Entity.h | 17 ----------- include/Engine/Core/EntityWrapper.h | 25 +++++++++++++++++ include/Engine/Core/System.h | 3 +- include/Engine/Core/SystemPipeline.h | 2 +- include/Game/HealthSystem.h | 2 +- include/Game/PlayerMovementSystem.h | 2 +- include/Game/PlayerSystem.h | 2 +- include/Game/RaptorCopterSystem.h | 6 ++-- .../Collision/CollidableOctreeSystem.cpp | 10 +++---- src/Engine/Collision/Collision.cpp | 10 +++---- src/Engine/Collision/CollisionSystem.cpp | 7 ++--- src/Engine/Collision/TriggerSystem.cpp | 8 +++--- src/Engine/Core/EntityWrapper.cpp | 28 +++++++++++++++++++ src/Game/HealthSystem.cpp | 14 +++++----- src/Game/PlayerMovementSystem.cpp | 7 ++--- src/Game/PlayerSystem.cpp | 26 ++++++++--------- 20 files changed, 106 insertions(+), 72 deletions(-) create mode 100644 include/Engine/Core/EntityWrapper.h create mode 100644 src/Engine/Core/EntityWrapper.cpp diff --git a/include/Engine/Collision/CollidableOctreeSystem.h b/include/Engine/Collision/CollidableOctreeSystem.h index 760503e9..8fa1f0a4 100644 --- a/include/Engine/Collision/CollidableOctreeSystem.h +++ b/include/Engine/Collision/CollidableOctreeSystem.h @@ -15,7 +15,7 @@ public: { } virtual void Update(World* world, double dt) override; - virtual void UpdateComponent(World* world, ComponentWrapper& component, double dt) override; + virtual void UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) override; private: Octree* m_Octree; diff --git a/include/Engine/Collision/Collision.h b/include/Engine/Collision/Collision.h index 2854d07b..4ea45a55 100644 --- a/include/Engine/Collision/Collision.h +++ b/include/Engine/Collision/Collision.h @@ -13,6 +13,7 @@ #include "../Rendering/RawModel.h" #include "../Rendering/RenderQueueFactory.h" #include "../Core/Entity.h" +#include "../Core/EntityWrapper.h" class World; struct ComponentWrapper; @@ -59,7 +60,7 @@ bool AABBVsAABB(const AABB& a, const AABB& b, glm::vec3& minimumTranslation); bool IsSameBoxProbably(const AABB& first, const AABB& second, const float epsilon = 0.0001f); // Calculates an absolute AABB from an entity AABB component -boost::optional EntityAbsoluteAABB(World* world, EntityID entity); +boost::optional EntityAbsoluteAABB(EntityWrapper& entity); } diff --git a/include/Engine/Collision/CollisionSystem.h b/include/Engine/Collision/CollisionSystem.h index b4e25072..ea6004d9 100644 --- a/include/Engine/Collision/CollisionSystem.h +++ b/include/Engine/Collision/CollisionSystem.h @@ -23,7 +23,7 @@ public: 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: Octree* m_Octree; diff --git a/include/Engine/Collision/TriggerSystem.h b/include/Engine/Collision/TriggerSystem.h index 7856a09d..ee53ad9b 100644 --- a/include/Engine/Collision/TriggerSystem.h +++ b/include/Engine/Collision/TriggerSystem.h @@ -20,7 +20,7 @@ public: , m_Octree(octree) { } - virtual void UpdateComponent(World* world, ComponentWrapper& collision, double dt) override; + virtual void UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) override; private: Octree* m_Octree; diff --git a/include/Engine/Core/Entity.h b/include/Engine/Core/Entity.h index c6730924..653ba650 100644 --- a/include/Engine/Core/Entity.h +++ b/include/Engine/Core/Entity.h @@ -4,22 +4,5 @@ typedef unsigned int EntityID; const static unsigned int EntityID_Invalid = -1; -class World; -struct EntityWrapper -{ - EntityWrapper(::World* world, EntityID id) - : World(world) - , ID(id) - { } - - ::World* World; - EntityID ID; - - bool operator==(const EntityWrapper& e) - { - return (this->World == e.World) && (this->ID == e.ID); - } - operator EntityID() { return this->ID; } -}; #endif \ No newline at end of file diff --git a/include/Engine/Core/EntityWrapper.h b/include/Engine/Core/EntityWrapper.h new file mode 100644 index 00000000..541dfe0d --- /dev/null +++ b/include/Engine/Core/EntityWrapper.h @@ -0,0 +1,25 @@ +#ifndef EntityWrapper_h__ +#define EntityWrapper_h__ + +#include +#include "ComponentWrapper.h" + +class World; +struct EntityWrapper +{ + EntityWrapper(::World* world, EntityID id) + : World(world) + , ID(id) + { } + + ::World* World; + EntityID ID; + + bool HasComponent(const std::string& componentName); + + ComponentWrapper operator[](const std::string& componentName); + bool operator==(const EntityWrapper& e); + explicit operator EntityID(); +}; + +#endif diff --git a/include/Engine/Core/System.h b/include/Engine/Core/System.h index cd8e9fc7..b7de9dc2 100644 --- a/include/Engine/Core/System.h +++ b/include/Engine/Core/System.h @@ -3,6 +3,7 @@ #include "EventBroker.h" #include "World.h" +#include "EntityWrapper.h" #include "ComponentWrapper.h" class System @@ -33,7 +34,7 @@ protected: 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 virtual System diff --git a/include/Engine/Core/SystemPipeline.h b/include/Engine/Core/SystemPipeline.h index 79d4ace4..c0cd8ed6 100644 --- a/include/Engine/Core/SystemPipeline.h +++ b/include/Engine/Core/SystemPipeline.h @@ -68,7 +68,7 @@ public: } for (auto& component : *pool) { for (auto& system : systems) { - system->UpdateComponent(world, component, dt); + system->UpdateComponent(world, EntityWrapper(world, component.EntityID), component, dt); } } } diff --git a/include/Game/HealthSystem.h b/include/Game/HealthSystem.h index a836e797..234244c2 100644 --- a/include/Game/HealthSystem.h +++ b/include/Game/HealthSystem.h @@ -19,7 +19,7 @@ public: HealthSystem(EventBroker* eventBroker); //updatecomponent - virtual void UpdateComponent(World* world, ComponentWrapper& health, double dt) override; + virtual void UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) override; private: //methods which will take care of specific events diff --git a/include/Game/PlayerMovementSystem.h b/include/Game/PlayerMovementSystem.h index aa40b5f6..35f8a22c 100644 --- a/include/Game/PlayerMovementSystem.h +++ b/include/Game/PlayerMovementSystem.h @@ -8,5 +8,5 @@ public: : PureSystem(eventBroker, "Player") { } - virtual void UpdateComponent(World* world, ComponentWrapper& player, double dt); + virtual void UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt); }; \ No newline at end of file diff --git a/include/Game/PlayerSystem.h b/include/Game/PlayerSystem.h index 50492617..a74cbb9f 100644 --- a/include/Game/PlayerSystem.h +++ b/include/Game/PlayerSystem.h @@ -20,7 +20,7 @@ public: EVENT_SUBSCRIBE_MEMBER(m_ELeave, &PlayerSystem::OnLeave); } - virtual void UpdateComponent(World* world, ComponentWrapper& player, double dt) override; + virtual void UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) override; private: float m_Speed = 5; EventRelay m_EEnter; diff --git a/include/Game/RaptorCopterSystem.h b/include/Game/RaptorCopterSystem.h index 14b49f4d..57a8de86 100644 --- a/include/Game/RaptorCopterSystem.h +++ b/include/Game/RaptorCopterSystem.h @@ -9,9 +9,9 @@ public: , PureSystem("RaptorCopter") { } - virtual void UpdateComponent(World* world, ComponentWrapper& raptorCopter, double dt) override + virtual void UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) override { - ComponentWrapper& transform = world->GetComponent(raptorCopter.EntityID, "Transform"); - (glm::vec3&)transform["Orientation"] += (float)(double)raptorCopter["Speed"] * (float)dt * (glm::vec3)raptorCopter["Axis"]; + ComponentWrapper& transform = world->GetComponent(component.EntityID, "Transform"); + (glm::vec3&)transform["Orientation"] += (float)(double)component["Speed"] * (float)dt * (glm::vec3)component["Axis"]; } }; \ No newline at end of file diff --git a/src/Engine/Collision/CollidableOctreeSystem.cpp b/src/Engine/Collision/CollidableOctreeSystem.cpp index c7fed0a0..62d742f5 100644 --- a/src/Engine/Collision/CollidableOctreeSystem.cpp +++ b/src/Engine/Collision/CollidableOctreeSystem.cpp @@ -5,16 +5,14 @@ void CollidableOctreeSystem::Update(World* world, double dt) m_Octree->ClearDynamicObjects(); } -void CollidableOctreeSystem::UpdateComponent(World* world, ComponentWrapper& cCollidable, double dt) +void CollidableOctreeSystem::UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) { - EntityID entity = cCollidable.EntityID; - - if (world->HasComponent(entity, "AABB")) { - boost::optional absoluteAABB = Collision::EntityAbsoluteAABB(world, entity); + if (entity.HasComponent("AABB")) { + boost::optional absoluteAABB = Collision::EntityAbsoluteAABB(entity); if (absoluteAABB) { m_Octree->AddDynamicObject(*absoluteAABB); } - } else if (world->HasComponent(entity, "Model")) { + } else if (entity.HasComponent("Model")) { // TODO: Derive AABB from model } } \ No newline at end of file diff --git a/src/Engine/Collision/Collision.cpp b/src/Engine/Collision/Collision.cpp index a1f24f59..92048e70 100644 --- a/src/Engine/Collision/Collision.cpp +++ b/src/Engine/Collision/Collision.cpp @@ -283,15 +283,15 @@ bool attachAABBComponentFromModel(World* world, EntityID id) return true; } -boost::optional EntityAbsoluteAABB(World* world, EntityID entity) +boost::optional EntityAbsoluteAABB(EntityWrapper& entity) { - if (!world->HasComponent(entity, "AABB")) { + if (!entity.HasComponent("AABB")) { return boost::none; } - ComponentWrapper& cAABB = world->GetComponent(entity, "AABB"); - glm::vec3 absPosition = RenderQueueFactory::AbsolutePosition(world, entity); - glm::vec3 absScale = RenderQueueFactory::AbsoluteScale(world, entity); + ComponentWrapper& cAABB = entity["AABB"]; + glm::vec3 absPosition = RenderQueueFactory::AbsolutePosition(entity.World, entity.ID); + glm::vec3 absScale = RenderQueueFactory::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); diff --git a/src/Engine/Collision/CollisionSystem.cpp b/src/Engine/Collision/CollisionSystem.cpp index ec2f14a7..92b7f7db 100644 --- a/src/Engine/Collision/CollisionSystem.cpp +++ b/src/Engine/Collision/CollisionSystem.cpp @@ -2,14 +2,13 @@ #include "Collision/CollisionSystem.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) { - EntityID entity = cAABB.EntityID; - boost::optional boundingBox = Collision::EntityAbsoluteAABB(world, entity); + boost::optional boundingBox = Collision::EntityAbsoluteAABB(entity); if (!boundingBox) { return; } - ComponentWrapper& cTransform = world->GetComponent(entity, "Transform"); + ComponentWrapper& cTransform = entity["Transform"]; AABB& boxA = *boundingBox; //Press 'Z' to enable/disable collision. diff --git a/src/Engine/Collision/TriggerSystem.cpp b/src/Engine/Collision/TriggerSystem.cpp index 2c8c7540..58d1e332 100644 --- a/src/Engine/Collision/TriggerSystem.cpp +++ b/src/Engine/Collision/TriggerSystem.cpp @@ -3,22 +3,22 @@ #include "Core/AABB.h" #include "Rendering/Model.h" -void TriggerSystem::UpdateComponent(World* world, ComponentWrapper& cTrigger, double dt) +void TriggerSystem::UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) { //Currently only players can trigger things. auto players = world->GetComponents("Player"); if (players == nullptr) { return; } - EntityID tId = cTrigger.EntityID; - boost::optional triggerBox = Collision::EntityAbsoluteAABB(world, tId); + EntityID tId = component.EntityID; + boost::optional triggerBox = Collision::EntityAbsoluteAABB(entity); //The trigger *should* have a bounding box, or something, to test against so it can be triggered. if (!triggerBox) { return; } for (auto& pc : *players) { EntityID pId = pc.EntityID; - boost::optional playerBox = Collision::EntityAbsoluteAABB(world, pId); + boost::optional playerBox = Collision::EntityAbsoluteAABB(EntityWrapper(world, pId)); //The player can't trigger anything without an AABB. if (!playerBox) { continue; diff --git a/src/Engine/Core/EntityWrapper.cpp b/src/Engine/Core/EntityWrapper.cpp new file mode 100644 index 00000000..9d15dd39 --- /dev/null +++ b/src/Engine/Core/EntityWrapper.cpp @@ -0,0 +1,28 @@ +#include "Core/EntityWrapper.h" +#include "Core/World.h" + +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; +} + diff --git a/src/Game/HealthSystem.cpp b/src/Game/HealthSystem.cpp index 858355fc..7986db9d 100644 --- a/src/Game/HealthSystem.cpp +++ b/src/Game/HealthSystem.cpp @@ -10,24 +10,24 @@ HealthSystem::HealthSystem(EventBroker* eventBroker) 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) - ComponentWrapper player = world->GetComponent(health.EntityID, "Player"); - double maxHealth = (double)health["MaxHealth"]; + ComponentWrapper player = world->GetComponent(component.EntityID, "Player"); + double maxHealth = (double)component["MaxHealth"]; //process the DeltaHealthVector and change the entitys health accordingly for (size_t i = m_DeltaHealthVector.size(); i > 0; i--) { 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 (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 - double newHealth = std::min((double)health["Health"] + (double)std::get<1>(deltaHP), maxHealth); - health["Health"] = newHealth; + double newHealth = std::min((double)component["Health"] + (double)std::get<1>(deltaHP), maxHealth); + component["Health"] = newHealth; m_DeltaHealthVector.erase(m_DeltaHealthVector.begin() + i - 1); //check if health is <= 0 - if ((double)health["Health"] <= 0.0f) { + if ((double)component["Health"] <= 0.0f) { //publish death event Events::PlayerDeath e; e.PlayerID = player.EntityID; diff --git a/src/Game/PlayerMovementSystem.cpp b/src/Game/PlayerMovementSystem.cpp index f9ffac44..c0946134 100644 --- a/src/Game/PlayerMovementSystem.cpp +++ b/src/Game/PlayerMovementSystem.cpp @@ -1,7 +1,6 @@ #include "RaptorCopterSystem.h" -void PlayerMovementSystem::UpdateComponent(World* world, ComponentWrapper& player, double dt) +void PlayerMovementSystem::UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) { - -} - + ComponentWrapper& transform = world->GetComponent(component.EntityID); +} \ No newline at end of file diff --git a/src/Game/PlayerSystem.cpp b/src/Game/PlayerSystem.cpp index 17b9a7f5..2d4d83c6 100644 --- a/src/Game/PlayerSystem.cpp +++ b/src/Game/PlayerSystem.cpp @@ -1,25 +1,25 @@ #include "PlayerSystem.h" -void PlayerSystem::UpdateComponent(World * world, ComponentWrapper & player, double dt) +void PlayerSystem::UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, 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; + component["Velocity"] = glm::vec3(0.f, 0.f, 0.f); + if ((bool&)component["Forward"] == true) { + ((glm::vec3&)component["Velocity"]).z = m_Speed * float(dt) * -1; } - if ((bool&)player["Left"] == true) { - ((glm::vec3&)player["Velocity"]).x = m_Speed * float(dt) * -1; + if ((bool&)component["Left"] == true) { + ((glm::vec3&)component["Velocity"]).x = m_Speed * float(dt) * -1; } - if ((bool&)player["Back"] == true) { - ((glm::vec3&)player["Velocity"]).z = m_Speed * float(dt); + if ((bool&)component["Back"] == true) { + ((glm::vec3&)component["Velocity"]).z = m_Speed * float(dt); } - if ((bool&)player["Right"] == true) { - ((glm::vec3&)player["Velocity"]).x = m_Speed * float(dt); + if ((bool&)component["Right"] == true) { + ((glm::vec3&)component["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"]; + if ((glm::vec3)component["Velocity"] != glm::vec3(0.f)) { + ComponentWrapper& transform = world->GetComponent(component.EntityID, "Transform"); + (glm::vec3&)transform["Position"] += (glm::vec3)component["Velocity"]; } } From 99406c32cf990aadb864944adf5706a245591130 Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Thu, 14 Jan 2016 17:01:39 +0100 Subject: [PATCH 08/23] Better error handling for EntityFilePreprocessor --- src/Engine/Core/EntityFilePreprocessor.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/Engine/Core/EntityFilePreprocessor.cpp b/src/Engine/Core/EntityFilePreprocessor.cpp index ca445042..4b720976 100644 --- a/src/Engine/Core/EntityFilePreprocessor.cpp +++ b/src/Engine/Core/EntityFilePreprocessor.cpp @@ -103,21 +103,25 @@ void EntityFilePreprocessor::parseComponentInfo() } } } else { - LOG_WARNING("Component is missing an annotation!"); + LOG_WARNING("Component \"%s\" is missing an annotation!", compInfo.Name.c_str()); } // auto typeDefinition = element->getTypeDefinition(); + // Allow empty components + if (typeDefinition == nullptr) { + continue; + } 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; } auto complexTypeDefinition = dynamic_cast(typeDefinition); // auto modelGroupParticle = complexTypeDefinition->getParticle(); - if (modelGroupParticle->getTermType() != XSParticle::TERM_MODELGROUP) { - LOG_ERROR("Model group particle wasn't TERM_MODELGROUP! Skipping."); + if (modelGroupParticle == nullptr || modelGroupParticle->getTermType() != XSParticle::TERM_MODELGROUP) { + LOG_ERROR("Failed to parse component definition for \"%s\": Model group particle was null or wasn't TERM_MODELGROUP!", compInfo.Name.c_str()); continue; } auto modelGroup = modelGroupParticle->getModelGroupTerm(); @@ -129,7 +133,7 @@ void EntityFilePreprocessor::parseComponentInfo() for (unsigned int i = 0; i < particles->size(); ++i) { auto particle = particles->elementAt(i); 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; } auto elementDeclaration = particle->getElementTerm(); @@ -139,7 +143,7 @@ void EntityFilePreprocessor::parseComponentInfo() size_t stride = EntityFile::GetTypeStride(type); if (stride == 0) { - std::cout << "Warning: Field \"" << name << "\" in component \"" << compInfo.Name << "\" uses unexpected field type \"" << type << "\". Skipping." << std::endl; + LOG_WARNING("Field \"%s\" in component \"%s\" uses unexpected field type \"%s\". Skipping.", name.c_str(), compInfo.Name.c_str(), type.c_str()); continue; } From 986af010918548b3ec8dd5c5110ea28a8ffa6d8f Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Thu, 14 Jan 2016 17:02:13 +0100 Subject: [PATCH 09/23] Fixed editor component fields with the same name across components being treated as the same value --- src/Engine/Editor/EditorSystem.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Engine/Editor/EditorSystem.cpp b/src/Engine/Editor/EditorSystem.cpp index 6d3dff3d..b5e527f0 100644 --- a/src/Engine/Editor/EditorSystem.cpp +++ b/src/Engine/Editor/EditorSystem.cpp @@ -492,7 +492,8 @@ void EditorSystem::drawUI(World* world, double dt) const std::string& fieldName = kv.first; auto& field = kv.second; - ImGui::PushID(fieldName.c_str()); + std::string uniqueID = componentType + fieldName; + ImGui::PushID(uniqueID.c_str()); if (field.Type == "Vector") { auto& val = component.Property(fieldName); if (fieldName == "Scale") { From 6ad1839def3f0fbc40250e445714294fd0e8b1bd Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Thu, 14 Jan 2016 17:03:42 +0100 Subject: [PATCH 10/23] Initial work on PlayerMovementSystem --- assets | 2 +- include/Game/Game.h | 2 - include/Game/{ => Systems}/HealthSystem.h | 6 +- .../Game/{ => Systems}/PlayerMovementSystem.h | 4 +- include/Game/{ => Systems}/PlayerSystem.h | 0 .../Game/{ => Systems}/RaptorCopterSystem.h | 0 resources/Schema/Components.xsd | 1 + resources/Schema/Components/Collidable.xml | 1 - resources/Schema/Components/Collidable.xsd | 5 -- resources/Schema/Components/Physics.xml | 3 + resources/Schema/Components/Physics.xsd | 16 +++++ resources/Schema/Components/Transform.xsd | 2 +- resources/Schema/Entities/MovementTest.xml | 64 +++++++++++++++++++ resources/Schema/Entities/Player.xml | 17 +++++ resources/Schema/Types/Entity.xsd | 1 + src/Engine/Collision/CollisionSystem.cpp | 10 ++- src/Game/CMakeLists.txt | 9 ++- src/Game/Game.cpp | 6 +- src/Game/PlayerMovementSystem.cpp | 6 -- src/Game/{ => Systems}/HealthSystem.cpp | 3 +- src/Game/Systems/PlayerMovementSystem.cpp | 16 +++++ src/Game/{ => Systems}/PlayerSystem.cpp | 2 +- 22 files changed, 146 insertions(+), 30 deletions(-) rename include/Game/{ => Systems}/HealthSystem.h (89%) rename include/Game/{ => Systems}/PlayerMovementSystem.h (77%) rename include/Game/{ => Systems}/PlayerSystem.h (100%) rename include/Game/{ => Systems}/RaptorCopterSystem.h (100%) create mode 100644 resources/Schema/Components/Physics.xml create mode 100644 resources/Schema/Components/Physics.xsd create mode 100644 resources/Schema/Entities/MovementTest.xml create mode 100644 resources/Schema/Entities/Player.xml delete mode 100644 src/Game/PlayerMovementSystem.cpp rename src/Game/{ => Systems}/HealthSystem.cpp (98%) create mode 100644 src/Game/Systems/PlayerMovementSystem.cpp rename src/Game/{ => Systems}/PlayerSystem.cpp (97%) diff --git a/assets b/assets index c8e631f4..a0d1615e 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit c8e631f449515cdbe3647b96ce472839748e28f9 +Subproject commit a0d1615e515a4d7db0073cc987d1d593ca942471 diff --git a/include/Game/Game.h b/include/Game/Game.h index de45c558..728070f3 100644 --- a/include/Game/Game.h +++ b/include/Game/Game.h @@ -15,8 +15,6 @@ #include "Core/EKeyDown.h" #include "Core/EntityFilePreprocessor.h" #include "Core/SystemPipeline.h" -#include "RaptorCopterSystem.h" -#include "PlayerSystem.h" #include "Editor/EditorSystem.h" #include "Core/EntityFile.h" #include "Core/EntityFileParser.h" diff --git a/include/Game/HealthSystem.h b/include/Game/Systems/HealthSystem.h similarity index 89% rename from include/Game/HealthSystem.h rename to include/Game/Systems/HealthSystem.h index 234244c2..0db3ec41 100644 --- a/include/Game/HealthSystem.h +++ b/include/Game/Systems/HealthSystem.h @@ -6,9 +6,9 @@ #include "Common.h" #include "Core/System.h" -#include "Core\EPlayerDamage.h"; -#include "Core\EPlayerHealthPickup.h"; -#include "Core\EPlayerDeath.h"; +#include "Core/EPlayerDamage.h" +#include "Core/EPlayerHealthPickup.h" +#include "Core/EPlayerDeath.h" #include #include diff --git a/include/Game/PlayerMovementSystem.h b/include/Game/Systems/PlayerMovementSystem.h similarity index 77% rename from include/Game/PlayerMovementSystem.h rename to include/Game/Systems/PlayerMovementSystem.h index 35f8a22c..6dc2dc31 100644 --- a/include/Game/PlayerMovementSystem.h +++ b/include/Game/Systems/PlayerMovementSystem.h @@ -1,11 +1,13 @@ #include "Common.h" +#include "GLM.h" #include "Core/System.h" class PlayerMovementSystem : public PureSystem { public: PlayerMovementSystem(EventBroker* eventBroker) - : PureSystem(eventBroker, "Player") + : System(eventBroker) + , PureSystem("Player") { } virtual void UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt); diff --git a/include/Game/PlayerSystem.h b/include/Game/Systems/PlayerSystem.h similarity index 100% rename from include/Game/PlayerSystem.h rename to include/Game/Systems/PlayerSystem.h diff --git a/include/Game/RaptorCopterSystem.h b/include/Game/Systems/RaptorCopterSystem.h similarity index 100% rename from include/Game/RaptorCopterSystem.h rename to include/Game/Systems/RaptorCopterSystem.h diff --git a/resources/Schema/Components.xsd b/resources/Schema/Components.xsd index 4f32b477..e1440b69 100644 --- a/resources/Schema/Components.xsd +++ b/resources/Schema/Components.xsd @@ -2,6 +2,7 @@ + diff --git a/resources/Schema/Components/Collidable.xml b/resources/Schema/Components/Collidable.xml index 0d1bb9b3..4f9c9033 100644 --- a/resources/Schema/Components/Collidable.xml +++ b/resources/Schema/Components/Collidable.xml @@ -1,3 +1,2 @@ - true \ No newline at end of file diff --git a/resources/Schema/Components/Collidable.xsd b/resources/Schema/Components/Collidable.xsd index f835d9a6..84c66f11 100644 --- a/resources/Schema/Components/Collidable.xsd +++ b/resources/Schema/Components/Collidable.xsd @@ -4,10 +4,5 @@ - - - - - \ No newline at end of file diff --git a/resources/Schema/Components/Physics.xml b/resources/Schema/Components/Physics.xml new file mode 100644 index 00000000..1ad81de0 --- /dev/null +++ b/resources/Schema/Components/Physics.xml @@ -0,0 +1,3 @@ + + + diff --git a/resources/Schema/Components/Physics.xsd b/resources/Schema/Components/Physics.xsd new file mode 100644 index 00000000..001dd2c8 --- /dev/null +++ b/resources/Schema/Components/Physics.xsd @@ -0,0 +1,16 @@ + + + + + + + + Physics stuff + + + + + + + + diff --git a/resources/Schema/Components/Transform.xsd b/resources/Schema/Components/Transform.xsd index b8d24777..f0db2472 100644 --- a/resources/Schema/Components/Transform.xsd +++ b/resources/Schema/Components/Transform.xsd @@ -17,4 +17,4 @@ - \ No newline at end of file + diff --git a/resources/Schema/Entities/MovementTest.xml b/resources/Schema/Entities/MovementTest.xml new file mode 100644 index 00000000..08e05417 --- /dev/null +++ b/resources/Schema/Entities/MovementTest.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + Models/Core/UnitCube.obj + + + + + + + + + + + + + + + + + + + Models/Assault.obj + + + + + + + + + + + + + + + + + + Models/Core/UnitCube.obj + + + + + + + + + + + + + diff --git a/resources/Schema/Entities/Player.xml b/resources/Schema/Entities/Player.xml new file mode 100644 index 00000000..6406a795 --- /dev/null +++ b/resources/Schema/Entities/Player.xml @@ -0,0 +1,17 @@ + + + + + + + + Models/Core/UnitSphere.obj + + + + + + + + + diff --git a/resources/Schema/Types/Entity.xsd b/resources/Schema/Types/Entity.xsd index 8790d8a9..88237697 100644 --- a/resources/Schema/Types/Entity.xsd +++ b/resources/Schema/Types/Entity.xsd @@ -11,6 +11,7 @@ + diff --git a/src/Engine/Collision/CollisionSystem.cpp b/src/Engine/Collision/CollisionSystem.cpp index 92b7f7db..96e49153 100644 --- a/src/Engine/Collision/CollisionSystem.cpp +++ b/src/Engine/Collision/CollisionSystem.cpp @@ -4,6 +4,11 @@ void CollisionSystem::UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) { + if (!entity.HasComponent("Physics")) { + return; + } + ComponentWrapper& cPhysics = entity["Physics"]; + boost::optional boundingBox = Collision::EntityAbsoluteAABB(entity); if (!boundingBox) { return; @@ -25,7 +30,10 @@ void CollisionSystem::UpdateComponent(World* world, EntityWrapper& entity, Compo continue; } if (Collision::AABBVsAABB(boxA, boxB, resolutionVector)) { - (glm::vec3&)cTransform["Position"] += resolutionVector; + if (entity.HasComponent("Physics")) { + (glm::vec3&)cTransform["Position"] += resolutionVector; + cPhysics["Velocity"] = glm::vec3(0, 0, 0); + } } } diff --git a/src/Game/CMakeLists.txt b/src/Game/CMakeLists.txt index 04146670..4be61127 100644 --- a/src/Game/CMakeLists.txt +++ b/src/Game/CMakeLists.txt @@ -11,16 +11,15 @@ include_directories( ) file(GLOB SOURCE_FILES - "${INCLUDE_PATH}/*.h" - #"*.cpp" + "${INCLUDE_PATH}/Systems/*.h" + "Systems/*.cpp" ) -#source_group(Core FILES ${SOURCE_FILES}) +source_group(Systems FILES ${SOURCE_FILES_Systems}) set(SOURCE_FILES ${SOURCE_FILES} "Game.cpp" - "HealthSystem.cpp" - "PlayerSystem.cpp" + ${SOURCE_FILES_Systems} ) set(LIBRARIES diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index 1865dd6c..29b9316b 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -2,7 +2,10 @@ #include "Collision/CollidableOctreeSystem.h" #include "Collision/TriggerSystem.h" #include "Collision/CollisionSystem.h" -#include "Game/HealthSystem.h" +#include "Systems/RaptorCopterSystem.h" +#include "Systems/PlayerSystem.h" +#include "Systems/HealthSystem.h" +#include "Systems/PlayerMovementSystem.h" #include "Core/EntityFileWriter.h" Game::Game(int argc, char* argv[]) @@ -69,6 +72,7 @@ Game::Game(int argc, char* argv[]) m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel, m_Renderer); m_SystemPipeline->AddSystem(updateOrderLevel); + m_SystemPipeline->AddSystem(updateOrderLevel); // Populate Octree with collidables ++updateOrderLevel; m_SystemPipeline->AddSystem(updateOrderLevel, m_OctreeCollision); diff --git a/src/Game/PlayerMovementSystem.cpp b/src/Game/PlayerMovementSystem.cpp deleted file mode 100644 index c0946134..00000000 --- a/src/Game/PlayerMovementSystem.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "RaptorCopterSystem.h" - -void PlayerMovementSystem::UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) -{ - ComponentWrapper& transform = world->GetComponent(component.EntityID); -} \ No newline at end of file diff --git a/src/Game/HealthSystem.cpp b/src/Game/Systems/HealthSystem.cpp similarity index 98% rename from src/Game/HealthSystem.cpp rename to src/Game/Systems/HealthSystem.cpp index 7986db9d..b6d46dc9 100644 --- a/src/Game/HealthSystem.cpp +++ b/src/Game/Systems/HealthSystem.cpp @@ -1,5 +1,4 @@ -#include "HealthSystem.h" -#include +#include "Systems/HealthSystem.h" HealthSystem::HealthSystem(EventBroker* eventBroker) : System(eventBroker) diff --git a/src/Game/Systems/PlayerMovementSystem.cpp b/src/Game/Systems/PlayerMovementSystem.cpp new file mode 100644 index 00000000..536624b3 --- /dev/null +++ b/src/Game/Systems/PlayerMovementSystem.cpp @@ -0,0 +1,16 @@ +#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"]; + velocity.y -= 9.82 * dt; + + glm::vec3& position = cTransform["Position"]; + position += velocity * (float)dt; +} \ No newline at end of file diff --git a/src/Game/PlayerSystem.cpp b/src/Game/Systems/PlayerSystem.cpp similarity index 97% rename from src/Game/PlayerSystem.cpp rename to src/Game/Systems/PlayerSystem.cpp index 2d4d83c6..8cdddf84 100644 --- a/src/Game/PlayerSystem.cpp +++ b/src/Game/Systems/PlayerSystem.cpp @@ -1,4 +1,4 @@ -#include "PlayerSystem.h" +#include "Systems/PlayerSystem.h" void PlayerSystem::UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) { From 5e721325a4ba8a535535d21d3a85981980bba17f Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Thu, 14 Jan 2016 18:20:51 +0100 Subject: [PATCH 11/23] Merge fixes --- include/Engine/Collision/Collision.h | 2 +- include/Engine/Rendering/RenderSystem.h | 10 +- resources/Schema/Components/Camera.xml | 2 +- resources/Schema/Components/Camera.xsd | 4 +- resources/Schema/Entities/MovementTest.xml | 7 ++ src/Engine/Collision/Collision.cpp | 4 +- src/Engine/Editor/EditorSystem.cpp | 3 + src/Engine/Rendering/PickingPass.cpp | 6 +- src/Engine/Rendering/RenderSystem.cpp | 122 ++++++++++----------- src/Game/Game.cpp | 4 +- 10 files changed, 85 insertions(+), 79 deletions(-) diff --git a/include/Engine/Collision/Collision.h b/include/Engine/Collision/Collision.h index 4ea45a55..148f688d 100644 --- a/include/Engine/Collision/Collision.h +++ b/include/Engine/Collision/Collision.h @@ -11,7 +11,7 @@ #include "../Core/Ray.h" #include "../Core/AABB.h" #include "../Rendering/RawModel.h" -#include "../Rendering/RenderQueueFactory.h" +#include "../Core/Transform.h" #include "../Core/Entity.h" #include "../Core/EntityWrapper.h" diff --git a/include/Engine/Rendering/RenderSystem.h b/include/Engine/Rendering/RenderSystem.h index 93e7233f..efe3b88c 100644 --- a/include/Engine/Rendering/RenderSystem.h +++ b/include/Engine/Rendering/RenderSystem.h @@ -14,22 +14,24 @@ #include "ModelJob.h" #include "Renderer.h" #include "../Core/Transform.h" +#include "DebugCameraInputController.h" class RenderSystem : public ImpureSystem { public: RenderSystem(EventBroker* eventBrokerer, const IRenderer* renderer, RenderFrame* renderFrame); + ~RenderSystem(); virtual void Update(World* world, double dt) override; private: World* m_World = nullptr; - const IRenderer* m_Renderer = nullptr; + const IRenderer* m_Renderer; RenderFrame* m_RenderFrame; bool m_SwitchCamera = false; - Camera* m_Camera = nullptr; - Camera* m_DefaultCamera = nullptr; + Camera* m_Camera; + DebugCameraInputController* m_DebugCameraInputController; std::list m_CameraComponents; @@ -41,8 +43,6 @@ private: void updateCamera(World* world, double dt); void updateProjectionMatrix(ComponentWrapper& cameraComponent); - glm::mat4 m_ViewMatrix; - glm::mat4 m_ProjectionMatrix; void fillModels(std::list>& jobs, World* world); diff --git a/resources/Schema/Components/Camera.xml b/resources/Schema/Components/Camera.xml index 92225dde..4f613ded 100644 --- a/resources/Schema/Components/Camera.xml +++ b/resources/Schema/Components/Camera.xml @@ -1,6 +1,6 @@ cam - 60.0 + 45 0.01 5000 \ No newline at end of file diff --git a/resources/Schema/Components/Camera.xsd b/resources/Schema/Components/Camera.xsd index 4f02deb0..2b896c74 100644 --- a/resources/Schema/Components/Camera.xsd +++ b/resources/Schema/Components/Camera.xsd @@ -10,7 +10,9 @@ - + + Vertical Field of View in degrees + diff --git a/resources/Schema/Entities/MovementTest.xml b/resources/Schema/Entities/MovementTest.xml index 08e05417..93b4d374 100644 --- a/resources/Schema/Entities/MovementTest.xml +++ b/resources/Schema/Entities/MovementTest.xml @@ -6,6 +6,13 @@ + + + + + + + diff --git a/src/Engine/Collision/Collision.cpp b/src/Engine/Collision/Collision.cpp index 92048e70..6a66be75 100644 --- a/src/Engine/Collision/Collision.cpp +++ b/src/Engine/Collision/Collision.cpp @@ -290,8 +290,8 @@ boost::optional EntityAbsoluteAABB(EntityWrapper& entity) } ComponentWrapper& cAABB = entity["AABB"]; - glm::vec3 absPosition = RenderQueueFactory::AbsolutePosition(entity.World, entity.ID); - glm::vec3 absScale = RenderQueueFactory::AbsoluteScale(entity.World, entity.ID); + 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); diff --git a/src/Engine/Editor/EditorSystem.cpp b/src/Engine/Editor/EditorSystem.cpp index 714d3d10..69889be5 100644 --- a/src/Engine/Editor/EditorSystem.cpp +++ b/src/Engine/Editor/EditorSystem.cpp @@ -125,6 +125,9 @@ bool EditorSystem::OnMouseMove(const Events::MouseMove& e) if (m_Selection == 0) { return false; } + if (m_Camera == nullptr) { + return false; + } auto widgetTransform = m_World->GetComponent(m_Widget, "Transform"); glm::vec3 widgetOrientation = widgetTransform["Orientation"]; diff --git a/src/Engine/Rendering/PickingPass.cpp b/src/Engine/Rendering/PickingPass.cpp index aa42a961..6800df1d 100644 --- a/src/Engine/Rendering/PickingPass.cpp +++ b/src/Engine/Rendering/PickingPass.cpp @@ -109,7 +109,7 @@ void PickingPass::ClearPicking() { m_PickingColorsToEntity.clear(); m_EntityColors.clear(); - m_ColorCounter[0] = 0; + m_ColorCounter[0] = 1; m_ColorCounter[1] = 0; m_PickingBuffer.Bind(); @@ -138,10 +138,10 @@ PickData PickingPass::Pick(glm::vec2 screenCoord) pickInfo = it->second; } else { pickData.Entity = EntityID_Invalid; + return pickData; } - pickData.Position = ScreenCoords::ToWorldPos(screenCoord.x, screenCoord.y, data.Depth, resolution, pickInfo.Camera->ProjectionMatrix(), pickInfo.Camera->ViewMatrix()); - + pickData.Position = ScreenCoords::ToWorldPos(screenCoord.x, screenCoord.y, data.Depth, resolution, pickInfo.Camera->ProjectionMatrix(), pickInfo.Camera->ViewMatrix()); pickData.Entity = pickInfo.Entity; pickData.Camera = pickInfo.Camera; pickData.World = pickInfo.World; diff --git a/src/Engine/Rendering/RenderSystem.cpp b/src/Engine/Rendering/RenderSystem.cpp index d6cdb9b3..1435e219 100644 --- a/src/Engine/Rendering/RenderSystem.cpp +++ b/src/Engine/Rendering/RenderSystem.cpp @@ -1,18 +1,21 @@ #include "Rendering/RenderSystem.h" -#include "Rendering/DebugCameraInputController.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_EInputCommand, &RenderSystem::OnInputCommand); - m_DefaultCamera = new Camera((float)m_Renderer->Resolution().Width / m_Renderer->Resolution().Height, glm::radians(45.f), 0.01f, 5000.f); - m_DefaultCamera->SetPosition(glm::vec3(0, 0, 10)); - if (m_Camera == nullptr) { - m_Camera = m_DefaultCamera; - } + 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(eventBroker, -1); +} + +RenderSystem::~RenderSystem() +{ + delete m_Camera; + delete m_DebugCameraInputController; } bool RenderSystem::OnSetCamera(const Events::SetCamera &event) @@ -54,14 +57,11 @@ void RenderSystem::switchCamera(EntityID entity) void RenderSystem::updateProjectionMatrix(ComponentWrapper& cameraComponent) { double fov = cameraComponent["FOV"]; - double aspectRatio = m_Renderer->Resolution().Width / m_Renderer->Resolution().Height; + double aspectRatio = (float)m_Renderer->Resolution().Width / m_Renderer->Resolution().Height; double nearClip = cameraComponent["NearClip"]; double farClip = cameraComponent["FarClip"]; - double fovY = atan(tan(glm::radians(fov)/2.0) * aspectRatio) * 2.0; - m_ProjectionMatrix = glm::perspective(fovY, aspectRatio, nearClip, farClip); - - m_Camera->SetFOV(fovY); + m_Camera->SetFOV(glm::radians(fov)); m_Camera->SetAspectRatio(aspectRatio); m_Camera->SetNearClip(nearClip); m_Camera->SetFarClip(farClip); @@ -129,66 +129,62 @@ void RenderSystem::Update(World* world, double dt) void RenderSystem::updateCamera(World* world, double dt) { - - static DebugCameraInputController firstPersonInputController(m_EventBroker, -1); - - if (m_SwitchCamera) { - auto cameras = world->GetComponents("Camera"); - for (auto it = cameras->begin(); it != cameras->end(); it++) { - if ((*it).EntityID == m_CurrentCamera) { - it++; - if (it != cameras->end()) { - switchCamera((*it).EntityID); - } else { - switchCamera((*cameras->begin()).EntityID); - } - break; + if (m_SwitchCamera) { + auto cameras = world->GetComponents("Camera"); + for (auto it = cameras->begin(); it != cameras->end(); it++) { + if ((*it).EntityID == m_CurrentCamera) { + it++; + if (it != cameras->end()) { + switchCamera((*it).EntityID); + } else { + switchCamera((*cameras->begin()).EntityID); } + break; } + } + ComponentWrapper& cameraComponent = world->GetComponent(m_CurrentCamera, "Camera"); + ComponentWrapper& cameraTransform = world->GetComponent(m_CurrentCamera, "Transform"); + + m_DebugCameraInputController->SetOrientation(glm::quat((glm::vec3)cameraTransform["Orientation"])); + m_DebugCameraInputController->SetPosition(cameraTransform["Position"]); + } + + if (m_World->ValidEntity(m_CurrentCamera)) { + if (world->HasComponent(m_CurrentCamera, "Camera") && world->HasComponent(m_CurrentCamera, "Transform")) { ComponentWrapper& cameraComponent = world->GetComponent(m_CurrentCamera, "Camera"); ComponentWrapper& cameraTransform = world->GetComponent(m_CurrentCamera, "Transform"); - firstPersonInputController.SetOrientation(glm::quat((glm::vec3)cameraTransform["Orientation"])); - firstPersonInputController.SetPosition(cameraTransform["Position"]); - - } + m_DebugCameraInputController->Update(dt); + (glm::vec3&)cameraTransform["Orientation"] = glm::eulerAngles(m_DebugCameraInputController->Orientation()); + (glm::vec3&)cameraTransform["Position"] = m_DebugCameraInputController->Position(); + + glm::vec3 position = Transform::AbsolutePosition(world, m_CurrentCamera); + glm::quat orientation = Transform::AbsoluteOrientation(world, m_CurrentCamera); + + m_Camera->SetPosition(position); + m_Camera->SetOrientation(orientation); + + updateProjectionMatrix(cameraComponent); + + } + } else { + m_Camera = m_Camera; + + auto cameras = world->GetComponents("Camera"); + if (cameras != nullptr) { + if (cameras->begin() != cameras->end()) { + ComponentWrapper& cameraC = *cameras->begin(); + switchCamera(cameraC.EntityID); - if (m_World->ValidEntity(m_CurrentCamera)) { - if (world->HasComponent(m_CurrentCamera, "Camera") && world->HasComponent(m_CurrentCamera, "Transform")) { ComponentWrapper& cameraComponent = world->GetComponent(m_CurrentCamera, "Camera"); ComponentWrapper& cameraTransform = world->GetComponent(m_CurrentCamera, "Transform"); - firstPersonInputController.Update(dt); - (glm::vec3&)cameraTransform["Orientation"] = glm::eulerAngles(firstPersonInputController.Orientation()); - (glm::vec3&)cameraTransform["Position"] = firstPersonInputController.Position(); - - glm::vec3 position = Transform::AbsolutePosition(world, m_CurrentCamera); - glm::quat orientation = Transform::AbsoluteOrientation(world, m_CurrentCamera); - - m_Camera->SetPosition(position); - m_Camera->SetOrientation(orientation); - - updateProjectionMatrix(cameraComponent); - - } - } else { - m_Camera = m_DefaultCamera; - - auto cameras = world->GetComponents("Camera"); - if (cameras != nullptr) { - if (cameras->begin() != cameras->end()) { - ComponentWrapper& cameraC = *cameras->begin(); - switchCamera(cameraC.EntityID); - - ComponentWrapper& cameraComponent = world->GetComponent(m_CurrentCamera, "Camera"); - ComponentWrapper& cameraTransform = world->GetComponent(m_CurrentCamera, "Transform"); - - firstPersonInputController.SetOrientation(glm::quat((glm::vec3)cameraTransform["Orientation"])); - firstPersonInputController.SetPosition(cameraTransform["Position"]); - } + m_DebugCameraInputController->SetOrientation(glm::quat((glm::vec3)cameraTransform["Orientation"])); + m_DebugCameraInputController->SetPosition(cameraTransform["Position"]); } } + } - m_Camera->UpdateViewMatrix(); + m_Camera->UpdateViewMatrix(); } diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index 2be1cb28..a49171bb 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -35,6 +35,7 @@ Game::Game(int argc, char* argv[]) )); m_Renderer->Initialize(); //m_Renderer->Camera()->SetFOV(glm::radians(m_Config->Get("Video.FOV", 90.f))); + m_RenderFrame = new RenderFrame(); // Create input manager m_InputManager = new InputManager(m_Renderer->Window(), m_EventBroker); @@ -59,8 +60,6 @@ Game::Game(int argc, char* argv[]) fp.MergeEntities(m_World); } - m_RenderFrame = new RenderFrame(); - // Create Octrees m_OctreeCollision = new Octree(AABB(glm::vec3(-100), glm::vec3(100)), 4); m_OctreeFrustrumCulling = new Octree(AABB(glm::vec3(-100), glm::vec3(100)), 4); @@ -82,7 +81,6 @@ Game::Game(int argc, char* argv[]) ++updateOrderLevel; m_SystemPipeline->AddSystem(updateOrderLevel, m_OctreeCollision); m_SystemPipeline->AddSystem(updateOrderLevel, m_OctreeCollision); - ++updateOrderLevel; m_SystemPipeline->AddSystem(updateOrderLevel, m_Renderer, m_RenderFrame); From 046946002988af38fc29cab057f82df16a302bdf Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Fri, 15 Jan 2016 16:32:04 +0100 Subject: [PATCH 12/23] Input binding format changed to allow custom values for bindings. Relevant code must clamp input values to prevent speedhaxx! --- include/Engine/Input/InputProxy.h | 1 + resources/DefaultInput.ini | 8 ++++---- src/Engine/Input/InputProxy.cpp | 23 ++++++++++++----------- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/include/Engine/Input/InputProxy.h b/include/Engine/Input/InputProxy.h index c7817c22..c9ba5ada 100644 --- a/include/Engine/Input/InputProxy.h +++ b/include/Engine/Input/InputProxy.h @@ -1,6 +1,7 @@ #ifndef InputProxy_h__ #define InputProxy_h__ +#include #include "../Common.h" #include "../Core/ResourceManager.h" #include "../Core/ConfigFile.h" diff --git a/resources/DefaultInput.ini b/resources/DefaultInput.ini index 95ebbc22..5ed46241 100644 --- a/resources/DefaultInput.ini +++ b/resources/DefaultInput.ini @@ -6,10 +6,10 @@ InvertPitch=false MouseLeft=PrimaryFire MouseX=Yaw MouseY=Pitch -W=+Forward -S=-Forward -D=+Right -A=-Right +W=Forward,1 +S=Forward,-1 +D=Right,1 +A=Right,-1 R=Reload Space=Jump LeftControl=Crouch diff --git a/src/Engine/Input/InputProxy.cpp b/src/Engine/Input/InputProxy.cpp index ad589df3..7e977542 100644 --- a/src/Engine/Input/InputProxy.cpp +++ b/src/Engine/Input/InputProxy.cpp @@ -20,15 +20,16 @@ void InputProxy::LoadBindings(std::string file) for (auto& origin : config->GetAll("Bindings")) { Events::BindOrigin e; e.Origin = origin.first; - e.Command = origin.second; - 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; - } + const std::string& command = origin.second; + if (!command.empty()) { + boost::char_separator separator(", "); + boost::tokenizer tokenizer(command, separator); + auto token = tokenizer.begin(); + e.Command = *token; + if (++token != tokenizer.end()) { + e.Value = boost::lexical_cast(*token); + } else { + e.Value = 1.f; } OnBindOrigin(e); } @@ -62,7 +63,7 @@ void InputProxy::Process() e.Command = command; e.Value = currentValue; m_EventBroker->Publish(e); - //LOG_DEBUG("Input: Published command %s=%f for player %i", e.Command.c_str(), e.Value, e.PlayerID); + LOG_DEBUG("Input: Published command %s=%f for player %i", e.Command.c_str(), e.Value, e.PlayerID); m_LastCommandValues[command] = currentValue; } } @@ -78,7 +79,7 @@ void InputProxy::Process() } //e.Value = std::max(-1.f, std::min(e.Value, 1.f)); m_EventBroker->Publish(e); - //LOG_DEBUG("Input: Published command %s=%f for player %i", e.Command.c_str(), e.Value, e.PlayerID); + LOG_DEBUG("Input: Published command %s=%f for player %i", e.Command.c_str(), e.Value, e.PlayerID); } m_CommandQueue.clear(); } From 97e12ff55054c6a497ac847c18b1549495afe064 Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Fri, 15 Jan 2016 18:31:32 +0100 Subject: [PATCH 13/23] Made EntityFileParser::MergeEntities return the base entity that was created, and also take an optional parent entity to create it under. --- include/Engine/Core/EntityFile.h | 2 +- include/Engine/Core/EntityFileParser.h | 3 ++- src/Engine/Core/EntityFileParser.cpp | 8 ++++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/include/Engine/Core/EntityFile.h b/include/Engine/Core/EntityFile.h index 27115264..b65c9f7d 100644 --- a/include/Engine/Core/EntityFile.h +++ b/include/Engine/Core/EntityFile.h @@ -77,7 +77,7 @@ public: : m_Handler(handler) , m_Reader(reader) { - // 0 is imaginary world entity + // 0 is imaginary base parent m_EntityStack.push(0); m_StateStack.push(State::Unknown); } diff --git a/include/Engine/Core/EntityFileParser.h b/include/Engine/Core/EntityFileParser.h index d46b508b..b4eee5b2 100644 --- a/include/Engine/Core/EntityFileParser.h +++ b/include/Engine/Core/EntityFileParser.h @@ -9,12 +9,13 @@ class EntityFileParser public: EntityFileParser(const EntityFile* entityFile); - void MergeEntities(World* world); + EntityID MergeEntities(World* world, EntityID baseParent = EntityID_Invalid); private: const EntityFile* m_EntityFile; EntityFileHandler m_Handler; World* m_World = nullptr; + EntityID m_FirstEntity = EntityID_Invalid; // Maps EntityIDs local to the file to real IDs in the world after they've been // created in order to resolve parent-child relationships. std::map m_EntityIDMapper; diff --git a/src/Engine/Core/EntityFileParser.cpp b/src/Engine/Core/EntityFileParser.cpp index 541da01d..9f338d71 100644 --- a/src/Engine/Core/EntityFileParser.cpp +++ b/src/Engine/Core/EntityFileParser.cpp @@ -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)); } -void EntityFileParser::MergeEntities(World* world) +EntityID EntityFileParser::MergeEntities(World* world, EntityID baseParent /*= EntityID_Invalid */) { m_World = world; - m_EntityIDMapper[0] = 0; + m_EntityIDMapper[0] = baseParent; m_EntityFile->Parse(&m_Handler); + return m_FirstEntity; } void EntityFileParser::onStartEntity(EntityID entity, EntityID parent, const std::string& name) { EntityID realParent = m_EntityIDMapper.at(parent); EntityID realEntity = m_World->CreateEntity(realParent); + if (m_FirstEntity == EntityID_Invalid) { + m_FirstEntity = realEntity; + } if (!name.empty()) { m_World->SetName(realEntity, name); } From db1b972cd1738335e61aa3e5965b4738944cabc0 Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Fri, 15 Jan 2016 18:32:47 +0100 Subject: [PATCH 14/23] Spawner, SpawnPoint and PlayerSpawn components, and base work on their systems --- assets | 2 +- include/Engine/Core/EntityWrapper.h | 5 ++ include/Engine/Core/EventBroker.h | 4 +- include/Engine/Core/World.h | 2 + include/Game/Events/ESpawnerSpawn.h | 18 +++++++ include/Game/Systems/PlayerSpawnSystem.h | 17 ++++++ include/Game/Systems/SpawnerSystem.h | 20 +++++++ resources/Schema/Components.xsd | 3 ++ resources/Schema/Components/PlayerSpawn.xml | 3 ++ resources/Schema/Components/PlayerSpawn.xsd | 18 +++++++ resources/Schema/Components/SpawnPoint.xml | 1 + resources/Schema/Components/SpawnPoint.xsd | 11 ++++ resources/Schema/Components/Spawner.xml | 3 ++ resources/Schema/Components/Spawner.xsd | 18 +++++++ resources/Schema/Entities/Player.xml | 1 + resources/Schema/Entities/SpawnTest.xml | 59 +++++++++++++++++++++ resources/Schema/Types/Entity.xsd | 3 ++ src/Engine/Core/World.cpp | 5 ++ src/Game/CMakeLists.txt | 9 +++- src/Game/Game.cpp | 4 ++ src/Game/Systems/PlayerSpawnSystem.cpp | 39 ++++++++++++++ src/Game/Systems/SpawnerSystem.cpp | 47 ++++++++++++++++ 22 files changed, 288 insertions(+), 4 deletions(-) create mode 100644 include/Game/Events/ESpawnerSpawn.h create mode 100644 include/Game/Systems/PlayerSpawnSystem.h create mode 100644 include/Game/Systems/SpawnerSystem.h create mode 100644 resources/Schema/Components/PlayerSpawn.xml create mode 100644 resources/Schema/Components/PlayerSpawn.xsd create mode 100644 resources/Schema/Components/SpawnPoint.xml create mode 100644 resources/Schema/Components/SpawnPoint.xsd create mode 100644 resources/Schema/Components/Spawner.xml create mode 100644 resources/Schema/Components/Spawner.xsd create mode 100644 resources/Schema/Entities/SpawnTest.xml create mode 100644 src/Game/Systems/PlayerSpawnSystem.cpp create mode 100644 src/Game/Systems/SpawnerSystem.cpp diff --git a/assets b/assets index a0d1615e..a3c92ac8 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit a0d1615e515a4d7db0073cc987d1d593ca942471 +Subproject commit a3c92ac876dd061776c36d1594bd82264372f028 diff --git a/include/Engine/Core/EntityWrapper.h b/include/Engine/Core/EntityWrapper.h index 541dfe0d..4cc8bbea 100644 --- a/include/Engine/Core/EntityWrapper.h +++ b/include/Engine/Core/EntityWrapper.h @@ -7,6 +7,11 @@ class World; struct EntityWrapper { + EntityWrapper() + : World(nullptr) + , ID(EntityID_Invalid) + { } + EntityWrapper(::World* world, EntityID id) : World(world) , ID(id) diff --git a/include/Engine/Core/EventBroker.h b/include/Engine/Core/EventBroker.h index dde5242a..dc1babc0 100644 --- a/include/Engine/Core/EventBroker.h +++ b/include/Engine/Core/EventBroker.h @@ -43,7 +43,7 @@ template class EventRelay : public BaseEventRelay { public: - typedef std::function CallbackType; + typedef std::function CallbackType; EventRelay() : m_Callback(nullptr) @@ -65,7 +65,7 @@ template bool EventRelay::Receive(const std::shared_ptr event) { if (m_Callback != nullptr) { - return m_Callback(*static_cast(event.get())); + return m_Callback(*static_cast(event.get())); } else { return false; } diff --git a/include/Engine/Core/World.h b/include/Engine/Core/World.h index 3c666ceb..b201d4ac 100644 --- a/include/Engine/Core/World.h +++ b/include/Engine/Core/World.h @@ -34,6 +34,8 @@ public: EntityID GetParent(EntityID entity); // Change the parent of an entity void SetParent(EntityID entity, EntityID parent); + // Get children of an entity + const std::pair::const_iterator, std::unordered_multimap::const_iterator> GetChildren(EntityID entity); // Get all component pools const std::unordered_map& GetComponentPools() const { return m_ComponentPools; } // Get the entity children map diff --git a/include/Game/Events/ESpawnerSpawn.h b/include/Game/Events/ESpawnerSpawn.h new file mode 100644 index 00000000..7af4f63e --- /dev/null +++ b/include/Game/Events/ESpawnerSpawn.h @@ -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 \ No newline at end of file diff --git a/include/Game/Systems/PlayerSpawnSystem.h b/include/Game/Systems/PlayerSpawnSystem.h new file mode 100644 index 00000000..414d32d8 --- /dev/null +++ b/include/Game/Systems/PlayerSpawnSystem.h @@ -0,0 +1,17 @@ +#include "Core/System.h" +#include "Input/EInputCommand.h" +#include "Events/ESpawnerSpawn.h" + +class PlayerSpawnSystem : public ImpureSystem +{ +public: + PlayerSpawnSystem(EventBroker* eventBroker); + + virtual void Update(World* world, double dt) override; + +private: + EventRelay m_OnInputCommand; + bool OnInputCommand(const Events::InputCommand& e); + + std::vector m_SpawnRequests; +}; \ No newline at end of file diff --git a/include/Game/Systems/SpawnerSystem.h b/include/Game/Systems/SpawnerSystem.h new file mode 100644 index 00000000..cbb7c100 --- /dev/null +++ b/include/Game/Systems/SpawnerSystem.h @@ -0,0 +1,20 @@ +#include +#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); + +private: + EventRelay m_OnSpawnerSpawn; + bool OnSpawnerSpawn(Events::SpawnerSpawn& e); + + void spawnEntity(EntityWrapper spawner, EntityID parent, glm::vec3 position); +}; \ No newline at end of file diff --git a/resources/Schema/Components.xsd b/resources/Schema/Components.xsd index 7d323df6..bcea14e9 100644 --- a/resources/Schema/Components.xsd +++ b/resources/Schema/Components.xsd @@ -12,4 +12,7 @@ + + + \ No newline at end of file diff --git a/resources/Schema/Components/PlayerSpawn.xml b/resources/Schema/Components/PlayerSpawn.xml new file mode 100644 index 00000000..b286e56f --- /dev/null +++ b/resources/Schema/Components/PlayerSpawn.xml @@ -0,0 +1,3 @@ + + 1 + \ No newline at end of file diff --git a/resources/Schema/Components/PlayerSpawn.xsd b/resources/Schema/Components/PlayerSpawn.xsd new file mode 100644 index 00000000..b076de27 --- /dev/null +++ b/resources/Schema/Components/PlayerSpawn.xsd @@ -0,0 +1,18 @@ + + + + + + + + Combined with a Spawner, defines a spawn point for a player team. + + + + + 1 = Spectator, 2 = Red, 3 = Blue + + + + + diff --git a/resources/Schema/Components/SpawnPoint.xml b/resources/Schema/Components/SpawnPoint.xml new file mode 100644 index 00000000..3f392555 --- /dev/null +++ b/resources/Schema/Components/SpawnPoint.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/Schema/Components/SpawnPoint.xsd b/resources/Schema/Components/SpawnPoint.xsd new file mode 100644 index 00000000..67169a9c --- /dev/null +++ b/resources/Schema/Components/SpawnPoint.xsd @@ -0,0 +1,11 @@ + + + + + + + + Defines this entity as a spawn point for a parent Spawner + + + diff --git a/resources/Schema/Components/Spawner.xml b/resources/Schema/Components/Spawner.xml new file mode 100644 index 00000000..f2ac77a8 --- /dev/null +++ b/resources/Schema/Components/Spawner.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/resources/Schema/Components/Spawner.xsd b/resources/Schema/Components/Spawner.xsd new file mode 100644 index 00000000..dcf74aea --- /dev/null +++ b/resources/Schema/Components/Spawner.xsd @@ -0,0 +1,18 @@ + + + + + + + + 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. + + + + + The entity template to spawn + + + + + diff --git a/resources/Schema/Entities/Player.xml b/resources/Schema/Entities/Player.xml index 6406a795..6c3b39c3 100644 --- a/resources/Schema/Entities/Player.xml +++ b/resources/Schema/Entities/Player.xml @@ -3,6 +3,7 @@ + Models/Core/UnitSphere.obj diff --git a/resources/Schema/Entities/SpawnTest.xml b/resources/Schema/Entities/SpawnTest.xml new file mode 100644 index 00000000..f4af726d --- /dev/null +++ b/resources/Schema/Entities/SpawnTest.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + Schema/Entities/Player.xml + + + + + + + + + + + Models/Core/UnitSphere.obj + + + + + + + + + + + + + Models/Core/UnitSphere.obj + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/Schema/Types/Entity.xsd b/resources/Schema/Types/Entity.xsd index 88237697..e1681407 100644 --- a/resources/Schema/Types/Entity.xsd +++ b/resources/Schema/Types/Entity.xsd @@ -20,6 +20,9 @@ + + + diff --git a/src/Engine/Core/World.cpp b/src/Engine/Core/World.cpp index 811de45f..3104e4e9 100644 --- a/src/Engine/Core/World.cpp +++ b/src/Engine/Core/World.cpp @@ -125,6 +125,11 @@ void World::SetParent(EntityID entity, EntityID parent) m_EntityChildren.insert(std::make_pair(parent, entity)); } +const std::pair::const_iterator, std::unordered_multimap::const_iterator> World::GetChildren(EntityID entity) +{ + return m_EntityChildren.equal_range(entity); +} + void World::SetName(EntityID entity, const std::string& name) { m_EntityNames[entity] = name; diff --git a/src/Game/CMakeLists.txt b/src/Game/CMakeLists.txt index 4be61127..4aaff273 100644 --- a/src/Game/CMakeLists.txt +++ b/src/Game/CMakeLists.txt @@ -10,16 +10,23 @@ include_directories( ${Boost_INCLUDE_DIRS} ) -file(GLOB SOURCE_FILES +file(GLOB SOURCE_FILES_Systems "${INCLUDE_PATH}/Systems/*.h" "Systems/*.cpp" ) 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 ${SOURCE_FILES} "Game.cpp" ${SOURCE_FILES_Systems} + ${SOURCE_FILES_Events} ) set(LIBRARIES diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index a3df754d..84b330c4 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -6,6 +6,8 @@ #include "Systems/PlayerSystem.h" #include "Systems/HealthSystem.h" #include "Systems/PlayerMovementSystem.h" +#include "Systems/SpawnerSystem.h" +#include "Systems/PlayerSpawnSystem.h" #include "Core/EntityFileWriter.h" Game::Game(int argc, char* argv[]) @@ -73,6 +75,8 @@ Game::Game(int argc, char* argv[]) m_SystemPipeline->AddSystem(updateOrderLevel, m_Renderer); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); + m_SystemPipeline->AddSystem(updateOrderLevel); + m_SystemPipeline->AddSystem(updateOrderLevel); // Populate Octree with collidables ++updateOrderLevel; m_SystemPipeline->AddSystem(updateOrderLevel, m_OctreeCollision); diff --git a/src/Game/Systems/PlayerSpawnSystem.cpp b/src/Game/Systems/PlayerSpawnSystem.cpp new file mode 100644 index 00000000..a522f679 --- /dev/null +++ b/src/Game/Systems/PlayerSpawnSystem.cpp @@ -0,0 +1,39 @@ +#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 componentPools = world->GetComponentPools(); + auto spawnerPool = componentPools.find("Spawner"); + if (spawnerPool == componentPools.end()) { + return; + } +; + for (auto& team : m_SpawnRequests) { + for (auto& spawner : *spawnerPool->second) { + Events::SpawnerSpawn e; + e.Spawner = EntityWrapper(world, spawner.EntityID); + m_EventBroker->Publish(e); + } + } + 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; +} + diff --git a/src/Game/Systems/SpawnerSystem.cpp b/src/Game/Systems/SpawnerSystem.cpp new file mode 100644 index 00000000..c1122d98 --- /dev/null +++ b/src/Game/Systems/SpawnerSystem.cpp @@ -0,0 +1,47 @@ +#include "Systems/SpawnerSystem.h" + +SpawnerSystem::SpawnerSystem(EventBroker* eventBroker) : System(eventBroker) +{ + EVENT_SUBSCRIBE_MEMBER(m_OnSpawnerSpawn, &SpawnerSystem::OnSpawnerSpawn); +} + +bool SpawnerSystem::OnSpawnerSpawn(Events::SpawnerSpawn& e) +{ + EntityWrapper& spawner = e.Spawner; + + auto children = spawner.World->GetChildren(spawner.ID); + std::vector spawnPoints; + for (auto kv = children.first; kv != children.second; ++kv) { + const EntityID& child = kv->second; + if (spawner.World->HasComponent(child, "SpawnPoint")) { + spawnPoints.push_back(child); + } + } + + EntityID spawnPoint = spawner.ID; + if (!spawnPoints.empty()) { + // Select a random spawn point + 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; + } + spawnEntity(spawner, e.Parent.ID, Transform::AbsolutePosition(spawner.World, spawnPoint)); + + return true; +} + +void SpawnerSystem::spawnEntity(EntityWrapper spawner, EntityID parent, glm::vec3 position) +{ + const std::string& entityFilePath = spawner["Spawner"]["EntityFile"]; + auto entityFile = ResourceManager::Load(entityFilePath); + if (entityFile == nullptr) { + return; + } + + EntityFileParser parser(entityFile); + EntityWrapper spawnedEntity(spawner.World, parser.MergeEntities(spawner.World, parent)); + spawnedEntity["Transform"]["Position"] = position; +} \ No newline at end of file From 8bd5a428b902d1800a73595c351e142ebb62413c Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Fri, 15 Jan 2016 20:25:48 +0100 Subject: [PATCH 15/23] EntityFileParser now ignores component fields not present in component definition instead of crashing. --- src/Engine/Core/EntityFileParser.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Engine/Core/EntityFileParser.cpp b/src/Engine/Core/EntityFileParser.cpp index 9f338d71..1633bbc7 100644 --- a/src/Engine/Core/EntityFileParser.cpp +++ b/src/Engine/Core/EntityFileParser.cpp @@ -42,7 +42,12 @@ void EntityFileParser::onStartComponentField(EntityID entity, const std::string& { EntityID realEntity = m_EntityIDMapper.at(entity); 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("Attributes:"); @@ -58,7 +63,11 @@ void EntityFileParser::onFieldData(EntityID entity, const std::string& component { EntityID realEntity = m_EntityIDMapper.at(entity); 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; EntityFile::WriteValueData(data, field, fieldData); From bbabc841273027376b5eb29cb32c8a7f251fc029 Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Fri, 15 Jan 2016 20:26:30 +0100 Subject: [PATCH 16/23] Fixed default values for CPlayerSpawn --- resources/Schema/Components/PlayerSpawn.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/Schema/Components/PlayerSpawn.xml b/resources/Schema/Components/PlayerSpawn.xml index b286e56f..2082822e 100644 --- a/resources/Schema/Components/PlayerSpawn.xml +++ b/resources/Schema/Components/PlayerSpawn.xml @@ -1,3 +1,3 @@ - - 1 - \ No newline at end of file + + 1 + \ No newline at end of file From f65ac65e30ba0d55f0dfc1f00de54c9d968ec982 Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Sat, 16 Jan 2016 17:03:00 +0100 Subject: [PATCH 17/23] Updated component defaults files to match component schema and made schema validation strict. --- resources/Schema/Components/AABB.xml | 5 ++-- resources/Schema/Components/Camera.xml | 5 ++-- resources/Schema/Components/Collidable.xml | 5 ++-- resources/Schema/Components/Health.xml | 5 ++-- resources/Schema/Components/Listener.xml | 5 ++-- resources/Schema/Components/Model.xml | 5 ++-- resources/Schema/Components/Physics.xml | 5 ++-- resources/Schema/Components/Player.xml | 5 ++-- resources/Schema/Components/PlayerSpawn.xml | 5 ++-- resources/Schema/Components/PointLight.xml | 5 ++-- resources/Schema/Components/PointLight.xsd | 9 +++++- resources/Schema/Components/RaptorCopter.xml | 5 ++-- resources/Schema/Components/SoundEmitter.xml | 5 ++-- resources/Schema/Components/SoundEmitter.xsd | 30 ++++++++++++-------- resources/Schema/Components/SpawnPoint.xml | 3 +- resources/Schema/Components/Spawner.xml | 5 ++-- resources/Schema/Components/Transform.xml | 5 ++-- resources/Schema/Components/Trigger.xml | 5 ++-- resources/Schema/Types/Entity.xsd | 1 + src/Engine/Core/EntityFile.cpp | 2 ++ src/Engine/Core/EntityFilePreprocessor.cpp | 4 +++ 21 files changed, 79 insertions(+), 45 deletions(-) diff --git a/resources/Schema/Components/AABB.xml b/resources/Schema/Components/AABB.xml index 6996b3dc..9c909ea1 100644 --- a/resources/Schema/Components/AABB.xml +++ b/resources/Schema/Components/AABB.xml @@ -1,4 +1,5 @@ - + + - \ No newline at end of file + \ No newline at end of file diff --git a/resources/Schema/Components/Camera.xml b/resources/Schema/Components/Camera.xml index 4f613ded..ccb12f01 100644 --- a/resources/Schema/Components/Camera.xml +++ b/resources/Schema/Components/Camera.xml @@ -1,6 +1,7 @@ - + + cam 45 0.01 5000 - \ No newline at end of file + \ No newline at end of file diff --git a/resources/Schema/Components/Collidable.xml b/resources/Schema/Components/Collidable.xml index 4f9c9033..9046ea99 100644 --- a/resources/Schema/Components/Collidable.xml +++ b/resources/Schema/Components/Collidable.xml @@ -1,2 +1,3 @@ - - \ No newline at end of file + + + \ No newline at end of file diff --git a/resources/Schema/Components/Health.xml b/resources/Schema/Components/Health.xml index 143a91d1..f53217b9 100644 --- a/resources/Schema/Components/Health.xml +++ b/resources/Schema/Components/Health.xml @@ -1,4 +1,5 @@ - + + 100 100 - \ No newline at end of file + \ No newline at end of file diff --git a/resources/Schema/Components/Listener.xml b/resources/Schema/Components/Listener.xml index 7d1fac13..d7e20f92 100644 --- a/resources/Schema/Components/Listener.xml +++ b/resources/Schema/Components/Listener.xml @@ -1,3 +1,2 @@ - - - \ No newline at end of file + + \ No newline at end of file diff --git a/resources/Schema/Components/Model.xml b/resources/Schema/Components/Model.xml index bd20147f..8f78b9ee 100644 --- a/resources/Schema/Components/Model.xml +++ b/resources/Schema/Components/Model.xml @@ -1,5 +1,6 @@ - + + true - \ No newline at end of file + \ No newline at end of file diff --git a/resources/Schema/Components/Physics.xml b/resources/Schema/Components/Physics.xml index 1ad81de0..7dce027c 100644 --- a/resources/Schema/Components/Physics.xml +++ b/resources/Schema/Components/Physics.xml @@ -1,3 +1,4 @@ - + + - + diff --git a/resources/Schema/Components/Player.xml b/resources/Schema/Components/Player.xml index 190f2ed0..caefd6e6 100644 --- a/resources/Schema/Components/Player.xml +++ b/resources/Schema/Components/Player.xml @@ -1,7 +1,8 @@ - + + false false false false - \ No newline at end of file + \ No newline at end of file diff --git a/resources/Schema/Components/PlayerSpawn.xml b/resources/Schema/Components/PlayerSpawn.xml index 2082822e..1c621ef9 100644 --- a/resources/Schema/Components/PlayerSpawn.xml +++ b/resources/Schema/Components/PlayerSpawn.xml @@ -1,3 +1,4 @@ - + + 1 - \ No newline at end of file + \ No newline at end of file diff --git a/resources/Schema/Components/PointLight.xml b/resources/Schema/Components/PointLight.xml index 6b1382db..814d7f4c 100644 --- a/resources/Schema/Components/PointLight.xml +++ b/resources/Schema/Components/PointLight.xml @@ -1,7 +1,8 @@ - + + 1.0 0.8 0.3 true - \ No newline at end of file + \ No newline at end of file diff --git a/resources/Schema/Components/PointLight.xsd b/resources/Schema/Components/PointLight.xsd index 039e7117..9b802d8c 100644 --- a/resources/Schema/Components/PointLight.xsd +++ b/resources/Schema/Components/PointLight.xsd @@ -12,7 +12,14 @@ - + + + + + + + + diff --git a/resources/Schema/Components/RaptorCopter.xml b/resources/Schema/Components/RaptorCopter.xml index cc1ece52..1dec4a44 100644 --- a/resources/Schema/Components/RaptorCopter.xml +++ b/resources/Schema/Components/RaptorCopter.xml @@ -1,4 +1,5 @@ - + + 0 - \ No newline at end of file + \ No newline at end of file diff --git a/resources/Schema/Components/SoundEmitter.xml b/resources/Schema/Components/SoundEmitter.xml index 11093e37..e0a38d2f 100644 --- a/resources/Schema/Components/SoundEmitter.xml +++ b/resources/Schema/Components/SoundEmitter.xml @@ -1,4 +1,5 @@ - + + 1.0 1.0 @@ -6,4 +7,4 @@ 20.0 1.0 1.0 - \ No newline at end of file + \ No newline at end of file diff --git a/resources/Schema/Components/SoundEmitter.xsd b/resources/Schema/Components/SoundEmitter.xsd index c734e6ba..9a73949b 100644 --- a/resources/Schema/Components/SoundEmitter.xsd +++ b/resources/Schema/Components/SoundEmitter.xsd @@ -7,18 +7,24 @@ - - The "volume" of the emitter. A value betweeen 0-1 - - The pitch of the emitter. A value betweeen 0-1 - - If the sound should loop or not. - - The distance where there will no longer be any attenuation. - - The rolloff rate of the source. - - The distance that the source will be the loudest. + + The "volume" of the emitter. A value betweeen 0-1 + + + The pitch of the emitter. A value betweeen 0-1 + + + If the sound should loop or not. + + + The distance where there will no longer be any attenuation. + + + The rolloff rate of the source. + + + The distance that the source will be the loudest. + diff --git a/resources/Schema/Components/SpawnPoint.xml b/resources/Schema/Components/SpawnPoint.xml index 3f392555..6b2f7ae3 100644 --- a/resources/Schema/Components/SpawnPoint.xml +++ b/resources/Schema/Components/SpawnPoint.xml @@ -1 +1,2 @@ - \ No newline at end of file + + \ No newline at end of file diff --git a/resources/Schema/Components/Spawner.xml b/resources/Schema/Components/Spawner.xml index f2ac77a8..da659c69 100644 --- a/resources/Schema/Components/Spawner.xml +++ b/resources/Schema/Components/Spawner.xml @@ -1,3 +1,4 @@ - + + - \ No newline at end of file + \ No newline at end of file diff --git a/resources/Schema/Components/Transform.xml b/resources/Schema/Components/Transform.xml index 00202aa4..7e2bcd83 100644 --- a/resources/Schema/Components/Transform.xml +++ b/resources/Schema/Components/Transform.xml @@ -1,5 +1,6 @@ - + + - \ No newline at end of file + \ No newline at end of file diff --git a/resources/Schema/Components/Trigger.xml b/resources/Schema/Components/Trigger.xml index 4c8aad58..38c6fce9 100644 --- a/resources/Schema/Components/Trigger.xml +++ b/resources/Schema/Components/Trigger.xml @@ -1,2 +1,3 @@ - - \ No newline at end of file + + + \ No newline at end of file diff --git a/resources/Schema/Types/Entity.xsd b/resources/Schema/Types/Entity.xsd index f64bae3b..8fc52e1e 100644 --- a/resources/Schema/Types/Entity.xsd +++ b/resources/Schema/Types/Entity.xsd @@ -16,6 +16,7 @@ + diff --git a/src/Engine/Core/EntityFile.cpp b/src/Engine/Core/EntityFile.cpp index 1e381df5..5589eddf 100644 --- a/src/Engine/Core/EntityFile.cpp +++ b/src/Engine/Core/EntityFile.cpp @@ -23,6 +23,8 @@ void EntityFile::Parse(const EntityFileHandler* handler) const EntityFileSAXHandler saxHandler(handler, nullptr); m_SAX2XMLReader->setFeature(XMLUni::fgXercesCacheGrammarFromParse, true); m_SAX2XMLReader->setFeature(XMLUni::fgXercesUseCachedGrammarInParse, true); + m_SAX2XMLReader->setFeature(XMLUni::fgXercesSchema, true); + m_SAX2XMLReader->setFeature(XMLUni::fgXercesSchemaFullChecking, true); m_SAX2XMLReader->setContentHandler(&saxHandler); m_SAX2XMLReader->setErrorHandler(&saxHandler); m_SAX2XMLReader->setDeclarationHandler(&saxHandler); diff --git a/src/Engine/Core/EntityFilePreprocessor.cpp b/src/Engine/Core/EntityFilePreprocessor.cpp index 4b720976..f9aae3d4 100644 --- a/src/Engine/Core/EntityFilePreprocessor.cpp +++ b/src/Engine/Core/EntityFilePreprocessor.cpp @@ -174,7 +174,11 @@ void EntityFilePreprocessor::parseDefaults() memset(ci.second.Defaults.get(), 0, ci.second.Meta.Stride); XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager); + parser.setDoSchema(true); + parser.setDoNamespaces(true); parser.setErrorHandler(&errorHandler); + parser.setValidationScheme(XercesDOMParser::Val_Always); + parser.setValidationSchemaFullChecking(true); std::string componentName = ci.first; LOG_DEBUG("Parsing defaults for component %s", componentName.c_str()); From 9ec32464bc6d9b46753799ad0b23c01999dfbf98 Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Sat, 16 Jan 2016 22:48:08 +0100 Subject: [PATCH 18/23] 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. --- include/Engine/Core/ComponentInfo.h | 6 +- include/Engine/Core/ComponentPool.h | 2 +- include/Engine/Core/ComponentWrapper.h | 19 +- include/Engine/Core/EntityFactory.h | 16 +- include/Engine/Core/EntityFile.h | 165 ++-------------- include/Engine/Core/EntityFilePreprocessor.h | 2 + resources/Schema/Components.xsd | 1 + resources/Schema/Components/Team.xml | 4 + resources/Schema/Components/Team.xsd | 28 +++ resources/Schema/Types.xsd | 3 + resources/Schema/Types/Entity.xsd | 1 + src/Engine/Core/EntityFile.cpp | 187 ++++++++++++++++++- src/Engine/Core/EntityFilePreprocessor.cpp | 139 +++++++++----- src/Engine/Core/EntityFileWriter.cpp | 2 +- src/Engine/Core/World.cpp | 2 +- src/Engine/Editor/EditorSystem.cpp | 24 ++- src/Tests/ComponentPoolTest.cpp | 4 +- 17 files changed, 383 insertions(+), 222 deletions(-) create mode 100755 resources/Schema/Components/Team.xml create mode 100755 resources/Schema/Components/Team.xsd diff --git a/include/Engine/Core/ComponentInfo.h b/include/Engine/Core/ComponentInfo.h index 985a057e..def2a323 100644 --- a/include/Engine/Core/ComponentInfo.h +++ b/include/Engine/Core/ComponentInfo.h @@ -9,7 +9,8 @@ struct ComponentInfo { std::string Annotation; unsigned int Allocation = 0; - unsigned int Stride = 0; + std::map FieldAnnotations; + std::map> FieldEnumDefinitions; }; struct Field_t @@ -23,8 +24,9 @@ struct ComponentInfo std::string Name; std::unordered_map Fields; std::vector FieldsInOrder; - Meta_t Meta; + unsigned int Stride = 0; std::shared_ptr Defaults = nullptr; + std::shared_ptr Meta = nullptr; }; template<> diff --git a/include/Engine/Core/ComponentPool.h b/include/Engine/Core/ComponentPool.h index 619aade8..ed81d72e 100644 --- a/include/Engine/Core/ComponentPool.h +++ b/include/Engine/Core/ComponentPool.h @@ -43,7 +43,7 @@ public: ComponentPool(const ::ComponentInfo& ci) : m_ComponentInfo(ci) - , m_Pool(ci.Meta.Allocation, sizeof(EntityID) + ci.Meta.Stride) + , m_Pool(ci.Meta->Allocation, sizeof(EntityID) + ci.Stride) { } ComponentPool(const ComponentPool& other) = delete; ComponentPool(const ComponentPool&& other) = delete; diff --git a/include/Engine/Core/ComponentWrapper.h b/include/Engine/Core/ComponentWrapper.h index 922b3d79..9d27b0f8 100644 --- a/include/Engine/Core/ComponentWrapper.h +++ b/include/Engine/Core/ComponentWrapper.h @@ -6,6 +6,7 @@ #include "ComponentInfo.h" #include "Util/Any.h" +// TODO: Change all instances "Property" to "Field" to remain consistent with ComponentInfo struct ComponentWrapper { ComponentWrapper(const ComponentInfo& componentInfo, char* data) @@ -18,6 +19,11 @@ struct ComponentWrapper const ::EntityID EntityID; char* Data; + int Enum(const char* fieldName, const char* enumKey) + { + return Info.Meta->FieldEnumDefinitions.at(fieldName).at(enumKey); + } + template T& Property(std::string name) { @@ -33,7 +39,7 @@ struct ComponentWrapper // Specialization for string literals template void SetProperty(std::string name, const char(&value)[N]) { Property(name) = std::string(value); } - + struct SubscriptProxy { friend struct ComponentWrapper; @@ -47,6 +53,9 @@ struct ComponentWrapper std::string m_PropertyName; public: + // Return the integer value of an enum type key for this field + int Enum(const char* enumKey) { return m_Component->Enum(m_PropertyName.c_str(), enumKey); } + template operator T&() { return m_Component->Property(m_PropertyName); } @@ -71,7 +80,7 @@ public: ComponentWrapperFactory(std::string componentTypeName, std::size_t allocation = 0) { m_ComponentInfo.Name = componentTypeName; - m_ComponentInfo.Meta.Allocation = allocation; + m_ComponentInfo.Meta->Allocation = allocation; } template @@ -79,14 +88,14 @@ public: { m_DefaultValues.push_back(defaultValue); 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.Meta.Stride += sizeof(T); + m_ComponentInfo.Stride += sizeof(T); } ComponentInfo& Finalize() { - m_ComponentInfo.Defaults = std::shared_ptr(new char[m_ComponentInfo.Meta.Stride]); + m_ComponentInfo.Defaults = std::shared_ptr(new char[m_ComponentInfo.Stride]); std::size_t offset = 0; for (auto& val : m_DefaultValues) { memcpy(m_ComponentInfo.Defaults.get() + offset, val.Data.get(), val.Size); diff --git a/include/Engine/Core/EntityFactory.h b/include/Engine/Core/EntityFactory.h index d1dbce03..c3c964bc 100644 --- a/include/Engine/Core/EntityFactory.h +++ b/include/Engine/Core/EntityFactory.h @@ -285,7 +285,7 @@ private: XSValue::Status status; XSValue* val = XSValue::getActualValue(child->getNodeValue(), XSValue::dt_integer, status); - compInfo.Meta.Allocation += val->fData.fValue.f_int; + compInfo.Meta->Allocation += val->fData.fValue.f_int; } // Save documentation string @@ -293,11 +293,11 @@ private: if (documentationTags->getLength() != 0) { auto child = documentationTags->item(0)->getFirstChild(); if (child != nullptr) { - compInfo.Meta.Annotation = XSTR(child->getNodeValue()); + compInfo.Meta->Annotation = XSTR(child->getNodeValue()); } } // TODO: Parse annotation string XML - // compInfo.Meta.Allocation = ... + // compInfo.Meta->Allocation = ... } else { std::cout << "Warning: Component is missing an annotation!" << std::endl; } @@ -344,7 +344,7 @@ private: fieldOffset += getTypeStride(type); } - compInfo.Meta.Stride = fieldOffset; + compInfo.Stride = fieldOffset; m_ComponentInfo[compInfo.Name] = compInfo; } } @@ -367,14 +367,14 @@ private: std::string componentName = XSTR(component->getLocalName()); auto& compInfo = m_ComponentInfo.at(componentName); - compInfo.Meta.Allocation += 1; + compInfo.Meta->Allocation += 1; } std::cout << "COMPONENT INFO" << std::endl; for (auto& pair : m_ComponentInfo) { ComponentInfo& ci = pair.second; - std::cout << "Component: " << ci.Name << " (" << ci.Meta.Annotation << ")" << std::endl; - std::cout << " Allocation: " << ci.Meta.Allocation << std::endl; + std::cout << "Component: " << ci.Name << " (" << ci.Meta->Annotation << ")" << std::endl; + std::cout << " Allocation: " << ci.Meta->Allocation << std::endl; std::cout << " Fields:" << std::endl; // Calculate component size @@ -393,7 +393,7 @@ private: cs.ComponentName = ci.Name; cs.Stride = stride; cs.Info = ci; - cs.Data = new char[stride*ci.Meta.Allocation]; + cs.Data = new char[stride*ci.Meta->Allocation]; m_ComponentStore[cs.ComponentName] = cs; } } diff --git a/include/Engine/Core/EntityFile.h b/include/Engine/Core/EntityFile.h index b65c9f7d..2549ed06 100644 --- a/include/Engine/Core/EntityFile.h +++ b/include/Engine/Core/EntityFile.h @@ -73,88 +73,15 @@ public: ComponentField }; - 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); - } + EntityFileSAXHandler(const EntityFileHandler* handler, xercesc::SAX2XMLReader* reader); - void startElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname, const xercesc::Attributes& attrs) override - { - std::string name = XS::ToString(_localName); + void startElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname, const xercesc::Attributes& attrs) override; + void characters(const XMLCh* const chars, const XMLSize_t length) override; + void endElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname) override; - if (m_StateStack.top() == State::Unknown || m_StateStack.top() == State::Entity) { - if (name == "Entity") { - m_StateStack.push(State::Entity); - onStartEntity(attrs); - return; - } - if (name == "EntityRef") { - onStartEntityRef(attrs); - return; - } - } - - std::string uri = XS::ToString(_uri); - if (m_StateStack.top() == State::Entity) { - if (uri == "components") { - m_StateStack.push(State::Component); - onStartComponent(name); - return; - } - } - - if (m_StateStack.top() == State::Component) { - m_StateStack.push(State::ComponentField); - onStartComponentField(name, attrs); - return; - } - } - - void characters(const XMLCh* const chars, const XMLSize_t length) override - { - if (m_StateStack.top() == State::ComponentField) { - char* transcoded = xercesc::XMLString::transcode(chars); - onFieldData(transcoded); - } - } - - void endElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname) override - { - std::string name = XS::ToString(_localName); - if (m_StateStack.top() == State::Entity) { - if (name == "Entity") { - m_StateStack.pop(); - onEndEntity(); - return; - } - } - - std::string uri = XS::ToString(_uri); - if (m_StateStack.top() == State::Component) { - //if (uri == "components") { - m_StateStack.pop(); - onEndComponent(name); - return; - //} - } - - if (m_StateStack.top() == State::ComponentField) { - m_StateStack.pop(); - onEndComponentField(name); - return; - } - } - - void fatalError(const xercesc::SAXParseException& e) - { - XS::ToString s(e.getMessage()); - LOG_ERROR("SAXParseException: %s", ((std::string)s).c_str()); - //throw e; - } + void warning(const xercesc::SAXParseException& e); + void error(const xercesc::SAXParseException& e); + void fatalError(const xercesc::SAXParseException& e); private: const EntityFileHandler* m_Handler; @@ -168,73 +95,14 @@ private: std::string m_CurrentField; std::map m_CurrentAttributes; - void onStartEntity(const xercesc::Attributes& attrs) - { - EntityID parent = m_EntityStack.top(); - - if (m_Handler->m_OnStartEntityCallback) { - std::string name; - auto xName = attrs.getValue(XS::ToXMLCh("name")); - if (xName != nullptr) { - name = XS::ToString(xName); - } - m_Handler->m_OnStartEntityCallback(m_NextEntityID, parent, name); - } - - m_EntityStack.push(m_NextEntityID); - m_NextEntityID++; - } - void onEndEntity() - { - m_EntityStack.pop(); - } - void onStartEntityRef(const xercesc::Attributes& attrs) - { - std::string path = XS::ToString(attrs.getValue(XS::ToXMLCh("file"))); - - xercesc::SAX2XMLReader* parser = xercesc::XMLReaderFactory::createXMLReader(); - parser->setContentHandler(this); - parser->setErrorHandler(this); - parser->parse(path.c_str()); - delete parser; - } - void onStartComponent(const std::string& name) - { - //LOG_DEBUG(" Component: %s", name.c_str()); - m_CurrentComponent = name; - if (m_Handler->m_OnStartComponentCallback) { - m_Handler->m_OnStartComponentCallback(m_EntityStack.top(), name); - } - } - void onEndComponent(const std::string& name) { } - void onStartComponentField(const std::string& field, const xercesc::Attributes& attrs) - { - //LOG_DEBUG(" Field: %s", field.c_str()); - m_CurrentField = field; - m_CurrentAttributes.clear(); - for (int i = 0; i < attrs.getLength(); i++) { - auto name = attrs.getQName(i); - auto value = attrs.getValue(name); - //LOG_DEBUG(" %s = %s", (char*)XS::ToString(name), (char*)XS::ToString(value)); - m_CurrentAttributes[XS::ToString(name).operator std::string()] = XS::ToString(value).operator std::string(); - } - - if (m_Handler->m_OnStartFieldCallback) { - m_Handler->m_OnStartFieldCallback(m_EntityStack.top(), m_CurrentComponent, field, m_CurrentAttributes); - } - } - void onEndComponentField(const std::string& field) { } - - void onFieldData(char* data) - { - //LOG_DEBUG(" Data: %s", data); - - if (m_Handler->m_OnStartFieldDataCallback) { - m_Handler->m_OnStartFieldDataCallback(m_EntityStack.top(), m_CurrentComponent, m_CurrentField, data); - } - - xercesc::XMLString::release(&data); - } + void onStartEntity(const xercesc::Attributes& attrs); + void onEndEntity(); + void onStartEntityRef(const xercesc::Attributes& attrs); + void onStartComponent(const std::string& name); + void onEndComponent(const std::string& name); + void onStartComponentField(const std::string& field, const xercesc::Attributes& attrs); + void onEndComponentField(const std::string& field); + void onFieldData(char* data); }; class EntityFileXMLErrorHandler : public xercesc::ErrorHandler @@ -269,6 +137,7 @@ private: class EntityFile : public Resource { friend class ResourceManager; + friend class EntityFileSAXHandler; private: EntityFile(boost::filesystem::path path); ~EntityFile(); @@ -288,6 +157,8 @@ private: xercesc::SAX2XMLReader* m_SAX2XMLReader; //std::map m_ComponentInfo; //std::vector m_EntityReferences; + + static void setReaderFeatures(xercesc::SAX2XMLReader* reader); }; #endif \ No newline at end of file diff --git a/include/Engine/Core/EntityFilePreprocessor.h b/include/Engine/Core/EntityFilePreprocessor.h index 3c3998b1..3139169f 100644 --- a/include/Engine/Core/EntityFilePreprocessor.h +++ b/include/Engine/Core/EntityFilePreprocessor.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -31,6 +32,7 @@ private: void onStartComponent(EntityID entity, std::string type); void parseComponentInfo(); void parseDefaults(); + std::string parseAnnotationXML(const XMLCh* xml); }; #endif \ No newline at end of file diff --git a/resources/Schema/Components.xsd b/resources/Schema/Components.xsd index 291cf938..88f09d6c 100644 --- a/resources/Schema/Components.xsd +++ b/resources/Schema/Components.xsd @@ -18,4 +18,5 @@ + \ No newline at end of file diff --git a/resources/Schema/Components/Team.xml b/resources/Schema/Components/Team.xml new file mode 100755 index 00000000..3eeb93bf --- /dev/null +++ b/resources/Schema/Components/Team.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/resources/Schema/Components/Team.xsd b/resources/Schema/Components/Team.xsd new file mode 100755 index 00000000..163d4a7f --- /dev/null +++ b/resources/Schema/Components/Team.xsd @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + Represents entity team affiliation + + + + + + + + diff --git a/resources/Schema/Types.xsd b/resources/Schema/Types.xsd index cd464201..fb584c64 100644 --- a/resources/Schema/Types.xsd +++ b/resources/Schema/Types.xsd @@ -4,6 +4,9 @@ + + + diff --git a/resources/Schema/Types/Entity.xsd b/resources/Schema/Types/Entity.xsd index 8fc52e1e..3ca6e545 100644 --- a/resources/Schema/Types/Entity.xsd +++ b/resources/Schema/Types/Entity.xsd @@ -27,6 +27,7 @@ + diff --git a/src/Engine/Core/EntityFile.cpp b/src/Engine/Core/EntityFile.cpp index 5589eddf..c1125e10 100644 --- a/src/Engine/Core/EntityFile.cpp +++ b/src/Engine/Core/EntityFile.cpp @@ -21,16 +21,24 @@ void EntityFile::Parse(const EntityFileHandler* handler) const using namespace xercesc; EntityFileSAXHandler saxHandler(handler, nullptr); - m_SAX2XMLReader->setFeature(XMLUni::fgXercesCacheGrammarFromParse, true); - m_SAX2XMLReader->setFeature(XMLUni::fgXercesUseCachedGrammarInParse, true); - m_SAX2XMLReader->setFeature(XMLUni::fgXercesSchema, true); - m_SAX2XMLReader->setFeature(XMLUni::fgXercesSchemaFullChecking, true); + setReaderFeatures(m_SAX2XMLReader); m_SAX2XMLReader->setContentHandler(&saxHandler); m_SAX2XMLReader->setErrorHandler(&saxHandler); m_SAX2XMLReader->setDeclarationHandler(&saxHandler); 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::map typeStrides{ @@ -39,6 +47,7 @@ std::size_t EntityFile::GetTypeStride(std::string typeName) { "float", sizeof(float) }, { "double", sizeof(double) }, { "string", sizeof(std::string) }, + { "enum", sizeof(int) }, { "Vector", sizeof(glm::vec3) }, { "Quaternion", sizeof(glm::quat) }, { "Color", sizeof(glm::vec4) } @@ -77,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) { - if (field.Type == "int") { + if (field.Type == "int" || field.Type == "enum") { int value = boost::lexical_cast(valueData); memcpy(outData, reinterpret_cast(&value), field.Stride); } else if (field.Type == "float") { @@ -95,3 +104,171 @@ void EntityFile::WriteValueData(char* outData, const ComponentInfo::Field_t& fie 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); +} diff --git a/src/Engine/Core/EntityFilePreprocessor.cpp b/src/Engine/Core/EntityFilePreprocessor.cpp index f9aae3d4..90151941 100644 --- a/src/Engine/Core/EntityFilePreprocessor.cpp +++ b/src/Engine/Core/EntityFilePreprocessor.cpp @@ -16,12 +16,12 @@ EntityFilePreprocessor::EntityFilePreprocessor(const EntityFile* entityFile) for (auto& kv : m_ComponentInfo) { auto& info = kv.second; - LOG_DEBUG("Component: %s (%s)", info.Name.c_str(), info.Meta.Annotation.c_str()); - LOG_DEBUG("Stride: %i", info.Meta.Stride); - LOG_DEBUG("Allocation: %i", info.Meta.Allocation); + LOG_DEBUG("Component: %s (%s)", info.Name.c_str(), info.Meta->Annotation.c_str()); + LOG_DEBUG("Stride: %i", info.Stride); + LOG_DEBUG("Allocation: %i", info.Meta->Allocation); for (auto& kv : info.Fields) { 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,46 +62,16 @@ void EntityFilePreprocessor::parseComponentInfo() } ComponentInfo compInfo; + compInfo.Meta = std::make_shared(); // Name compInfo.Name = XS::ToString(element->getName()); // Known allocation - compInfo.Meta.Allocation = m_ComponentCounts[compInfo.Name]; + compInfo.Meta->Allocation = m_ComponentCounts[compInfo.Name]; // Annotation auto componentAnnotation = element->getAnnotation(); if (componentAnnotation != nullptr) { - // Parse annotation XML - char* annotationString = XMLString::transcode(componentAnnotation->getAnnotationString()); - MemBufInputSource annotationInput(reinterpret_cast(annotationString), strlen(annotationString), "MemBuf: Annotation String"); - XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager, 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(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()); - } - } + compInfo.Meta->Annotation = parseAnnotationXML(componentAnnotation->getAnnotationString()); } else { LOG_WARNING("Component \"%s\" is missing an annotation!", compInfo.Name.c_str()); } @@ -140,24 +110,58 @@ void EntityFilePreprocessor::parseComponentInfo() std::string name = XS::ToString(elementDeclaration->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); if (stride == 0) { - LOG_WARNING("Field \"%s\" in component \"%s\" uses unexpected field type \"%s\". Skipping.", name.c_str(), compInfo.Name.c_str(), type.c_str()); - continue; + 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; + } + 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(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(enumValue); + LOG_DEBUG("ENUM %s = %s", enumName.c_str(), enumValue.c_str()); + } + } } auto& field = compInfo.Fields[name]; field.Name = name; - field.Type = type; + field.Type = effectiveType; field.Offset = fieldOffset; field.Stride = stride; compInfo.FieldsInOrder.push_back(name); - fieldOffset += stride; } - compInfo.Meta.Stride = fieldOffset; + compInfo.Stride = fieldOffset; m_ComponentInfo[compInfo.Name] = compInfo; } } @@ -170,8 +174,10 @@ void EntityFilePreprocessor::parseDefaults() for (auto& ci : m_ComponentInfo) { // Allocate memory for default values - ci.second.Defaults = std::shared_ptr(new char[ci.second.Meta.Stride]); - memset(ci.second.Defaults.get(), 0, ci.second.Meta.Stride); + ci.second.Defaults = std::shared_ptr(new char[ci.second.Stride]); + memset(ci.second.Defaults.get(), 0, ci.second.Stride); + + std::string componentName = ci.first; XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager); parser.setDoSchema(true); @@ -179,8 +185,11 @@ void EntityFilePreprocessor::parseDefaults() 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"); - std::string componentName = ci.first; LOG_DEBUG("Parsing defaults for component %s", componentName.c_str()); boost::filesystem::path defaultsFile = "Schema/Components/" + componentName + ".xml"; @@ -192,7 +201,7 @@ void EntityFilePreprocessor::parseDefaults() } // 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)); if (rootNodes->getLength() == 0) { LOG_ERROR("Couldn't find defaults for component \"%s\"! Skipping.", componentName.c_str()); @@ -225,9 +234,19 @@ void EntityFilePreprocessor::parseDefaults() EntityFile::WriteAttributeData(data, field, attributes); } - // Handle potential field values 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()); EntityFile::WriteValueData(data, field, cstrValue); XMLString::release(&cstrValue); @@ -236,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(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(); +} diff --git a/src/Engine/Core/EntityFileWriter.cpp b/src/Engine/Core/EntityFileWriter.cpp index 5b6c466d..4d46be06 100644 --- a/src/Engine/Core/EntityFileWriter.cpp +++ b/src/Engine/Core/EntityFileWriter.cpp @@ -114,7 +114,7 @@ void EntityFileWriter::appentEntityComponents(xercesc::DOMElement* parentElement fieldElement->setAttribute(X("Y"), X(boost::lexical_cast(q.y))); fieldElement->setAttribute(X("Z"), X(boost::lexical_cast(q.z))); fieldElement->setAttribute(X("W"), X(boost::lexical_cast(q.w))); - } else if (field.Type == "int") { + } else if (field.Type == "int" || field.Type == "enum") { const int& value = c[fieldName]; fieldElement->appendChild(doc->createTextNode(X(boost::lexical_cast(value)))); } else if (field.Type == "float") { diff --git a/src/Engine/Core/World.cpp b/src/Engine/Core/World.cpp index 3104e4e9..477e2ab2 100644 --- a/src/Engine/Core/World.cpp +++ b/src/Engine/Core/World.cpp @@ -75,7 +75,7 @@ ComponentWrapper World::AttachComponent(EntityID entity, const std::string& comp // Allocate space for the component ComponentWrapper c = pool->Allocate(entity); // Write default values - memcpy(c.Data, ci.Defaults.get(), ci.Meta.Stride); + memcpy(c.Data, ci.Defaults.get(), ci.Stride); return c; } diff --git a/src/Engine/Editor/EditorSystem.cpp b/src/Engine/Editor/EditorSystem.cpp index 69889be5..22e1bfc0 100644 --- a/src/Engine/Editor/EditorSystem.cpp +++ b/src/Engine/Editor/EditorSystem.cpp @@ -484,8 +484,8 @@ void EditorSystem::drawUI(World* world, double dt) } if (ImGui::CollapsingHeader(componentType.c_str())) { - if (!ci.Meta.Annotation.empty()) { - ImGui::Text(ci.Meta.Annotation.c_str()); + if (!ci.Meta->Annotation.empty()) { + ImGui::Text(ci.Meta->Annotation.c_str()); } auto& component = world->GetComponent(m_Selection, componentType); @@ -529,6 +529,26 @@ void EditorSystem::drawUI(World* world, double dt) if (ImGui::InputFloat("", &tempVal, 0.01f, 1.f)) { component.SetProperty(fieldName, static_cast(tempVal)); } + } else if (field.Type == "int") { + int val = component.Property(fieldName); + ImGui::InputInt("", &val); + } else if (field.Type == "enum") { + int currentValue = component.Property(fieldName); + int item = -1; + std::stringstream enumKeys; + std::vector 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.SetProperty(fieldName, enumValues.at(item)); + } } else if (field.Type == "bool") { auto& val = component.Property(fieldName); ImGui::Checkbox("", &val); diff --git a/src/Tests/ComponentPoolTest.cpp b/src/Tests/ComponentPoolTest.cpp index 25bdf1d3..1df13c10 100644 --- a/src/Tests/ComponentPoolTest.cpp +++ b/src/Tests/ComponentPoolTest.cpp @@ -10,8 +10,8 @@ BOOST_AUTO_TEST_CASE(ComponentPoolTest) //ci.Name = "Test"; //ci.FieldTypes["Field"] = "int"; //ci.FieldOffsets["Field"] = 0; - //ci.Meta.Allocation = 3; - //ci.Meta.Stride = sizeof(EntityID) + sizeof(int); + //ci.Meta->Allocation = 3; + //ci.Stride = sizeof(EntityID) + sizeof(int); //std::vector wrappers; //ComponentPool pool(ci); From d8a24bbfde07562a2419c425912be2a21a1b8381 Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Sat, 16 Jan 2016 23:24:45 +0100 Subject: [PATCH 19/23] Renamed all instances of "Property" to "Field" in ComponentWrapper to maintain consistent naming with ComponentInfo --- include/Engine/Core/ComponentWrapper.h | 21 ++++++++++----------- src/Engine/Editor/EditorSystem.cpp | 18 +++++++++--------- src/Tests/WorldTest.cpp | 2 +- 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/include/Engine/Core/ComponentWrapper.h b/include/Engine/Core/ComponentWrapper.h index 9d27b0f8..b1e5f9ad 100644 --- a/include/Engine/Core/ComponentWrapper.h +++ b/include/Engine/Core/ComponentWrapper.h @@ -5,8 +5,7 @@ #include "Entity.h" #include "ComponentInfo.h" #include "Util/Any.h" - -// TODO: Change all instances "Property" to "Field" to remain consistent with ComponentInfo +Minecraft hard drilling struct ComponentWrapper { ComponentWrapper(const ComponentInfo& componentInfo, char* data) @@ -25,20 +24,20 @@ struct ComponentWrapper } template - T& Property(std::string name) + T& Field(std::string name) { unsigned int offset = Info.Fields.at(name).Offset; return *reinterpret_cast(&Data[offset]); } template - void SetProperty(std::string name, const T value) { Property(name) = value; } + void SetField(std::string name, const T value) { Field(name) = value; } //template - //void SetProperty(std::string name, T& value) { Property(name) = value; } + //void SetField(std::string name, T& value) { Field(name) = value; } // Specialization for string literals template - void SetProperty(std::string name, const char(&value)[N]) { Property(name) = std::string(value); } + void SetField(std::string name, const char(&value)[N]) { Field(name) = std::string(value); } struct SubscriptProxy { @@ -57,17 +56,17 @@ struct ComponentWrapper int Enum(const char* enumKey) { return m_Component->Enum(m_PropertyName.c_str(), enumKey); } template - operator T&() { return m_Component->Property(m_PropertyName); } + operator T&() { return m_Component->Field(m_PropertyName); } template - void operator=(const T val) { m_Component->SetProperty(m_PropertyName, val); } + void operator=(const T val) { m_Component->SetField(m_PropertyName, val); } // TODO: Pass by reference and rvalue (universal reference?) //template - //void operator=(T& val) { m_Component->SetProperty(m_PropertyName, val); } + //void operator=(T& val) { m_Component->SetField(m_PropertyName, val); } // Specialization for string literals - template - void operator=(const char(&val)[N]) { m_Component->SetProperty(m_PropertyName, val); } + template + void operator=(const char(&val)[N]) { m_Component->SetField(m_PropertyName, val); } }; SubscriptProxy operator[](std::string propertyName) { return SubscriptProxy(this, propertyName); } }; diff --git a/src/Engine/Editor/EditorSystem.cpp b/src/Engine/Editor/EditorSystem.cpp index 22e1bfc0..d5863814 100644 --- a/src/Engine/Editor/EditorSystem.cpp +++ b/src/Engine/Editor/EditorSystem.cpp @@ -496,7 +496,7 @@ void EditorSystem::drawUI(World* world, double dt) std::string uniqueID = componentType + fieldName; ImGui::PushID(uniqueID.c_str()); if (field.Type == "Vector") { - auto& val = component.Property(fieldName); + auto& val = component.Field(fieldName); if (fieldName == "Scale") { ImGui::DragFloat3("", glm::value_ptr(val), 0.1f, 0.f, std::numeric_limits::max()); } else if (fieldName == "Orientation") { @@ -508,10 +508,10 @@ void EditorSystem::drawUI(World* world, double dt) ImGui::DragFloat3("", glm::value_ptr(val), 0.1f, std::numeric_limits::lowest(), std::numeric_limits::max()); } } else if (field.Type == "Color") { - auto& val = component.Property(fieldName); + auto& val = component.Field(fieldName); ImGui::ColorEdit4("", glm::value_ptr(val), true); } else if (field.Type == "string") { - std::string& val = component.Property(fieldName); + std::string& val = component.Field(fieldName); char tempString[1024]; memcpy(tempString, val.c_str(), std::min(val.length() + 1, sizeof(tempString))); if (ImGui::InputText("", tempString, sizeof(tempString))) { @@ -525,15 +525,15 @@ void EditorSystem::drawUI(World* world, double dt) } } else if (field.Type == "double") { - float tempVal = static_cast(component.Property(fieldName)); + float tempVal = static_cast(component.Field(fieldName)); if (ImGui::InputFloat("", &tempVal, 0.01f, 1.f)) { - component.SetProperty(fieldName, static_cast(tempVal)); + component.SetField(fieldName, static_cast(tempVal)); } } else if (field.Type == "int") { - int val = component.Property(fieldName); + int val = component.Field(fieldName); ImGui::InputInt("", &val); } else if (field.Type == "enum") { - int currentValue = component.Property(fieldName); + int currentValue = component.Field(fieldName); int item = -1; std::stringstream enumKeys; std::vector enumValues; @@ -547,10 +547,10 @@ void EditorSystem::drawUI(World* world, double dt) i++; } if (ImGui::Combo("", &item, enumKeys.str().c_str())) { - component.SetProperty(fieldName, enumValues.at(item)); + component.SetField(fieldName, enumValues.at(item)); } } else if (field.Type == "bool") { - auto& val = component.Property(fieldName); + auto& val = component.Field(fieldName); ImGui::Checkbox("", &val); } else { ImGui::TextDisabled(field.Type.c_str()); diff --git a/src/Tests/WorldTest.cpp b/src/Tests/WorldTest.cpp index 8d92a328..03008562 100644 --- a/src/Tests/WorldTest.cpp +++ b/src/Tests/WorldTest.cpp @@ -20,7 +20,7 @@ BOOST_AUTO_TEST_CASE(WorldTestSingleAllocation, * boost::unit_test::tolerance(0. ComponentWrapper c = w.AttachComponent(e, "Test"); // Check default values - BOOST_TEST((int)c["TestInteger"] == c.Property("TestInteger")); + BOOST_TEST((int)c["TestInteger"] == c.Field("TestInteger")); BOOST_TEST((int)c["TestInteger"] == 1337); BOOST_TEST((double)c["TestDouble"] == 13.37); BOOST_TEST((std::string)c["TestString"] == "Carlito"); From 6385a98ecae2f4c3895dc6462fffbe4e3e087110 Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Sun, 17 Jan 2016 00:53:31 +0100 Subject: [PATCH 20/23] Added runtime type size check to ComponentWrapper to avoid corruption when types don't match --- include/Engine/Common.h | 1 + include/Engine/Core/ComponentWrapper.h | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/include/Engine/Common.h b/include/Engine/Common.h index ebdc90d0..7d6f520d 100644 --- a/include/Engine/Common.h +++ b/include/Engine/Common.h @@ -1,5 +1,6 @@ #include #include +#include #include #include #include diff --git a/include/Engine/Core/ComponentWrapper.h b/include/Engine/Core/ComponentWrapper.h index b1e5f9ad..f124d3d5 100644 --- a/include/Engine/Core/ComponentWrapper.h +++ b/include/Engine/Core/ComponentWrapper.h @@ -5,7 +5,7 @@ #include "Entity.h" #include "ComponentInfo.h" #include "Util/Any.h" -Minecraft hard drilling + struct ComponentWrapper { ComponentWrapper(const ComponentInfo& componentInfo, char* data) @@ -26,8 +26,13 @@ struct ComponentWrapper template T& Field(std::string name) { - unsigned int offset = Info.Fields.at(name).Offset; - return *reinterpret_cast(&Data[offset]); + 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(&Data[field.Offset]); } template From f281d220de9e466a701d8d0f9200833fa00a5cab Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Sun, 17 Jan 2016 01:00:48 +0100 Subject: [PATCH 21/23] Working Spawner, SpawnPoint, PlayerSpawn and Team components, along with their systems. --- include/Engine/Core/EntityWrapper.h | 2 + include/Game/Systems/PlayerSpawnSystem.h | 1 + include/Game/Systems/SpawnerSystem.h | 9 +++- resources/Schema/Components.xsd | 1 - resources/Schema/Components/PlayerSpawn.xml | 4 +- resources/Schema/Components/PlayerSpawn.xsd | 9 +--- resources/Schema/Entities/SpawnTest.xml | 9 +++- resources/Schema/Entities/TeamTest.xml | 13 +++++ resources/Schema/Types/Entity.xsd | 1 - src/Engine/Core/EntityWrapper.cpp | 2 + src/Engine/Input/InputProxy.cpp | 4 +- src/Game/Systems/PlayerSpawnSystem.cpp | 28 +++++++--- src/Game/Systems/SpawnerSystem.cpp | 60 +++++++++++++-------- 13 files changed, 93 insertions(+), 50 deletions(-) create mode 100755 resources/Schema/Entities/TeamTest.xml diff --git a/include/Engine/Core/EntityWrapper.h b/include/Engine/Core/EntityWrapper.h index 4cc8bbea..55b64c6f 100644 --- a/include/Engine/Core/EntityWrapper.h +++ b/include/Engine/Core/EntityWrapper.h @@ -20,6 +20,8 @@ struct EntityWrapper ::World* World; EntityID ID; + static const EntityWrapper Invalid; + bool HasComponent(const std::string& componentName); ComponentWrapper operator[](const std::string& componentName); diff --git a/include/Game/Systems/PlayerSpawnSystem.h b/include/Game/Systems/PlayerSpawnSystem.h index 414d32d8..f0e10949 100644 --- a/include/Game/Systems/PlayerSpawnSystem.h +++ b/include/Game/Systems/PlayerSpawnSystem.h @@ -1,5 +1,6 @@ #include "Core/System.h" #include "Input/EInputCommand.h" +#include "Systems/SpawnerSystem.h" #include "Events/ESpawnerSpawn.h" class PlayerSpawnSystem : public ImpureSystem diff --git a/include/Game/Systems/SpawnerSystem.h b/include/Game/Systems/SpawnerSystem.h index cbb7c100..2c094528 100644 --- a/include/Game/Systems/SpawnerSystem.h +++ b/include/Game/Systems/SpawnerSystem.h @@ -1,3 +1,6 @@ +#ifndef SpawnerSystem_h__ +#define SpawnerSystem_h__ + #include #include "Common.h" #include "GLM.h" @@ -12,9 +15,11 @@ class SpawnerSystem : public System public: SpawnerSystem(EventBroker* eventBroker); + static EntityWrapper Spawn(EntityWrapper spawner, EntityWrapper parent = EntityWrapper::Invalid); + private: EventRelay m_OnSpawnerSpawn; bool OnSpawnerSpawn(Events::SpawnerSpawn& e); +}; - void spawnEntity(EntityWrapper spawner, EntityID parent, glm::vec3 position); -}; \ No newline at end of file +#endif \ No newline at end of file diff --git a/resources/Schema/Components.xsd b/resources/Schema/Components.xsd index 88f09d6c..8d837aea 100644 --- a/resources/Schema/Components.xsd +++ b/resources/Schema/Components.xsd @@ -4,7 +4,6 @@ - diff --git a/resources/Schema/Components/PlayerSpawn.xml b/resources/Schema/Components/PlayerSpawn.xml index 1c621ef9..edc1394e 100644 --- a/resources/Schema/Components/PlayerSpawn.xml +++ b/resources/Schema/Components/PlayerSpawn.xml @@ -1,4 +1,2 @@ - - 1 - \ No newline at end of file + \ No newline at end of file diff --git a/resources/Schema/Components/PlayerSpawn.xsd b/resources/Schema/Components/PlayerSpawn.xsd index b076de27..6e321724 100644 --- a/resources/Schema/Components/PlayerSpawn.xsd +++ b/resources/Schema/Components/PlayerSpawn.xsd @@ -5,14 +5,7 @@ - Combined with a Spawner, defines a spawn point for a player team. + Combined with a Spawner and a Team component, defines a spawn point for a player team. - - - - 1 = Spectator, 2 = Red, 3 = Blue - - - diff --git a/resources/Schema/Entities/SpawnTest.xml b/resources/Schema/Entities/SpawnTest.xml index f4af726d..a5574027 100644 --- a/resources/Schema/Entities/SpawnTest.xml +++ b/resources/Schema/Entities/SpawnTest.xml @@ -8,9 +8,13 @@ + Schema/Entities/Player.xml + + 2 + @@ -47,9 +51,10 @@ + - - + + diff --git a/resources/Schema/Entities/TeamTest.xml b/resources/Schema/Entities/TeamTest.xml new file mode 100755 index 00000000..69be6141 --- /dev/null +++ b/resources/Schema/Entities/TeamTest.xml @@ -0,0 +1,13 @@ + + + + + + 3 + + + + + + + diff --git a/resources/Schema/Types/Entity.xsd b/resources/Schema/Types/Entity.xsd index 3ca6e545..1aaa8497 100644 --- a/resources/Schema/Types/Entity.xsd +++ b/resources/Schema/Types/Entity.xsd @@ -13,7 +13,6 @@ - diff --git a/src/Engine/Core/EntityWrapper.cpp b/src/Engine/Core/EntityWrapper.cpp index 9d15dd39..7b321a63 100644 --- a/src/Engine/Core/EntityWrapper.cpp +++ b/src/Engine/Core/EntityWrapper.cpp @@ -1,6 +1,8 @@ #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); diff --git a/src/Engine/Input/InputProxy.cpp b/src/Engine/Input/InputProxy.cpp index 7e977542..6c3591e3 100644 --- a/src/Engine/Input/InputProxy.cpp +++ b/src/Engine/Input/InputProxy.cpp @@ -63,7 +63,7 @@ void InputProxy::Process() e.Command = command; e.Value = currentValue; m_EventBroker->Publish(e); - LOG_DEBUG("Input: Published command %s=%f for player %i", e.Command.c_str(), e.Value, e.PlayerID); + //LOG_DEBUG("Input: Published command %s=%f for player %i", e.Command.c_str(), e.Value, e.PlayerID); m_LastCommandValues[command] = currentValue; } } @@ -79,7 +79,7 @@ void InputProxy::Process() } //e.Value = std::max(-1.f, std::min(e.Value, 1.f)); m_EventBroker->Publish(e); - LOG_DEBUG("Input: Published command %s=%f for player %i", e.Command.c_str(), e.Value, e.PlayerID); + //LOG_DEBUG("Input: Published command %s=%f for player %i", e.Command.c_str(), e.Value, e.PlayerID); } m_CommandQueue.clear(); } diff --git a/src/Game/Systems/PlayerSpawnSystem.cpp b/src/Game/Systems/PlayerSpawnSystem.cpp index a522f679..0bf5bdea 100644 --- a/src/Game/Systems/PlayerSpawnSystem.cpp +++ b/src/Game/Systems/PlayerSpawnSystem.cpp @@ -8,17 +8,29 @@ PlayerSpawnSystem::PlayerSpawnSystem(EventBroker* eventBroker) void PlayerSpawnSystem::Update(World* world, double dt) { - auto componentPools = world->GetComponentPools(); - auto spawnerPool = componentPools.find("Spawner"); - if (spawnerPool == componentPools.end()) { + auto playerSpawns = world->GetComponents("PlayerSpawn"); + if (playerSpawns == nullptr) { return; } -; + for (auto& team : m_SpawnRequests) { - for (auto& spawner : *spawnerPool->second) { - Events::SpawnerSpawn e; - e.Spawner = EntityWrapper(world, spawner.EntityID); - m_EventBroker->Publish(e); + 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(); diff --git a/src/Game/Systems/SpawnerSystem.cpp b/src/Game/Systems/SpawnerSystem.cpp index c1122d98..3454c58b 100644 --- a/src/Game/Systems/SpawnerSystem.cpp +++ b/src/Game/Systems/SpawnerSystem.cpp @@ -5,43 +5,57 @@ SpawnerSystem::SpawnerSystem(EventBroker* eventBroker) : System(eventBroker) EVENT_SUBSCRIBE_MEMBER(m_OnSpawnerSpawn, &SpawnerSystem::OnSpawnerSpawn); } -bool SpawnerSystem::OnSpawnerSpawn(Events::SpawnerSpawn& e) +EntityWrapper SpawnerSystem::Spawn(EntityWrapper spawner, EntityWrapper parent /*= EntityWrapper::Invalid*/) { - EntityWrapper& spawner = e.Spawner; + // 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 spawnPoints; + std::vector spawnPoints; for (auto kv = children.first; kv != children.second; ++kv) { const EntityID& child = kv->second; if (spawner.World->HasComponent(child, "SpawnPoint")) { - spawnPoints.push_back(child); + spawnPoints.push_back(EntityWrapper(spawner.World, child)); } } - EntityID spawnPoint = spawner.ID; + // Choose a random SpawnPoint + EntityWrapper spawnPoint = spawner; if (!spawnPoints.empty()) { - // Select a random spawn point - 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; + 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(); + } } - spawnEntity(spawner, e.Parent.ID, Transform::AbsolutePosition(spawner.World, spawnPoint)); - - return true; -} - -void SpawnerSystem::spawnEntity(EntityWrapper spawner, EntityID parent, glm::vec3 position) -{ + + // Load the entity file and parse it const std::string& entityFilePath = spawner["Spawner"]["EntityFile"]; auto entityFile = ResourceManager::Load(entityFilePath); if (entityFile == nullptr) { - return; + return EntityWrapper::Invalid; } - EntityFileParser parser(entityFile); - EntityWrapper spawnedEntity(spawner.World, parser.MergeEntities(spawner.World, parent)); - spawnedEntity["Transform"]["Position"] = position; + 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; } \ No newline at end of file From 942064c450977355aba5928619273a8e094692b4 Mon Sep 17 00:00:00 2001 From: William Moberg Date: Mon, 18 Jan 2016 13:07:04 +0100 Subject: [PATCH 22/23] Removed class PlayerSystem and associated files. --- include/Engine/Collision/TriggerSystem.h | 14 +++++++- include/Game/Systems/PlayerSystem.h | 34 ------------------- src/Engine/Collision/TriggerSystem.cpp | 17 ++++++++++ src/Game/Game.cpp | 2 -- src/Game/Systems/PlayerSystem.cpp | 42 ------------------------ 5 files changed, 30 insertions(+), 79 deletions(-) delete mode 100644 include/Game/Systems/PlayerSystem.h delete mode 100644 src/Game/Systems/PlayerSystem.cpp diff --git a/include/Engine/Collision/TriggerSystem.h b/include/Engine/Collision/TriggerSystem.h index ee53ad9b..65e7c271 100644 --- a/include/Engine/Collision/TriggerSystem.h +++ b/include/Engine/Collision/TriggerSystem.h @@ -18,7 +18,11 @@ public: : 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, EntityWrapper& entity, ComponentWrapper& component, double dt) override; @@ -27,6 +31,14 @@ private: std::unordered_map> m_EntitiesTouchingTrigger; std::unordered_map> m_EntitiesCompletelyInTrigger; + //TODO: Only exists for debug purposes, remove later. + EventRelay m_EEnter; + bool OnEnter(const Events::TriggerEnter &event); + EventRelay m_ETouch; + bool OnTouch(const Events::TriggerTouch &event); + EventRelay m_ELeave; + bool OnLeave(const Events::TriggerLeave &event); + //True if leave event was thrown. bool throwLeaveIfWasInTrigger(std::unordered_set& triggerSet, EntityID pId, EntityID tId); template diff --git a/include/Game/Systems/PlayerSystem.h b/include/Game/Systems/PlayerSystem.h deleted file mode 100644 index a74cbb9f..00000000 --- a/include/Game/Systems/PlayerSystem.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef PlayerSystem_h__ -#define PlayerSystem_h__ - -#include -#include - -#include "Common.h" -#include "Core/System.h" -#include "Collision/ETrigger.h" - -class PlayerSystem : public PureSystem -{ -public: - PlayerSystem(EventBroker* eventBroker) - : System(eventBroker) - , PureSystem("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, EntityWrapper& entity, ComponentWrapper& component, double dt) override; -private: - float m_Speed = 5; - EventRelay m_EEnter; - bool OnEnter(const Events::TriggerEnter &event); - EventRelay m_ETouch; - bool PlayerSystem::OnTouch(const Events::TriggerTouch &event); - EventRelay m_ELeave; - bool PlayerSystem::OnLeave(const Events::TriggerLeave &event); -}; - -#endif \ No newline at end of file diff --git a/src/Engine/Collision/TriggerSystem.cpp b/src/Engine/Collision/TriggerSystem.cpp index 58d1e332..0ff4345e 100644 --- a/src/Engine/Collision/TriggerSystem.cpp +++ b/src/Engine/Collision/TriggerSystem.cpp @@ -78,3 +78,20 @@ bool TriggerSystem::throwLeaveIfWasInTrigger(std::unordered_set& trigg 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; +} \ No newline at end of file diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index ff1e28fd..b0ffa646 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -3,7 +3,6 @@ #include "Collision/TriggerSystem.h" #include "Collision/CollisionSystem.h" #include "Systems/RaptorCopterSystem.h" -#include "Systems/PlayerSystem.h" #include "Systems/HealthSystem.h" #include "Systems/PlayerMovementSystem.h" #include "Systems/SpawnerSystem.h" @@ -76,7 +75,6 @@ Game::Game(int argc, char* argv[]) // All systems with orderlevel 0 will be updated first. unsigned int updateOrderLevel = 0; m_SystemPipeline->AddSystem(updateOrderLevel); - m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel, m_Renderer); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); diff --git a/src/Game/Systems/PlayerSystem.cpp b/src/Game/Systems/PlayerSystem.cpp deleted file mode 100644 index 8cdddf84..00000000 --- a/src/Game/Systems/PlayerSystem.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "Systems/PlayerSystem.h" - -void PlayerSystem::UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) -{ - component["Velocity"] = glm::vec3(0.f, 0.f, 0.f); - if ((bool&)component["Forward"] == true) { - ((glm::vec3&)component["Velocity"]).z = m_Speed * float(dt) * -1; - - } - if ((bool&)component["Left"] == true) { - ((glm::vec3&)component["Velocity"]).x = m_Speed * float(dt) * -1; - } - if ((bool&)component["Back"] == true) { - ((glm::vec3&)component["Velocity"]).z = m_Speed * float(dt); - } - if ((bool&)component["Right"] == true) { - ((glm::vec3&)component["Velocity"]).x = m_Speed * float(dt); - } - - if ((glm::vec3)component["Velocity"] != glm::vec3(0.f)) { - ComponentWrapper& transform = world->GetComponent(component.EntityID, "Transform"); - (glm::vec3&)transform["Position"] += (glm::vec3)component["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; -} \ No newline at end of file From 0669d917679b4ab55f4de8ef65774cfbe14d65c8 Mon Sep 17 00:00:00 2001 From: William Moberg Date: Mon, 18 Jan 2016 13:29:10 +0100 Subject: [PATCH 23/23] CollisionSystem loops over Collidable components. --- include/Engine/Collision/CollisionSystem.h | 2 +- src/Engine/Collision/CollisionSystem.cpp | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/include/Engine/Collision/CollisionSystem.h b/include/Engine/Collision/CollisionSystem.h index ea6004d9..561c5158 100644 --- a/include/Engine/Collision/CollisionSystem.h +++ b/include/Engine/Collision/CollisionSystem.h @@ -15,7 +15,7 @@ class CollisionSystem : public PureSystem public: CollisionSystem(EventBroker* eventBroker, Octree* octree) : System(eventBroker) - , PureSystem("AABB") + , PureSystem("Collidable") , m_Octree(octree) , zPress(false) { diff --git a/src/Engine/Collision/CollisionSystem.cpp b/src/Engine/Collision/CollisionSystem.cpp index 96e49153..d841c75e 100644 --- a/src/Engine/Collision/CollisionSystem.cpp +++ b/src/Engine/Collision/CollisionSystem.cpp @@ -30,10 +30,8 @@ void CollisionSystem::UpdateComponent(World* world, EntityWrapper& entity, Compo continue; } if (Collision::AABBVsAABB(boxA, boxB, resolutionVector)) { - if (entity.HasComponent("Physics")) { - (glm::vec3&)cTransform["Position"] += resolutionVector; - cPhysics["Velocity"] = glm::vec3(0, 0, 0); - } + (glm::vec3&)cTransform["Position"] += resolutionVector; + cPhysics["Velocity"] = glm::vec3(0, 0, 0); } }