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

# Conflicts:
#	include/Game/Game.h
#	src/Engine/Core/OctTree.cpp
#	src/Game/Game.cpp
#	src/Tests/CMakeLists.txt
#	src/Tests/OctTreeTest.cpp
#	src/Tests/WorldTest.cpp
This commit is contained in:
verysecrethero
2015-12-18 11:57:21 +01:00
42 changed files with 1804 additions and 310 deletions
+59
View File
@@ -0,0 +1,59 @@
#ifndef Collision_h__
#define Collision_h__
//NOTE: Collision.h needs to be #included before <GLFW/glfw3.h>,
//because Collision #includes "RawModel.h", which has "Texture.h", which has "OpenGL.h" which must be #included first
//or you will get "fatal error C1189: #error: gl.h included before glew.h"
#include <vector>
#include "Core/Ray.h"
#include "Core/AABB.h"
#include "Engine/Rendering/RawModel.h"
#include "Core/Entity.h"
class World;
struct ComponentWrapper;
namespace Collision
{
//Return true if the ray hits the box.
bool RayAABBIntr(const Ray& ray, const AABB& box);
bool RayVsAABB(const Ray& ray, const AABB& box);
//Return true if the ray hits the box, also outputs distance from ray origin to intersection point in [outDistance].
bool RayVsAABB(const Ray& ray, const AABB& box, float& outDistance);
//Return true if the ray hits any of the triangles in the model. Stops checking when a hit is detected.
bool RayVsModel(const Ray& ray,
const std::vector<RawModel::Vertex>& modelVertices,
const std::vector<unsigned int>& modelIndices);
//Return true if the ray hits any of the triangles in the model.
//Also returns the position of the intersection point. Will loop through all the whole model indices.
bool RayVsModel(const Ray& ray,
const std::vector<RawModel::Vertex>& modelVertices,
const std::vector<unsigned int>& modelIndices,
glm::vec3& outHitPosition);
//Return true if the ray hits any of the triangles in the model.
//Also returns the distance from the ray origin to the closest
//intersection point, and the barycentric u,v-coordinates. Will loop through all the whole model indices.
bool RayVsModel(const Ray& ray,
const std::vector<RawModel::Vertex>& modelVertices,
const std::vector<unsigned int>& modelIndices,
float& outDistance,
float& outUCoord,
float& outVCoord);
//Return true if the boxes are intersecting.
bool AABBVsAABB(const AABB& a, const AABB& b);
//Return true if the boxes are intersecting.
//Also outputs the minimum translation that box [a] would need in order to resolve collision.
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);
}
#endif
@@ -0,0 +1,31 @@
#ifndef CollisionSystem_h__
#define CollisionSystem_h__
#include <GLFW/glfw3.h>
#include <glm/common.hpp>
#include "Common.h"
#include "Core/System.h"
#include "Core/EventBroker.h"
#include "Core/EKeyUp.h"
class CollisionSystem : public PureSystem
{
public:
CollisionSystem(EventBroker* eventBroker)
: PureSystem(eventBroker, "AABB")
, zPress(false)
{
//TODO: Debug stuff, remove later.
EVENT_SUBSCRIBE_MEMBER(m_EKeyUp, &CollisionSystem::OnKeyUp);
}
virtual void UpdateComponent(World* world, ComponentWrapper& cAABB, double dt) override;
private:
bool zPress;
EventRelay<CollisionSystem, Events::KeyUp> m_EKeyUp;
bool OnKeyUp(const Events::KeyUp &event);
};
#endif
+39
View File
@@ -0,0 +1,39 @@
#ifndef Events_TriggerEnter_h__
#define Events_TriggerEnter_h__
#include "../Core/EventBroker.h"
#include "../Core/Entity.h"
namespace Events
{
/** Thrown once, when an entity is only touching a trigger. */
struct TriggerTouch : Event
{
/** The id of the entity that touches the trigger. */
EntityID Entity;
/** The id of the trigger entity. */
EntityID Trigger;
};
/** Thrown once, when an entity has completely left a trigger. */
struct TriggerLeave : Event
{
/** The id of the entity that left the trigger. */
EntityID Entity;
/** The id of the trigger entity. */
EntityID Trigger;
};
/** Thrown once, when an entity is completely contained inside a trigger. */
struct TriggerEnter : Event
{
/** The id of the entity that entered the trigger. */
EntityID Entity;
/** The id of the trigger entity. */
EntityID Trigger;
};
}
#endif
+38
View File
@@ -0,0 +1,38 @@
#ifndef TriggerSystem_h__
#define TriggerSystem_h__
#include <glm/common.hpp>
#include <unordered_set>
#include "Core/System.h"
#include "Core/EventBroker.h"
#include "ETrigger.h"
class AABB;
class TriggerSystem : public PureSystem
{
public:
TriggerSystem(EventBroker* eventBroker)
: PureSystem(eventBroker, "Trigger")
{}
virtual void UpdateComponent(World* world, ComponentWrapper& collision, double dt) override;
private:
std::unordered_map<EntityID, std::unordered_set<EntityID>> m_EntitiesTouchingTrigger;
std::unordered_map<EntityID, std::unordered_set<EntityID>> m_EntitiesCompletelyInTrigger;
//True if leave event was thrown.
bool throwLeaveIfWasInTrigger(std::unordered_set<EntityID>& triggerSet, EntityID pId, EntityID tId);
template<typename Event>
void publish(EntityID pId, EntityID tId)
{
Event e;
e.Trigger = tId;
e.Entity = pId;
m_EventBroker->Publish(e);
}
};
#endif
+2 -1
View File
@@ -4,4 +4,5 @@
#include <map>
#include <unordered_map>
#include "Core/Util/Logging.h"
#include "Core/Util/Logging.h"
#include "Core/Util/IfDebug.h"
+2 -1
View File
@@ -9,6 +9,7 @@ public:
AABB() = default;
//No checks are made. Values in minPos must be less than values in maxPos, i.e. min.x < max.x, etc.
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);
virtual ~AABB();
@@ -16,7 +17,7 @@ public:
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& Size() const { return 2.0f * m_HalfSize; }
const glm::vec3 Size() const { return 2.0f * m_HalfSize; }
const glm::vec3& HalfSize() const { return m_HalfSize; }
private:
glm::vec3 m_MinCorner;
-17
View File
@@ -1,17 +0,0 @@
#ifndef Collision_h__
#define Collision_h__
#include "Core/Ray.h"
#include "Core/AABB.h"
namespace Collision
{
bool RayAABBIntr(const Ray& ray, const AABB& box);
bool RayVsAABB(const Ray& ray, const AABB& box);
bool RayVsAABB(const Ray& ray, const AABB& box, float& outDistance);
bool AABBVsAABB(const AABB& a, const AABB& b);
}
#endif
+1 -1
View File
@@ -20,7 +20,7 @@ public:
~ComponentPoolForwardIterator() = default;
ComponentPoolForwardIterator& operator=(const ComponentPoolForwardIterator& other) = default;
ComponentPoolForwardIterator& operator++();
ComponentPoolForwardIterator& operator++(int);
ComponentPoolForwardIterator operator++(int);
bool operator!=(const ComponentPoolForwardIterator& other) const;
bool operator==(const ComponentPoolForwardIterator& other) const;
ComponentWrapper operator*() const;
+1 -1
View File
@@ -253,7 +253,7 @@ public:
}
//Postfix increment i.e. iter++. Prefer pre-increment (++iter) for efficiency.
MemoryPoolForwardIterator& operator++(int)
MemoryPoolForwardIterator operator++(int)
{
MemoryPoolForwardIterator<T> copyIter(*this);
operator++();
+65 -27
View File
@@ -3,9 +3,7 @@
#include "Core/AABB.h"
struct Ray;
class World;
class Camera;
class Ray;
class OctTree
{
@@ -13,54 +11,94 @@ public:
struct Output
{
float CollideDistance;
};
};
OctTree();
~OctTree();
//For the root OctTree, [octTreeBounds] should be a box containing the entire level.
OctTree(const AABB& octTreeBounds, int subDivisions);
//We should only ever need one OctTree in the game, and it should not need to be copied.
//Define these if the OctTree suddenly needs to be copied, think of the children OctTree* ptrs.
//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;
//Collision test function. WTODO: Probably remove or relocate elsewhere, Collision system?
void Update(float dt, World* world, Camera* cam);
//Add a dynamic object (one that moves around) into the tree.
void AddDynamicObject(const AABB& box);
//Add a static object (that does not move) into the tree.
void AddStaticObject(const AABB& box);
void BoxesInSameRegion(const AABB& box, std::vector<AABB>& outBoxes) const;
//Get the boxes that are in the same area as the input [box], the boxes are put in [outBoxes].
void BoxesInSameRegion(const AABB& box, std::vector<AABB>& outBoxes);
//Empty the tree of all objects, static and dynamic.
void ClearObjects();
//Empty the tree of all dynamic objects. Static objects remain in the tree.
void ClearDynamicObjects();
//Returns true if the ray collides with something in the tree. Result is written to [data].
bool RayCollides(const Ray& ray, Output& data) const;
bool RayCollides(const Ray& ray, Output& data);
//Returns true if the box collides with something in the tree.
//On collision with a box, that box is written to [outBoxIntersected].
bool BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const;
//Note: More efficient than calling BoxesInSameRegion from outside and testing there.
bool BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected);
private:
OctTree* m_Children[8];
//WTODO: Do -derived class from AABB- struct containing AABB, with a bool Tested, falsify at
//start of Collision test, set on check, don't check if set already. Solves duplicate boxes in tree.
//Store indices in the struct, pointing to grand ancestor list of boxes, need the same AABB not copies to save Tested.
//WTODO: Boxes collide with themselves? Fix somehow, maybe float epsilon stuff.
std::vector<AABB> m_StaticObjects;
std::vector<AABB> m_DynamicObjects;
AABB m_Box;
struct OctChild; //Fwd declaration;
struct ContainedObject
{
ContainedObject()
: Box(AABB())
, Checked(false)
{}
ContainedObject(AABB box)
: Box(box)
, Checked(false)
{}
AABB Box;
bool Checked;
};
OctChild* m_Root;
std::vector<ContainedObject> m_StaticObjects;
std::vector<ContainedObject> m_DynamicObjects;
bool m_UpdatedOnce;
unsigned int m_BoxID;
glm::vec3 m_PrevPos;
glm::quat m_PrevOri;
inline bool hasChildren() const;
public:
int childIndexContainingPoint(const glm::vec3& point) const;
std::vector<int> childIndicesContainingBox(const AABB& box) const;
void falsifyObjectChecks();
struct OctChild
{
~OctChild();
OctChild(const AABB& octTreeBounds,
int subDivisions,
std::vector<OctTree::ContainedObject>& staticObjects,
std::vector<OctTree::ContainedObject>& dynamicObjects);
OctChild(const OctChild& other) = delete;
OctChild(const OctChild&& other) = delete;
OctChild& operator= (const OctChild& other) = delete;
void AddDynamicObject(const AABB& box);
void AddStaticObject(const AABB& box);
void BoxesInSameRegion(const AABB& box, std::vector<AABB>& outBoxes) const;
void ClearObjects();
void ClearDynamicObjects();
bool RayCollides(const Ray& ray, Output& data) const;
bool BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const;
OctChild* m_Children[8];
//Indices into the lists in OctTree.
std::vector<int> m_StaticObjIndices;
std::vector<int> m_DynamicObjIndices;
AABB m_Box;
//Reference to the lists in OctTree.
std::vector<OctTree::ContainedObject>& m_StaticObjectsRef;
std::vector<OctTree::ContainedObject>& m_DynamicObjectsRef;
inline bool hasChildren() const;
int childIndexContainingPoint(const glm::vec3& point) const;
std::vector<int> childIndicesContainingBox(const AABB& box) const;
};
};
#endif
+22 -3
View File
@@ -2,11 +2,30 @@
#define Ray_h__
#include "../GLM.h"
#include "Common.h"
struct Ray
class Ray
{
glm::vec3 Origin;
glm::vec3 Direction;
public:
Ray(const glm::vec3& origin, const glm::vec3& dir)
: m_Origin(origin)
, m_Direction(glm::normalize(dir))
{
DEBUG_IF(true) {
if (glm::any(glm::isnan(m_Direction))) {
LOG_WARNING("Ray Direction was set to the zero-vector, expect unknown side effects and/or crashes.");
}
}
}
const glm::vec3& Origin() const { return m_Origin; }
const glm::vec3& Direction() const { return m_Direction; }
//Sets the ray origin at parameter.
void SetOrigin(const glm::vec3& origin) { m_Origin = origin; }
//Normalizes the parameter and sets direction to it.
void SetDirection(const glm::vec3& direction) { m_Direction = glm::normalize(direction); }
private:
glm::vec3 m_Origin;
glm::vec3 m_Direction;
};
#endif // Ray_h__
+12
View File
@@ -0,0 +1,12 @@
// Example:
// DEBUG_IF(condition) {
// // This code is executed only in debug mode and if condition is true.
// }
// NOTE: condition statement is not executed at all in release mode.
#ifndef DEBUG_IF
#ifndef DEBUG
#define DEBUG_IF(c) if(c)
#else
#define DEBUG_IF(c) if(false)
#endif
#endif