Compare commits

..

5 Commits

548 changed files with 6063 additions and 47294 deletions
-11
View File
@@ -4,14 +4,3 @@ bin/
lib/ lib/
# Because apparently nobody has any self control # Because apparently nobody has any self control
*.orig *.orig
*.suo
*.sdf
tools/MayaExporter/MayaExporter/x64/Debug/
tools/MayaExporter/x64/Debug/
tools/MayaExporter/MayaExporter/Debug/
tools/MayaExporter/MayaExporter/GeneratedFiles/
tools/MayaExporter/MayaExporter/x64/*
tools/MayaExporter/x64/*
-9
View File
@@ -14,9 +14,6 @@ endif()
if(CMAKE_COMPILER_IS_GNUCXX) if(CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
elseif(MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
endif() endif()
#set(BUILD_SHARED_LIBS FALSE) #set(BUILD_SHARED_LIBS FALSE)
@@ -37,12 +34,6 @@ foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES})
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY})
endforeach(OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES) endforeach(OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES)
# DEBUG definition
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS
$<$<CONFIG:Debug>:DEBUG>
$<$<CONFIG:RelWithDebInfo>:DEBUG>
)
include(cotire) include(cotire)
add_subdirectory(src/Engine) add_subdirectory(src/Engine)
add_subdirectory(src/Game) add_subdirectory(src/Game)
+1 -2
View File
@@ -11,8 +11,7 @@ Libraries bundled along with binaries for Windows (MSVC14), available as a submo
| **[libpng](http://www.libpng.org/pub/png/libpng.html)** | 1.6.19 | [libpng License](http://www.libpng.org/pub/png/src/libpng-LICENSE.txt) | | **[libpng](http://www.libpng.org/pub/png/libpng.html)** | 1.6.19 | [libpng License](http://www.libpng.org/pub/png/src/libpng-LICENSE.txt) |
| **[Xerces-C++](https://xerces.apache.org/xerces-c)** | 3.1.2 | [Apache License Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) | | **[Xerces-C++](https://xerces.apache.org/xerces-c)** | 3.1.2 | [Apache License Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) |
| **[ImGui](https://github.com/ocornut/imgui)** | 2015-12-12 | [MIT License](https://github.com/ocornut/imgui/blob/de3a154f3801de22c8e0bd2aeabf663a70c05972/LICENSE) | | **[ImGui](https://github.com/ocornut/imgui)** | 2015-12-12 | [MIT License](https://github.com/ocornut/imgui/blob/de3a154f3801de22c8e0bd2aeabf663a70c05972/LICENSE) |
| **[nativefiledialog](https://github.com/mlabbe/nativefiledialog)** | 2016-01-08 | [nativefiledialog Licence](https://github.com/mlabbe/nativefiledialog/blob/master/LICENSE) | | **[nativefiledialog](https://github.com/mlabbe/nativefiledialog) | 2016-01-08 | https://github.com/mlabbe/nativefiledialog/blob/master/LICENSE |
| **[OpenAL](https://www.openal.org/)** | 1.1 | [OpenAL License](resources/Licenses/OpenAL.txt)
#### External libraries #### External libraries
Libraries that are too big to be bundled with the project. Libraries that are too big to be bundled with the project.
+1 -1
Submodule assets updated: 10a611659d...c8e631f449
+1 -1
Submodule deps updated: ed45883a44...bf83f099ba
+12 -61
View File
@@ -6,23 +6,15 @@
//or you will get "fatal error C1189: #error: gl.h included before glew.h" //or you will get "fatal error C1189: #error: gl.h included before glew.h"
#include <vector> #include <vector>
#include <boost/optional.hpp>
#include "../Core/Ray.h" #include "Core/Ray.h"
#include "../Core/AABB.h" #include "Core/AABB.h"
#include "Rendering/RawModelCustom.h" #include "Engine/Rendering/RawModel.h"
//#include "Rendering/RawModelAssimp.h" #include "Core/Entity.h"
#include "../Core/Transform.h"
#include "../Core/Entity.h"
#include "../Core/EntityWrapper.h"
#include "EntityAABB.h"
class World; class World;
struct ComponentWrapper; struct ComponentWrapper;
template<typename T>
class Octree;
namespace Collision namespace Collision
{ {
//Return true if the ray hits the box. //Return true if the ray hits the box.
@@ -31,77 +23,36 @@ 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]. //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); bool RayVsAABB(const Ray& ray, const AABB& box, float& outDistance);
//Return true if the ray hits the triangle.
bool RayVsTriangle(const Ray& ray,
const glm::vec3& v0,
const glm::vec3& v1,
const glm::vec3& v2,
bool trueOnNegativeDistance = false);
//Return true if the ray hits the triangle, and the distance is less than outDistance.
bool RayVsTriangle(const Ray& ray,
const glm::vec3& v0,
const glm::vec3& v1,
const glm::vec3& v2,
float& outDistance,
float& outUCoord,
float& outVCoord,
bool trueOnNegativeDistance = false);
//Return true if the ray hits any of the triangles in the model. Stops checking when a hit is detected. //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, bool RayVsModel(const Ray& ray,
const RawModel::Vertex* modelVertices, const std::vector<RawModel::Vertex>& modelVertices,
const std::vector<unsigned int>& modelIndices, const std::vector<unsigned int>& modelIndices);
const glm::mat4& modelMatrix);
//Return true if the ray hits any of the triangles in the model. //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. //Also returns the position of the intersection point. Will loop through all the whole model indices.
bool RayVsModel(const Ray& ray, bool RayVsModel(const Ray& ray,
const RawModel::Vertex* modelVertices, const std::vector<RawModel::Vertex>& modelVertices,
const std::vector<unsigned int>& modelIndices, const std::vector<unsigned int>& modelIndices,
const glm::mat4& modelMatrix,
glm::vec3& outHitPosition); glm::vec3& outHitPosition);
//Return true if the ray hits any of the triangles in the model. //Return true if the ray hits any of the triangles in the model.
//Also returns the distance from the ray origin to the closest //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. //intersection point, and the barycentric u,v-coordinates. Will loop through all the whole model indices.
bool RayVsModel(const Ray& ray, bool RayVsModel(const Ray& ray,
const RawModel::Vertex* modelVertices, const std::vector<RawModel::Vertex>& modelVertices,
const std::vector<unsigned int>& modelIndices, const std::vector<unsigned int>& modelIndices,
const glm::mat4& modelMatrix,
float& outDistance, float& outDistance,
float& outUCoord, float& outUCoord,
float& outVCoord); float& outVCoord);
bool AABBvsTriangles(const AABB& box,
const RawModel::Vertex* modelVertices,
const std::vector<unsigned int>& modelIndices,
const glm::mat4& modelMatrix,
glm::vec3& boxVelocity,
float verticalStepHeight,
bool& isOnGround,
glm::vec3& outResolutionVector);
//Detects collision, but does not resolve.
bool AABBvsTriangles(const AABB& box,
const RawModel::Vertex* modelVertices,
const std::vector<unsigned int>& modelIndices,
const glm::mat4& modelMatrix);
//Return true if the boxes are intersecting. //Return true if the boxes are intersecting.
bool AABBVsAABB(const AABB& a, const AABB& b); bool AABBVsAABB(const AABB& a, const AABB& b);
//Return true if the boxes are intersecting. //Return true if the boxes are intersecting.
//Also outputs the minimum translation that box [a] would need in order to resolve collision. //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 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 or Model component. //Returns true if the entity has a boundingbox. Outputs the aabb in [outBox].
// if takeModelBox is true, the AABB component will be ignored and box is calculated from Model. bool GetEntityBox(World* world, EntityID entity, AABB& outBox, bool forceBoxFromModel = false);
// if takeModelBox is false, the AABB component will be prefered, if it exists. bool GetEntityBox(World* world, ComponentWrapper& AABBComponent, AABB& outBox);
boost::optional<EntityAABB> EntityAbsoluteAABB(EntityWrapper& entity, bool takeModelBox = false);
boost::optional<EntityAABB> AbsoluteAABBExplosionEffect(EntityWrapper& entity);
//Returns the first entity hit by the input ray. entitiesPotentiallyHitSorted needs to be sorted
//by their distance to the ray, e.g. result from Octree<EntityAABB>::ObjectsPossiblyHitByRay.
//Returns boost::none if none was hit. outDistance will be the distance to the intersection point if the ray intersects.
boost::optional<EntityAABB> EntityFirstHitByRay(const Ray& ray, std::vector<EntityAABB> entitiesPotentiallyHitSorted, float& outDistance, glm::vec3& outIntersectPos);
//Returns the first entity hit by the input ray that exists in the octree.
//outDistance will be the distance to the intersection point if the ray intersects.
boost::optional<EntityAABB> EntityFirstHitByRay(const Ray& ray, Octree<EntityAABB>* octree, float& outDistance, glm::vec3& outIntersectPos);
} }
+15 -13
View File
@@ -4,26 +4,28 @@
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <glm/common.hpp> #include <glm/common.hpp>
#include "../Common.h" #include "Common.h"
#include "../Core/System.h" #include "Core/System.h"
#include "../Core/EventBroker.h" #include "Core/EventBroker.h"
#include "../Core/Octree.h" #include "Core/EKeyUp.h"
#include "EntityAABB.h"
class CollisionSystem : public PureSystem class CollisionSystem : public PureSystem
{ {
public: public:
CollisionSystem(SystemParams params, Octree<EntityAABB>* octree) CollisionSystem(EventBroker* eventBroker)
: System(params) : PureSystem(eventBroker, "AABB")
, PureSystem("Physics") , zPress(false)
, m_Octree(octree) {
{ } //TODO: Debug stuff, remove later.
EVENT_SUBSCRIBE_MEMBER(m_EKeyUp, &CollisionSystem::OnKeyUp);
}
virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cPhysics, double dt) override; virtual void UpdateComponent(World* world, ComponentWrapper& cAABB, double dt) override;
private: private:
Octree<EntityAABB>* m_Octree; bool zPress;
std::vector<EntityAABB> m_OctreeResult; EventRelay<CollisionSystem, Events::KeyUp> m_EKeyUp;
bool OnKeyUp(const Events::KeyUp &event);
}; };
#endif #endif
+7 -7
View File
@@ -2,7 +2,7 @@
#define Events_TriggerEnter_h__ #define Events_TriggerEnter_h__
#include "../Core/EventBroker.h" #include "../Core/EventBroker.h"
#include "../Core/EntityWrapper.h" #include "../Core/Entity.h"
namespace Events namespace Events
{ {
@@ -11,27 +11,27 @@ namespace Events
struct TriggerTouch : Event struct TriggerTouch : Event
{ {
/** The id of the entity that touches the trigger. */ /** The id of the entity that touches the trigger. */
EntityWrapper Entity; EntityID Entity;
/** The id of the trigger entity. */ /** The id of the trigger entity. */
EntityWrapper Trigger; EntityID Trigger;
}; };
/** Thrown once, when an entity has completely left a trigger. */ /** Thrown once, when an entity has completely left a trigger. */
struct TriggerLeave : Event struct TriggerLeave : Event
{ {
/** The id of the entity that left the trigger. */ /** The id of the entity that left the trigger. */
EntityWrapper Entity; EntityID Entity;
/** The id of the trigger entity. */ /** The id of the trigger entity. */
EntityWrapper Trigger; EntityID Trigger;
}; };
/** Thrown once, when an entity is completely contained inside a trigger. */ /** Thrown once, when an entity is completely contained inside a trigger. */
struct TriggerEnter : Event struct TriggerEnter : Event
{ {
/** The id of the entity that entered the trigger. */ /** The id of the entity that entered the trigger. */
EntityWrapper Entity; EntityID Entity;
/** The id of the trigger entity. */ /** The id of the trigger entity. */
EntityWrapper Trigger; EntityID Trigger;
}; };
} }
-22
View File
@@ -1,22 +0,0 @@
#ifndef EntityAABB_h__
#define EntityAABB_h__
#include "../Core/AABB.h"
#include "../Core/EntityWrapper.h"
struct EntityAABB : AABB
{
EntityAABB() = default;
EntityAABB(const glm::vec3& minPos, const glm::vec3& maxPos)
: AABB(minPos, maxPos)
{ }
EntityAABB(const AABB& aabb)
: AABB(aabb)
{ }
EntityWrapper Entity;
};
#endif
@@ -1,25 +0,0 @@
#ifndef FillFrustumOctreeSystem_h__
#define FillFrustumOctreeSystem_h__
#include "../Core/System.h"
#include "../Core/Octree.h"
#include "Collision.h"
#include "EntityAABB.h"
class FillFrustumOctreeSystem : public ImpureSystem, public PureSystem
{
public:
FillFrustumOctreeSystem(SystemParams params, Octree<EntityAABB>* octree)
: System(params)
, PureSystem("Model")
, m_Octree(octree)
{ }
virtual void Update(double dt) override;
virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) override;
private:
Octree<EntityAABB>* m_Octree;
};
#endif
@@ -1,25 +0,0 @@
#ifndef FillOctreeSystem_h__
#define FillOctreeSystem_h__
#include "../Core/System.h"
#include "../Core/Octree.h"
#include "Collision.h"
#include "EntityAABB.h"
class FillOctreeSystem : public ImpureSystem, public PureSystem
{
public:
FillOctreeSystem(SystemParams params, Octree<EntityAABB>* octree, const std::string& fillComponentType)
: System(params)
, PureSystem(fillComponentType)
, m_Octree(octree)
{ }
virtual void Update(double dt) override;
virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) override;
private:
Octree<EntityAABB>* m_Octree;
};
#endif
+12 -30
View File
@@ -4,51 +4,33 @@
#include <glm/common.hpp> #include <glm/common.hpp>
#include <unordered_set> #include <unordered_set>
#include "../Core/System.h" #include "Core/System.h"
#include "../Core/EventBroker.h" #include "Core/EventBroker.h"
#include "../Core/Octree.h"
#include "ETrigger.h" #include "ETrigger.h"
#include "EntityAABB.h"
class AABB; class AABB;
class TriggerSystem : public PureSystem class TriggerSystem : public PureSystem
{ {
public: public:
TriggerSystem(SystemParams params, Octree<EntityAABB>* octree) TriggerSystem(EventBroker* eventBroker)
: System(params) : PureSystem(eventBroker, "Trigger")
, 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(EntityWrapper& entity, ComponentWrapper& component, double dt) override; virtual void UpdateComponent(World* world, ComponentWrapper& collision, double dt) override;
private: private:
Octree<EntityAABB>* m_Octree; std::unordered_map<EntityID, std::unordered_set<EntityID>> m_EntitiesTouchingTrigger;
std::vector<EntityAABB> m_OctreeOut; std::unordered_map<EntityID, std::unordered_set<EntityID>> m_EntitiesCompletelyInTrigger;
std::unordered_map<EntityWrapper, std::unordered_set<EntityWrapper>> m_EntitiesTouchingTrigger;
std::unordered_map<EntityWrapper, std::unordered_set<EntityWrapper>> m_EntitiesCompletelyInTrigger;
//TODO: Only exists for debug purposes, remove later.
EventRelay<TriggerSystem, Events::TriggerEnter> m_EEnter;
bool OnEnter(const Events::TriggerEnter &event);
EventRelay<TriggerSystem, Events::TriggerTouch> m_ETouch;
bool OnTouch(const Events::TriggerTouch &event);
EventRelay<TriggerSystem, Events::TriggerLeave> m_ELeave;
bool OnLeave(const Events::TriggerLeave &event);
//True if leave event was thrown. //True if leave event was thrown.
bool throwLeaveIfWasInTrigger(std::unordered_set<EntityWrapper>& triggerSet, EntityWrapper colliderENtity, EntityWrapper triggerEntity); bool throwLeaveIfWasInTrigger(std::unordered_set<EntityID>& triggerSet, EntityID pId, EntityID tId);
template<typename Event> template<typename Event>
void publish(EntityWrapper collider, EntityWrapper trigger) void publish(EntityID pId, EntityID tId)
{ {
Event e; Event e;
e.Trigger = trigger; e.Trigger = tId;
e.Entity = collider; e.Entity = pId;
m_EventBroker->Publish(e); m_EventBroker->Publish(e);
} }
}; };
-3
View File
@@ -1,11 +1,8 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <sstream>
#include <vector> #include <vector>
#include <map> #include <map>
#include <unordered_map> #include <unordered_map>
#include <algorithm>
#include <array>
#include "Core/Util/Logging.h" #include "Core/Util/Logging.h"
#include "Core/Util/IfDebug.h" #include "Core/Util/IfDebug.h"
+4 -3
View File
@@ -9,19 +9,20 @@ public:
AABB() = default; AABB() = default;
//No checks are made. Values in minPos must be less than values in maxPos, i.e. min.x < max.x, etc. //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::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. //No checks are made. Size must consist of non-negative numbers.
static AABB FromOriginSize(const glm::vec3& origin, const glm::vec3& size); virtual void CreateFromCenter(const glm::vec3& center, const glm::vec3& size);
virtual ~AABB(); virtual ~AABB();
const glm::vec3& MinCorner() const { return m_MinCorner; } const glm::vec3& MinCorner() const { return m_MinCorner; }
const glm::vec3& MaxCorner() const { return m_MaxCorner; } const glm::vec3& MaxCorner() const { return m_MaxCorner; }
const glm::vec3& Origin() const { return m_Origin; } 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; } const glm::vec3& HalfSize() const { return m_HalfSize; }
private: private:
glm::vec3 m_MinCorner; glm::vec3 m_MinCorner;
glm::vec3 m_MaxCorner; glm::vec3 m_MaxCorner;
glm::vec3 m_Origin; glm::vec3 m_Center;
glm::vec3 m_HalfSize; glm::vec3 m_HalfSize;
}; };
+4 -12
View File
@@ -2,24 +2,18 @@
#define ComponentInfo_h__ #define ComponentInfo_h__
#include "../Common.h" #include "../Common.h"
#include <boost/shared_array.hpp>
struct ComponentInfo struct ComponentInfo
{ {
typedef int EnumType;
struct Meta_t struct Meta_t
{ {
std::string Annotation; std::string Annotation;
unsigned int Allocation = 0; unsigned int Allocation = 0;
std::map<std::string, std::string> FieldAnnotations; unsigned int Stride = 0;
std::map<std::string, std::map<std::string, EnumType>> FieldEnumDefinitions;
bool NetworkReplicated = true;
}; };
struct Field_t struct Field_t
{ {
std::string Name;
std::string Type; std::string Type;
unsigned int Offset; unsigned int Offset;
unsigned int Stride; unsigned int Stride;
@@ -27,11 +21,9 @@ struct ComponentInfo
std::string Name; std::string Name;
std::unordered_map<std::string, Field_t> Fields; std::unordered_map<std::string, Field_t> Fields;
std::vector<std::string> FieldsInOrder; std::vector<const Field_t*> FieldsInOrder;
std::vector<std::string> StringFields; Meta_t Meta;
unsigned int Stride = 0; std::shared_ptr<char> Defaults = nullptr;
boost::shared_array<char> Defaults = nullptr;
std::shared_ptr<Meta_t> Meta = nullptr;
}; };
template<> template<>
+2 -5
View File
@@ -1,7 +1,6 @@
#ifndef ComponentPool_h__ #ifndef ComponentPool_h__
#define ComponentPool_h__ #define ComponentPool_h__
#include <set>
#include "MemoryPool.h" #include "MemoryPool.h"
#include "ComponentInfo.h" #include "ComponentInfo.h"
#include "ComponentWrapper.h" #include "ComponentWrapper.h"
@@ -44,10 +43,9 @@ public:
ComponentPool(const ::ComponentInfo& ci) ComponentPool(const ::ComponentInfo& ci)
: m_ComponentInfo(ci) : m_ComponentInfo(ci)
, m_Pool(ci.Meta->Allocation, sizeof(EntityID) + ci.Stride) , m_Pool(ci.Meta.Allocation, sizeof(EntityID) + ci.Meta.Stride)
{ } { }
~ComponentPool(); ComponentPool(const ComponentPool& other) = delete;
ComponentPool(const ComponentPool& other);
ComponentPool(const ComponentPool&& other) = delete; ComponentPool(const ComponentPool&& other) = delete;
const ::ComponentInfo& ComponentInfo() const { return m_ComponentInfo; } const ::ComponentInfo& ComponentInfo() const { return m_ComponentInfo; }
@@ -63,7 +61,6 @@ public:
iterator begin() const; iterator begin() const;
iterator end() const; iterator end() const;
size_t size() const;
//Dumps information about what the pool memory looks like right now //Dumps information about what the pool memory looks like right now
//into an output stream (e.g. file/std::cout, anything that has an operator<<) //into an output stream (e.g. file/std::cout, anything that has an operator<<)
+25 -110
View File
@@ -1,30 +1,11 @@
#ifndef ComponentWrapper_h__ #ifndef ComponentWrapper_h__
#define ComponentWrapper_h__ #define ComponentWrapper_h__
#include <boost/shared_array.hpp>
#include <boost/any.hpp>
#include "../Common.h" #include "../Common.h"
#include "Entity.h" #include "Entity.h"
#include "ComponentInfo.h" #include "ComponentInfo.h"
#include "Util/Any.h" #include "Util/Any.h"
template <typename T, typename Enable = void>
struct ComponentField { };
template <typename T>
struct ComponentField<T, typename std::enable_if<std::is_trivially_copyable<T>::value>::type>
{
static T& Get(const ComponentInfo::Field_t& info, char* data) { return *reinterpret_cast<T*>(data); }
static void Set(const ComponentInfo::Field_t& info, char* data, const T& value) { Get(data) = value; }
};
template <>
struct ComponentField<std::string, void>
{
static std::string& Get(const ComponentInfo::Field_t& info, char* data) { return **reinterpret_cast<std::string**>(data); }
static void Set(const ComponentInfo::Field_t& info, char* data, const std::string& value) { Get(info, data) = value; }
};
struct ComponentWrapper struct ComponentWrapper
{ {
ComponentWrapper(const ComponentInfo& componentInfo, char* data) ComponentWrapper(const ComponentInfo& componentInfo, char* data)
@@ -37,60 +18,21 @@ struct ComponentWrapper
const ::EntityID EntityID; const ::EntityID EntityID;
char* Data; char* Data;
ComponentInfo::EnumType Enum(const char* fieldName, const char* enumKey) template <typename T>
T& Property(std::string name)
{ {
return Info.Meta->FieldEnumDefinitions.at(fieldName).at(enumKey); unsigned int offset = Info.Fields.at(name).Offset;
return *reinterpret_cast<T*>(&Data[offset]);
} }
template <typename T> template <typename T>
T& Field(std::string name) void SetProperty(std::string name, const T value) { Property<T>(name) = value; }
{
const ComponentInfo::Field_t& field = Info.Fields.at(name);
if (sizeof(T) > field.Stride) {
std::stringstream message;
message << "Type size of \"" << typeid(T).name() << "\" doesn't match size of component field \"" << Info.Name << "." << name << "\"!";
throw new std::runtime_error(message.str().c_str());
}
return *reinterpret_cast<T*>(&Data[field.Offset]);
}
template <typename T>
void SetField(std::string name, const T value) { Field<T>(name) = value; }
//template <typename T> //template <typename T>
//void SetField(std::string name, T& value) { Field<T>(name) = value; } //void SetProperty(std::string name, T& value) { Property<T>(name) = value; }
// Specialization for string literals // Specialization for string literals
template <std::size_t N> template <std::size_t N>
void SetField(std::string name, const char(&value)[N]) { Field<std::string>(name) = std::string(value); } void SetProperty(std::string name, const char(&value)[N]) { Property<std::string>(name) = std::string(value); }
void Copy(ComponentWrapper& destination)
{
// Copy trivial data
memcpy(destination.Data, Data, Info.Stride);
// Duplicate strings
SolidifyStrings(destination);
}
// When component data has been copied, strings need to be reconstructed or they'll refer to the same data!
static void SolidifyStrings(ComponentWrapper& component)
{
for (auto& name : component.Info.StringFields) {
std::size_t offset = component.Info.Fields.at(name).Offset;
std::string value = *reinterpret_cast<const std::string*>(component.Data + offset);
new (component.Data + offset) std::string(value);
}
}
// This needs to be called to properly free component data, because strings.
static void Destroy(ComponentInfo info, char* data)
{
// Call std::string destructors
for (auto& name : info.StringFields) {
std::size_t offset = info.Fields.at(name).Offset;
auto field = reinterpret_cast<std::string*>(data + offset);
field->~basic_string();
}
}
struct SubscriptProxy struct SubscriptProxy
{ {
@@ -105,77 +47,50 @@ struct ComponentWrapper
std::string m_PropertyName; std::string m_PropertyName;
public: public:
// Return the integer value of an enum type key for this field template <typename T>
ComponentInfo::EnumType Enum(const char* enumKey) { return m_Component->Enum(m_PropertyName.c_str(), enumKey); } operator T&() { return m_Component->Property<T>(m_PropertyName); }
template <typename T> template <typename T>
operator T&() { return m_Component->Field<T>(m_PropertyName); } void operator=(const T val) { m_Component->SetProperty<T>(m_PropertyName, val); }
template <typename T>
void operator=(const T val) { m_Component->SetField<T>(m_PropertyName, val); }
// TODO: Pass by reference and rvalue (universal reference?) // TODO: Pass by reference and rvalue (universal reference?)
//template <typename T> //template <typename T>
//void operator=(T& val) { m_Component->SetField<T>(m_PropertyName, val); } //void operator=(T& val) { m_Component->SetProperty<T>(m_PropertyName, val); }
// Specialization for string literals // Specialization for string literals
template <std::size_t N> template<std::size_t N>
void operator=(const char(&val)[N]) { m_Component->SetField<N>(m_PropertyName, val); } void operator=(const char(&val)[N]) { m_Component->SetProperty<N>(m_PropertyName, val); }
}; };
SubscriptProxy operator[](std::string propertyName) { return SubscriptProxy(this, propertyName); } SubscriptProxy operator[](std::string propertyName) { return SubscriptProxy(this, propertyName); }
}; };
// A component wrapper that "owns" its data through a shared pointer
struct SharedComponentWrapper : ComponentWrapper
{
SharedComponentWrapper(const ComponentInfo& componentInfo, boost::shared_array<char> data)
: ComponentWrapper(componentInfo, data.get())
, m_DataReference(data)
{ }
private:
boost::shared_array<char> m_DataReference;
};
// TODO: Move this to Tests once entity importing is finished // TODO: Move this to Tests once entity importing is finished
class ComponentWrapperFactory class ComponentWrapperFactory
{ {
public: public:
ComponentWrapperFactory() = default; ComponentWrapperFactory() = default;
ComponentWrapperFactory(std::string componentTypeName, unsigned int allocation = 0) ComponentWrapperFactory(std::string componentTypeName, std::size_t allocation = 0)
{ {
m_ComponentInfo.Name = componentTypeName; m_ComponentInfo.Name = componentTypeName;
m_ComponentInfo.Meta = std::make_shared<ComponentInfo::Meta_t>(); m_ComponentInfo.Meta.Allocation = allocation;
m_ComponentInfo.Meta->Allocation = allocation;
} }
template <typename T> template <typename T>
void AddProperty(std::string fieldName, T defaultValue) void AddProperty(std::string fieldName, T defaultValue)
{ {
auto& field = m_ComponentInfo.Fields[fieldName]; m_DefaultValues.push_back(defaultValue);
field.Name = fieldName; m_ComponentInfo.Fields[fieldName].Name = typeid(T).name();
field.Type = typeid(T).name(); m_ComponentInfo.Fields[fieldName].Offset = m_ComponentInfo.Meta.Stride;
field.Offset = m_ComponentInfo.Stride; m_ComponentInfo.Fields[fieldName].Stride = sizeof(T);
field.Stride = sizeof(T); m_ComponentInfo.Meta.Stride += sizeof(T);
m_ComponentInfo.FieldsInOrder.push_back(field.Name);
if (field.Type == typeid(std::string).name()) {
field.Type = "string";
m_ComponentInfo.StringFields.push_back(field.Name);
}
m_ComponentInfo.Stride += sizeof(T);
m_DefaultValues.push_back(std::make_pair(field, defaultValue));
} }
ComponentInfo& Finalize() ComponentInfo& Finalize()
{ {
m_ComponentInfo.Defaults = boost::shared_array<char>(new char[m_ComponentInfo.Stride]); m_ComponentInfo.Defaults = std::shared_ptr<char>(new char[m_ComponentInfo.Meta.Stride]);
std::size_t offset = 0; std::size_t offset = 0;
for (auto& pair : m_DefaultValues) { for (auto& val : m_DefaultValues) {
if (pair.first.Type == "string") { memcpy(m_ComponentInfo.Defaults.get() + offset, val.Data.get(), val.Size);
new (m_ComponentInfo.Defaults.get() + offset) std::string(*reinterpret_cast<std::string*>(pair.second.Data.get())); offset += val.Size;
} else {
memcpy(m_ComponentInfo.Defaults.get() + offset, pair.second.Data.get(), pair.second.Size);
}
offset += pair.second.Size;
} }
return m_ComponentInfo; return m_ComponentInfo;
@@ -185,7 +100,7 @@ public:
private: private:
ComponentInfo m_ComponentInfo; ComponentInfo m_ComponentInfo;
std::vector<std::pair<ComponentInfo::Field_t, Any>> m_DefaultValues; std::vector<Any> m_DefaultValues;
}; };
#endif #endif
+31 -25
View File
@@ -3,10 +3,10 @@
#include <string> #include <string>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/range/adaptors.hpp>
#include <ini_file/ini_file.hpp>
#include "../Common.h" #include "../Common.h"
#include "ResourceManager.h" #include "ResourceManager.h"
@@ -20,46 +20,52 @@ private:
public: public:
template <typename T> template <typename T>
T Get(std::string key, T defaultValue); T Get(std::string key, T defaultValue);
template <typename T>
std::vector<std::pair<std::string, T>> GetAll(std::string key);
template <typename T> template <typename T>
void Set(std::string key, T value); void Set(std::string key, T value);
const ini_file::section* GetSection(std::string section);
const ini_file::section_map& GetSections() { return m_Merged; }
const ini_file::param* GetParam(std::string key);
void SaveToDisk(); void SaveToDisk();
private: private:
boost::filesystem::path m_Path; boost::filesystem::path m_Path;
boost::property_tree::ptree m_PTreeDefaults; ini_file::section_map m_Defaults;
boost::property_tree::ptree m_PTreeOverrides; ini_file::section_map m_Overrides;
boost::property_tree::ptree m_PTreeMerged; ini_file::section_map m_Merged;
// Merge ini file section map b into a
void mergeINI(ini_file::section_map& a, const ini_file::section_map& b);
// Convert an ini key delimited by periods to a section and a param
boost::optional<std::pair<std::string, std::string>> tokenizeKey(std::string key);
}; };
template <typename T> template <typename T>
T ConfigFile::Get(std::string key, T defaultValue) T ConfigFile::Get(std::string key, T defaultValue)
{ {
return m_PTreeMerged.get<T>(key, defaultValue); auto param = GetParam(key);
} if (param == nullptr) {
return defaultValue;
}
template <typename T> return boost::lexical_cast<T>(param->get_value());
std::vector<std::pair<std::string, T>> ConfigFile::GetAll(std::string key)
{
std::vector<std::pair<std::string, T>> out;
auto parent = m_PTreeMerged.find(key);
if (parent == m_PTreeMerged.not_found()) {
return out;
}
for (auto& child : parent->second) {
T value = boost::lexical_cast<T>(child.second.data());
out.push_back(std::make_pair(child.first, value));
}
return out;
} }
template <typename T> template <typename T>
void ConfigFile::Set(std::string key, T value) void ConfigFile::Set(std::string key, T value)
{ {
m_PTreeOverrides.put<T>(key, value); std::string section;
m_PTreeMerged.put<T>(key, value); std::string param;
if (auto tokens = tokenizeKey(key)) {
std::tie(section, param) = *tokens;
} else {
LOG_WARNING("%s: Malformed config key \"%s\"", m_Path.string().c_str(), key.c_str());
return;
}
m_Overrides[section][param] = boost::lexical_cast<std::string>(value);
m_Merged[section][param] = boost::lexical_cast<std::string>(value);
} }
#endif #endif
+157
View File
@@ -0,0 +1,157 @@
#ifndef DeveloperConsole_h__
#define DeveloperConsole_h__
#include <iostream>
#include <boost/lexical_cast.hpp>
#include <boost/tokenizer.hpp>
#include "../Common.h"
#include "ConfigFile.h"
class DeveloperConsole
{
public:
DeveloperConsole() = delete;
static void MergeConfig(std::string configFile)
{
auto config = ResourceManager::Load<ConfigFile>("Config.ini");
LOG_DEBUG("Debug.LogLevel %i", config->Get<int>("Debug.LogLevel", -1));
config->Set("Debug.LogLevel", 8);
LOG_DEBUG("Debug.LogLevel %i", config->Get<int>("Debug.LogLevel", -1));
config->Set("Test.TesTest.Testies", "Hello");
config->SaveToDisk();
for (auto& section : config->GetSections()) {
for (auto& param : *section.second) {
std::cout << "// " << param.second->get_comment() << std::endl;
std::cout << section.first << "." << param.first << " " << param.second->get_value() << std::endl;
}
}
for (auto& section : config->GetSections()) {
for (auto& param : *section.second) {
std::string key = section.first + "." + param.first;
m_VariableBindingSetters[key] = [config, key](std::string value) {
config->Set<std::string>(key, value);
};
m_VariableBindingGetters[key] = [config, key]() {
return config->Get<std::string>(key, "");
};
}
}
}
template <typename T>
static typename std::enable_if<std::is_enum<T>::value, void>::type
BindVariable(std::string path, T& variable)
{
BindVariable<T, std::underlying_type<T>::type>(path, variable);
}
template <typename T, typename R = T>
static typename std::enable_if<!std::is_enum<R>::value, void>::type
BindVariable(std::string path, T& variable)
{
m_VariableBindingSetters[path] = [&variable](std::string value) {
variable = static_cast<T>(boost::lexical_cast<R>(value));
};
m_VariableBindingGetters[path] = [&variable]() {
return boost::lexical_cast<std::string>(static_cast<R>(variable));
};
}
static void Consume(const std::string& command)
{
if (command.empty()) {
return;
}
boost::char_separator<char> argumentSeparator(" ");
tokenizer tokens(command, argumentSeparator);
for (tokenizer::const_iterator it = tokens.begin(); it != tokens.end(); it++) {
consumeToken(it, tokens.end());
}
}
static void Consume(std::istream& stream)
{
std::string input;
std::getline(stream, input);
Consume(input);
/*if (stream.peek() == '\n') {
printValue(key);
} else {
std::string newValue;
stream >> newValue;
if (m_VariableBindingSetters.find(key) != m_VariableBindingSetters.end()) {
m_VariableBindingSetters.at(key)(newValue);
} else {
std::cout << "Unknown path: " << key << std::endl;
}
return;
for (auto& config : m_ConfigFiles) {
config->Set(key, newValue);
config->SaveToDisk();
LOG_DEBUG("Key %s set to new value %s and saved to disk.", key.c_str(), newValue.c_str());
}
} */
}
private:
typedef boost::tokenizer<boost::char_separator<char>> tokenizer;
static std::map<std::string, std::function<std::string()>> m_VariableBindingGetters;
static std::map<std::string, std::function<void(std::string)>> m_VariableBindingSetters;
static std::map<std::string, std::function<std::string(std::string)>> m_VariableBindingMappers;
static std::map<std::string, std::string> m_VariableDocumentation;
static void consumeToken(tokenizer::iterator& token, const tokenizer::iterator end)
{
tokenizer::iterator next = token;
next++;
if (next == end) {
printValue(token);
} else {
setValue(token, end);
}
}
static void printValue(tokenizer::iterator token)
{
std::string key = *token;
std::string value;
if (m_VariableBindingGetters.find(key) != m_VariableBindingGetters.end()) {
std::cout << key << " = " << m_VariableBindingGetters.at(key)() << std::endl;
} else {
std::cout << "Unknown path: " << key << std::endl;
}
return;
if (!value.empty()) {
std::cout << key << " = " << value << std::endl;
} else {
std::cerr << "Unknown path: " << key << std::endl;
}
}
static void setValue(tokenizer::iterator& token, const tokenizer::iterator end)
{
std::string key = *token;
std::string value = *(++token);
if (m_VariableBindingSetters.find(key) != m_VariableBindingSetters.end()) {
m_VariableBindingSetters.at(key)(value);
} else {
std::cout << "Unknown path: " << key << std::endl;
}
}
};
#endif
-18
View File
@@ -1,18 +0,0 @@
#ifndef EAmmoPickup_h__
#define EAmmoPickup_h__
#include "EventBroker.h"
#include "../Core/EntityWrapper.h"
namespace Events
{
struct AmmoPickup : Event
{
EntityWrapper Player;
int AmmoGain;
};
}
#endif
-20
View File
@@ -1,20 +0,0 @@
#ifndef ECaptured_h__
#define ECaptured_h__
#include "EventBroker.h"
#include "../Core/Entity.h"
#include "Engine/GLM.h"
namespace Events
{
//triggers when a capturePoint has been taken over
struct Captured : Event
{
int TeamNumberThatCapturedCapturePoint;
EntityID CapturePointID;
};
}
#endif
-20
View File
@@ -1,20 +0,0 @@
#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
-21
View File
@@ -1,21 +0,0 @@
#ifndef EComponentDeleted_h__
#define EComponentDeleted_h__
#include "../Common.h"
#include "Event.h"
#include "Entity.h"
namespace Events
{
struct ComponentDeleted : Event
{
EntityID Entity;
std::string ComponentType;
// True if the component was deleted as a result of the entity it was attached to being deleted
bool Cascaded;
};
}
#endif
-19
View File
@@ -1,19 +0,0 @@
#ifndef EEntityDeleted_h__
#define EEntityDeleted_h__
#include "Event.h"
#include "Entity.h"
namespace Events
{
struct EntityDeleted : Event
{
EntityID DeletedEntity;
// True if the entity deletion was triggered because the entity's parent was deleted before it
bool Cascaded;
};
}
#endif
-3
View File
@@ -11,9 +11,6 @@ struct KeyDown : Event
{ {
/** GLFW key code */ /** GLFW key code */
int KeyCode; int KeyCode;
bool ModCtrl;
bool ModAlt;
bool ModShift;
}; };
} }
-3
View File
@@ -11,9 +11,6 @@ struct KeyUp : Event
{ {
/** GLFW key code */ /** GLFW key code */
int KeyCode; int KeyCode;
bool ModCtrl;
bool ModAlt;
bool ModShift;
}; };
} }
-22
View File
@@ -1,22 +0,0 @@
#ifndef EPause_h__
#define EPause_h__
#include "EventBroker.h"
#include "World.h"
namespace Events
{
struct Pause : Event
{
::World* World;
};
struct Resume : Event
{
::World* World;
};
}
#endif
-17
View File
@@ -1,17 +0,0 @@
#ifndef EPickupSpawned_h__
#define EPickupSpawned_h__
#include "Core/Event.h"
#include "Core/EntityWrapper.h"
namespace Events
{
struct PickupSpawned : Event
{
EntityWrapper Pickup;
};
}
#endif
+5 -4
View File
@@ -2,16 +2,17 @@
#define EPlayerDamage_h__ #define EPlayerDamage_h__
#include "EventBroker.h" #include "EventBroker.h"
#include "../Core/EntityWrapper.h" #include "../Core/Entity.h"
namespace Events namespace Events
{ {
struct PlayerDamage : Event struct PlayerDamage : Event
{ {
EntityWrapper Inflictor; double DamageAmount;
EntityWrapper Victim; EntityID PlayerDamagedID;
double Damage; //optional TypeOfDamage
std::string TypeOfDamage;
}; };
} }
+3 -2
View File
@@ -2,7 +2,7 @@
#define EPlayerDeath_h__ #define EPlayerDeath_h__
#include "EventBroker.h" #include "EventBroker.h"
#include "../Core/EntityWrapper.h" #include "../Core/Entity.h"
namespace Events namespace Events
{ {
@@ -10,7 +10,8 @@ namespace Events
struct PlayerDeath : Event struct PlayerDeath : Event
{ {
//KilledBy,KilledByWhat is optional for now. It might be used later in the playerlog-system //KilledBy,KilledByWhat is optional for now. It might be used later in the playerlog-system
EntityWrapper Player; EntityID KilledBy;
EntityID PlayerID;
std::string KilledByWhat; std::string KilledByWhat;
}; };
+6 -6
View File
@@ -2,16 +2,16 @@
#define EPlayerHealthPickup_h__ #define EPlayerHealthPickup_h__
#include "EventBroker.h" #include "EventBroker.h"
#include "../Core/EntityWrapper.h" #include "../Core/Entity.h"
namespace Events namespace Events
{ {
struct PlayerHealthPickup : Event struct PlayerHealthPickup : Event
{ {
EntityWrapper Player; double HealthAmount;
double HealthAmount; EntityID PlayerHealedID;
}; };
} }
-20
View File
@@ -1,20 +0,0 @@
#ifndef EPlayerSpawned_h__
#define EPlayerSpawned_h__
#include "Core/Event.h"
#include "Core/EntityWrapper.h"
namespace Events
{
struct PlayerSpawned : Event
{
int PlayerID;
EntityWrapper Player;
EntityWrapper Spawner;
std::string PlayerName;
};
}
#endif
-18
View File
@@ -1,18 +0,0 @@
#ifndef EShoot_h__
#define EShoot_h__
#include "EventBroker.h"
#include "../Core/EntityWrapper.h"
namespace Events
{
struct Shoot : Event
{
EntityWrapper Inflictor;
double Damage;
};
}
#endif
-20
View File
@@ -1,20 +0,0 @@
#ifndef EWin_h__
#define EWin_h__
#include "EventBroker.h"
#include "../Core/Entity.h"
#include "Engine/GLM.h"
namespace Events
{
//triggers when a team has captured all capturePoints
struct Win : Event
{
//can be 0 = none, 1,2
int TeamThatWon;
};
}
#endif
-1
View File
@@ -4,5 +4,4 @@
typedef unsigned int EntityID; typedef unsigned int EntityID;
const static unsigned int EntityID_Invalid = -1; const static unsigned int EntityID_Invalid = -1;
#endif #endif
+8 -8
View File
@@ -285,7 +285,7 @@ private:
XSValue::Status status; XSValue::Status status;
XSValue* val = XSValue::getActualValue(child->getNodeValue(), XSValue::dt_integer, status); XSValue* val = XSValue::getActualValue(child->getNodeValue(), XSValue::dt_integer, status);
compInfo.Meta->Allocation += val->fData.fValue.f_int; compInfo.Meta.Allocation += val->fData.fValue.f_int;
} }
// Save documentation string // Save documentation string
@@ -293,11 +293,11 @@ private:
if (documentationTags->getLength() != 0) { if (documentationTags->getLength() != 0) {
auto child = documentationTags->item(0)->getFirstChild(); auto child = documentationTags->item(0)->getFirstChild();
if (child != nullptr) { if (child != nullptr) {
compInfo.Meta->Annotation = XSTR(child->getNodeValue()); compInfo.Meta.Annotation = XSTR(child->getNodeValue());
} }
} }
// TODO: Parse annotation string XML // TODO: Parse annotation string XML
// compInfo.Meta->Allocation = ... // compInfo.Meta.Allocation = ...
} else { } else {
std::cout << "Warning: Component is missing an annotation!" << std::endl; std::cout << "Warning: Component is missing an annotation!" << std::endl;
} }
@@ -344,7 +344,7 @@ private:
fieldOffset += getTypeStride(type); fieldOffset += getTypeStride(type);
} }
compInfo.Stride = fieldOffset; compInfo.Meta.Stride = fieldOffset;
m_ComponentInfo[compInfo.Name] = compInfo; m_ComponentInfo[compInfo.Name] = compInfo;
} }
} }
@@ -367,14 +367,14 @@ private:
std::string componentName = XSTR(component->getLocalName()); std::string componentName = XSTR(component->getLocalName());
auto& compInfo = m_ComponentInfo.at(componentName); auto& compInfo = m_ComponentInfo.at(componentName);
compInfo.Meta->Allocation += 1; compInfo.Meta.Allocation += 1;
} }
std::cout << "COMPONENT INFO" << std::endl; std::cout << "COMPONENT INFO" << std::endl;
for (auto& pair : m_ComponentInfo) { for (auto& pair : m_ComponentInfo) {
ComponentInfo& ci = pair.second; ComponentInfo& ci = pair.second;
std::cout << "Component: " << ci.Name << " (" << ci.Meta->Annotation << ")" << std::endl; std::cout << "Component: " << ci.Name << " (" << ci.Meta.Annotation << ")" << std::endl;
std::cout << " Allocation: " << ci.Meta->Allocation << std::endl; std::cout << " Allocation: " << ci.Meta.Allocation << std::endl;
std::cout << " Fields:" << std::endl; std::cout << " Fields:" << std::endl;
// Calculate component size // Calculate component size
@@ -393,7 +393,7 @@ private:
cs.ComponentName = ci.Name; cs.ComponentName = ci.Name;
cs.Stride = stride; cs.Stride = stride;
cs.Info = ci; cs.Info = ci;
cs.Data = new char[stride*ci.Meta->Allocation]; cs.Data = new char[stride*ci.Meta.Allocation];
m_ComponentStore[cs.ComponentName] = cs; m_ComponentStore[cs.ComponentName] = cs;
} }
} }
+148 -19
View File
@@ -73,15 +73,88 @@ public:
ComponentField ComponentField
}; };
EntityFileSAXHandler(const EntityFileHandler* handler, xercesc::SAX2XMLReader* reader); EntityFileSAXHandler(const EntityFileHandler* handler, xercesc::SAX2XMLReader* reader)
: m_Handler(handler)
, m_Reader(reader)
{
// 0 is imaginary world entity
m_EntityStack.push(0);
m_StateStack.push(State::Unknown);
}
void startElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname, const xercesc::Attributes& attrs) override; void startElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname, const xercesc::Attributes& attrs) override
void characters(const XMLCh* const chars, const XMLSize_t length) override; {
void endElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname) override; std::string name = XS::ToString(_localName);
void warning(const xercesc::SAXParseException& e); if (m_StateStack.top() == State::Unknown || m_StateStack.top() == State::Entity) {
void error(const xercesc::SAXParseException& e); if (name == "Entity") {
void fatalError(const xercesc::SAXParseException& e); 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;
}
private: private:
const EntityFileHandler* m_Handler; const EntityFileHandler* m_Handler;
@@ -95,14 +168,73 @@ private:
std::string m_CurrentField; std::string m_CurrentField;
std::map<std::string, std::string> m_CurrentAttributes; std::map<std::string, std::string> m_CurrentAttributes;
void onStartEntity(const xercesc::Attributes& attrs); void onStartEntity(const xercesc::Attributes& attrs)
void onEndEntity(); {
void onStartEntityRef(const xercesc::Attributes& attrs); EntityID parent = m_EntityStack.top();
void onStartComponent(const std::string& name);
void onEndComponent(const std::string& name); if (m_Handler->m_OnStartEntityCallback) {
void onStartComponentField(const std::string& field, const xercesc::Attributes& attrs); std::string name;
void onEndComponentField(const std::string& field); auto xName = attrs.getValue(XS::ToXMLCh("name"));
void onFieldData(char* data); 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);
}
}; };
class EntityFileXMLErrorHandler : public xercesc::ErrorHandler class EntityFileXMLErrorHandler : public xercesc::ErrorHandler
@@ -137,13 +269,12 @@ private:
class EntityFile : public Resource class EntityFile : public Resource
{ {
friend class ResourceManager; friend class ResourceManager;
friend class EntityFileSAXHandler;
private: private:
EntityFile(boost::filesystem::path path); EntityFile(boost::filesystem::path path);
~EntityFile(); ~EntityFile();
public: public:
static unsigned int GetTypeStride(std::string typeName); static std::size_t GetTypeStride(std::string typeName);
static void WriteAttributeData(char* outData, const ComponentInfo::Field_t& field, const std::map<std::string, std::string>& attributes); static void WriteAttributeData(char* outData, const ComponentInfo::Field_t& field, const std::map<std::string, std::string>& attributes);
static void WriteValueData(char* outData, const ComponentInfo::Field_t& field, const char* valueData); static void WriteValueData(char* outData, const ComponentInfo::Field_t& field, const char* valueData);
@@ -157,8 +288,6 @@ private:
xercesc::SAX2XMLReader* m_SAX2XMLReader; xercesc::SAX2XMLReader* m_SAX2XMLReader;
//std::map<std::string, ::ComponentInfo> m_ComponentInfo; //std::map<std::string, ::ComponentInfo> m_ComponentInfo;
//std::vector<std::string> m_EntityReferences; //std::vector<std::string> m_EntityReferences;
static void setReaderFeatures(xercesc::SAX2XMLReader* reader);
}; };
#endif #endif
+1 -2
View File
@@ -9,13 +9,12 @@ class EntityFileParser
public: public:
EntityFileParser(const EntityFile* entityFile); EntityFileParser(const EntityFile* entityFile);
EntityID MergeEntities(World* world, EntityID baseParent = EntityID_Invalid); void MergeEntities(World* world);
private: private:
const EntityFile* m_EntityFile; const EntityFile* m_EntityFile;
EntityFileHandler m_Handler; EntityFileHandler m_Handler;
World* m_World = nullptr; World* m_World = nullptr;
EntityID m_FirstEntity = EntityID_Invalid;
// Maps EntityIDs local to the file to real IDs in the world after they've been // Maps EntityIDs local to the file to real IDs in the world after they've been
// created in order to resolve parent-child relationships. // created in order to resolve parent-child relationships.
std::map<EntityID, EntityID> m_EntityIDMapper; std::map<EntityID, EntityID> m_EntityIDMapper;
@@ -3,11 +3,8 @@
#include <xercesc/framework/psvi/XSElementDeclaration.hpp> #include <xercesc/framework/psvi/XSElementDeclaration.hpp>
#include <xercesc/framework/psvi/XSComplexTypeDefinition.hpp> #include <xercesc/framework/psvi/XSComplexTypeDefinition.hpp>
#include <xercesc/framework/psvi/XSAttributeUse.hpp>
#include <xercesc/framework/psvi/XSAttributeDeclaration.hpp>
#include <xercesc/framework/psvi/XSParticle.hpp> #include <xercesc/framework/psvi/XSParticle.hpp>
#include <xercesc/framework/psvi/XSModelGroup.hpp> #include <xercesc/framework/psvi/XSModelGroup.hpp>
#include <xercesc/framework/psvi/XSModelGroupDefinition.hpp>
#include <xercesc/framework/psvi/XSAnnotation.hpp> #include <xercesc/framework/psvi/XSAnnotation.hpp>
#include <xercesc/framework/psvi/XSValue.hpp> #include <xercesc/framework/psvi/XSValue.hpp>
#include <xercesc/framework/MemBufFormatTarget.hpp> #include <xercesc/framework/MemBufFormatTarget.hpp>
@@ -34,7 +31,6 @@ private:
void onStartComponent(EntityID entity, std::string type); void onStartComponent(EntityID entity, std::string type);
void parseComponentInfo(); void parseComponentInfo();
void parseDefaults(); void parseDefaults();
std::string parseAnnotationXML(const XMLCh* xml);
}; };
#endif #endif
-58
View File
@@ -1,58 +0,0 @@
#ifndef EntityWrapper_h__
#define EntityWrapper_h__
#include <boost/optional.hpp>
#include <boost/functional/hash.hpp>
#include "ComponentWrapper.h"
class World;
struct EntityWrapper
{
EntityWrapper()
: World(nullptr)
, ID(EntityID_Invalid)
{ }
EntityWrapper(::World* world, EntityID id)
: World(world)
, ID(id)
{ }
::World* World;
EntityID ID;
static const EntityWrapper Invalid;
const std::string Name();
bool HasComponent(const std::string& componentType);
void AttachComponent(const char* componentName);
EntityWrapper Parent();
EntityWrapper FirstChildByName(const std::string& name);
EntityWrapper FirstParentWithComponent(const std::string& componentType);
bool IsChildOf(EntityWrapper potentialParent);
bool Valid() const;
ComponentWrapper operator[](const char* componentName);
bool operator==(const EntityWrapper& e) const;
bool operator!=(const EntityWrapper& e) const;
explicit operator EntityID() const;
private:
EntityWrapper firstChildByNameRecursive(const std::string& name, EntityID parent);
};
namespace std
{
template<> struct hash<EntityWrapper>
{
std::size_t operator()(const EntityWrapper& e) const
{
std::size_t seed = 0;
boost::hash_combine(seed, e.World);
boost::hash_combine(seed, e.ID);
return seed;
}
};
}
#endif
+3 -4
View File
@@ -5,7 +5,6 @@
#include <functional> #include <functional>
#include <list> #include <list>
#include <tuple> #include <tuple>
#include <set>
#include "../Common.h" #include "../Common.h"
#include "Event.h" #include "Event.h"
@@ -44,7 +43,7 @@ template <typename ContextType, typename EventType>
class EventRelay : public BaseEventRelay class EventRelay : public BaseEventRelay
{ {
public: public:
typedef std::function<bool(EventType&)> CallbackType; typedef std::function<bool(const EventType&)> CallbackType;
EventRelay() EventRelay()
: m_Callback(nullptr) : m_Callback(nullptr)
@@ -66,7 +65,7 @@ template <typename ContextType, typename EventType>
bool EventRelay<ContextType, EventType>::Receive(const std::shared_ptr<Event> event) bool EventRelay<ContextType, EventType>::Receive(const std::shared_ptr<Event> event)
{ {
if (m_Callback != nullptr) { if (m_Callback != nullptr) {
return m_Callback(*static_cast<EventType*>(event.get())); return m_Callback(*static_cast<const EventType*>(event.get()));
} else { } else {
return false; return false;
} }
@@ -108,7 +107,7 @@ private:
typedef std::unordered_map<ContextTypeName_t, EventRelays_t> ContextRelays_t; typedef std::unordered_map<ContextTypeName_t, EventRelays_t> ContextRelays_t;
ContextRelays_t m_ContextRelays; ContextRelays_t m_ContextRelays;
std::vector<BaseEventRelay*> m_RelaysToSubscribe; std::vector<BaseEventRelay*> m_RelaysToSubscribe;
std::unordered_map<BaseEventRelay*, std::tuple<EventID, ContextTypeName_t, EventTypeName_t>> m_RelaysToUnsubscribe; std::vector<std::tuple<EventID, ContextTypeName_t, EventTypeName_t>> m_RelaysToUnsubscribe;
typedef std::list<std::pair<EventTypeName_t, std::shared_ptr<Event>>> EventQueue_t; typedef std::list<std::pair<EventTypeName_t, std::shared_ptr<Event>>> EventQueue_t;
std::shared_ptr<EventQueue_t> m_EventQueueRead; std::shared_ptr<EventQueue_t> m_EventQueueRead;
-77
View File
@@ -1,77 +0,0 @@
#ifndef Frustum_h__
#define Frustum_h__
#include "../GLM.h"
#include "AABB.h"
#include <bitset>
//A frustum defined by 6 planes.
struct Frustum
{
//Contains points P in: dot(normal, P) + d = 0
struct Plane
{
glm::vec3 Normal;
float Distance;
};
enum class Output
{
Inside,
Outside,
Intersects
};
Plane Planes[6];
Frustum() = default;
Frustum(glm::mat4x4 viewProjMatrix)
{
//Order: Right, left, top, bottom, far, near.
int sign = 1;
for (int i = 0; i < 6; ++i) {
sign = -sign;
int index = i / 2;
Plane& plane = Planes[i];
plane.Normal.x = viewProjMatrix[0].w + sign * viewProjMatrix[0][index];
plane.Normal.y = viewProjMatrix[1].w + sign * viewProjMatrix[1][index];
plane.Normal.z = viewProjMatrix[2].w + sign * viewProjMatrix[2][index];
plane.Distance = viewProjMatrix[3].w + sign * viewProjMatrix[3][index];
float divByNormalLength = 1.0f / glm::length(plane.Normal);
plane.Normal *= divByNormalLength;
plane.Distance *= divByNormalLength;
}
}
Output VsAABB(const AABB& box) const
{
const glm::vec3& maxCorner = box.MaxCorner();
const glm::vec3& minCorner = box.MinCorner();
bool completelyInside = true;
for (const Plane& p : Planes) {
bool anyWasInside = false;
bool anyWasOutside = false;
//If points are on both sides of the plane, we can stop.
for (int i = 0; i < 8 && (!anyWasInside || !anyWasOutside); ++i) {
std::bitset<3> bits(i);
glm::vec3 corner;
corner.x = bits.test(0) ? maxCorner.x : minCorner.x;
corner.y = bits.test(1) ? maxCorner.y : minCorner.y;
corner.z = bits.test(2) ? maxCorner.z : minCorner.z;
if (glm::dot(p.Normal, corner) > -p.Distance) {
anyWasInside = true;
} else {
anyWasOutside = true;
}
}
if (!anyWasInside) {
return Output::Outside;
}
if (anyWasOutside) {
completelyInside = false;
}
}
return completelyInside ? Output::Inside : Output::Intersects;
}
};
#endif
+9 -36
View File
@@ -5,14 +5,6 @@
template <typename T> template <typename T>
class MemoryPoolForwardIterator; class MemoryPoolForwardIterator;
namespace DisableMemoryPool
{
//if true -> Pool allocation is not used when calling Allocate/Free, just use regular dynamic allocation.
//if false -> Use pool allocation.
//Should default to false, unless the DisableMemoryPool is true in the Config.ini files.
extern bool Value;
}
//This is the class to use if you want to allocate blocks (slots) of raw memory, with a fixed maximum size (stride). //This is the class to use if you want to allocate blocks (slots) of raw memory, with a fixed maximum size (stride).
//Additionally, if you know that every memory-block will contain one object of a specific type, (i.e. the stride for the slot //Additionally, if you know that every memory-block will contain one object of a specific type, (i.e. the stride for the slot
//will the size of the object type) you should use ObjectPool<T> instead, your life will become easier. //will the size of the object type) you should use ObjectPool<T> instead, your life will become easier.
@@ -66,25 +58,9 @@ public:
, m_LowestAllocatedSlot(m_NumSlots) , m_LowestAllocatedSlot(m_NumSlots)
{ } { }
MemoryPool(const MemoryPool<T>& other) //We may get problems with memory being released
: m_StartAddress(new char[other.m_NumSlots*other.m_Stride]) //prematurely, etc. if we allow copies.
, m_SlotIsAllocated(other.m_SlotIsAllocated) MemoryPool(const MemoryPool<T>& other) = delete;
, m_ExtraMemory()
, m_NumSlots(other.m_NumSlots)
, m_LowestAllocatedSlot(other.m_LowestAllocatedSlot)
, m_NumAllocatedSlots(other.m_NumAllocatedSlots)
, m_Stride(other.m_Stride)
, m_CurrentAllocSlot(other.m_CurrentAllocSlot)
{
// Copy statically allocated pool
memcpy(m_StartAddress, other.m_StartAddress, m_NumSlots*m_Stride);
// Copy dynamically allocated memory
for (char* otherAddr : other.m_ExtraMemory) {
char* addr = (char*)malloc(m_Stride);
memcpy(addr, otherAddr, m_Stride);
m_ExtraMemory.push_back(addr);
}
}
MemoryPool(const MemoryPool<T>&& other) = delete; MemoryPool(const MemoryPool<T>&& other) = delete;
//Free all memory that has been allocated. //Free all memory that has been allocated.
@@ -94,9 +70,8 @@ public:
delete[] m_StartAddress; delete[] m_StartAddress;
m_StartAddress = nullptr; m_StartAddress = nullptr;
} }
for (char* addr : m_ExtraMemory) { for (char* addr : m_ExtraMemory)
free(addr); free(addr);
}
m_ExtraMemory.clear(); m_ExtraMemory.clear();
} }
@@ -105,8 +80,8 @@ public:
//If element cannot be allocated in the pool, because the memory ran out, memory is allocated dynamically with malloc() "outside the pool". //If element cannot be allocated in the pool, because the memory ran out, memory is allocated dynamically with malloc() "outside the pool".
char* Allocate() char* Allocate()
{ {
for (; m_CurrentAllocSlot < m_NumSlots && m_SlotIsAllocated[m_CurrentAllocSlot] && !DisableMemoryPool::Value; ++m_CurrentAllocSlot); for (; m_CurrentAllocSlot < m_NumSlots && m_SlotIsAllocated[m_CurrentAllocSlot]; ++m_CurrentAllocSlot);
if (m_CurrentAllocSlot < m_NumSlots && !DisableMemoryPool::Value) { if (m_CurrentAllocSlot < m_NumSlots) {
if (m_LowestAllocatedSlot > m_CurrentAllocSlot) if (m_LowestAllocatedSlot > m_CurrentAllocSlot)
m_LowestAllocatedSlot = m_CurrentAllocSlot; m_LowestAllocatedSlot = m_CurrentAllocSlot;
//Mark the slot as allocated. //Mark the slot as allocated.
@@ -118,9 +93,7 @@ public:
else { else {
m_ExtraMemory.push_back((char*)malloc(m_Stride)); m_ExtraMemory.push_back((char*)malloc(m_Stride));
//We should preferably not enter here to avoid performance issues. Set more numMaxElements in constructor instead. //We should preferably not enter here to avoid performance issues. Set more numMaxElements in constructor instead.
if (!DisableMemoryPool::Value) { LOG_WARNING("Allocated slots exceed Pool size, extra memory allocated dynamically. Pool size: %u, dynamic size: %u.", m_NumSlots, m_ExtraMemory.size());
LOG_DEBUG("Allocated slots exceed Pool size, extra memory allocated dynamically. Pool size: %u, dynamic size: %u.", m_NumSlots, m_ExtraMemory.size());
}
return m_ExtraMemory.back(); return m_ExtraMemory.back();
} }
} }
@@ -135,7 +108,7 @@ public:
//(i.e. IsAllocatedInPool may give false positives) //(i.e. IsAllocatedInPool may give false positives)
//if it was malloc():ed //if it was malloc():ed
//so, we may enter here even if we shouldn't. //so, we may enter here even if we shouldn't.
if (!DisableMemoryPool::Value && IsAllocatedInPool(obj)) { if (IsAllocatedInPool(obj)) {
--m_NumAllocatedSlots; --m_NumAllocatedSlots;
const size_t freeSlot = (obj - m_StartAddress) / m_Stride; const size_t freeSlot = (obj - m_StartAddress) / m_Stride;
m_SlotIsAllocated[freeSlot] = false; m_SlotIsAllocated[freeSlot] = false;
+104
View File
@@ -0,0 +1,104 @@
#ifndef OctTree_h__
#define OctTree_h__
#include "Core/AABB.h"
class Ray;
class OctTree
{
public:
struct Output
{
float CollideDistance;
};
OctTree();
~OctTree();
//For the root OctTree, [octTreeBounds] should be a box containing the entire level.
OctTree(const AABB& octTreeBounds, int subDivisions);
//We cannot copy the OctTree as of now, because of the recursive dynamic allocation.
//Define these if the OctTree suddenly needs to be copied, think of the children OctChild* ptrs.
OctTree(const OctTree& other) = delete;
OctTree(const OctTree&& other) = delete;
OctTree& operator= (const OctTree& other) = delete;
//Add a dynamic object (one that moves around) into the tree.
void AddDynamicObject(const AABB& box);
//Add a static object (that does not move) into the tree.
void AddStaticObject(const AABB& box);
//Get the boxes that are in the same area as the input [box], the boxes are put in [outBoxes].
void BoxesInSameRegion(const AABB& box, std::vector<AABB>& outBoxes);
//Empty the tree of all objects, static and dynamic.
void ClearObjects();
//Empty the tree of all dynamic objects. Static objects remain in the tree.
void ClearDynamicObjects();
//Returns true if the ray collides with something in the tree. Result is written to [data].
bool RayCollides(const Ray& ray, Output& data);
//Returns true if the box collides with something in the tree.
//On collision with a box, that box is written to [outBoxIntersected].
//Note: More efficient than calling BoxesInSameRegion from outside and testing there.
bool BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected);
private:
struct OctChild; //Fwd declaration;
struct ContainedObject
{
ContainedObject()
: Box(AABB())
, Checked(false)
{}
ContainedObject(AABB box)
: Box(box)
, Checked(false)
{}
AABB Box;
bool Checked;
};
OctChild* m_Root;
std::vector<ContainedObject> m_StaticObjects;
std::vector<ContainedObject> m_DynamicObjects;
bool m_UpdatedOnce;
unsigned int m_BoxID;
glm::vec3 m_PrevPos;
glm::quat m_PrevOri;
void falsifyObjectChecks();
struct OctChild
{
~OctChild();
OctChild(const AABB& octTreeBounds,
int subDivisions,
std::vector<OctTree::ContainedObject>& staticObjects,
std::vector<OctTree::ContainedObject>& dynamicObjects);
OctChild(const OctChild& other) = delete;
OctChild(const OctChild&& other) = delete;
OctChild& operator= (const OctChild& other) = delete;
void AddDynamicObject(const AABB& box);
void AddStaticObject(const AABB& box);
void BoxesInSameRegion(const AABB& box, std::vector<AABB>& outBoxes) const;
void ClearObjects();
void ClearDynamicObjects();
bool RayCollides(const Ray& ray, Output& data) const;
bool BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const;
OctChild* m_Children[8];
//Indices into the lists in OctTree.
std::vector<int> m_StaticObjIndices;
std::vector<int> m_DynamicObjIndices;
AABB m_Box;
//Reference to the lists in OctTree.
std::vector<OctTree::ContainedObject>& m_StaticObjectsRef;
std::vector<OctTree::ContainedObject>& m_DynamicObjectsRef;
inline bool hasChildren() const;
int childIndexContainingPoint(const glm::vec3& point) const;
std::vector<int> childIndicesContainingBox(const AABB& box) const;
};
};
#endif
-360
View File
@@ -1,360 +0,0 @@
#ifndef Octree_h__
#define Octree_h__
#include <type_traits>
#include "../Common.h"
#include "AABB.h"
#include "Frustum.h"
#include "Ray.h"
namespace OctSpace
{
struct Output;
struct ContainedObject;
struct Child;
}
//T needs to be AABB, or inherit from AABB.
//T also needs to have a default constructor.
template<typename T>
class Octree
{
public:
Octree() = delete;
~Octree();
//For the root Octree, [octreeBounds] should be a box containing the entire level.
Octree(const AABB& octreeBounds, int subDivisions);
//We cannot copy the Octree as of now, because of the recursive dynamic allocation.
//Define these if the Octree suddenly needs to be copied, think of the children Child* ptrs.
Octree(const Octree& other) = delete;
Octree(const Octree&& other) = delete;
Octree& operator= (const Octree& other) = delete;
//Add a dynamic object (one that moves around) into the tree.
void AddDynamicObject(const T& object);
//Add a static object (that does not move) into the tree.
void AddStaticObject(const T& object);
//Get the objects that are in the same area as the input [box], the objects are put in [outObjects].
//The type Box must be AABB, or inherit from AABB.
template<typename Box>
void ObjectsInSameRegion(const Box& box, std::vector<T>& outObjects);
//Get the objects that are inside the frustum, the objects are put in outObjects.
void ObjectsInFrustum(const Frustum& frustum, std::vector<T>& outObjects);
//Get objects, which AABB the input ray intersects, the objects are put in outObjects.
void ObjectsPossiblyHitByRay(const Ray& ray, std::vector<T>& outObjects);
//Empty the tree of all objects, static and dynamic.
void ClearObjects();
//Empty the tree of all dynamic objects. Static objects remain in the tree.
void ClearDynamicObjects();
//Returns true if the ray collides with something in the tree. Result is written to [data].
bool RayCollides(const Ray& ray, OctSpace::Output& data);
//Returns true if the box collides with something in the tree.
//On collision with a box, that box is written to [outBoxIntersected].
//Note: More efficient than calling ObjectsInSameRegion from outside and testing there.
bool BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected);
private:
OctSpace::Child* m_Root;
std::vector<OctSpace::ContainedObject> m_StaticObjects;
std::vector<OctSpace::ContainedObject> m_DynamicObjects;
void falsifyObjectChecks();
};
namespace OctSpace
{
struct Output
{
float CollideDistance;
};
struct ContainedObject
{
ContainedObject()
: Box(nullptr)
, Checked(false)
{}
template<typename BoxlikeObject>
ContainedObject(const BoxlikeObject& box)
: Box(new BoxlikeObject(box))
, Checked(false)
{}
std::unique_ptr<AABB> Box;
bool Checked;
};
struct Child
{
~Child();
Child(const AABB& octTreeBounds,
int subDivisions,
std::vector<ContainedObject>& staticObjects,
std::vector<ContainedObject>& dynamicObjects);
Child(const Child& other) = delete;
Child(const Child&& other) = delete;
Child& operator= (const Child& other) = delete;
void AddDynamicObject(const AABB& box);
void AddStaticObject(const AABB& box);
template<typename T, typename Box>
void ObjectsInSameRegion(const Box& box, std::vector<T>& outObjects) const;
template<typename T>
void ObjectsInFrustum(const Frustum& frustum, std::vector<T>& outObjects, bool takeAllDontTest) const;
template<typename T>
void ObjectsPossiblyHitByRay(const Ray& ray, std::vector<T>& outObjects) const;
void ClearObjects();
void ClearDynamicObjects();
bool RayCollides(const Ray& ray, Output& data) const;
bool BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const;
Child* m_Children[8];
//Indices into the lists in Octree.
std::vector<int> m_StaticObjIndices;
std::vector<int> m_DynamicObjIndices;
AABB m_Box;
//Reference to the lists in Octree.
std::vector<ContainedObject>& m_StaticObjectsRef;
std::vector<ContainedObject>& m_DynamicObjectsRef;
inline bool hasChildren() const { return m_Children[0] != nullptr; }
int childIndexContainingPoint(const glm::vec3& point) const;
std::vector<int> childIndicesContainingBox(const AABB& box) const;
};
//To be able to sort child nodes and contained objects based on distance to ray origin.
struct RaySorterInfo
{
int Index;
float Distance;
};
bool isFirstLower(const RaySorterInfo& first, const RaySorterInfo& second);
}
template<typename T>
Octree<T>::Octree(const AABB& octTreeBounds, int subDivisions)
: m_Root(new OctSpace::Child(octTreeBounds, subDivisions, m_StaticObjects, m_DynamicObjects))
{
static_assert(std::is_base_of<AABB, T>::value, "template argument type T in Octree must be a subclass of AABB.");
}
template<typename T>
Octree<T>::~Octree()
{
delete m_Root;
}
template<typename T>
void Octree<T>::AddDynamicObject(const T& object)
{
m_Root->AddDynamicObject(object);
m_DynamicObjects.emplace_back(object);
}
template<typename T>
void Octree<T>::AddStaticObject(const T& object)
{
m_Root->AddStaticObject(object);
m_StaticObjects.emplace_back(object);
}
template<typename T>
template<typename Box>
void Octree<T>::ObjectsInSameRegion(const Box& box, std::vector<T>& outObjects)
{
static_assert(std::is_base_of<AABB, Box>::value, "template argument type Box in Octree<T>::ObjectsInSameRegion must be a subclass of AABB.");
falsifyObjectChecks();
m_Root->ObjectsInSameRegion(box, outObjects);
}
template<typename T>
void Octree<T>::ObjectsInFrustum(const Frustum& frustum, std::vector<T>& outObjects)
{
falsifyObjectChecks();
m_Root->ObjectsInFrustum(frustum, outObjects, false);
}
template<typename T>
void Octree<T>::ObjectsPossiblyHitByRay(const Ray& ray, std::vector<T>& outObjects)
{
falsifyObjectChecks();
m_Root->ObjectsPossiblyHitByRay(ray, outObjects);
}
template<typename T>
void Octree<T>::ClearObjects()
{
m_StaticObjects.clear();
m_DynamicObjects.clear();
m_Root->ClearObjects();
}
template<typename T>
void Octree<T>::ClearDynamicObjects()
{
m_DynamicObjects.clear();
m_Root->ClearDynamicObjects();
}
template<typename T>
bool Octree<T>::RayCollides(const Ray& ray, OctSpace::Output& data)
{
falsifyObjectChecks();
data.CollideDistance = -1;
return m_Root->RayCollides(ray, data);
}
template<typename T>
bool Octree<T>::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected)
{
falsifyObjectChecks();
return m_Root->BoxCollides(boxToTest, outBoxIntersected);
}
template<typename T>
void Octree<T>::falsifyObjectChecks()
{
for (auto& obj : m_StaticObjects) {
obj.Checked = false;
}
for (auto& obj : m_DynamicObjects) {
obj.Checked = false;
}
}
template<typename T, typename Box>
void OctSpace::Child::ObjectsInSameRegion(const Box& box, std::vector<T>& outObjects) const
{
if (hasChildren()) {
for (auto i : childIndicesContainingBox(box)) {
m_Children[i]->ObjectsInSameRegion(box, outObjects);
}
} else {
size_t startIndex = outObjects.size();
int numDuplicates = 0;
outObjects.resize(outObjects.size() + m_StaticObjIndices.size() + m_DynamicObjIndices.size());
for (size_t i = 0; i < m_StaticObjIndices.size(); ++i) {
ContainedObject& obj = m_StaticObjectsRef[m_StaticObjIndices[i]];
if (obj.Checked) {
++numDuplicates;
} else {
obj.Checked = true;
outObjects[startIndex + i - numDuplicates] = *static_cast<T*>(obj.Box.get());
}
}
for (size_t i = 0; i < m_DynamicObjIndices.size(); ++i) {
ContainedObject& obj = m_DynamicObjectsRef[m_DynamicObjIndices[i]];
if (obj.Checked) {
++numDuplicates;
} else {
obj.Checked = true;
outObjects[startIndex + i - numDuplicates] = *static_cast<T*>(obj.Box.get());
}
}
for (size_t i = 0; i < numDuplicates; ++i) {
outObjects.pop_back();
}
}
}
template<typename T>
void OctSpace::Child::ObjectsInFrustum(const Frustum& frustum, std::vector<T>& outObjects, bool takeAllDontTest) const
{
if (hasChildren()) {
for (const Child* c : m_Children) {
Frustum::Output out = Frustum::Output::Inside;
if (!takeAllDontTest) {
out = frustum.VsAABB(c->m_Box);
if (out == Frustum::Output::Outside) {
continue;
}
}
c->ObjectsInFrustum(frustum, outObjects, out == Frustum::Output::Inside);
}
} else {
size_t startIndex = outObjects.size();
int numDuplicates = 0;
outObjects.resize(outObjects.size() + m_StaticObjIndices.size() + m_DynamicObjIndices.size());
for (size_t i = 0; i < m_StaticObjIndices.size(); ++i) {
ContainedObject& obj = m_StaticObjectsRef[m_StaticObjIndices[i]];
if (obj.Checked || frustum.VsAABB(*obj.Box) == Frustum::Output::Outside) {
++numDuplicates;
} else {
obj.Checked = true;
outObjects[startIndex + i - numDuplicates] = *static_cast<T*>(obj.Box.get());
}
}
for (size_t i = 0; i < m_DynamicObjIndices.size(); ++i) {
ContainedObject& obj = m_DynamicObjectsRef[m_DynamicObjIndices[i]];
if (obj.Checked || frustum.VsAABB(*obj.Box) == Frustum::Output::Outside) {
++numDuplicates;
} else {
obj.Checked = true;
outObjects[startIndex + i - numDuplicates] = *static_cast<T*>(obj.Box.get());
}
}
for (size_t i = 0; i < numDuplicates; ++i) {
outObjects.pop_back();
}
}
}
template<typename T>
void OctSpace::Child::ObjectsPossiblyHitByRay(const Ray& ray, std::vector<T>& outObjects) const
{
//If the node AABB is missed, everything it contains is missed.
if (Collision::RayAABBIntr(ray, m_Box)) {
//If the ray shoots the tree, and it is a parent.
if (hasChildren()) {
//Sort children according to their distance from the ray origin.
std::vector<RaySorterInfo> childInfos;
childInfos.resize(8);
for (int i = 0; i < 8; ++i) {
childInfos[i] = { 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.
for (const RaySorterInfo& info : childInfos) {
m_Children[info.Index]->ObjectsPossiblyHitByRay(ray, outObjects);
}
} else {
//Check against boxes in the node.
bool intersected = false;
float dist;
//Sort all contained objects according to the distance from the ray origin to
//the intersection, if they are intersecting.
std::vector<RaySorterInfo> objectHitInfos;
objectHitInfos.reserve(m_StaticObjIndices.size() + m_DynamicObjIndices.size());
for (int i : m_StaticObjIndices) {
//If we haven't tested against this object before, and the ray hits.
if (!m_StaticObjectsRef[i].Checked &&
Collision::RayVsAABB(ray, *m_StaticObjectsRef[i].Box, dist)) {
objectHitInfos.push_back({ i, dist });
}
m_StaticObjectsRef[i].Checked = true;
}
for (int i : m_DynamicObjIndices) {
//If we haven't tested against this object before, and the ray hits.
if (!m_DynamicObjectsRef[i].Checked &&
Collision::RayVsAABB(ray, *m_DynamicObjectsRef[i].Box, dist)) {
objectHitInfos.push_back({ i + (int)m_StaticObjIndices.size(), dist });
}
m_DynamicObjectsRef[i].Checked = true;
}
std::sort(objectHitInfos.begin(), objectHitInfos.end(), isFirstLower);
int startSize = (int)outObjects.size();
outObjects.resize(startSize + objectHitInfos.size());
for (int i = 0; i < objectHitInfos.size(); ++i) {
outObjects[startSize + i] = (objectHitInfos[i].Index < m_StaticObjIndices.size()) ?
*static_cast<T*>(m_StaticObjectsRef[objectHitInfos[i].Index].Box.get()) :
*static_cast<T*>(m_DynamicObjectsRef[objectHitInfos[i].Index - m_StaticObjIndices.size()].Box.get());
}
}
}
}
#endif
-25
View File
@@ -1,25 +0,0 @@
#ifndef PerformanceTimer_h__
#define PerformanceTimer_h__
#include "../Common.h"
#include <boost/timer/timer.hpp>
using boost::timer::cpu_timer;
class PerformanceTimer
{
public:
static void StartTimer(std::string nameOfTimer);
static void StartTimerAndStopPrevious(std::string nameOfTimer);
static void StopTimer(std::string nameOfTimer);
static void SetFrameNumber(int frameNumber);
static void ResetAllTimers();
static void CreateExcelData();
private:
static std::map<std::string, cpu_timer> timers;
static cpu_timer m_Timer;
static std::string currentTimerRunning;
};
#endif
+1 -5
View File
@@ -2,15 +2,11 @@
#define Ray_h__ #define Ray_h__
#include "../GLM.h" #include "../GLM.h"
#include "../Common.h" #include "Common.h"
class Ray class Ray
{ {
public: public:
Ray()
: m_Origin(glm::vec3(0.f))
, m_Direction(glm::vec3(0, 0, 1))
{}
Ray(const glm::vec3& origin, const glm::vec3& dir) Ray(const glm::vec3& origin, const glm::vec3& dir)
: m_Origin(origin) : m_Origin(origin)
, m_Direction(glm::normalize(dir)) , m_Direction(glm::normalize(dir))
+39 -135
View File
@@ -12,6 +12,7 @@
/** Base Resource class. /** Base Resource class.
Implement this class for every resource to be handled by the resource manager. Implement this class for every resource to be handled by the resource manager.
Implement Create() to return a new object of that type.
*/ */
class Resource class Resource
{ {
@@ -21,23 +22,6 @@ protected:
Resource() { } Resource() { }
public: public:
//Should be thrown in a Resource's constructor if it cannot complete because another resource is still loading.
//Not actually an error, just a message to the ResourceManager.
struct StillLoadingException : public std::exception
{
virtual const char* what() const throw()
{
return "Resource is still loading.";
}
};
struct FailedLoadingException : public std::exception
{
FailedLoadingException(char const* const _Message)
: std::exception(_Message)
{ }
FailedLoadingException() :std::exception("Resource failed to load.") { };
};
// Pretend that this is a pure virtual function that you have to implement // Pretend that this is a pure virtual function that you have to implement
// FIXME: Why did we do this again instead of just using the constructor? // FIXME: Why did we do this again instead of just using the constructor?
// static Resource* Create(std::string resourceName); // static Resource* Create(std::string resourceName);
@@ -49,15 +33,6 @@ public:
unsigned int ResourceID; unsigned int ResourceID;
}; };
//Any class inheriting from this class will always be loaded on the master thread, not on a parallel worker thread.
//This is important in case some instructions must be executed on the main thread, e.g. OpenGL commands, like glBindBuffer.
//This resource can still be loaded asyncronously, but it will not be loaded in a thread, instead it's constructor will
//be called once on every ResourceManager::Load, just throw StillLoadingException in the constructor if it is not done yet.
class ThreadUnsafeResource : public Resource
{
friend class ResourceManager;
};
/** Singleton resource manager to keep track of and cache any external engine assets */ /** Singleton resource manager to keep track of and cache any external engine assets */
class ResourceManager class ResourceManager
{ {
@@ -65,7 +40,6 @@ private:
ResourceManager(); ResourceManager();
public: public:
static bool UseThreading;
/*static ResourceManager& Instance() /*static ResourceManager& Instance()
{ {
static ResourceManager s; static ResourceManager s;
@@ -75,6 +49,15 @@ public:
template <typename T> template <typename T>
static void RegisterType(std::string typeName); static void RegisterType(std::string typeName);
/** Preloads a resource and caches it for future use
@tparam T Resource type.
@param resourceName Fully qualified name of the resource to preload.
*/
template <typename T>
static void Preload(std::string resourceName);
static void Preload(std::string resourceType, std::string resourceName);
/** Checks if a resource is in cache /** Checks if a resource is in cache
@param resourceType Resource type as string. @param resourceType Resource type as string.
@@ -83,19 +66,14 @@ public:
// TODO: Templateify // TODO: Templateify
static bool IsResourceLoaded(std::string resourceType, std::string resourceName); static bool IsResourceLoaded(std::string resourceType, std::string resourceName);
/** Return value should always be a valid pointer, will throw an exception on error. /** Hot-loads a resource and caches it for future use
If the resource has been loaded already, returns a pointer to it.
If Async is false: Hot-loads a resource, caches it for future use, and returns a pointer to it.
If Async is true: If the resource is not loaded yet, starts loading the resource
in the background and throws Resource::StillLoadingException immediately.
@tparam T Resource type. @tparam T Resource type.
@tparam async Set this to true if the resource should be loaded asyncronously.
@param resourceName Fully qualified name of the resource to load. @param resourceName Fully qualified name of the resource to load.
*/ */
template <typename T, bool async = false> template <typename T>
static T* Load(const std::string& resourceName, Resource* parent = nullptr); static T* Load(std::string resourceName, Resource* parent = nullptr);
static Resource* Load(std::string resourceType, std::string resourceName, Resource* parent = nullptr);
/** Reloads an already loaded resource, keeping its resource ID intact. /** Reloads an already loaded resource, keeping its resource ID intact.
@@ -109,31 +87,19 @@ public:
static void Update(); static void Update();
private: private:
//This is a haxy way to make sure that IsMainThread is run when the program starts, so the master thread id is set.
struct MasterThreadChecker
{
MasterThreadChecker()
{
ResourceManager::IsMainThread();
}
};
const static MasterThreadChecker m_Checker;
static std::unordered_map<std::string, std::string> m_CompilerTypenameToResourceType; static std::unordered_map<std::string, std::string> m_CompilerTypenameToResourceType;
static std::unordered_map<std::string, std::function<Resource*(std::string)>> m_FactoryFunctions; // type -> factory function static std::unordered_map<std::string, std::function<Resource*(std::string)>> m_FactoryFunctions; // type -> factory function
static std::unordered_map<std::pair<std::string, std::string>, Resource*> m_ResourceCache; // (type, name) -> resource static std::unordered_map<std::pair<std::string, std::string>, Resource*> m_ResourceCache; // (type, name) -> resource
static std::unordered_map<std::string, Resource*> m_ResourceFromName; // name -> resource static std::unordered_map<std::string, Resource*> m_ResourceFromName; // name -> resource
static std::unordered_map<Resource*, Resource*> m_ResourceParents; // resource -> parent resource static std::unordered_map<Resource*, Resource*> m_ResourceParents; // resource -> parent resource
static std::unordered_map<std::pair<std::string, std::string>, boost::thread> m_LoadingThreads; // (type, name) -> loading thread
static std::unordered_map<std::pair<std::string, std::string>, std::exception_ptr> m_LoadingThreadExceptions; // (type, name) -> exceptions
static boost::recursive_mutex m_Mutex;
// TODO: Getters for IDs // TODO: Getters for IDs
static unsigned int m_CurrentResourceTypeID; static unsigned int m_CurrentResourceTypeID;
static std::unordered_map<std::string, unsigned int> m_ResourceTypeIDs; static std::unordered_map<std::string, unsigned int> m_ResourceTypeIDs;
// Number of resources of a type. Doubles as local ID. // Number of resources of a type. Doubles as local ID.
static std::unordered_map<unsigned int, unsigned int> m_ResourceCount; static std::unordered_map<unsigned int, unsigned int> m_ResourceCount;
// Flag to suppress hot-load warnings when a preloading resource chain loads another resource
static bool m_Preloading;
static FileWatcher m_FileWatcher; static FileWatcher m_FileWatcher;
static void fileWatcherCallback(std::string path, FileWatcher::FileEventFlags flags); static void fileWatcherCallback(std::string path, FileWatcher::FileEventFlags flags);
@@ -142,13 +108,22 @@ private:
static unsigned int GetNewResourceID(unsigned int typeID); static unsigned int GetNewResourceID(unsigned int typeID);
// Internal: Create a resource and cache it // Internal: Create a resource and cache it
static Resource* createResourceThrowing(const std::string& resourceType, const std::string& resourceName, Resource* parent); static Resource* CreateResource(std::string resourceType, std::string resourceName, Resource* parent);
static Resource* createResource(const std::string& resourceType, const std::string& resourceName, Resource* parent, std::exception_ptr& exception);
static Resource* cacheResource(Resource* resource, const std::string& resourceType, const std::string& resourceName, Resource* parent);
static bool IsMainThread();
}; };
template <typename T>
T* ResourceManager::Load(std::string resourceName, Resource* parent /* = nullptr */)
{
auto resourceTypename = typeid(T).name();
auto it = m_CompilerTypenameToResourceType.find(resourceTypename);
if (it == m_CompilerTypenameToResourceType.end()) {
LOG_ERROR("Failed to load resource \"%s\" of type \"%s\": type not registered", resourceName.c_str(), resourceTypename);
return nullptr;
}
return static_cast<T*>(Load(it->second, resourceName, parent));
}
template <typename T> template <typename T>
void ResourceManager::RegisterType(std::string typeName) void ResourceManager::RegisterType(std::string typeName)
{ {
@@ -156,88 +131,17 @@ void ResourceManager::RegisterType(std::string typeName)
m_FactoryFunctions[typeName] = [](std::string resourceName) { return new T(resourceName); }; m_FactoryFunctions[typeName] = [](std::string resourceName) { return new T(resourceName); };
} }
template <typename T, bool async> template <typename T>
static T* ResourceManager::Load(const std::string& resourceName, Resource* parent /* = nullptr */) void ResourceManager::Preload(std::string resourceName)
{ {
auto resourceTypename = typeid(T).name(); auto resourceTypename = typeid(T).name();
auto iter = m_CompilerTypenameToResourceType.find(resourceTypename); auto it = m_CompilerTypenameToResourceType.find(resourceTypename);
if (iter == m_CompilerTypenameToResourceType.end()) { if (it == m_CompilerTypenameToResourceType.end()) {
LOG_ERROR("Failed to load resource \"%s\" of type \"%s\": type not registered", resourceName.c_str(), resourceTypename); LOG_ERROR("Failed to load resource \"%s\" of type \"%s\": type not registered", resourceName.c_str(), resourceTypename);
throw Resource::FailedLoadingException(); return;
} }
std::string resourceType = iter->second; Preload(it->second, resourceName);
constexpr bool mustNotLoadInThread = std::is_base_of<ThreadUnsafeResource, T>::value;
if (mustNotLoadInThread && !IsMainThread()) {
LOG_ERROR("Failed to Load \"%s\": ThreadUnsafeResource type \"%s\" load in the constructor of another resource that is loaded asyncronously.", resourceName.c_str(), iter->second.c_str());
throw Resource::FailedLoadingException();
}
auto cacheKey = std::make_pair(resourceType, resourceName);
decltype(m_ResourceCache)::iterator it;
//If a thread has already been launched to load this resource.
auto tIt = m_LoadingThreads.find(cacheKey);
if (UseThreading && tIt != m_LoadingThreads.end()) {
if (async) {
//Throw StillLoadingException if the thread is still working.
if (!tIt->second.try_join_for(boost::chrono::nanoseconds(1))) {
throw Resource::StillLoadingException();
}
//Else we know the thread has completed.
} else {
//Wait for the thread to finish loading.
tIt->second.join();
}
//When the thread is done, delete the thread.
m_LoadingThreads.erase(tIt);
//Rethrow the thread exception if it threw any.
auto excIt = m_LoadingThreadExceptions.find(cacheKey);
std::exception_ptr exception = excIt->second;
m_LoadingThreadExceptions.erase(excIt);
if (exception) {
std::rethrow_exception(exception);
}
}
//If resource has already been cached and completely loaded.
{
boost::lock_guard<decltype(m_Mutex)> guard(m_Mutex);
it = m_ResourceCache.find(cacheKey);
if (it != m_ResourceCache.end()) {
if (it->second != nullptr) {
return static_cast<T*>(it->second);
} else {
//Don't return null on failure, exception instead.
throw Resource::FailedLoadingException();
}
}
}
//If resource is not cached..
if (UseThreading && async) {
if (mustNotLoadInThread) {
try {
return static_cast<T*>(createResourceThrowing(resourceType, resourceName, parent));
} catch (const Resource::StillLoadingException&) {
throw;
}
} else {
//Create a thread that loads the resource into cache.
m_LoadingThreads[cacheKey] = boost::thread(createResource, resourceType, resourceName, parent, m_LoadingThreadExceptions[cacheKey]);
throw Resource::StillLoadingException();
}
} else {
//load and return the resource.
while (true) {
try {
return static_cast<T*>(createResourceThrowing(resourceType, resourceName, parent));
} catch (const Resource::StillLoadingException&) {
continue;
} catch (const std::exception&) {
throw;
}
}
}
} }
#endif #endif
+13 -48
View File
@@ -3,83 +3,48 @@
#include "EventBroker.h" #include "EventBroker.h"
#include "World.h" #include "World.h"
#include "EntityWrapper.h"
#include "ComponentWrapper.h" #include "ComponentWrapper.h"
#include "EPlayerSpawned.h"
struct SystemParams
{
SystemParams(::World* World, ::EventBroker* EventBroker, bool IsClient, bool IsServer)
: World(World)
, EventBroker(EventBroker)
, IsClient(IsClient)
, IsServer(IsServer)
{ }
::World* World;
::EventBroker* EventBroker;
bool IsClient = false;
bool IsServer = false;
};
class System class System
{ {
friend class SystemPipeline; friend class SystemPipeline;
protected: protected:
System(SystemParams params) System(EventBroker* eventBroker)
: m_World(params.World) : m_EventBroker(eventBroker)
, m_EventBroker(params.EventBroker) { }
, IsClient(params.IsClient)
, IsServer(params.IsServer)
{
if (IsClient) {
EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &System::setLocalPlayer);
}
}
virtual ~System() = default; virtual ~System() = default;
World* m_World;
EventBroker* m_EventBroker; EventBroker* m_EventBroker;
bool IsClient = false;
bool IsServer = false;
EntityWrapper LocalPlayer = EntityWrapper::Invalid;
private:
EventRelay<System, Events::PlayerSpawned> m_EPlayerSpawned;
virtual bool setLocalPlayer(Events::PlayerSpawned& e)
{
if (e.PlayerID == -1) {
LocalPlayer = e.Player;
}
return true;
}
}; };
class PureSystem : public virtual System class PureSystem : public System
{ {
friend class SystemPipeline; friend class SystemPipeline;
protected: protected:
PureSystem(std::string componentType) PureSystem(EventBroker* eventBroker, std::string componentType)
: m_ComponentType(componentType) : System(eventBroker)
, m_ComponentType(componentType)
{ } { }
virtual ~PureSystem() = default; virtual ~PureSystem() = default;
const std::string m_ComponentType; const std::string m_ComponentType;
virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cPlayer, double dt) = 0; virtual void UpdateComponent(World* world, ComponentWrapper& component, double dt) = 0;
}; };
class ImpureSystem : public virtual System class ImpureSystem : public System
{ {
friend class SystemPipeline; friend class SystemPipeline;
protected: protected:
ImpureSystem() = default; ImpureSystem(EventBroker* eventBroker)
: System(eventBroker)
{ }
virtual ~ImpureSystem() = default; virtual ~ImpureSystem() = default;
virtual void Update(double dt) = 0; virtual void Update(World* world, double dt) = 0;
}; };
#endif #endif
+14 -56
View File
@@ -5,22 +5,13 @@
#include "EventBroker.h" #include "EventBroker.h"
#include "System.h" #include "System.h"
#include "World.h" #include "World.h"
#include "EPause.h"
#include "PerformanceTimer.h"
class SystemPipeline class SystemPipeline
{ {
public: public:
SystemPipeline(World* world, EventBroker* eventBroker, bool isClient, bool isServer) SystemPipeline(EventBroker* eventBroker)
: m_World(world) : m_EventBroker(eventBroker)
, m_EventBroker(eventBroker) { }
, m_IsClient(isClient)
, m_IsServer(isServer)
{
EVENT_SUBSCRIBE_MEMBER(m_EPause, &SystemPipeline::OnPause);
EVENT_SUBSCRIBE_MEMBER(m_EResume, &SystemPipeline::OnResume);
}
~SystemPipeline() ~SystemPipeline()
{ {
for (UnorderedSystems& group : m_OrderedSystemGroups) { for (UnorderedSystems& group : m_OrderedSystemGroups) {
@@ -38,11 +29,11 @@ public:
m_OrderedSystemGroups.resize(updateOrderLevel + 1); m_OrderedSystemGroups.resize(updateOrderLevel + 1);
} }
UnorderedSystems& group = m_OrderedSystemGroups[updateOrderLevel]; UnorderedSystems& group = m_OrderedSystemGroups[updateOrderLevel];
System* system = new T(SystemParams(m_World, m_EventBroker, m_IsClient, m_IsServer), args...); System* system = new T(m_EventBroker, args...);
group.Systems[typeid(T).name()] = system; group.Systems[typeid(T).name()] = system;
PureSystem* pureSystem = dynamic_cast<PureSystem*>(system); if (std::is_base_of<PureSystem, T>::value) {
if (pureSystem != nullptr) { PureSystem* pureSystem = static_cast<PureSystem*>(system);
if (!pureSystem->m_ComponentType.empty()) { if (!pureSystem->m_ComponentType.empty()) {
group.PureSystems[pureSystem->m_ComponentType].push_back(pureSystem); group.PureSystems[pureSystem->m_ComponentType].push_back(pureSystem);
} else { } else {
@@ -50,21 +41,14 @@ public:
} }
} }
ImpureSystem* impureSystem = dynamic_cast<ImpureSystem*>(system); if (std::is_base_of<ImpureSystem, T>::value) {
if (impureSystem != nullptr) { ImpureSystem* impureSystem = static_cast<ImpureSystem*>(system);
group.ImpureSystems.push_back(impureSystem); group.ImpureSystems.push_back(impureSystem);
} }
} }
void Update(double dt) void Update(World* world, double dt)
{ {
if (m_Paused) {
dt = 0.0;
}
// Process utility events for the System base class
m_EventBroker->Process<System>();
for (UnorderedSystems& group : m_OrderedSystemGroups) { for (UnorderedSystems& group : m_OrderedSystemGroups) {
// Process events // Process events
for (auto& pair : group.Systems) { for (auto& pair : group.Systems) {
@@ -72,38 +56,27 @@ public:
} }
// Update // Update
for (auto& system : group.ImpureSystems) {
auto className = (std::string)typeid(*system).name();
PerformanceTimer::StartTimer(className);
system->Update(dt);
PerformanceTimer::StopTimer(className);
}
for (auto& pair : group.PureSystems) { for (auto& pair : group.PureSystems) {
const std::string& componentName = pair.first; const std::string& componentName = pair.first;
auto& systems = pair.second; auto& systems = pair.second;
const ComponentPool* pool = m_World->GetComponents(componentName); const ComponentPool* pool = world->GetComponents(componentName);
if (pool == nullptr) { if (pool == nullptr) {
continue; continue;
} }
for (auto& component : *pool) { for (auto& component : *pool) {
for (auto& system : systems) { for (auto& system : systems) {
auto className = (std::string)typeid(*system).name(); system->UpdateComponent(world, component, dt);
PerformanceTimer::StartTimer(className);
system->UpdateComponent(EntityWrapper(m_World, component.EntityID), component, dt);
PerformanceTimer::StopTimer(className);
} }
} }
} }
for (auto& system : group.ImpureSystems) {
system->Update(world, dt);
}
} }
} }
private: private:
World* m_World;
EventBroker* m_EventBroker; EventBroker* m_EventBroker;
bool m_IsClient = false;
bool m_IsServer = false;
bool m_Paused = false;
struct UnorderedSystems struct UnorderedSystems
{ {
std::map<std::string, System*> Systems; std::map<std::string, System*> Systems;
@@ -111,21 +84,6 @@ private:
std::vector<ImpureSystem*> ImpureSystems; std::vector<ImpureSystem*> ImpureSystems;
}; };
std::vector<UnorderedSystems> m_OrderedSystemGroups; std::vector<UnorderedSystems> m_OrderedSystemGroups;
EventRelay<SystemPipeline, Events::Pause> m_EPause;
bool OnPause(const Events::Pause& e) {
if (e.World == m_World) {
m_Paused = true;
}
return true;
}
EventRelay<SystemPipeline, Events::Resume> m_EResume;
bool OnResume(const Events::Resume& e) {
if (e.World == m_World) {
m_Paused = false;
}
return true;
}
}; };
#endif #endif
-25
View File
@@ -1,25 +0,0 @@
#ifndef Transform_h__
#define Transform_h__
#include "../GLM.h"
#include "World.h"
#include "EntityWrapper.h"
namespace Transform
{
glm::mat4 AbsoluteTransformation(EntityWrapper entity);
glm::vec3 AbsolutePosition(EntityWrapper entity);
glm::vec3 AbsolutePosition(World* world, EntityID entity);
glm::vec3 AbsoluteOrientationEuler(EntityWrapper entity);
glm::quat AbsoluteOrientation(EntityWrapper entity);
glm::quat AbsoluteOrientation(World* world, EntityID entity);
glm::vec3 AbsoluteScale(EntityWrapper entity);
glm::vec3 AbsoluteScale(World* world, EntityID entity);
glm::mat4 ModelMatrix(EntityWrapper entity);
glm::mat4 ModelMatrix(EntityID entity, World* world);
glm::vec3 TransformPoint(const glm::vec3& point, const glm::mat4& matrix);
}
#endif
-22
View File
@@ -1,22 +0,0 @@
#ifndef UniformScaleSystem_h__
#define UniformScaleSystem_h__
#include "../GLM.h"
#include "System.h"
#include "../Rendering/ESetCamera.h"
class UniformScaleSystem : public PureSystem
{
public:
UniformScaleSystem(SystemParams params);
virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cUniformScale, double dt) override;
private:
EntityWrapper m_Camera = EntityWrapper::Invalid;
EventRelay<UniformScaleSystem, Events::SetCamera> m_ESetCamera;
bool OnSetCamera(const Events::SetCamera& e);
};
#endif
+3 -4
View File
@@ -2,7 +2,6 @@
#define Util_Any_h__ #define Util_Any_h__
#include <memory> #include <memory>
#include <boost/shared_array.hpp>
struct Any struct Any
{ {
@@ -11,7 +10,7 @@ struct Any
template <typename T> template <typename T>
Any(const T& value) Any(const T& value)
{ {
Data = boost::shared_array<char>(new char[sizeof(T)]); Data = std::shared_ptr<char>(new char[sizeof(T)]);
Size = sizeof(T); Size = sizeof(T);
memcpy(Data.get(), &value, Size); memcpy(Data.get(), &value, Size);
} }
@@ -19,7 +18,7 @@ struct Any
template <typename T> template <typename T>
Any(T&& value) Any(T&& value)
{ {
Data = boost::shared_array<char>(new char[sizeof(T)]); Data = std::shared_ptr<char>(new char[sizeof(T)]);
Size = sizeof(T); Size = sizeof(T);
memcpy(Data.get(), &value, Size); memcpy(Data.get(), &value, Size);
} }
@@ -36,7 +35,7 @@ struct Any
return Any(value); return Any(value);
} }
boost::shared_array<char> Data = nullptr; std::shared_ptr<char> Data = nullptr;
std::size_t Size = 0; std::size_t Size = 0;
}; };
+2 -2
View File
@@ -42,7 +42,7 @@ enum class FileWatcher::FileEventFlags
}; };
inline FileWatcher::FileEventFlags operator|(FileWatcher::FileEventFlags a, FileWatcher::FileEventFlags b) { return static_cast<FileWatcher::FileEventFlags>(static_cast<int>(a) | static_cast<int>(b)); } inline FileWatcher::FileEventFlags operator|(FileWatcher::FileEventFlags a, FileWatcher::FileEventFlags b) { return static_cast<FileWatcher::FileEventFlags>(static_cast<int>(a) | static_cast<int>(b)); }
inline bool operator&(FileWatcher::FileEventFlags a, FileWatcher::FileEventFlags b) { return (static_cast<int>(a) & static_cast<int>(b)) != 0; } inline bool operator&(FileWatcher::FileEventFlags a, FileWatcher::FileEventFlags b) { return static_cast<int>(a)& static_cast<int>(b); }
class FileWatcher::Worker class FileWatcher::Worker
{ {
@@ -54,7 +54,7 @@ public:
private: private:
struct FileInfo struct FileInfo
{ {
std::size_t Size; int Size;
std::time_t Timestamp; std::time_t Timestamp;
}; };
+1 -1
View File
@@ -4,7 +4,7 @@
// } // }
// NOTE: condition statement is not executed at all in release mode. // NOTE: condition statement is not executed at all in release mode.
#ifndef DEBUG_IF #ifndef DEBUG_IF
#ifdef DEBUG #ifndef DEBUG
#define DEBUG_IF(c) if(c) #define DEBUG_IF(c) if(c)
#else #else
#define DEBUG_IF(c) if(false) #define DEBUG_IF(c) if(false)
+57 -6
View File
@@ -29,9 +29,41 @@ enum _LOG_LEVEL
extern _LOG_LEVEL LOG_LEVEL; extern _LOG_LEVEL LOG_LEVEL;
extern const char* _LOG_LEVEL_PREFIX[]; const static char* _LOG_LEVEL_PREFIX[] =
{
"EE: ",
"",
"WW: ",
"DD: "
};
extern void _LOG(_LOG_LEVEL logLevel, const char* file, const char* func, unsigned int line, const char* format, ...); static void _LOG(_LOG_LEVEL logLevel, const char* file, const char* func, unsigned int line, const char* format, ...)
{
if (logLevel > LOG_LEVEL) {
return;
}
char* message = nullptr;
va_list args;
va_start(args, format);
size_t size = vsnprintf(message, 0, format, args) + 1;
va_end(args);
va_start(args, format);
message = new char[size];
vsnprintf(message, size, format, args);
va_end(args);
if (logLevel == LOG_LEVEL_ERROR) {
std::cerr << file << ":" << line << " " << func << std::endl;
std::cerr << _LOG_LEVEL_PREFIX[logLevel] << message << std::endl;
} else {
std::cout << _LOG_LEVEL_PREFIX[logLevel] << message << std::endl;
}
delete[] message;
}
#define LOG(logLevel, format, ...) \ #define LOG(logLevel, format, ...) \
_LOG(logLevel, __BASE_FILE__, __func__, __LINE__, format, ##__VA_ARGS__) _LOG(logLevel, __BASE_FILE__, __func__, __LINE__, format, ##__VA_ARGS__)
@@ -45,11 +77,30 @@ extern void _LOG(_LOG_LEVEL logLevel, const char* file, const char* func, unsign
#define LOG_INFO(format, ...) \ #define LOG_INFO(format, ...) \
LOG(LOG_LEVEL_INFO, format, ##__VA_ARGS__) LOG(LOG_LEVEL_INFO, format, ##__VA_ARGS__)
#ifdef DEBUG
#define LOG_DEBUG(format, ...) \ #define LOG_DEBUG(format, ...) \
LOG(LOG_LEVEL_DEBUG, format, ##__VA_ARGS__) LOG(LOG_LEVEL_DEBUG, format, ##__VA_ARGS__)
#else
#define LOG_DEBUG(format, ...) // Set the log level temporarily for the current scope
#endif #define LOG_LEVEL_SCOPE(logLevel) \
_LOG_LEVEL_SCOPED_HELPER<logLevel> _logLevelScopedHelper;
template <_LOG_LEVEL LEVEL>
class _LOG_LEVEL_SCOPED_HELPER
{
public:
_LOG_LEVEL_SCOPED_HELPER()
{
m_OriginalLogLevel = LOG_LEVEL;
LOG_LEVEL = LEVEL;
}
~_LOG_LEVEL_SCOPED_HELPER()
{
LOG_LEVEL = m_OriginalLogLevel;
}
private:
_LOG_LEVEL m_OriginalLogLevel;
};
#endif // Logging_h__ #endif // Logging_h__
+5 -14
View File
@@ -5,17 +5,12 @@
#include "Entity.h" #include "Entity.h"
#include "ObjectPool.h" #include "ObjectPool.h"
#include "ComponentPool.h" #include "ComponentPool.h"
#include "EventBroker.h"
class World class World
{ {
public: public:
World() = default; World() = default;
World(EventBroker* eventBroker)
: m_EventBroker(eventBroker)
{ }
~World(); ~World();
World(const World& other);
// Create empty entity // Create empty entity
EntityID CreateEntity(EntityID parent = 0); EntityID CreateEntity(EntityID parent = 0);
@@ -26,21 +21,19 @@ public:
// Register a component type and allocate space for it // Register a component type and allocate space for it
void RegisterComponent(ComponentInfo& ci); void RegisterComponent(ComponentInfo& ci);
// Attach a component to an entity and fill it with default values // Attach a component to an entity and fill it with default values
ComponentWrapper AttachComponent(EntityID entity, const std::string& componentType); ComponentWrapper AttachComponent(EntityID entity, std::string componentType);
// Check if an entity has a component // Check if an entity has a component
bool HasComponent(EntityID entity, const std::string& componentType) const; bool HasComponent(EntityID entity, std::string componentType) const;
// Get a component of an entity // Get a component of an entity
ComponentWrapper GetComponent(EntityID entity, const std::string& componentType); ComponentWrapper GetComponent(EntityID entity, std::string componentType);
// Delete a component off an entity // Delete a component off an entity
void DeleteComponent(EntityID entity, const std::string& componentType); void DeleteComponent(EntityID entity, std::string componentType);
// Get all components of the specified type // Get all components of the specified type
const ComponentPool* GetComponents(const std::string& componentType); const ComponentPool* GetComponents(std::string componentType);
// Get entity parent // Get entity parent
EntityID GetParent(EntityID entity); EntityID GetParent(EntityID entity);
// Change the parent of an entity // Change the parent of an entity
void SetParent(EntityID entity, EntityID parent); void SetParent(EntityID entity, EntityID parent);
// Get children of an entity
const std::pair<std::unordered_multimap<EntityID, EntityID>::const_iterator, std::unordered_multimap<EntityID, EntityID>::const_iterator> GetChildren(EntityID entity);
// Get all component pools // Get all component pools
const std::unordered_map<std::string, ComponentPool*>& GetComponentPools() const { return m_ComponentPools; } const std::unordered_map<std::string, ComponentPool*>& GetComponentPools() const { return m_ComponentPools; }
// Get the entity children map // Get the entity children map
@@ -51,7 +44,6 @@ public:
std::string GetName(EntityID entity) const; std::string GetName(EntityID entity) const;
private: private:
EventBroker* m_EventBroker = nullptr;
EntityID m_CurrentEntityID = 0; EntityID m_CurrentEntityID = 0;
std::unordered_map<EntityID, EntityID> m_EntityParents; std::unordered_map<EntityID, EntityID> m_EntityParents;
@@ -61,7 +53,6 @@ private:
std::unordered_map<EntityID, std::string> m_EntityNames; std::unordered_map<EntityID, std::string> m_EntityNames;
EntityID generateEntityID(); EntityID generateEntityID();
void deleteEntityRecursive(EntityID entity, bool cascaded = false);
}; };
#endif #endif
@@ -1,115 +0,0 @@
#ifndef EditorCameraInputController_h__
#define EditorCameraInputController_h__
#include <imgui/imgui.h>
#include "../Input/FirstPersonInputController.h"
#include "../Core/EMousePress.h"
#include "../Core/EMouseRelease.h"
#include "../Core/EMouseScroll.h"
#include "../Core/ConfigFile.h"
template <typename EventContext>
class EditorCameraInputController : public FirstPersonInputController<EventContext>
{
public:
EditorCameraInputController(EventBroker* eventBroker, unsigned int playerID)
: FirstPersonInputController(eventBroker, playerID)
{
EVENT_SUBSCRIBE_MEMBER(m_EMousePress, &EditorCameraInputController::OnMousePress);
EVENT_SUBSCRIBE_MEMBER(m_EMouseRelease, &EditorCameraInputController::OnMouseRelease);
EVENT_SUBSCRIBE_MEMBER(m_EMouseScroll, &EditorCameraInputController::OnMouseScroll);
m_Config = ResourceManager::Load<ConfigFile>("Config.ini");
m_SpeedMultiplier = m_Config->Get<float>("Editor.CameraSpeed", 3.f);
}
virtual const glm::vec3 Movement() const override { return m_Movement * static_cast<float>(m_SpeedMultiplier); }
void Enable() { m_Enabled = true; }
void Disable() { m_Enabled = false; }
virtual bool OnCommand(const Events::InputCommand& e) override
{
if (glm::abs(e.Value) > 0 && !m_MouseLocked) {
return false;
}
ImGuiIO& io = ImGui::GetIO();
if (glm::abs(e.Value) > 0 && (io.WantCaptureKeyboard || io.WantCaptureMouse)) {
return false;
}
if (e.Command == "Jump") {
if (e.Value > 0) {
m_Movement.y = glm::max(e.Value, 1.f);
} else {
m_Movement.y = 0.f;
}
}
if (e.Command == "Crouch") {
if (e.Value > 0) {
m_Movement.y = glm::min(-e.Value, -1.f);
} else {
m_Movement.y = 0.f;
}
}
if (e.Command == "Sprint") {
if (e.Value > 0) {
m_SpeedMultiplier *= 2.f;
} else {
m_SpeedMultiplier /= 2.f;
}
}
return FirstPersonInputController::OnCommand(e);
}
protected:
ConfigFile* m_Config;
bool m_Enabled = false;
double m_SpeedMultiplier = 1.f;
EventRelay<EventContext, Events::MousePress> m_EMousePress;
bool OnMousePress(const Events::MousePress& e)
{
if (!m_Enabled) {
return false;
}
if (e.Button == GLFW_MOUSE_BUTTON_2) {
ImGuiIO& io = ImGui::GetIO();
if (!io.WantCaptureMouse) {
LockMouse();
}
}
return true;
}
EventRelay<EventContext, Events::MouseRelease> m_EMouseRelease;
bool OnMouseRelease(const Events::MouseRelease& e)
{
if (!m_Enabled) {
return false;
}
if (e.Button == GLFW_MOUSE_BUTTON_2) {
UnlockMouse();
}
return true;
}
EventRelay<EventContext, Events::MouseScroll> m_EMouseScroll;
bool OnMouseScroll(const Events::MouseScroll& e)
{
if (!m_Enabled) {
return false;
}
m_SpeedMultiplier += e.DeltaY * (0.1 * m_SpeedMultiplier);
m_Config->Set("Editor.CameraSpeed", m_SpeedMultiplier);
m_Config->SaveToDisk();
return true;
}
};
#endif
-183
View File
@@ -1,183 +0,0 @@
#ifndef EditorGUI_h__
#define EditorGUI_h__
#include <imgui/imgui.h>
#define IMGUI_DEFINE_MATH_OPERATORS
#include <imgui/imgui_internal.h>
#include <nativefiledialog/nfd.h>
#include <boost/filesystem.hpp>
#include <boost/any.hpp>
#include <boost/algorithm/string/replace.hpp>
#include "../Common.h"
#include "../GLM.h"
#include <glm/gtx/common.hpp>
#include "EditorWidgetSystem.h"
#include "../Core/EventBroker.h"
#include "../Core/World.h"
#include "../Core/EntityWrapper.h"
#include "../Core/ResourceManager.h"
#include "../Core/EPause.h"
#include "../Core/EKeyDown.h"
#include "../Core/ELockMouse.h"
#include "../Core/EFileDropped.h"
#include "../Rendering/Texture.h"
class EditorGUI
{
public:
EditorGUI(World* world, EventBroker* eventBroker);
enum class WidgetMode
{
Translate,
Rotate,
Scale
};
enum class WidgetSpace
{
Global,
Local
};
void Draw();
void SelectEntity(EntityWrapper entity);
void SetDirty(EntityWrapper entity);
// Called when an entity is selected in the entity tree
typedef std::function<void(EntityWrapper)> OnEntitySelectedCallback_t;
void SetEntitySelectedCallback(OnEntitySelectedCallback_t f) { m_OnEntitySelected = f; }
// Called when the user means to import an entity file.
// @param EntityWrapper The entity to parent the imported entity to. The entity will be imported into the world of this entity.
// @param boost::filesystem::path The path to the entity to import
// @return EntityWrapper The newly created entity
typedef std::function<EntityWrapper(EntityWrapper, boost::filesystem::path)> OnEntityImport_t;
void SetEntityImportCallback(OnEntityImport_t f) { m_OnEntityImport = f; }
// Called when the user means to save an entity to file.
// Permitted to throw exceptions on save failure.
typedef std::function<void(EntityWrapper, boost::filesystem::path)> OnEntitySave_t;
void SetEntitySaveCallback(OnEntitySave_t f) { m_OnEntitySave = f; }
// Called when the user means to create a new entity.
// @param EntityWrapper The parent of the entity to be created
// @return EntityWrapper The newly created entity
typedef std::function<EntityWrapper(EntityWrapper)> OnEntityCreate_t;
void SetEntityCreateCallback(OnEntityCreate_t f) { m_OnEntityCreate = f; }
// Called when the user means to delete an entity.
typedef std::function<void(EntityWrapper)> OnEntityDelete_t;
void SetEntityDeleteCallback(OnEntityDelete_t f) { m_OnEntityDelete = f; }
// Called when the user means to change the parent of an entity.
typedef std::function<void(EntityWrapper, EntityWrapper)> OnEntityChangeParent_t;
void SetEntityChangeParentCallback(OnEntityChangeParent_t f) { m_OnEntityChangeParent = f; }
// Called when the user means to rename an entity.
typedef std::function<void(EntityWrapper, const std::string&)> OnEntityChangeName_t;
void SetEntityChangeNameCallback(OnEntityChangeName_t f) { m_OnEntityChangeName = f; }
// Called when the user means to attach a new component to an entity.
typedef std::function<void(EntityWrapper, const std::string&)> OnComponentAttach_t;
void SetComponentAttachCallback(OnComponentAttach_t f) { m_OnComponentAttach = f; }
// Called when the user means to delete a component off an entity.
typedef std::function<void(EntityWrapper, const std::string&)> OnComponentDelete_t;
void SetComponentDeleteCallback(OnComponentDelete_t f) { m_OnComponentDelete = f; }
// Called when the user selects a widget mode.
typedef std::function<void(WidgetMode)> OnWidgetMode_t;
void SetWidgetModeCallback(OnWidgetMode_t f) { m_OnWidgetMode = f; }
// Called when the user selects a widget space.
typedef std::function<void(WidgetSpace)> OnWidgetSpace_t;
void SetWidgetSpaceCallback(OnWidgetSpace_t f) { m_OnWidgetSpace = f; }
private:
World* m_World;
EventBroker* m_EventBroker;
struct EntityFileInfo
{
boost::filesystem::path Path;
bool Dirty = false;
};
// Config variables
const boost::filesystem::path m_DefaultEntityPath = boost::filesystem::path("Schema") / boost::filesystem::path("Entities");
// State
EntityWrapper m_CurrentSelection = EntityWrapper::Invalid;
std::unordered_map<EntityWrapper, EntityFileInfo> m_EntityFiles;
EntityWrapper m_CurrentlyDragging = EntityWrapper::Invalid;
std::string m_LastErrorMessage;
WidgetMode m_CurrentWidgetMode = WidgetMode::Translate;
WidgetSpace m_CurrentWidgetSpace = WidgetSpace::Global;
std::set<std::string> m_ModalsToOpen;
std::map<std::string, boost::any> m_ModalData;
std::string m_DroppedFile = "";
bool m_Paused = false;
bool m_MouseLocked = false;
// Callbacks
OnEntitySelectedCallback_t m_OnEntitySelected = nullptr;
OnEntityImport_t m_OnEntityImport = nullptr;
OnEntitySave_t m_OnEntitySave = nullptr;
OnEntityCreate_t m_OnEntityCreate = nullptr;
OnEntityDelete_t m_OnEntityDelete = nullptr;
OnEntityChangeParent_t m_OnEntityChangeParent = nullptr;
OnEntityChangeName_t m_OnEntityChangeName = nullptr;
OnComponentAttach_t m_OnComponentAttach = nullptr;
OnComponentDelete_t m_OnComponentDelete = nullptr;
OnWidgetMode_t m_OnWidgetMode = nullptr;
OnWidgetSpace_t m_OnWidgetSpace = nullptr;
// Events
EventRelay<EditorGUI, Events::KeyDown> m_EKeyDown;
bool OnKeyDown(const Events::KeyDown& e);
EventRelay<EditorGUI, Events::FileDropped> m_EFileDropped;
bool OnFileDropped(const Events::FileDropped& e);
EventRelay<EditorGUI, Events::Pause> m_EPause;
bool OnPause(const Events::Pause& e);
EventRelay<EditorGUI, Events::Resume> m_EResume;
bool OnResume(const Events::Resume& e);
EventRelay<EditorGUI, Events::LockMouse> m_ELockMouse;
bool OnLockMouse(const Events::LockMouse& e);
EventRelay<EditorGUI, Events::UnlockMouse> m_EUnlockMouse;
bool OnUnlockMouse(const Events::UnlockMouse& e);
// Utility functions
boost::filesystem::path fileOpenDialog();
boost::filesystem::path fileSaveDialog();
const std::string formatEntityName(EntityWrapper entity);
GLuint tryLoadTexture(std::string filePath);
void openModal(const std::string& modal);
void setWidgetMode(WidgetMode mode);
void toggleWidgetSpace();
static bool compareCharArray(const char* c1, const char* c2);
// Entity file handling methods
void entityImport(World* world);
void entitySave(EntityWrapper entity, bool saveAs = false);
void entityCreate(World* world, EntityWrapper parent);
void entityDelete(EntityWrapper entity);
void entityChangeParent(EntityWrapper entity, EntityWrapper parent);
// UI drawing methods
void drawMenu();
void drawTools();
void drawEntities(World* world);
void drawEntitiesRecursive(World* world, EntityID parent);
bool drawEntityNode(EntityWrapper entity);
void drawComponents(EntityWrapper entity);
bool drawComponentNode(EntityWrapper entity, const ComponentInfo& componentType);
bool drawComponentField(ComponentWrapper& c, const ComponentInfo::Field_t& field);
bool drawComponentField_Vector(ComponentWrapper &c, const ComponentInfo::Field_t &field);
bool drawComponentField_Color(ComponentWrapper &c, const ComponentInfo::Field_t &field);
bool drawComponentField_int(ComponentWrapper &c, const ComponentInfo::Field_t &field);
bool drawComponentField_enum(ComponentWrapper &c, const ComponentInfo::Field_t &field);
bool drawComponentField_float(ComponentWrapper &c, const ComponentInfo::Field_t &field);
bool drawComponentField_double(ComponentWrapper &c, const ComponentInfo::Field_t &field);
bool drawComponentField_bool(ComponentWrapper &c, const ComponentInfo::Field_t &field);
bool drawComponentField_string(ComponentWrapper &c, const ComponentInfo::Field_t &field);
void drawModals();
// Custom UI elements
bool createDeleteButton(const std::string& componentType);
void createWidgetToolButton(WidgetMode mode);
};
#endif
@@ -1,27 +0,0 @@
#ifndef EditorRenderSystem_h__
#define EditorRenderSystem_h__
#include "../Core/System.h"
#include "../Rendering/IRenderer.h"
#include "../Rendering/ModelJob.h"
#include "../Rendering/Camera.h"
#include "../Rendering/ESetCamera.h"
class EditorRenderSystem : public ImpureSystem
{
public:
EditorRenderSystem(SystemParams params, IRenderer* renderer, RenderFrame* renderFrame);
virtual void Update(double dt) override;
private:
IRenderer* m_Renderer;
RenderFrame* m_RenderFrame;
Camera* m_EditorCamera;
EntityWrapper m_CurrentCamera = EntityWrapper::Invalid;
EventRelay<EditorRenderSystem, Events::SetCamera> m_ESetCamera;
bool OnSetCamera(Events::SetCamera& e);
};
#endif
-29
View File
@@ -1,29 +0,0 @@
#include <numeric>
#include <iomanip>
#include <imgui/imgui.h>
#include "../Common.h"
#include "../GLM.h"
#include "../OpenGL.h"
class EditorStats
{
public:
EditorStats();
void Draw(double dt);
private:
// FPS graph
const unsigned int m_SampleSize = 100;
unsigned int m_FrameCount = 0;
std::vector<double> m_FrameTimes;
double m_TimeAccumulator = 0.0;
double m_AveragedSamplesPerSecond = 10.0;
const unsigned int m_AveragedSampleSize = 100;
unsigned int m_CurrentAveragedSampleIndex = 0;
std::vector<double> m_AveragedSamples;
void drawFPSGraph(double dt);
void drawRAMUsage(double dt);
void drawVRAMStats(double dt);
};
+74 -52
View File
@@ -1,72 +1,94 @@
#include <imgui/imgui.h>
#include <glm/gtx/common.hpp>
#include <boost/filesystem/path.hpp>
#include <nativefiledialog/nfd.h>
#include "../Core/System.h" #include "../Core/System.h"
#include "../Core/EMousePress.h"
#include "../Core/EMouseRelease.h"
#include "../Core/EMouseMove.h"
#include "../Core/ConfigFile.h"
#include "../Input/EInputCommand.h"
#include "../Rendering/IRenderer.h" #include "../Rendering/IRenderer.h"
#include "../Rendering/Camera.h" #include "../Rendering/EPicking.h"
#include "../Rendering/ESetCamera.h" #include "../Core/EFileDropped.h"
#include "../Core/World.h" #include "../Rendering/RenderQueueFactory.h"
#include "../Core/SystemPipeline.h"
#include "../Core/ResourceManager.h"
#include "../Core/EntityFilePreprocessor.h" #include "../Core/EntityFilePreprocessor.h"
#include "../Core/EntityFileParser.h" #include "../Core/EntityFileParser.h"
#include "../Core/EntityFileWriter.h" #include "../Core/EntityFileWriter.h"
#include "../Core/EMousePress.h"
#include "../Input/EInputCommand.h"
#include "EditorGUI.h"
#include "EditorStats.h"
#include "EditorCameraInputController.h"
class EditorSystem : public ImpureSystem class EditorSystem : public ImpureSystem
{ {
public: public:
EditorSystem(SystemParams params, IRenderer* renderer, RenderFrame* renderFrame); EditorSystem(EventBroker* eventBroker, IRenderer* renderer);
~EditorSystem();
void Update(double dt); virtual void Update(World* world, double dt) override;
void Enable();
void Disable();
private: private:
IRenderer* m_Renderer; IRenderer* m_Renderer;
RenderFrame* m_RenderFrame; World* m_World = nullptr;
World* m_EditorWorld;
SystemPipeline* m_EditorWorldSystemPipeline;
//Camera* m_EditorCamera;
EntityWrapper m_EditorCamera = EntityWrapper::Invalid;
EntityWrapper m_ActualCamera = EntityWrapper::Invalid;
EditorCameraInputController<EditorSystem>* m_EditorCameraInputController;
EditorGUI* m_EditorGUI;
EditorStats* m_EditorStats;
// State bool m_Enabled;
double m_LastTime = 0.f; bool m_Visible;
bool m_Enabled = true; boost::filesystem::path m_DefaultEntityDir;
EditorGUI::WidgetMode m_WidgetMode = EditorGUI::WidgetMode::Translate; boost::filesystem::path m_CurrentFile;
EditorGUI::WidgetSpace m_WidgetSpace = EditorGUI::WidgetSpace::Global; std::vector<glm::vec2> m_PickingQueue;
EntityWrapper m_Widget = EntityWrapper::Invalid;
EntityWrapper m_CurrentSelection = EntityWrapper::Invalid;
// Utility functions enum class WidgetMode
EntityWrapper importEntity(EntityWrapper parent, boost::filesystem::path filePath); {
void setWidgetMode(EditorGUI::WidgetMode mode); None,
Translate,
Rotate,
Scale
} m_WidgetMode = WidgetMode::None;
// GUI callbacks enum class WidgetSpace
void OnEntitySelected(EntityWrapper entity); {
void OnEntitySave(EntityWrapper entity, boost::filesystem::path filePath); Local,
EntityWrapper OnEntityCreate(EntityWrapper parent); Global
void OnEntityDelete(EntityWrapper entity); } m_WidgetSpace = WidgetSpace::Global;
void OnEntityChangeParent(EntityWrapper entity, EntityWrapper parent);
void OnEntityChangeName(EntityWrapper entity, const std::string& name); EntityID m_Widget = EntityID_Invalid;
void OnComponentAttach(EntityWrapper entity, const std::string& componentType); EntityID m_WidgetX = EntityID_Invalid;
void OnComponentDelete(EntityWrapper entity, const std::string& componentType); EntityID m_WidgetPlaneX = EntityID_Invalid;
void OnWidgetSpace(EditorGUI::WidgetSpace widgetSpace); EntityID m_WidgetY = EntityID_Invalid;
EntityID m_WidgetPlaneY = EntityID_Invalid;
EntityID m_WidgetZ = EntityID_Invalid;
EntityID m_WidgetPlaneZ = EntityID_Invalid;
EntityID m_WidgetOrigin = EntityID_Invalid;
glm::vec3 m_WidgetCurrentAxis;
float m_WidgetPickingDepth = 0.f;
EntityID m_Selection = EntityID_Invalid;
EntityID m_LastSelection = EntityID_Invalid;
EntityID m_UIDraggingEntity = EntityID_Invalid;
glm::vec3 m_Position;
std::string m_LastDroppedFile;
static boost::filesystem::path openDialog(boost::filesystem::path defaultPath);
static boost::filesystem::path saveDialog(boost::filesystem::path defaultPath);
// Events
EventRelay<EditorSystem, Events::MousePress> m_EMousePress;
bool OnMousePress(const Events::MousePress& e);
EventRelay<EditorSystem, Events::WidgetDelta> m_EWidgetDelta;
bool OnWidgetDelta(const Events::WidgetDelta& e);
EventRelay<EditorSystem, Events::InputCommand> m_EInputCommand; EventRelay<EditorSystem, Events::InputCommand> m_EInputCommand;
bool OnInputCommand(const Events::InputCommand& e); bool OnInputCommand(const Events::InputCommand& e);
EventRelay<EditorSystem, Events::SetCamera> m_ESetCamera; EventRelay<EditorSystem, Events::MouseRelease> m_EMouseRelease;
bool OnSetCamera(const Events::SetCamera& e); bool OnMouseRelease(const Events::MouseRelease& e);
EventRelay<EditorSystem, Events::MousePress> m_EMousePress;
bool OnMousePress(const Events::MousePress& e);
EventRelay<EditorSystem, Events::MouseMove> m_EMouseMove;
bool OnMouseMove(const Events::MouseMove& e);
EventRelay<EditorSystem, Events::Picking> m_EPicking;
bool OnPicking(const Events::Picking& e);
EventRelay<EditorSystem, Events::FileDropped> m_EFileDropped;
bool OnFileDropped(const Events::FileDropped& e);
void createWidget();
void updateWidget();
void setWidgetMode(WidgetMode newMode);
void setWidgetSpace(WidgetSpace space);
void drawUI(World* world, double dt);
bool createDeleteButton(std::string componentType);
bool createEntityNode(World* world, EntityID entity);
void changeParent(EntityID entity, EntityID newParent);
void fileImport(World* world);
void fileSave(World* world);
void fileSaveAs(World* world);
}; };
@@ -1,49 +0,0 @@
#ifndef EditorWidgetSystem_h__
#define EditorWidgetSystem_h__
#include <imgui/imgui.h>
#include "../GLM.h"
#include "../Core/System.h"
#include "../Rendering/IRenderer.h"
#include "../Rendering/Util/ScreenCoords.h"
#include "../Core/EMouseMove.h"
#include "../Core/EMousePress.h"
#include "../Core/EMouseRelease.h"
namespace Events
{
struct WidgetDelta : Event
{
glm::vec3 Translation;
glm::vec3 Rotation;
glm::vec3 Scale;
};
}
class EditorWidgetSystem : public ImpureSystem, PureSystem
{
public:
EditorWidgetSystem(SystemParams params, IRenderer* renderer);
virtual void Update(double dt) override;
virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cEditorWidget, double dt) override;
private:
IRenderer* m_Renderer;
// State
EntityWrapper m_PickEntity = EntityWrapper::Invalid;
PickData m_PickData;
glm::vec2 m_MouseDelta;
EventRelay<EditorWidgetSystem, Events::MouseMove> m_EMouseMove;
bool OnMouseMove(const Events::MouseMove& e);
EventRelay<EditorWidgetSystem, Events::MousePress> m_EMousePress;
bool OnMousePress(const Events::MousePress& e);
EventRelay<EditorWidgetSystem, Events::MouseRelease> m_EMouseRelease;
bool OnMouseRelease(const Events::MouseRelease& e);
};
#endif
-1
View File
@@ -8,4 +8,3 @@
#include <glm/gtc/quaternion.hpp> #include <glm/gtc/quaternion.hpp>
#include <glm/gtx/quaternion.hpp> #include <glm/gtx/quaternion.hpp>
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/projection.hpp>
+165
View File
@@ -0,0 +1,165 @@
#ifndef GUI_BUTTON_H__
#define GUI_BUTTON_H__
#include "GUI/TextureFrame.h"
#include "GUI/EButtonEnter.h"
#include "GUI/EButtonLeave.h"
#include "GUI/EButtonPress.h"
#include "GUI/EButtonRelease.h"
#include "Core/EMouseMove.h"
#include "Core/EMousePress.h"
#include "Core/EMouseRelease.h"
namespace dd
{
namespace GUI
{
class Button : public TextureFrame
{
public:
Button(Frame* parent, std::string name)
: TextureFrame(parent, name)
{
EVENT_SUBSCRIBE_MEMBER(m_EMouseMove, &Button::OnMouseMove);
EVENT_SUBSCRIBE_MEMBER(m_EMousePress, &Button::OnMousePress);
EVENT_SUBSCRIBE_MEMBER(m_EMouseRelease, &Button::OnMouseRelease);
}
void SetTextureHover(std::string resourceName)
{
m_TextureHover = resourceName;
}
void SetTextureReleased(std::string resourceName)
{
m_TextureReleased = resourceName;
SetTexture(resourceName);
}
void SetTexturePressed(std::string resourceName)
{
m_TexturePressed = resourceName;
}
void Draw(RenderQueueCollection& rq) override
{
if (m_Texture == nullptr && !m_TextureReleased.empty()) {
SetTexture(m_TextureReleased);
}
TextureFrame::Draw(rq);
}
virtual void OnEnter() { }
virtual void OnLeave() { }
virtual void OnPress() { }
virtual void OnRelease() { }
protected:
bool m_MouseIsOver = false;
bool m_IsDown = false;
virtual bool OnMouseMove(const Events::MouseMove& event)
{
if (Hidden()) {
return false;
}
bool isOver = Rectangle::Intersects(AbsoluteRectangle(), Rectangle(event.X, event.Y, 1, 1));
if (isOver && !m_MouseIsOver) { // Enter
if (!m_IsDown) {
if (!m_TextureHover.empty()) {
SetTexture(m_TextureHover);
}
}
OnEnter();
Events::ButtonEnter e;
e.FrameName = m_Name;
EventBroker->Publish(e);
Events::PlaySound soundEvent;
soundEvent.FilePath = "Sounds/GUI/hover-n.wav";
EventBroker->Publish(soundEvent);
} else if (!isOver && m_MouseIsOver) { // Leave
if (!m_IsDown) {
if (!m_TextureReleased.empty()) {
SetTexture(m_TextureReleased);
}
}
OnLeave();
Events::ButtonLeave e;
e.FrameName = m_Name;
EventBroker->Publish(e);
}
m_MouseIsOver = isOver;
return true;
}
virtual bool OnMousePress(const Events::MousePress& event)
{
if (Hidden()) {
//LOG_DEBUG("Pressed hidden button");
return false;
}
if (!Rectangle::Intersects(AbsoluteRectangle(), Rectangle(event.X, event.Y, 1, 1))) {
return false;
}
if (!m_TexturePressed.empty()) {
SetTexture(m_TexturePressed);
}
m_IsDown = true;
OnPress();
Events::ButtonPress e;
e.FrameName = m_Name;
e.Button = this;
EventBroker->Publish(e);
return true;
}
virtual bool OnMouseRelease(const Events::MouseRelease& event)
{
if (Hidden()) {
//LOG_DEBUG("Released hidden button");
return false;
}
bool isOver = Rectangle::Intersects(AbsoluteRectangle(), Rectangle(event.X, event.Y, 1, 1));
if (!isOver && !m_IsDown) {
return false;
}
if (m_MouseIsOver) {
if (!m_TextureHover.empty()) {
SetTexture(m_TextureHover);
}
} else {
if (!m_TextureReleased.empty()) {
SetTexture(m_TextureReleased);
}
}
m_IsDown = false;
OnRelease();
Events::ButtonRelease e;
e.FrameName = m_Name;
e.Button = this;
EventBroker->Publish(e);
return true;
}
private:
EventRelay<Frame, Events::MouseMove> m_EMouseMove;
EventRelay<Frame, Events::MousePress> m_EMousePress;
EventRelay<Frame, Events::MouseRelease> m_EMouseRelease;
std::string m_TextureHover;
std::string m_TexturePressed;
std::string m_TextureReleased;
};
}
}
#endif
-44
View File
@@ -1,44 +0,0 @@
#ifndef ButtonSystem_h__
#define ButtonSystem_h__
#include "../Rendering/IRenderer.h"
#include "../Core/ConfigFile.h"
#include "../Rendering/PickingPass.h"
#include "../Core/ResourceManager.h"
#include "../Core/System.h"
#include "../Core/Event.h"
#include "../Core/EMousePress.h"
#include "../Core/EMouseRelease.h"
#include "../Core/ELockMouse.h"
#include "EButtonPressed.h"
#include "EButtonReleased.h"
#include "EButtonClicked.h"
class ButtonSystem : public PureSystem
{
public:
ButtonSystem(SystemParams params, IRenderer* renderer);
virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) override;
private:
IRenderer* m_Renderer;
bool m_MouseIsLocked = false;
EntityWrapper m_PickEntity = EntityWrapper::Invalid;
PickData m_PickData;
EventRelay<ButtonSystem, Events::LockMouse> m_EMouseLock;
bool OnMouseLock(const Events::LockMouse& e);
EventRelay<ButtonSystem, Events::UnlockMouse> m_EMouseUnlock;
bool OnMouseUnlock(const Events::UnlockMouse& e);
EventRelay<ButtonSystem, Events::MousePress> m_EMousePress;
bool OnMousePress(const Events::MousePress& e);
EventRelay<ButtonSystem, Events::MouseRelease> m_EMouseRelease;
bool OnMouseRelease(const Events::MouseRelease& e);
};
#endif
-16
View File
@@ -1,16 +0,0 @@
#ifndef Events_ButtonClicked_h__
#define Events_ButtonClicked_h__
#include "Core/Event.h"
namespace Events
{
struct ButtonClicked : public Event {
std::string EntityName;
EntityWrapper Entity;
};
}
#endif
+17
View File
@@ -0,0 +1,17 @@
#ifndef Events_ButtonEnter_h__
#define Events_ButtonEnter_h__
#include "../Core/EventBroker.h"
namespace Events
{
/** Thrown on GUI button hover. */
struct ButtonEnter : Event
{
std::string FrameName;
};
}
#endif
+17
View File
@@ -0,0 +1,17 @@
#ifndef Events_ButtonLeave_h__
#define Events_ButtonLeave_h__
#include "../Core/EventBroker.h"
namespace Events
{
/** Thrown on GUI button hover. */
struct ButtonLeave : Event
{
std::string FrameName;
};
}
#endif
+20
View File
@@ -0,0 +1,20 @@
#ifndef Events_ButtonPress_h__
#define Events_ButtonPress_h__
#include "../Core/EventBroker.h"
namespace GUI { class Button; }
namespace Events
{
/** Thrown on GUI button press. */
struct ButtonPress : Event
{
std::string FrameName;
GUI::Button* Button;
};
}
#endif
-16
View File
@@ -1,16 +0,0 @@
#ifndef Events_ButtonPressed_h__
#define Events_ButtonPressed_h__
#include "Core/Event.h"
namespace Events
{
struct ButtonPressed : public Event {
std::string EntityName;
EntityWrapper Entity;
};
}
#endif
+20
View File
@@ -0,0 +1,20 @@
#ifndef Events_ButtonRelease_h__
#define Events_ButtonRelease_h__
#include "../Core/EventBroker.h"
namespace GUI { class Button; }
namespace Events
{
/** Thrown on GUI button release. */
struct ButtonRelease : Event
{
std::string FrameName;
GUI::Button* Button;
};
}
#endif
-16
View File
@@ -1,16 +0,0 @@
#ifndef Events_ButtonReleased_h__
#define Events_ButtonReleased_h__
#include "Core/Event.h"
namespace Events
{
struct ButtonReleased : public Event {
std::string EntityName;
EntityWrapper Entity;
};
}
#endif
+261
View File
@@ -0,0 +1,261 @@
#ifndef GUI_Frame_h__
#define GUI_Frame_h__
#include "../Common.h"
#include "../Core/Util/Rectangle.h"
#include "../Core/EventBroker.h"
#include "../Core/EKeyDown.h"
#include "../Core/EKeyUp.h"
#include "../Core/ResourceManager.h"
#include "../Rendering/RenderQueue.h"
#include "../Rendering/Texture.h"
#include "../Input/EInputCommand.h"
namespace GUI
{
class Frame : public Rectangle
{
public:
enum class Anchor
{
Left,
Right,
Top,
Bottom
};
static const int BaseWidth = 1280;
static const int BaseHeight = 720;
// Set up a base frame with an event broker
Frame(EventBroker* eventBroker)
: m_EventBroker(eventBroker)
, BaseFrame(this)
, m_Name("UIParent")
, Rectangle() { }
// Create a frame as a child
Frame(Frame* parent, std::string name)
: m_Name(name)
{
SetParent(parent);
Width = parent->Width;
Height = parent->Height;
EVENT_SUBSCRIBE_MEMBER(m_EKeyDown, &Frame::OnKeyDown);
EVENT_SUBSCRIBE_MEMBER(m_EKeyUp, &Frame::OnKeyUp);
EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &Frame::OnCommand);
}
~Frame()
{
/*for (auto layer : m_Children)
{
for (auto child : layer.second)
{
delete child.second;
}
}
if (m_Parent)
{
m_Parent->RemoveChild(this);
}*/
}
Frame* Parent() const { return m_Parent; }
void SetParent(Frame* parent)
{
if (parent == nullptr) {
LOG_ERROR("Failed to parent frame \"%s\": Invalid parent", m_Name.c_str());
return;
}
m_Layer = parent->Layer() + 1;
parent->AddChild(this);
m_Parent = parent;
m_EventBroker = parent->m_EventBroker;
BaseFrame = parent->BaseFrame;
}
void AddChild(Frame* child)
{
m_Children[child->m_Layer].insert(std::make_pair(child->Name(), child));
if (m_Parent) {
m_Parent->AddChild(child);
}
}
void RemoveChild(Frame* child)
{
auto it = m_Children.find(child->m_Layer);
if (it != m_Children.end()) {
m_Children.erase(it);
}
if (m_Parent) {
m_Parent->RemoveChild(child);
}
}
std::string Name() const { return m_Name; }
void SetName(std::string val) { m_Name = val; }
int Layer() const { return m_Layer; }
bool Hidden() const
{
if (m_Parent)
return m_Parent->Hidden() || m_Hidden;
else
return m_Hidden;
}
bool Visible() const
{
return !Hidden();
}
virtual void Hide() { m_Hidden = true; }
virtual void Show() { m_Hidden = false; }
int Left() const override
{
if (m_Parent)
return m_Parent->Left() + X;
else
return X;
}
void SetLeft(int absLeft) override
{
if (m_Parent) {
X = absLeft - m_Parent->Left();
} else {
X = absLeft;
}
}
int Right() const override
{
return Left() + Width;
}
void SetRight(int absRight) override
{
if (m_Parent) {
X = absRight - Width - m_Parent->Left();
} else {
X = absRight - Width;
}
}
int Top() const override
{
if (m_Parent)
return m_Parent->Top() + Y;
else
return Y;
}
void SetTop(int absTop) override
{
if (m_Parent) {
Y = absTop - m_Parent->Top();
} else {
Y = absTop;
}
}
int Bottom() const override
{
return Top() + Height;
}
void SetBottom(int absBottom) override
{
if (m_Parent) {
Y = absBottom - Height - m_Parent->Top();
} else {
Y = absBottom - Height;
}
}
glm::vec2 Scale()
{
if (m_Parent)
return m_Parent->Scale();
else
return glm::vec2(Width, Height) / glm::vec2(BaseWidth, BaseHeight);
}
Rectangle AbsoluteRectangle()
{
int left = Left();
if (m_Parent)
left = std::max(left, m_Parent->Left());
int top = Top();
if (m_Parent)
top = std::max(top, m_Parent->Top());
int width = Right() - left;
int height = Bottom() - top;
return Rectangle(left, top, width, height);
}
void UpdateLayered(double dt)
{
// Update ourselves
this->Update(dt);
// Update children
for (auto& pairLayer : m_Children) {
auto children = pairLayer.second;
for (auto& pairChild : children) {
auto child = pairChild.second;
child->Update(dt);
}
}
}
virtual void Update(double dt) { }
void DrawLayered(RenderQueueCollection& rq)
{
if (this->Hidden())
return;
// Draw ourselves
this->Draw(rq);
// Draw children
for (auto& pairLayer : m_Children) {
auto children = pairLayer.second;
for (auto& pairChild : children) {
auto child = pairChild.second;
if (child->Hidden())
continue;
child->Draw(rq);
}
}
}
virtual void Draw(RenderQueueCollection& rq) { }
protected:
::EventBroker* m_EventBroker;
Frame* BaseFrame = nullptr;
std::string m_Name = "Unnamed";
int m_Layer = 0;
bool m_Hidden = false;
Frame* m_Parent = nullptr;
typedef std::multimap<std::string, Frame*> Children_t; // name -> frame
std::map<int, Children_t> m_Children; // layer -> Children_t
virtual bool OnKeyDown(const Events::KeyDown& event) { return false; }
virtual bool OnKeyUp(const Events::KeyUp& event) { return false; }
virtual bool OnCommand(const Events::InputCommand& event) { return false; }
private:
EventRelay<Frame, Events::KeyDown> m_EKeyDown;
EventRelay<Frame, Events::KeyUp> m_EKeyUp;
EventRelay<Frame, Events::InputCommand> m_EInputCommand;
};
}
#endif
-33
View File
@@ -1,33 +0,0 @@
#ifndef MainMenuSystem_h__
#define MainMenuSystem_h__
#include "../Core/System.h"
#include "../Rendering/IRenderer.h"
#include "../Core/ResourceManager.h"
#include "../Core/Event.h"
#include "EButtonClicked.h"
#include "EButtonPressed.h"
#include "EButtonReleased.h"
class MainMenuSystem : public ImpureSystem
{
public:
MainMenuSystem(SystemParams params, IRenderer* renderer);
virtual void Update(double dt) override;
private:
IRenderer* m_Renderer;
EventRelay<MainMenuSystem, Events::ButtonClicked> m_EClicked;
bool OnButtonClick(const Events::ButtonClicked& e);
EventRelay<MainMenuSystem, Events::ButtonReleased> m_EReleased;
bool OnButtonRelease(const Events::ButtonReleased& e);
EventRelay<MainMenuSystem, Events::ButtonPressed> m_EPressed;
bool OnButtonPress(const Events::ButtonPressed& e);
};
#endif
+111
View File
@@ -0,0 +1,111 @@
#ifndef GUI_TextureFrame_h__
#define GUI_TextureFrame_h__
#include "Frame.h"
#include "../Rendering/Texture.h"
namespace GUI
{
class TextureFrame : public Frame
{
public:
TextureFrame(Frame* parent, std::string name)
: Frame(parent, name) { }
void EnableScissor() { m_ScissorEnabled = true; }
void DisableScissor() { m_ScissorEnabled = false; }
void Draw(RenderQueueCollection& rq) override
{
if (m_Texture == nullptr)
return;
// Texture while fading
if (m_FadeTexture && m_CurrentFade < 1) {
FrameJob job;
job.Scissor = (m_ScissorEnabled) ? m_Parent->AbsoluteRectangle() : Rectangle();
job.Viewport = Rectangle(Left(), Top(), Width, Height);
job.TextureID = m_FadeTexture->ResourceID;
job.DiffuseTexture = m_FadeTexture;
job.Color = glm::vec4(m_Color.r, m_Color.g, m_Color.b, m_Color.a);
job.Name = Name();
rq.GUI.Add(job);
}
// Main texture
{
FrameJob job;
job.Scissor = (m_ScissorEnabled) ? m_Parent->AbsoluteRectangle() : Rectangle();
job.Viewport = Rectangle(Left(), Top(), Width, Height);
job.TextureID = m_Texture->ResourceID;
job.DiffuseTexture = m_Texture;
job.Color = glm::vec4(m_Color.r, m_Color.g, m_Color.b, m_Color.a * m_CurrentFade);
job.Name = Name();
rq.GUI.Add(job);
}
}
std::string Texture() const { return m_TextureName; }
void SetTexture(std::string resourceName)
{
if (resourceName.empty()) {
m_Texture = nullptr;
return;
}
m_Texture = ResourceManager::Load<Texture>(resourceName);
m_TextureName = resourceName;
if (m_Texture == nullptr) {
m_Texture = ResourceManager::Load<Texture>("Textures/Core/ErrorTexture.png");
}
SizeToTexture();
}
void SizeToTexture()
{
if (m_Texture != nullptr) {
this->Width = m_Texture->Width;
this->Height = m_Texture->Height;
}
}
void FadeToTexture(std::string resourceName, double duration)
{
m_FadeTexture = m_Texture;
SetTexture(resourceName);
m_FadeDuration = duration;
m_CurrentFade = 0.f;
}
void Update(double dt) override
{
if (m_CurrentFade < 1) {
m_CurrentFade += dt / m_FadeDuration;
if (m_CurrentFade > 1) {
m_FadeTexture = nullptr;
m_CurrentFade = 1;
m_FadeDuration = 0;
}
}
}
glm::vec4 Color() const { return m_Color; }
void SetColor(glm::vec4 val) { m_Color = val; }
protected:
bool m_ScissorEnabled = true;
Texture* m_Texture = nullptr;
std::string m_TextureName;
Texture* m_FadeTexture = nullptr;
glm::vec4 m_Color = glm::vec4(1.f, 1.f, 1.f, 1.f);
float m_FadeDuration = 0.f;
float m_CurrentFade = 1.f;
};
}
#endif
+1 -3
View File
@@ -2,7 +2,6 @@
#define Events_InputCommand_h__ #define Events_InputCommand_h__
#include "Core/EventBroker.h" #include "Core/EventBroker.h"
#include "Core/EntityWrapper.h"
namespace Events namespace Events
{ {
@@ -10,8 +9,7 @@ namespace Events
struct InputCommand : Event struct InputCommand : Event
{ {
/** Numerical ID of the player. */ /** Numerical ID of the player. */
int PlayerID; unsigned int PlayerID;
EntityWrapper Player;
/** The command that was sent. */ /** The command that was sent. */
std::string Command; std::string Command;
/** The value of the command. */ /** The value of the command. */
+45 -219
View File
@@ -4,241 +4,67 @@
#include "../GLM.h" #include "../GLM.h"
#include "../Core/InputController.h" #include "../Core/InputController.h"
#include "../Core/ELockMouse.h" #include "../Core/ELockMouse.h"
#include "../Game/Events/EDashAbility.h"
#include "InputHandler.h"
template <typename EventContext> template <typename EventContext>
class FirstPersonInputController : public InputController<EventContext> class FirstPersonInputController : public InputController<EventContext>
{ {
public: public:
FirstPersonInputController(EventBroker* eventBroker, int playerID); FirstPersonInputController(EventBroker* eventBroker, unsigned int playerID)
: InputController(eventBroker)
virtual const glm::vec3 Movement() const { return m_Movement; } , m_PlayerID(playerID)
virtual const glm::vec3 Rotation() const { return m_Rotation; } {
virtual bool Jumping() const { return m_Jumping; } EVENT_SUBSCRIBE_MEMBER(m_ELockMouse, &FirstPersonInputController::OnLockMouse);
virtual bool Crouching() const { return m_Crouching; } EVENT_SUBSCRIBE_MEMBER(m_EUnlockMouse, &FirstPersonInputController::OnUnlockMouse);
virtual bool DoubleJumping() const { return m_DoubleJumping; }
virtual void SetDoubleJumping(bool isDoubleJumping) {
m_DoubleJumping = isDoubleJumping;
} }
void LockMouse(); const glm::quat Orientation() const { return m_Orientation; }
void UnlockMouse();
virtual bool OnCommand(const Events::InputCommand& e) override;
virtual void Reset();
void AssaultDashCheck(double dt, bool isJumping, double assaultDashCoolDownMaxTimer); void LockMouse()
virtual bool AssaultDashDoubleTapped() const { return m_AssaultDashDoubleTapped; } {
virtual bool PlayerIsDashing() const { return m_PlayerIsDashing; } Events::LockMouse e;
m_EventBroker->Publish(e);
m_MouseLocked = true;
}
protected: void UnlockMouse()
const int m_PlayerID; {
bool m_MouseLocked = false; Events::UnlockMouse e;
glm::vec3 m_Rotation; m_EventBroker->Publish(e);
glm::vec3 m_Movement; m_MouseLocked = false;
bool m_Jumping = false; }
bool m_DoubleJumping = false;
bool m_Crouching = false;
//assault dash membervariables - needed to calculate the doubletap- and dashlogic
double m_AssaultDashDoubleTapDeltaTime = 0.0;
double m_AssaultDashCoolDownTimer = 0.0;
//i will let m_AssaultDashDoubleTapSensitivityTimer stay hardcoded, its not really a gamevariable (more an inputvariable),
//and its very unlikely that someone wants to change that value
const float m_AssaultDashDoubleTapSensitivityTimer = 0.25f;
std::string m_AssaultDashTapDirection = "";
std::string m_CurrentDirectionVector = "";
bool m_AssaultDashDoubleTapped = false;
bool m_PlayerIsDashing = false;
bool m_ShiftDashing = false;
bool m_ValidDoubleTap = false;
//specialabilitys virtual bool OnCommand(const Events::InputCommand& e) override
bool m_MovementKeyDown = false; {
bool m_SpecialAbilityKeyDown = false; if (m_PlayerID != e.PlayerID) {
int m_NumberOfMovementKeysDown = 0; return false;
}
EventRelay<EventContext, Events::LockMouse> m_ELockMouse; if (m_MouseLocked) {
bool OnLockMouse(const Events::LockMouse& e); if (e.Command == "Pitch") {
EventRelay<EventContext, Events::UnlockMouse> m_EUnlockMouse; float val = glm::radians(e.Value);
bool OnUnlockMouse(const Events::UnlockMouse& e); m_Orientation = m_Orientation * glm::angleAxis<float>(-val, glm::vec3(1, 0, 0));
}; return true;
}
template <typename EventContext> if (e.Command == "Yaw") {
FirstPersonInputController<EventContext>::FirstPersonInputController(EventBroker* eventBroker, int playerID) float val = glm::radians(e.Value);
: InputController(eventBroker) m_Orientation = glm::angleAxis<float>(-val, glm::vec3(0, 1, 0)) * m_Orientation;
, m_PlayerID(playerID) return true;
{ }
EVENT_SUBSCRIBE_MEMBER(m_ELockMouse, &FirstPersonInputController::OnLockMouse); }
EVENT_SUBSCRIBE_MEMBER(m_EUnlockMouse, &FirstPersonInputController::OnUnlockMouse);
}
template <typename EventContext>
void FirstPersonInputController<EventContext>::Reset()
{
m_Rotation = glm::vec3(0.f, 0.f, 0.f);
m_Jumping = false;
}
template <typename EventContext>
void FirstPersonInputController<EventContext>::LockMouse()
{
Events::LockMouse e;
m_EventBroker->Publish(e);
m_MouseLocked = true;
}
template <typename EventContext>
void FirstPersonInputController<EventContext>::UnlockMouse()
{
Events::UnlockMouse e;
m_EventBroker->Publish(e);
m_MouseLocked = false;
}
template <typename EventContext>
bool FirstPersonInputController<EventContext>::OnCommand(const Events::InputCommand& e)
{
if (m_PlayerID != e.PlayerID) {
return false; return false;
} }
if (e.Command == "Pitch") { protected:
float val = glm::radians(e.Value); const unsigned int m_PlayerID;
m_Rotation.x += -val; glm::quat m_Orientation;
//m_Rotation.x = glm::clamp(m_Rotation.x, -glm::half_pi<float>(), glm::half_pi<float>()); bool m_MouseLocked = false;
}
if (e.Command == "Yaw") { EventRelay<EventContext, Events::LockMouse> m_ELockMouse;
float val = glm::radians(e.Value); bool OnLockMouse(const Events::LockMouse& e) { m_MouseLocked = true; return true; }
m_Rotation.y += -val; EventRelay<EventContext, Events::UnlockMouse> m_EUnlockMouse;
} bool OnUnlockMouse(const Events::UnlockMouse& e) { m_MouseLocked = false; return true; }
};
if (e.Command == "Forward" || e.Command == "Right") {
if (e.Command == "Forward") {
float val = glm::clamp(e.Value, -1.f, 1.f);
m_Movement.z = -val;
}
if (e.Command == "Right") {
float val = glm::clamp(e.Value, -1.f, 1.f);
m_Movement.x = val;
}
if (glm::length2(m_Movement) > 0) {
m_Movement = glm::normalize(m_Movement);
}
}
if (e.Command == "Forward" || e.Command == "Right") {
if (e.Value != 0) {
m_CurrentDirectionVector = e.Command == "Right" ? (e.Value > 0 ? "Right" : "Left") : (e.Value > 0 ? "Forward" : "Backward");
}
//if value = 0 then you have just released this key
if (e.Value != 0) {
m_NumberOfMovementKeysDown++;
m_MovementKeyDown = true;
//if you pressed the same key within m_AssaultDashDoubleTapSensitivityTimer then you have doubletapped it
if (m_AssaultDashDoubleTapDeltaTime < m_AssaultDashDoubleTapSensitivityTimer && m_AssaultDashTapDirection == m_CurrentDirectionVector) {
m_ValidDoubleTap = true;
}
} else {
//== 0
m_NumberOfMovementKeysDown--;
if (m_NumberOfMovementKeysDown == 0) {
m_MovementKeyDown = false;
}
//you have just released the key, store what key it was and reset the doubletap-sensitivity-timer
m_AssaultDashTapDirection = m_CurrentDirectionVector;
m_AssaultDashDoubleTapDeltaTime = 0.f;
}
}
if (e.Command == "Jump") {
m_Jumping = e.Value > 0;
}
if (e.Command == "Crouch") {
m_Crouching = e.Value > 0;
}
if (e.Command == "SpecialAbility") {
if (e.Value > 0) {
m_SpecialAbilityKeyDown = true;
} else {
m_SpecialAbilityKeyDown = false;
}
}
if (m_SpecialAbilityKeyDown && m_MovementKeyDown) {
m_ShiftDashing = true;
} else {
m_ShiftDashing = false;
}
return true;
}
template <typename EventContext>
bool FirstPersonInputController<EventContext>::OnUnlockMouse(const Events::UnlockMouse& e)
{
m_MouseLocked = false;
return true;
}
template <typename EventContext>
bool FirstPersonInputController<EventContext>::OnLockMouse(const Events::LockMouse& e)
{
m_MouseLocked = true;
return true;
}
template <typename EventContext>
void FirstPersonInputController<EventContext>::AssaultDashCheck(double dt, bool isJumping, double assaultDashCoolDownMaxTimer) {
m_AssaultDashDoubleTapDeltaTime += dt;
m_AssaultDashCoolDownTimer -= dt;
//cooldown = assaultDashCoolDownMaxTimer sec, pretend the dash lasts 0.25 sec (for friction to do its work)
if (m_AssaultDashCoolDownTimer > (assaultDashCoolDownMaxTimer - 0.25f)) {
m_PlayerIsDashing = true;
} else {
m_PlayerIsDashing = false;
}
//dashing with shift
if (m_ShiftDashing && m_AssaultDashCoolDownTimer <= 0.0f) {
//player is dashing with shift
//the wanted-direction is set in playermovement already so we dont need to check what direction we want to dash in!
m_AssaultDashCoolDownTimer = assaultDashCoolDownMaxTimer;
m_AssaultDashDoubleTapped = true;
m_AssaultDashDoubleTapDeltaTime = 0.f;
return;
}
//reset the DoubleTapped state in case we recently doubleTapped (doubletap will only happen during 1 frame)
if (m_AssaultDashDoubleTapped) {
m_AssaultDashDoubleTapped = false;
}
//dashing with doubletap - check if doubletap to dash enabled
if (!ResourceManager::Load<ConfigFile>("Input.ini")->Get<bool>("Keyboard.DoubleTapToDash", false)) {
return;
}
//check if we have received a valid doubletap
if (!m_ValidDoubleTap) {
return;
}
m_ValidDoubleTap = false;
if (!(m_AssaultDashCoolDownTimer <= 0.0f)) {
//if we cant dash at the moment, then just reset the tap-sensitivity-timer
m_AssaultDashDoubleTapDeltaTime = 0.f;
return;
}
//ok, we have a valid tap, lets do it
m_AssaultDashDoubleTapped = true;
m_AssaultDashDoubleTapDeltaTime = 0.f;
m_AssaultDashCoolDownTimer = assaultDashCoolDownMaxTimer;
Events::DashAbility e;
m_EventBroker->Publish(e);
}
#endif #endif
-1
View File
@@ -1,7 +1,6 @@
#ifndef InputProxy_h__ #ifndef InputProxy_h__
#define InputProxy_h__ #define InputProxy_h__
#include <boost/tokenizer.hpp>
#include "../Common.h" #include "../Common.h"
#include "../Core/ResourceManager.h" #include "../Core/ResourceManager.h"
#include "../Core/ConfigFile.h" #include "../Core/ConfigFile.h"
+35 -92
View File
@@ -3,139 +3,82 @@
#include <string> #include <string>
#include <ctime> #include <ctime>
#include <limits>
#include <queue>
#include <glm/common.hpp> #include <glm/common.hpp>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/shared_array.hpp>
#include "Network/Network.h" #include "Network/Network.h"
#include "Network/MessageType.h" #include "Network/MessageType.h"
#include "Network/PlayerDefinition.h" #include "Network/PlayerDefinition.h"
#include "Network/UDPClient.h"
#include "Network/TCPClient.h"
#include "Network/SnapshotDefinitions.h" #include "Network/SnapshotDefinitions.h"
#include "Core/World.h" #include "Core/World.h"
#include "Core/EventBroker.h" #include "Core/EventBroker.h"
#include "Core/ConfigFile.h" #include "Core/ConfigFile.h"
#include "Input/EInputCommand.h" #include "Input/EInputCommand.h"
#include "Core/EPlayerDamage.h"
#include "Network/EInterpolate.h"
#include "Network/SnapshotFilter.h"
#include "Core/EPlayerSpawned.h"
#include "Network/ESearchForServers.h"
struct ServerInfo
{
ServerInfo(std::string a, int b, std::string c, int d)
{
Address = a; Port = b; Name = c; PlayersConnected = d;
}
std::string Address = "";
int Port = 0;
std::string Name = "";
int PlayersConnected = 0;
};
class Client : public Network class Client : public Network
{ {
public: public:
Client(World* world, EventBroker* eventBroker); Client(ConfigFile* config);
Client(World* world, EventBroker* eventBroker, std::unique_ptr<SnapshotFilter> snapshotFilter);
~Client(); ~Client();
void Start(World* world, EventBroker* eventBroker) override;
void Connect(std::string address, int port);
void Update() override; void Update() override;
void Close();
private:
// Assio UDP logic
boost::asio::ip::udp::endpoint m_ReceiverEndpoint;
boost::asio::io_service m_IOService;
boost::asio::ip::udp::socket m_Socket;
std::vector<Events::PlayerSpawned> m_PlayerSpawnEvents;
void parseSpawnEvents();
// Save for children
std::unique_ptr<SnapshotFilter> m_SnapshotFilter = nullptr;
std::string m_Address;
int m_Port = 0;
// Sending message to server logic // Sending message to server logic
size_t bytesRead = 0; int bytesRead = -1;
char readBuf[1024] = { 0 };
int snapshotInterval = 33;
std::clock_t previousSnapshotMessage = std::clock();
// Packet loss logic // Packet loss logic
PacketID m_PacketID = 0; unsigned int m_PacketID = 0;
PacketID m_PreviousPacketID = 0; unsigned int m_PreviousPacketID = 0;
PacketID m_SendPacketID = 0; unsigned int m_SendPacketID = 0;
// Game logic // Game logic
World* m_World;
std::string m_PlayerName; std::string m_PlayerName;
PlayerID m_PlayerID = -1; int m_PlayerID = -1;
bool m_IsConnected = false;
EntityWrapper m_LocalPlayer = EntityWrapper::Invalid;
// Server Client Lookup map
// Assumes that root node for client and server is EntityID 0.
// Don't Add items to these two maps with insert, use insertIntoServerClientMaps(EntityID, EntityID)!!!!
std::unordered_map<EntityID, EntityID> m_ServerIDToClientID;
std::unordered_map<EntityID, EntityID> m_ClientIDToServerID;
// Network logic // Network logic
PlayerDefinition m_PlayerDefinitions[8]; PlayerDefinition m_PlayerDefinitions[MAXCONNECTIONS];
SnapshotDefinitions m_NextSnapshot; SnapshotDefinitions m_NextSnapshot;
bool m_ThreadIsRunning = true;
double m_DurationOfPingTime; double m_DurationOfPingTime;
std::clock_t m_StartPingTime; std::clock_t m_StartPingTime;
std::clock_t m_TimeSinceSentInputs; // Use to check if we should send disconnect message
unsigned int m_SendInputIntervalMs; // if game is turned of by closing window.
std::vector<Events::InputCommand> m_InputCommandBuffer; bool m_WasStarted = false;
// Private member functions // Private member functions
size_t receive(char* data); void readFromServer();
void sendSnapshotToServer();
int receive(char* data, size_t length);
void send(Packet& packet);
void connect();
void disconnect(); void disconnect();
void ping();
void moveMessageHead(char*& data, size_t& length, size_t stepSize);
void parseMessageType(Packet& packet); void parseMessageType(Packet& packet);
void updateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID); void parseEventMessage(Packet& packet);
SharedComponentWrapper createSharedComponent(Packet& packet, EntityID entityID, const ComponentInfo& componentInfo); void parseConnect(Packet& packet);
void ignoreFields(Packet& packet, const ComponentInfo& componentInfo);
void parseUDPConnect(Packet& packet);
void parseTCPConnect(Packet& packet);
void parsePlayerConnected(Packet& packet);
void parsePing(); void parsePing();
void parseServerlist(Packet& packet); void parseServerPing();
void parseKick();
void parsePlayersSpawned(Packet& packet);
void parseEntityDeletion(Packet& packet);
void parsePlayerDamage(Packet& packet);
void parseComponentDeletion(Packet& packet);
void InterpolateFields(Packet & packet, const ComponentInfo & componentInfo, const EntityID & entityID, const std::string & componentType);
void parseSnapshot(Packet& packet); void parseSnapshot(Packet& packet);
void UpdateLocalCapturePointHUD(EntityWrapper capturePointHUD);
void identifyPacketLoss(); void identifyPacketLoss();
void hasServerTimedOut(); bool isConnected();
EntityID createPlayer(); EntityID createPlayer();
void sendInputCommands();
void sendLocalPlayerTransform();
void becomePlayer();
void displayServerlist();
// Mapping Logic
// Returns if local EntityID exist in map
bool clientServerMapsHasEntity(EntityID clientEntityID);
// Returns if server EntityID exist in map
bool serverClientMapsHasEntity(EntityID serverEntityID);
void insertIntoServerClientMaps(EntityID serverEntityID, EntityID clientEntityID);
void deleteFromServerClientMaps(EntityID serverEntityID, EntityID clientEntityID);
// Events // Events
EventBroker* m_EventBroker;
EventRelay<Client, Events::InputCommand> m_EInputCommand; EventRelay<Client, Events::InputCommand> m_EInputCommand;
bool OnInputCommand(const Events::InputCommand& e); bool OnInputCommand(const Events::InputCommand &e);
EventRelay<Client, Events::PlayerDamage> m_EPlayerDamage;
bool OnPlayerDamage(const Events::PlayerDamage& e);
EventRelay<Client, Events::PlayerSpawned> m_EPlayerSpawned;
bool OnPlayerSpawned(const Events::PlayerSpawned& e);
EventRelay< Client, Events::SearchForServers> m_ESearchForServers;
bool OnSearchForServers(const Events::SearchForServers& e);
private:
UDPClient m_Unreliable;
UDPClient m_ServerlistRequest;
TCPClient m_Reliable;
std::vector<ServerInfo> m_Serverlist;
bool m_SearchingForServers = false;
std::clock_t m_StartSearchTime;
double m_SearchingTime = 2000; // Config I guess
}; };
#endif #endif
-25
View File
@@ -1,25 +0,0 @@
#ifndef Events_Interpolate_h__
#define Events_Interpolate_h__
#include <boost/shared_array.hpp>
#include "Core/EventBroker.h"
#include "Core/Entity.h"
namespace Events
{
struct Interpolate : Event
{
Interpolate(EntityWrapper Entity, SharedComponentWrapper Component)
: Entity(Entity)
, Component(Component)
{ }
EntityWrapper Entity;
SharedComponentWrapper Component;
};
}
#endif
@@ -1,18 +0,0 @@
#ifndef Events_PlayerDisconnected
#define Events_PlayerDisconnected
#include "Core/EventBroker.h"
#include "Core/Entity.h"
namespace Events
{
struct PlayerDisconnected : public Event
{
unsigned int PlayerID;
EntityID Entity;
};
}
#endif
@@ -1,12 +0,0 @@
#ifndef Events_SearchForServers_h__
#define Events_SearchForServers_h__
#include "Core/Event.h"
namespace Events
{
struct SearchForServers : public Event { };
}
#endif
+7 -16
View File
@@ -5,22 +5,13 @@
// Used to determine what type of message was sent. // Used to determine what type of message was sent.
enum class MessageType enum class MessageType
{ {
Connect, Connect,
Disconnect, Disconnect,
Ping, ClientPing,
Message, ServerPing,
Snapshot, Message,
OnInputCommand, Snapshot,
OnPlayerDamage, Event,
PlayerConnected,
BecomePlayer,
Kick,
OnPlayerSpawned,
EntityDeleted,
ComponentDeleted,
PlayerTransform,
ServerlistRequest,
Invalid
}; };
#endif #endif
+3 -28
View File
@@ -1,44 +1,19 @@
#ifndef Network_h__ #ifndef Network_h__
#define Network_h__ #define Network_h__
#include <ctime>
#include "Core/World.h" #include "Core/World.h"
#include "Core/EventBroker.h" #include "Core/EventBroker.h"
#include "Network/Packet.h" #include "Network/Packet.h"
#include "Network/NetworkData.h"
#include "Core/ResourceManager.h"
#include "Core/ConfigFile.h"
#include <fstream>
#include <iostream>
#define BUFFERSIZE 32000 #define MAXCONNECTIONS 8
typedef unsigned int PlayerID; #define INPUTSIZE 128
typedef unsigned int PacketID;
class Network class Network
{ {
public: public:
Network(World* world, EventBroker* eventBroker);
virtual ~Network() { }; virtual ~Network() { };
virtual void Start(World* m_world, EventBroker *eventBroker) = 0;
virtual void Update() = 0; virtual void Update() = 0;
protected:
World* m_World;
EventBroker* m_EventBroker;
// For Debug
bool isReadingData = false;
NetworkData m_NetworkData;
unsigned int m_SaveDataIntervalMs = 1000;
std::clock_t m_SaveDataTimer;
unsigned int m_MaxConnections;
double m_TimeoutMs;
void logSentData(int bytesSent);
void logReceivedData(int bytesReceived);
void saveToFile();
void updateNetworkData();
}; };
#endif #endif
-24
View File
@@ -1,24 +0,0 @@
#ifndef NetworkClient_h__
#define NetworkClient_h__
#include "Network/Packet.h"
#define BUFFERSIZE 64000
typedef unsigned int PlayerID;
typedef unsigned int PacketID;
class NetworkClient
{
public:
NetworkClient();
virtual ~NetworkClient();
virtual void Connect(std::string playerName, std::string address, int port) = 0;
virtual void Disconnect() = 0;
virtual void Receive(Packet& packet) = 0;
virtual void Send(Packet & packet) = 0;
virtual bool IsSocketAvailable() = 0;
protected:
char* m_ReadBuffer;
unsigned int m_BufferSize = BUFFERSIZE;
};
#endif
-18
View File
@@ -1,18 +0,0 @@
#ifndef NetworkData_h__
#define NetworkData_h__
#include <vector>
struct NetworkData {
double TotalTime = 0;
size_t TotalDataReceived = 0;
size_t TotalDataSent = 0;
size_t AmountOfMessagesReceived = 0;
unsigned int AmountOfMessagesSent = 0;
// Interval based
size_t DataReceivedThisInterval = 0;
size_t DataSentThisInterval = 0;
// pair: first=reveived, second=send
std::vector<std::pair<size_t, size_t>> BandwidthBytes;
};
#endif
-24
View File
@@ -1,24 +0,0 @@
#ifndef NetworkServer_h__
#define NetworkServer_h__
#include <boost/asio.hpp>
#include "Network/Packet.h"
#include "Network/PlayerDefinition.h"
#define BUFFERSIZE 64000
typedef unsigned int PlayerID;
typedef unsigned int PacketID;
class NetworkServer
{
public:
NetworkServer();
virtual ~NetworkServer();
virtual void AcceptNewConnections(int& nextPlayerID, std::map<PlayerID, PlayerDefinition>& connectedPlayers) = 0;
virtual void Receive(Packet & packet, PlayerDefinition & playerDefinition) = 0;
virtual void Send(Packet & packet, PlayerDefinition & playerDefinition) = 0;
virtual void Send(Packet & packet) = 0;
protected:
char* m_ReadBuffer;
unsigned int m_BufferSize = BUFFERSIZE;
};
#endif
+9 -23
View File
@@ -13,19 +13,16 @@ public:
// arg2: PacketID for identifying packet loss. // arg2: PacketID for identifying packet loss.
Packet(MessageType type, unsigned int& packetID); Packet(MessageType type, unsigned int& packetID);
// Used to create packet from already existing data buffer. // Used to create packet from already existing data buffer.
Packet(char* data, const size_t sizeOfPacket); Packet(char* data, const int sizeOfPacket);
Packet(MessageType type);
~Packet();
void Init(MessageType type, unsigned int& packetID);
~Packet();
// Add primitive types like int, float, char... // Add primitive types like int, float, char...
template<typename T> template<typename T>
void WritePrimitive(T val) void WritePrimitive(T val)
{ {
// Check if we are trying to add more than the package can fit. // Check if we are trying to add more than the package can fit.
if (m_MaxPacketSize < m_Offset + sizeof(T)) { if (m_MaxPacketSize < m_Offset + sizeof(T)) {
LOG_WARNING("Packet AddPrimitive(): You are trying to add more than we have allocated for! New size is %i bytes\n", m_MaxPacketSize*2); LOG_WARNING("Packet AddPrimitive(): You are trying to add more than we have allocated for!");
resizeData();
} }
memcpy(m_Data + m_Offset, &val, sizeof(T)); memcpy(m_Data + m_Offset, &val, sizeof(T));
m_Offset += sizeof(T); m_Offset += sizeof(T);
@@ -44,32 +41,21 @@ public:
return returnValue; return returnValue;
} }
// Add a string to the message // Add a string to the message
void WriteString(const std::string& str); void WriteString(std::string str);
// Add data to the message // Add data to the message
void WriteData(char* data, int sizeOfData); void WriteData(char* data, int sizeOfData);
// Pops the first element as if it was a string. // Pops the first element as if it was a string.
std::string ReadString(); std::string ReadString();
// Construct a packet
void ReconstructFromData(char* data, size_t SizeOfData);
// Update size of packet variable in header
void UpdateSize();
char* ReadData(int SizeOfData); char* ReadData(int SizeOfData);
void ChangePacketID(unsigned int& packetID);
size_t Size() { return m_Offset; }; int Size() { return m_Offset; };
char* Data() { return m_Data; }; char* Data() { return m_Data; };
MessageType GetMessageType();
size_t DataReadSize() { return m_ReturnDataOffset; }
size_t MaxSize() { return m_MaxPacketSize; }
size_t HeaderSize() { return m_HeaderSize; }
private: private:
char* m_Data; char* m_Data;
size_t m_ReturnDataOffset = 0; unsigned int m_ReturnDataOffset = 0;
size_t m_Offset = 0; int m_Offset = 0;
size_t m_MaxPacketSize = 512; unsigned int m_MaxPacketSize = 128;
size_t m_HeaderSize = 0;
void resizeData();
void resizeData(int size);
}; };
#endif #endif
+1 -9
View File
@@ -1,19 +1,11 @@
#ifndef PlayerDefinition_h__ #ifndef PlayerDefinition_h__
#define PlayerDefinition_h__ #define PlayerDefinition_h__
#include <string> #include <string>
#include "../Core/Entity.h"
#include <boost/asio.hpp>
struct PlayerDefinition { struct PlayerDefinition {
::EntityID EntityID = EntityID_Invalid; int EntityID = -1;
std::string Name = ""; std::string Name = "";
boost::asio::ip::udp::endpoint Endpoint; boost::asio::ip::udp::endpoint Endpoint;
unsigned int PacketID;
std::clock_t StopTime;
boost::asio::ip::address TCPAddress;
unsigned short TCPPort;
// use for tcp connections
boost::shared_ptr<boost::asio::ip::tcp::socket> TCPSocket;
}; };
#endif #endif
+44 -62
View File
@@ -5,99 +5,81 @@
#include <ctime> #include <ctime>
#include <glm/common.hpp> #include <glm/common.hpp>
#include <boost/asio/ip/udp.hpp>
#include "Network/TCPServer.h"
#include "Network/UDPServer.h"
#include "Network/UDPClient.h" //LOL
#include "Network/MessageType.h" #include "Network/MessageType.h"
#include "Network/PlayerDefinition.h" #include "Network/PlayerDefinition.h"
#include "Core/World.h" #include "Core/World.h"
#include "Core/EventBroker.h" #include "Core/EventBroker.h"
#include "../Network/Network.h" #include "Network/Network.h"
#include "Input/EInputCommand.h"
#include "Core/EPlayerDamage.h"
#include "Network/EPlayerDisconnected.h"
#include "Core/EPlayerSpawned.h"
#include "Core/EEntityDeleted.h"
#include "Core/EComponentDeleted.h"
class Server : public Network class Server : public Network
{ {
public: public:
Server(World* world, EventBroker* eventBroker, int port); Server();
~Server(); ~Server();
void Start(World* m_world, EventBroker *eventBroker) override;
void Update() override; void Update() override;
void Close();
private: private:
// Network channels // UDP logic
TCPServer m_Reliable; boost::asio::ip::udp::endpoint m_ReceiverEndpoint;
UDPServer m_Unreliable; boost::asio::io_service m_IOService;
UDPServer m_ServerlistRequest; boost::asio::ip::udp::socket m_Socket;
// dont forget to set these in the childrens receive logic PlayerDefinition m_PlayerDefinitions[MAXCONNECTIONS];
boost::asio::ip::address m_Address;
int m_Port = 27666;
// Sending messages to client logic // Sending messages to client logic
std::map<PlayerID, PlayerDefinition> m_ConnectedPlayers; char readBuffer[1024] = { 0 };
std::vector<PlayerID> m_PlayersToDisconnect; int bytesRead = 0;
// HACK: Fix INPUTSIZE
char readBuffer[BUFFERSIZE] = { 0 };
size_t bytesRead = 0;
// time for previouse message // time for previouse message
std::clock_t previousePingMessage = std::clock(); std::clock_t previousePingMessage = std::clock();
std::clock_t previousSnapshotMessage = std::clock(); std::clock_t previousSnapshotMessage = std::clock();
std::clock_t timOutTimer = std::clock(); std::clock_t timOutTimer = std::clock();
// How often we send messages (milliseconds) // How often we send messages (milliseconds)
float pingIntervalMs; int intervalMs = 1000;
float snapshotInterval; int snapshotInterval = 50;
int checkTimeOutInterval = 100; int checkTimeOutInterval = 100;
int m_NextPlayerID = 0;
std::vector<Events::InputCommand> m_InputCommandsToBroadcast;
//Timers //Timers
std::clock_t m_StartPingTime; std::clock_t m_StartPingTime;
std::clock_t m_StopTimes[8];
// Game logic
World* m_World;
EventBroker* m_EventBroker;
// vec.size() = ammount of players to create, stores playerID's
std::vector<unsigned int> m_PlayersToCreate;
// Packet loss logic // Packet loss logic
PacketID m_PacketID = 0; unsigned int m_PacketID;
PacketID m_PreviousPacketID = 0; unsigned int m_PreviousPacketID;
unsigned int m_SendPacketID;
// Close logic
bool m_ThreadIsRunning = true;
// Private member functions // Private member functions
//int receive(char* data); int receive(char* data, size_t length);
void reliableBroadcast(Packet& packet); void readFromClients();
void unreliableBroadcast(Packet& packet); void send(Packet& packet, int playerID);
void send(Packet& packet);
void moveMessageHead(char*& data, size_t& length, size_t stepSize);
void broadcast(std::string message);
void broadcast(Packet& packet);
void sendSnapshot(); void sendSnapshot();
void addPlayersToPacket(Packet& packet, EntityID entityID);
void addChildrenToPacket(Packet& packet, EntityID entityID);
void addInputCommandsToPacket(Packet& packet);
void sendPing(); void sendPing();
void checkForTimeOuts(); void checkForTimeOuts();
void disconnect(PlayerID playerID); void disconnect(int i);
void parseMessageType(Packet& packet); void parseMessageType(Packet& packet);
void parseOnPlayerDamage(Packet& packet); void parseEvent(Packet& packet);
void identifyPacketLoss(); void parseConnect(Packet& packet);
void kick(PlayerID player);
PlayerID GetPlayerIDFromEndpoint();
void parsePlayerTransform(Packet& packet);
void parseOnInputCommand(Packet& packet);
void parseClientPing();
void parsePing();
void parseUDPConnect(Packet & packet);
void parseTCPConnect(Packet & packet);
void parseDisconnect(); void parseDisconnect();
void parseServerlistRequest(boost::asio::ip::udp::endpoint endpoint); void parseClientPing();
bool shouldSendToClient(EntityWrapper childEntity); void parseServerPing();
void parseSnapshot(Packet& packet);
// Debug event void identifyPacketLoss();
EventRelay<Server, Events::InputCommand> m_EInputCommand; EntityID createPlayer();
bool OnInputCommand(const Events::InputCommand& e);
EventRelay<Server, Events::PlayerSpawned> m_EPlayerSpawned;
bool OnPlayerSpawned(const Events::PlayerSpawned& e);
EventRelay<Server, Events::EntityDeleted> m_EEntityDeleted;
bool OnEntityDeleted(const Events::EntityDeleted& e);
EventRelay<Server, Events::ComponentDeleted> m_EComponentDeleted;
bool OnComponentDeleted(const Events::ComponentDeleted& e);
EventRelay<Server, Events::PlayerDamage> m_EPlayerDamage;
bool OnPlayerDamage(const Events::PlayerDamage& e);
}; };
#endif #endif
-19
View File
@@ -1,19 +0,0 @@
#ifndef SnapshotFilter_h__
#define SnapshotFilter_h__
#include "../Core/EntityWrapper.h"
#include "../Core/ComponentWrapper.h"
class SnapshotFilter
{
public:
// Filters an incoming snapshot.
// Modify the component and return true if the component snapshot should be applied.
// Otherwise return false and it will be ignored.
virtual bool FilterComponent(EntityWrapper entity, SharedComponentWrapper& component)
{
return true;
}
};
#endif
-28
View File
@@ -1,28 +0,0 @@
#ifndef TCPClient_h__
#define TCPClient_h__
#include <boost/asio.hpp>
#include "NetworkClient.h"
class TCPClient : public NetworkClient
{
public:
TCPClient();
~TCPClient();
void Connect(std::string playerName, std::string address, int port);
void Disconnect();
void Receive(Packet& packet);
void Send(Packet & packet);
bool IsSocketAvailable();
private:
// Assio TCP logic
boost::asio::ip::tcp::endpoint m_Endpoint;
boost::asio::io_service m_IOService;
std::unique_ptr<boost::asio::ip::tcp::socket> m_Socket;
size_t readBuffer();
PacketID m_SendPacketID = 0;
bool m_IsConnected = false;
};
#endif
-38
View File
@@ -1,38 +0,0 @@
#ifndef TCPServer_h__
#define TCPServer_h__
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <map>
#include "NetworkServer.h"
class TCPServer : public NetworkServer
{
public:
TCPServer();
~TCPServer();
void AcceptNewConnections(int& nextPlayerID, std::map<PlayerID, PlayerDefinition>& connectedPlayers);
void Receive(Packet & packet, PlayerDefinition & playerDefinition);
void Send(Packet & packet, PlayerDefinition & playerDefinition);
void Send(Packet & packet);
void Disconnect();
int Port() { return m_Port; }
std::string Address() { return m_Address; }
private:
// TCP logic
boost::asio::io_service m_IOService;
std::unique_ptr<boost::asio::ip::tcp::acceptor> acceptor;
boost::shared_ptr<boost::asio::ip::tcp::socket> lastReceivedSocket;
void handle_accept(boost::shared_ptr<boost::asio::ip::tcp::socket> socket,
int& nextPlayerID, std::map<PlayerID, PlayerDefinition>& connectedPlayers,
const boost::system::error_code& error);
int readBuffer(PlayerDefinition& playerDefinition);
int GetPort();
std::string GetAddress();
int m_Port = 0;
std::string m_Address = "";
};
#endif
-28
View File
@@ -1,28 +0,0 @@
#ifndef UDPClient_h__
#define UDPClient_h__
#include <boost/asio.hpp>
#include "Network/NetworkClient.h"
class UDPClient : public NetworkClient
{
public:
UDPClient();
~UDPClient();
void Connect(std::string playerName, std::string address, int port);
void Disconnect();
void Receive(Packet& packet);
void Send(Packet & packet);
void Broadcast(Packet& packet, int port);
bool IsSocketAvailable();
private:
// Assio UDP logic
boost::asio::io_service m_IOService;
boost::asio::ip::udp::endpoint m_ReceiverEndpoint;
boost::shared_ptr<boost::asio::ip::udp::socket> m_Socket;
int readBuffer();
PacketID m_SendPacketID = 0;
};
#endif
-28
View File
@@ -1,28 +0,0 @@
#ifndef UDPServer_h__
#define UDPServer_h__
#include "NetworkServer.h"
#include <boost/asio/ip/udp.hpp>
class UDPServer : public NetworkServer
{
public:
UDPServer();
UDPServer(int port);
~UDPServer();
void AcceptNewConnections(int& nextPlayerID, std::map<PlayerID, PlayerDefinition>& connectedPlayers);
void Receive(Packet & packet, PlayerDefinition & playerDefinition);
void Send(Packet & packet, PlayerDefinition & playerDefinition);
void Send(Packet & packet);
void Send(Packet & packet, boost::asio::ip::udp::endpoint endpoint);
void Broadcast(Packet & packet, int port);
bool IsSocketAvailable();
private:
// UDP logic
boost::asio::io_service m_IOService;
boost::asio::ip::udp::endpoint m_ReceiverEndpoint;
std::unique_ptr<boost::asio::ip::udp::socket> m_Socket;
int readBuffer();
};
#endif
@@ -1,29 +0,0 @@
#ifndef AnimationSystem_h__
#define AnimationSystem_h__
#include "GLM.h"
#include "Common.h"
#include "Core/System.h"
#include "Core/ResourceManager.h"
#include "Rendering/Model.h"
#include "Rendering/EAnimationComplete.h"
#include "Rendering/Skeleton.h"
#include <imgui/imgui.h>
class AnimationSystem : public PureSystem
{
public:
AnimationSystem(SystemParams params)
: System(params)
, PureSystem("Animation")
{
}
~AnimationSystem() { }
virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& animationComponent, double dt) override;
private:
};
#endif
+1 -1
View File
@@ -3,7 +3,7 @@
#include "../Core/ResourceManager.h" #include "../Core/ResourceManager.h"
class BaseTexture : public ThreadUnsafeResource class BaseTexture : public Resource
{ {
friend class ResourceManager; friend class ResourceManager;
@@ -1,29 +0,0 @@
#ifndef BoneAttachmentSystem_h__
#define BoneAttachmentSystem_h__
#include "GLM.h"
#include "Common.h"
#include "Core/System.h"
#include "Core/ResourceManager.h"
#include "Rendering/Model.h"
#include "Rendering/Skeleton.h"
//Needs to be a higher orderlevel than AnimationSystem
class BoneAttachmentSystem : public PureSystem
{
public:
BoneAttachmentSystem(SystemParams params)
: System(params)
, PureSystem("BoneAttachment")
{
}
~BoneAttachmentSystem() { }
virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& BoneAttachmentComponent, double dt) override;
private:
};
#endif
+7 -9
View File
@@ -2,7 +2,6 @@
#define Camera_h__ #define Camera_h__
#include "../GLM.h" #include "../GLM.h"
#include "../Core/Util/Rectangle.h"
class Camera class Camera
{ {
@@ -27,13 +26,13 @@ public:
glm::quat Orientation() const { return m_Orientation; } glm::quat Orientation() const { return m_Orientation; }
void SetOrientation(glm::quat val); void SetOrientation(glm::quat val);
/*float Pitch() const { return m_Pitch; }
void Pitch(float val);
float Yaw() const { return m_Yaw; }
void Yaw(float val);*/
glm::mat4 ProjectionMatrix() const { return m_ProjectionMatrix; } glm::mat4 ProjectionMatrix() const { return m_ProjectionMatrix; }
void SetProjectionMatrix(glm::mat4 val);
glm::mat4 ViewMatrix() const { return m_ViewMatrix; } glm::mat4 ViewMatrix() const { return m_ViewMatrix; }
void SetViewMatrix(glm::mat4 val);
glm::mat4 BillboardMatrix();
float AspectRatio() const { return m_AspectRatio; } float AspectRatio() const { return m_AspectRatio; }
void SetAspectRatio(float val); void SetAspectRatio(float val);
@@ -47,12 +46,11 @@ public:
float FarClip() const { return m_FarClip; } float FarClip() const { return m_FarClip; }
void SetFarClip(float val); void SetFarClip(float val);
void UpdateViewMatrix();
void UpdateProjectionMatrix();
glm::vec2 WorldToScreen(glm::vec3 worldCoord, Rectangle resolution);
private: private:
void UpdateViewMatrix();
void UpdateProjectionMatrix();
glm::vec3 m_Position; glm::vec3 m_Position;
glm::quat m_Orientation; glm::quat m_Orientation;

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