Compare commits

..

4 Commits

Author SHA1 Message Date
maqu14 7fc83d1471 Live texturing 2016-03-18 10:14:02 +01:00
maqu14 65e5729118 Added assets 2016-01-27 12:34:24 +01:00
maqu14 26d6f4c7cf Live texturing, fixed so Maya wont crash when the plugin is unloaded and Photoshop not being able to read the file under specific circumstances. 2015-12-16 17:45:20 +01:00
Teejoon e513059522 This is the "working"(little buggy) PhotoShop to Maya connection.
Ask Johan if you want to get this to work, since you need to install zmq, nodeJS, add a line to Maya.env file and som othe stuff for it to work.
2015-12-09 15:11:53 +01:00
1049 changed files with 39428 additions and 189616 deletions
+2 -9
View File
@@ -5,13 +5,6 @@ lib/
# Because apparently nobody has any self control # Because apparently nobody has any self control
*.orig *.orig
tools/LiveTexturing/mayaPluginRTT/mayaPluginRTT/x64/Debug/
tools/LiveTexturing/mayaPluginRTT/x64/Debug/
*.suo *.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)
+10 -13
View File
@@ -1,22 +1,19 @@
#### Bundled libraries #### Bundled libraries
Libraries bundled along with binaries for Windows (MSVC14), available as a submodule in the *deps* directory of the source tree. Libraries bundled along with binaries for Windows (MSVC14), available as a submodule in the *deps* directory of the source tree.
| Project | Version | License | | Project | Version | License |
| ---------------------------------------------------------------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ------------------------------------------------------------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **[GLFW](http://www.glfw.org)** | 3.1.2 | [zlib/libpng License](http://www.glfw.org/license.html) | | **[GLFW](http://www.glfw.org)** | 3.1.2 | [zlib/libpng License](http://www.glfw.org/license.html) |
| **[GLM](http://glm.g-truc.net/0.9.5/index.html)** | 0.9.7.1 | [MIT License](http://glm.g-truc.net/copying.txt) | | **[GLM](http://glm.g-truc.net/0.9.5/index.html)** | 0.9.7.1 | [MIT License](http://glm.g-truc.net/copying.txt) |
| **[GLEW](http://glew.sourceforge.net)** | 1.13.0 | [Modified BSD License](http://glew.sourceforge.net/glew.txt), [Mesa 3-D License](http://glew.sourceforge.net/mesa.txt), [Khronos License](http://glew.sourceforge.net/khronos.txt) | | **[GLEW](http://glew.sourceforge.net)** | 1.13.0 | [Modified BSD License](http://glew.sourceforge.net/glew.txt), [Mesa 3-D License](http://glew.sourceforge.net/mesa.txt), [Khronos License](http://glew.sourceforge.net/khronos.txt) |
| **[Assimp](http://assimp.sourceforge.net)** | 3.1.1 | [BSD 3-Clause License](http://assimp.sourceforge.net/main_license.html) | | **[Assimp](http://assimp.sourceforge.net)** | 3.1.1 | [BSD 3-Clause License](http://assimp.sourceforge.net/main_license.html) |
| **[zlib](http://www.zlib.net)** | 1.28 | [zlib License](http://www.zlib.net/zlib_license.html) | | **[zlib](http://www.zlib.net)** | 1.28 | [zlib License](http://www.zlib.net/zlib_license.html) |
| **[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) |
| **[nativefiledialog](https://github.com/mlabbe/nativefiledialog)** | 2016-01-08 | [nativefiledialog Licence](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.
| Project | Version | License | Root folder environment variable (Windows) | | Project | Version | License | Root folder environment variable (Windows) |
| ---------------------------------------------------------- | ----------- | --------------------------------------------------------------------------- | ------------------------------------------ | | ---------------------------------------------------------- | ----------- | --------------------------------------------------------------------------- | ------------------------------------------ |
| **[Boost](http://www.boost.org)** | 1.60.0+ | [Boost Software License, Version 1.0](http://www.boost.org/LICENSE_1_0.txt) | BOOST_ROOT | | **[Boost](http://www.boost.org)** | 1.59.0+ | [Boost Software License, Version 1.0](http://www.boost.org/LICENSE_1_0.txt) | BOOST_ROOT |
+1 -1
Submodule assets updated: ed93148764...e4dc9529f2
+9 -9
View File
@@ -1,13 +1,13 @@
# Xerces_FOUND # XERCES_FOUND
# Xerces_INCLUDE_DIRS # XERCES_INCLUDE_DIRS
# Xerces_LIBRARIES # XERCES_LIBRARIES
find_path(Xerces_INCLUDE_DIR xercesc/dom/dom.hpp find_path(XERCES_INCLUDE_DIR xercesc/dom/dom.hpp
/usr/local/include /usr/local/include
/usr/include /usr/include
) )
find_library(Xerces_LIBRARY find_library(XERCES_LIBRARY
NAMES NAMES
xerces-c_3 xerces-c_3
xerces-c_3D xerces-c_3D
@@ -16,8 +16,8 @@ find_library(Xerces_LIBRARY
/usr/lib /usr/lib
) )
set(Xerces_INCLUDE_DIRS ${Xerces_INCLUDE_DIR}) set(XERCES_INCLUDE_DIRS ${XERCES_INCLUDE_DIR})
set(Xerces_LIBRARIES ${Xerces_LIBRARY}) set(XERCES_LIBRARIES ${XERCES_LIBRARY})
find_package_handle_standard_args(Xerces DEFAULT_MSG Xerces_LIBRARY Xerces_INCLUDE_DIR) find_package_handle_standard_args(Xerces DEFAULT_MSG XERCES_LIBRARY XERCES_INCLUDE_DIR)
mark_as_advanced(Xerces_FOUND Xerces_INCLUDE_DIR Xerces_LIBRARY) mark_as_advanced(Xerces_FOUND XERCES_INCLUDE_DIR XERCES_LIBRARY)
+1 -1
Submodule deps updated: 49ef585366...1b478d3159
-120
View File
@@ -1,120 +0,0 @@
#ifndef Collision_h__
#define Collision_h__
//NOTE: Collision.h needs to be #included before <GLFW/glfw3.h>,
//because Collision #includes "RawModel.h", which has "Texture.h", which has "OpenGL.h" which must be #included first
//or you will get "fatal error C1189: #error: gl.h included before glew.h"
#include <vector>
#include <boost/optional.hpp>
#include "../Core/Ray.h"
#include "../Core/AABB.h"
#include "Rendering/RawModelCustom.h"
//#include "Rendering/RawModelAssimp.h"
#include "../Core/TransformSystem.h"
#include "../Core/Entity.h"
#include "../Core/EntityWrapper.h"
#include "EntityAABB.h"
class World;
struct ComponentWrapper;
template<typename T>
class Octree;
namespace Collision
{
//Return true if the ray hits the box.
bool RayAABBIntr(const Ray& ray, const AABB& box);
bool RayVsAABB(const Ray& ray, const AABB& box);
//Return true if the ray hits the box, also outputs distance from ray origin to intersection point in [outDistance].
bool RayVsAABB(const Ray& ray, const AABB& box, float& outDistance);
//Return true if the ray hits 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.
bool RayVsModel(const Ray& ray,
const std::vector<glm::vec3>& modelVertices,
const std::vector<unsigned int>& modelIndices,
const glm::mat4& modelMatrix);
//Return true if the ray hits any of the triangles in the model.
//Also returns the position of the intersection point. Will loop through all the whole model indices.
bool RayVsModel(const Ray& ray,
const std::vector<glm::vec3>& modelVertices,
const std::vector<unsigned int>& modelIndices,
const glm::mat4& modelMatrix,
glm::vec3& outHitPosition);
//Return true if the ray hits any of the triangles in the model.
//Also returns the distance from the ray origin to the closest
//intersection point, and the barycentric u,v-coordinates. Will loop through all the whole model indices.
bool RayVsModel(const Ray& ray,
const std::vector<glm::vec3>& modelVertices,
const std::vector<unsigned int>& modelIndices,
const glm::mat4& modelMatrix,
float& outDistance,
float& outUCoord,
float& outVCoord);
bool AABBvsTriangles(const AABB& box,
const std::vector<glm::vec3>& 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 std::vector<glm::vec3>& modelVertices,
const std::vector<unsigned int>& modelIndices,
const glm::mat4& modelMatrix);
enum Output
{
OutContained,
OutSeparated,
OutIntersecting
};
//Detects intersection and containment.
Output AABBvsTrianglesWContainment(const AABB& box,
const std::vector<glm::vec3>& modelVertices,
const std::vector<unsigned int>& modelIndices,
const glm::mat4& modelMatrix);
//Return true if the boxes are intersecting.
bool AABBVsAABB(const AABB& a, const AABB& b);
//Return true if the boxes are intersecting.
//Also outputs the minimum translation that box [a] would need in order to resolve collision.
bool AABBVsAABB(const AABB& a, const AABB& b, glm::vec3& minimumTranslation);
// Calculates an absolute AABB from an entity AABB component or Model component.
// if takeModelBox is true, the AABB component will be ignored and box is calculated from Model.
// if takeModelBox is false, the AABB component will be prefered, if it exists.
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);
}
#endif
@@ -1,30 +0,0 @@
#ifndef CollisionSystem_h__
#define CollisionSystem_h__
#include <GLFW/glfw3.h>
#include <glm/common.hpp>
#include "../Common.h"
#include "../Core/System.h"
#include "../Core/EventBroker.h"
#include "../Core/Octree.h"
#include "EntityAABB.h"
class CollisionSystem : public PureSystem
{
public:
CollisionSystem(SystemParams params, Octree<EntityAABB>* octree)
: System(params)
, PureSystem("Physics")
, m_Octree(octree)
{ }
virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cPhysics, double dt) override;
private:
Octree<EntityAABB>* m_Octree;
std::vector<EntityAABB> m_OctreeResult;
std::unordered_map<EntityWrapper, glm::vec3> m_PrevPositions;
};
#endif
-39
View File
@@ -1,39 +0,0 @@
#ifndef Events_TriggerEnter_h__
#define Events_TriggerEnter_h__
#include "../Core/EventBroker.h"
#include "../Core/EntityWrapper.h"
namespace Events
{
/** Thrown once, when an entity is only touching a trigger. */
struct TriggerTouch : Event
{
/** The id of the entity that touches the trigger. */
EntityWrapper Entity;
/** The id of the trigger entity. */
EntityWrapper Trigger;
};
/** Thrown once, when an entity has completely left a trigger. */
struct TriggerLeave : Event
{
/** The id of the entity that left the trigger. */
EntityWrapper Entity;
/** The id of the trigger entity. */
EntityWrapper Trigger;
};
/** Thrown once, when an entity is completely contained inside a trigger. */
struct TriggerEnter : Event
{
/** The id of the entity that entered the trigger. */
EntityWrapper Entity;
/** The id of the trigger entity. */
EntityWrapper Trigger;
};
}
#endif
-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
-56
View File
@@ -1,56 +0,0 @@
#ifndef TriggerSystem_h__
#define TriggerSystem_h__
#include <glm/common.hpp>
#include <unordered_set>
#include "../Core/System.h"
#include "../Core/EventBroker.h"
#include "../Core/Octree.h"
#include "ETrigger.h"
#include "EntityAABB.h"
class AABB;
class TriggerSystem : public PureSystem
{
public:
TriggerSystem(SystemParams params, Octree<EntityAABB>* octree)
: System(params)
, 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;
private:
Octree<EntityAABB>* m_Octree;
std::vector<EntityAABB> m_OctreeOut;
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.
bool throwLeaveIfWasInTrigger(std::unordered_set<EntityWrapper>& triggerSet, EntityWrapper colliderENtity, EntityWrapper triggerEntity);
template<typename Event>
void publish(EntityWrapper collider, EntityWrapper trigger)
{
Event e;
e.Trigger = trigger;
e.Entity = collider;
m_EventBroker->Publish(e);
}
};
#endif
-4
View File
@@ -1,11 +1,7 @@
#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"
-28
View File
@@ -1,28 +0,0 @@
#ifndef AABB_h__
#define AABB_h__
#include "../GLM.h"
class AABB
{
public:
AABB() = default;
//No checks are made. Values in minPos must be less than values in maxPos, i.e. min.x < max.x, etc.
AABB(const glm::vec3& minPos, const glm::vec3& maxPos);
//No checks are made. Size must consist of non-negative numbers.
static AABB FromOriginSize(const glm::vec3& origin, const glm::vec3& size);
virtual ~AABB();
const glm::vec3& MinCorner() const { return m_MinCorner; }
const glm::vec3& MaxCorner() const { return m_MaxCorner; }
const glm::vec3& Origin() const { return m_Origin; }
const glm::vec3 Size() const { return 2.0f * m_HalfSize; }
const glm::vec3& HalfSize() const { return m_HalfSize; }
private:
glm::vec3 m_MinCorner;
glm::vec3 m_MaxCorner;
glm::vec3 m_Origin;
glm::vec3 m_HalfSize;
};
#endif
+5 -32
View File
@@ -2,48 +2,21 @@
#define ComponentInfo_h__ #define ComponentInfo_h__
#include "../Common.h" #include "../Common.h"
#include "Entity.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
{
std::string Name;
std::string Type;
unsigned char Index;
unsigned int Offset;
unsigned int Stride;
};
std::string Name; std::string Name;
std::unordered_map<std::string, Field_t> Fields; std::unordered_map<std::string, std::string> FieldTypes;
std::vector<std::string> FieldsInOrder; std::unordered_map<std::string, unsigned int> FieldOffsets;
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;
std::size_t GetHeaderSize() const
{
std::size_t size = 0;
// A component block starts with an entity ID
size += sizeof(EntityID);
return size;
}
}; };
template<> template<>
+11 -20
View File
@@ -1,32 +1,31 @@
#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"
#include "DirtySet.h"
class ComponentPool;
class ComponentPoolForwardIterator class ComponentPoolForwardIterator
: public std::iterator<std::forward_iterator_tag, ComponentWrapper> : public std::iterator<std::forward_iterator_tag, ComponentWrapper>
{ {
public: public:
ComponentPoolForwardIterator(ComponentPool* pool, const MemoryPool<char>::iterator begin, const MemoryPool<char>::iterator end); ComponentPoolForwardIterator(const ComponentInfo& componentInfo, const MemoryPool<char>::iterator begin, const MemoryPool<char>::iterator end)
: m_ComponentInfo(componentInfo)
, m_MemoryPoolIterator(begin)
, m_MemoryPoolEnd(end)
{ }
ComponentPoolForwardIterator(const ComponentPoolForwardIterator& other) = default; ComponentPoolForwardIterator(const ComponentPoolForwardIterator& other) = default;
ComponentPoolForwardIterator(ComponentPoolForwardIterator&& other) = default; ComponentPoolForwardIterator(ComponentPoolForwardIterator&& other) = default;
~ComponentPoolForwardIterator() = default; ~ComponentPoolForwardIterator() = default;
ComponentPoolForwardIterator& operator=(const ComponentPoolForwardIterator& other) = default; ComponentPoolForwardIterator& operator=(const ComponentPoolForwardIterator& other) = default;
ComponentPoolForwardIterator& operator++(); ComponentPoolForwardIterator& operator++();
ComponentPoolForwardIterator operator++(int); ComponentPoolForwardIterator& operator++(int);
bool operator!=(const ComponentPoolForwardIterator& other) const; bool operator!=(const ComponentPoolForwardIterator& other) const;
bool operator==(const ComponentPoolForwardIterator& other) const; bool operator==(const ComponentPoolForwardIterator& other) const;
ComponentWrapper operator*() const; ComponentWrapper operator*() const;
private: private:
ComponentPool* m_ComponentPool;
const ComponentInfo& m_ComponentInfo; const ComponentInfo& m_ComponentInfo;
MemoryPool<char>::iterator m_MemoryPoolIterator; MemoryPool<char>::iterator m_MemoryPoolIterator;
const MemoryPool<char>::iterator m_MemoryPoolEnd; const MemoryPool<char>::iterator m_MemoryPoolEnd;
@@ -34,7 +33,6 @@ private:
class ComponentPool class ComponentPool
{ {
friend class ComponentPoolForwardIterator;
public: public:
typedef ComponentPoolForwardIterator iterator; typedef ComponentPoolForwardIterator iterator;
typedef ptrdiff_t difference_type; typedef ptrdiff_t difference_type;
@@ -43,13 +41,11 @@ public:
typedef ComponentWrapper* pointer; typedef ComponentWrapper* pointer;
typedef ComponentWrapper& reference; typedef ComponentWrapper& reference;
ComponentPool(const ::ComponentInfo& ci, World* world) ComponentPool(const ::ComponentInfo& ci)
: m_ComponentInfo(ci) : m_ComponentInfo(ci)
, m_Pool(ci.Meta->Allocation, ci.GetHeaderSize() + ci.Stride) , m_Pool(ci.Meta.Allocation, sizeof(EntityID) + ci.Meta.Stride)
, m_World(world)
{ } { }
~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; }
@@ -58,14 +54,11 @@ public:
ComponentWrapper Allocate(EntityID entity); ComponentWrapper Allocate(EntityID entity);
// Get the component belonging to a specific entity // Get the component belonging to a specific entity
ComponentWrapper GetByEntity(EntityID ent); ComponentWrapper GetByEntity(EntityID ent);
// Returns true if the pool contains a component for the specified entity
bool KnowsEntity(EntityID ent);
// Delete a component and free its memory // Delete a component and free its memory
void Delete(ComponentWrapper& wrapper); void Delete(ComponentWrapper& wrapper);
iterator begin(); iterator begin() const;
iterator end(); 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<<)
@@ -82,8 +75,6 @@ private:
::ComponentInfo m_ComponentInfo; ::ComponentInfo m_ComponentInfo;
MemoryPool<char> m_Pool; MemoryPool<char> m_Pool;
std::unordered_map<EntityID, char*> m_EntityToComponent; std::unordered_map<EntityID, char*> m_EntityToComponent;
DirtySet m_DirtySet;
World* m_World;
}; };
#endif #endif
+38 -235
View File
@@ -1,250 +1,66 @@
#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 "../GLM.h" #include "EntityWrapper.h"
#include "Entity.h"
#include "ComponentInfo.h" #include "ComponentInfo.h"
#include "DirtySet.h"
#include "Util/Any.h" #include "Util/Any.h"
class World;
struct ComponentWrapper struct ComponentWrapper
{ {
ComponentWrapper(const ComponentInfo& componentInfo, char* data, ::DirtyBitField* dirtyBitField, World* world); ComponentWrapper(const ComponentInfo& componentInfo, char* data)
: Info(componentInfo)
, EntityID(*reinterpret_cast<::EntityID*>(data))
, Data(data + sizeof(EntityID))
{ }
World* m_World;
const ComponentInfo& Info; const ComponentInfo& Info;
const ::EntityID EntityID; const ::EntityID EntityID;
char* Data; char* Data;
::DirtyBitField* DirtyBitField = nullptr;
ComponentInfo::EnumType Enum(const char* fieldName, const char* enumKey);
bool Dirty(DirtySetType type, const std::string& fieldName);
void SetDirty(DirtySetType type, const std::string& fieldName, bool dirty = true);
void SetAllDirty(const std::string& fieldName, bool dirty = true);
template <typename T> template <typename T>
T& Field(const std::string& name) T& Property(std::string name)
{ {
const ComponentInfo::Field_t& field = Info.Fields.at(name); unsigned int offset = Info.FieldOffsets.at(name);
if (sizeof(T) > field.Stride) { return *reinterpret_cast<T*>(&Data[offset]);
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> template <typename T>
void SetField(const std::string& name, const T& value) void SetProperty(std::string name, const T value) { Property<T>(name) = value; }
{ //template <typename T>
Field<T>(name) = value; //void SetProperty(std::string name, T& value) { Property<T>(name) = value; }
SetAllDirty(name);
}
// Specialization for string literals // Specialization for string literals
template <std::size_t N> template <std::size_t N>
void SetField(const std::string& name, const char(&value)[N]) { SetField(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
{ {
friend struct ComponentWrapper; friend struct ComponentWrapper;
private:
public: SubscriptProxy(ComponentWrapper* component, std::string propertyName)
SubscriptProxy(ComponentWrapper* component, std::string fieldName)
: m_Component(component) : m_Component(component)
, m_FieldName(fieldName) , m_PropertyName(propertyName)
{ } { }
ComponentWrapper* m_Component; ComponentWrapper* m_Component;
std::string m_FieldName; std::string m_PropertyName;
public: public:
// Return the integer value of an enum type key for this field
ComponentInfo::EnumType Enum(const char* enumKey) { return m_Component->Enum(m_FieldName.c_str(), enumKey); }
bool Dirty(DirtySetType type) { return m_Component->Dirty(type, m_FieldName); }
void SetDirty(DirtySetType type, bool dirty = true) { m_Component->SetDirty(type, m_FieldName, dirty); }
void SetAllDirty(bool dirty = true) { m_Component->SetAllDirty(m_FieldName, dirty); }
operator const double&() { return m_Component->Field<double>(m_FieldName); }
operator const float&() { return m_Component->Field<float>(m_FieldName); }
operator const int&() { return m_Component->Field<int>(m_FieldName); }
operator const glm::vec3&() { return m_Component->Field<glm::vec3>(m_FieldName); }
operator const glm::vec4&() { return m_Component->Field<glm::vec4>(m_FieldName); }
operator const glm::quat&() { return m_Component->Field<glm::quat>(m_FieldName); }
operator const bool&() { return m_Component->Field<bool>(m_FieldName); }
operator const std::string&() { return m_Component->Field<std::string>(m_FieldName); }
// Don't allow non-const references
// If this wasn't deleted, the above overloads would still get called for some reason...
template <
typename T,
typename = typename std::enable_if<!std::is_base_of<::FIELDLOL, T>::value>::type
>
//operator T&() = delete;
operator T&() { static_assert(constexpr(false), "https://github.com/teamfisk/TacticalZ/pull/212"); }
// Value assignment
template <typename T> template <typename T>
void operator=(const T& val) { m_Component->SetField<T>(m_FieldName, val); } operator T&() { return m_Component->Property<T>(m_PropertyName); }
template <typename T>
void operator=(const T val) { m_Component->SetProperty<T>(m_PropertyName, val); }
// TODO: Pass by reference and rvalue (universal reference?)
//template <typename T>
//void operator=(T& val) { m_Component->SetProperty<T>(m_PropertyName, val); }
// 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_FieldName, val); } void operator=(const char(&val)[N]) { m_Component->SetProperty<N>(m_PropertyName, val); }
}; };
SubscriptProxy operator[](const std::string& propertyName) { return SubscriptProxy(this, propertyName); } SubscriptProxy operator[](std::string propertyName) { return SubscriptProxy(this, propertyName); }
};
struct FIELDLOL { }; // lol
template <typename T>
struct FieldBase : FIELDLOL
{
FieldBase(ComponentWrapper::SubscriptProxy& Proxy)
: Proxy(Proxy)
, Data(Proxy.m_Component->Field<T>(Proxy.m_FieldName))
{ }
void SetAllDirty() { Proxy.SetAllDirty(); }
FieldBase& operator=(const FieldBase& rhs) { Data = rhs.Data; SetAllDirty(); return *this; }
FieldBase& operator=(const T& rhs) { Data = rhs; SetAllDirty(); return *this; }
template <typename T2> FieldBase& operator+=(const T2& rhs) { Data += rhs; SetAllDirty(); return *this; }
template <typename T2> FieldBase& operator-=(const T2& rhs) { Data -= rhs; SetAllDirty(); return *this; }
template <typename T2> FieldBase& operator*=(const T2& rhs) { Data *= rhs; SetAllDirty(); return *this; }
template <typename T2> FieldBase& operator/=(const T2& rhs) { Data /= rhs; SetAllDirty(); return *this; }
template <typename T2> FieldBase& operator%=(const T2& rhs) { Data %= rhs; SetAllDirty(); return *this; }
template <typename T2> FieldBase& operator&=(const T2& rhs) { Data &= rhs; SetAllDirty(); return *this; }
template <typename T2> FieldBase& operator|=(const T2& rhs) { Data |= rhs; SetAllDirty(); return *this; }
template <typename T2> FieldBase& operator^=(const T2& rhs) { Data ^= rhs; SetAllDirty(); return *this; }
template <typename T2> FieldBase& operator<<=(const T2& rhs) { Data <<= rhs; SetAllDirty(); return *this; }
template <typename T2> FieldBase& operator>>=(const T2& rhs) { Data >>= rhs; SetAllDirty(); return *this; }
T operator+() const { return +Data; }
T operator-() const { return -Data; }
T operator~() const { return ~Data; }
FieldBase& operator++() { Data++; SetAllDirty(); return *this; }
T operator++(int) { T tmp = Data; operator++(); return tmp; }
FieldBase& operator--() { Data--; SetAllDirty(); return *this; }
T operator--(int) { T tmp = Data; operator--(); return tmp; }
operator const T&() const { return Data; }
const T& operator*() const { return operator const T&(); }
protected:
ComponentWrapper::SubscriptProxy Proxy;
T& Data;
};
template <typename T>
struct Field : FieldBase<T>
{
using FieldBase<T>::FieldBase;
using FieldBase<T>::operator=;
};
template <>
struct Field<glm::vec3> : FieldBase<glm::vec3>
{
using FieldBase<glm::vec3>::FieldBase;
using FieldBase<glm::vec3>::operator=;
glm::vec3::value_type x() const { return Data.x; }
void x(glm::vec3::value_type val) { Data.x = val; SetAllDirty(); }
glm::vec3::value_type y() const { return Data.y; }
void y(glm::vec3::value_type val) { Data.y = val; SetAllDirty(); }
glm::vec3::value_type z() const { return Data.z; }
void z(glm::vec3::value_type val) { Data.z = val; SetAllDirty(); }
template <typename T> friend glm::vec3 operator+(const Field<glm::vec3>& lhs, const T& rhs) { return static_cast<glm::vec3>(lhs) + glm::vec3(rhs); }
template <typename T> friend glm::vec3 operator-(const Field<glm::vec3>& lhs, const T& rhs) { return static_cast<glm::vec3>(lhs) - glm::vec3(rhs); }
template <typename T> friend glm::vec3 operator*(const Field<glm::vec3>& lhs, const T& rhs) { return static_cast<glm::vec3>(lhs) * glm::vec3(rhs); }
template <typename T> friend glm::vec3 operator/(const Field<glm::vec3>& lhs, const T& rhs) { return static_cast<glm::vec3>(lhs) / glm::vec3(rhs); }
template <typename T> friend glm::vec3 operator+(const T& lhs, const Field<glm::vec3>& rhs) { return glm::vec3(lhs) + static_cast<glm::vec3>(rhs); }
template <typename T> friend glm::vec3 operator-(const T& lhs, const Field<glm::vec3>& rhs) { return glm::vec3(lhs) - static_cast<glm::vec3>(rhs); }
template <typename T> friend glm::vec3 operator*(const T& lhs, const Field<glm::vec3>& rhs) { return glm::vec3(lhs) * static_cast<glm::vec3>(rhs); }
template <typename T> friend glm::vec3 operator/(const T& lhs, const Field<glm::vec3>& rhs) { return glm::vec3(lhs) / static_cast<glm::vec3>(rhs); }
friend glm::vec3& operator+=(glm::vec3& lhs, const Field<glm::vec3>& rhs) { lhs += *rhs; return lhs; }
};
template <>
struct Field<glm::vec4> : FieldBase<glm::vec4>
{
//Field(glm::vec4& Data)
// : FieldBase(Data)
//{ }
using FieldBase<glm::vec4>::FieldBase;
using FieldBase<glm::vec4>::operator=;
glm::vec4::value_type x() const { return Data.x; }
void x(glm::vec4::value_type val) { Data.x = val; SetAllDirty(); }
glm::vec4::value_type y() const { return Data.y; }
void y(glm::vec4::value_type val) { Data.y = val; SetAllDirty(); }
glm::vec4::value_type z() const { return Data.z; }
void z(glm::vec4::value_type val) { Data.z = val; SetAllDirty(); }
glm::vec4::value_type w() const { return Data.w; }
void w(glm::vec4::value_type val) { Data.w = val; SetAllDirty(); }
template <typename T> friend glm::vec4 operator+(const Field<glm::vec4>& lhs, const T& rhs) { return static_cast<glm::vec4>(lhs) + glm::vec4(rhs); }
template <typename T> friend glm::vec4 operator-(const Field<glm::vec4>& lhs, const T& rhs) { return static_cast<glm::vec4>(lhs) - glm::vec4(rhs); }
template <typename T> friend glm::vec4 operator*(const Field<glm::vec4>& lhs, const T& rhs) { return static_cast<glm::vec4>(lhs) * glm::vec4(rhs); }
template <typename T> friend glm::vec4 operator/(const Field<glm::vec4>& lhs, const T& rhs) { return static_cast<glm::vec4>(lhs) / glm::vec4(rhs); }
template <typename T> friend glm::vec4 operator+(const T& lhs, const Field<glm::vec4>& rhs) { return glm::vec4(lhs) + static_cast<glm::vec4>(rhs); }
template <typename T> friend glm::vec4 operator-(const T& lhs, const Field<glm::vec4>& rhs) { return glm::vec4(lhs) - static_cast<glm::vec4>(rhs); }
template <typename T> friend glm::vec4 operator*(const T& lhs, const Field<glm::vec4>& rhs) { return glm::vec4(lhs) * static_cast<glm::vec4>(rhs); }
template <typename T> friend glm::vec4 operator/(const T& lhs, const Field<glm::vec4>& rhs) { return glm::vec4(lhs) / static_cast<glm::vec4>(rhs); }
friend glm::vec4& operator+=(glm::vec4& lhs, const Field<glm::vec4>& rhs) { lhs += *rhs; return lhs; }
};
// 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(), nullptr, nullptr)
, 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
@@ -252,41 +68,28 @@ 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.FieldTypes[fieldName] = typeid(T).name();
field.Type = typeid(T).name(); m_ComponentInfo.FieldOffsets[fieldName] = m_ComponentInfo.Meta.Stride;
field.Offset = m_ComponentInfo.Stride; m_ComponentInfo.Meta.Stride += sizeof(T);
field.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;
@@ -296,7 +99,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
+1 -19
View File
@@ -5,7 +5,6 @@
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/property_tree/ptree.hpp> #include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp> #include <boost/property_tree/ini_parser.hpp>
#include <boost/lexical_cast.hpp>
#include "../Common.h" #include "../Common.h"
#include "ResourceManager.h" #include "ResourceManager.h"
@@ -20,14 +19,12 @@ 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);
void SaveToDisk(); void SaveToDisk();
private: private:
boost::filesystem::path m_Path; boost::filesystem::path m_Path;
boost::property_tree::ptree m_PTreeDefaults; boost::property_tree::ptree m_PTreeDefaults;
boost::property_tree::ptree m_PTreeOverrides; boost::property_tree::ptree m_PTreeOverrides;
@@ -40,21 +37,6 @@ T ConfigFile::Get(std::string key, T defaultValue)
return m_PTreeMerged.get<T>(key, defaultValue); return m_PTreeMerged.get<T>(key, defaultValue);
} }
template <typename T>
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)
{ {
-16
View File
@@ -1,16 +0,0 @@
#ifndef DirtySet_h__
#define DirtySet_h__
#include <set>
#include "ComponentInfo.h"
enum class DirtySetType
{
Transform,
Network
};
typedef std::unordered_map<DirtySetType, std::set<decltype(ComponentInfo::Field_t::Index)>> DirtyBitField;
typedef std::unordered_map<EntityID, DirtyBitField> DirtySet;
#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
-22
View File
@@ -1,22 +0,0 @@
#ifndef Events_Captured_h__
#define Events_Captured_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 CapturePointTakenID;
EntityWrapper BlueTeamNextCapturePoint;
EntityWrapper RedTeamNextCapturePoint;
};
}
#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 "EntityWrapper.h"
namespace Events
{
struct EntityDeleted : Event
{
EntityWrapper DeletedEntity;
// True if the entity deletion was triggered because the entity's parent was deleted before it
bool Cascaded;
};
}
#endif
-16
View File
@@ -1,16 +0,0 @@
#ifndef EFileDropped_h__
#define EFileDropped_h__
#include "EventBroker.h"
namespace Events
{
struct FileDropped : Event
{
std::string Path;
};
}
#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;
}; };
} }
-17
View File
@@ -1,17 +0,0 @@
#ifndef Events_KeyboardChar_h__
#define Events_KeyboardChar_h__
#include "EventBroker.h"
namespace Events
{
struct KeyboardChar : Event
{
double Timestamp = 0.f;
unsigned int Char = 0;
};
}
#endif
-17
View File
@@ -1,17 +0,0 @@
#ifndef Events_MouseScroll_h__
#define Events_MouseScroll_h__
#include "EventBroker.h"
namespace Events
{
struct MouseScroll : Event
{
double DeltaX;
double DeltaY;
};
}
#endif
-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
-19
View File
@@ -1,19 +0,0 @@
#ifndef EPlayerDamage_h__
#define EPlayerDamage_h__
#include "EventBroker.h"
#include "../Core/EntityWrapper.h"
namespace Events
{
struct PlayerDamage : Event
{
EntityWrapper Inflictor;
EntityWrapper Victim;
double Damage;
};
}
#endif
-20
View File
@@ -1,20 +0,0 @@
#ifndef EPlayerDeath_h__
#define EPlayerDeath_h__
#include "EventBroker.h"
#include "../Core/EntityWrapper.h"
namespace Events
{
struct PlayerDeath : Event
{
//KilledBy,KilledByWhat is optional for now. It might be used later in the playerlog-system
EntityWrapper Player = EntityWrapper::Invalid;
EntityWrapper Killer = EntityWrapper::Invalid;
std::string KilledByWhat = "";
};
}
#endif
-18
View File
@@ -1,18 +0,0 @@
#ifndef EPlayerHealthPickup_h__
#define EPlayerHealthPickup_h__
#include "EventBroker.h"
#include "../Core/EntityWrapper.h"
namespace Events
{
struct PlayerHealthPickup : Event
{
EntityWrapper Player;
double HealthAmount;
};
}
#endif
-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
-8
View File
@@ -1,8 +0,0 @@
#ifndef Entity_h__
#define Entity_h__
typedef unsigned int EntityID;
const static unsigned int EntityID_Invalid = -1;
#endif
+8 -8
View File
@@ -285,7 +285,7 @@ private:
XSValue::Status status; XSValue::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;
} }
} }
+7 -16
View File
@@ -1,21 +1,12 @@
#ifndef EntityFile_h__ #include "ResourceManager.h"
#define EntityFile_h__
#include "World.h" class EntityFile : public Resource
#include "EntityXMLFile.h"
#include "EntityXMLFilePreprocessor.h"
#include "EntityXMLFileParser.h"
#include "EntityWrapper.h"
class EntityFile : private World, public Resource
{ {
public: friend class ResourceManager;
EntityFile(std::string path);
EntityWrapper MergeInto(World* other);
private: private:
EntityID m_RootEntity = EntityID_Invalid; EntityFile(std::string path);
};
#endif public:
};
+6 -58
View File
@@ -1,67 +1,15 @@
#ifndef EntityWrapper_h__ #ifndef Entity_h__
#define EntityWrapper_h__ #define Entity_h__
#include <boost/optional.hpp> typedef unsigned int EntityID;
#include <boost/functional/hash.hpp>
#include "ComponentWrapper.h"
class World;
struct EntityWrapper struct EntityWrapper
{ {
EntityWrapper() EntityWrapper(EntityID entityID)
: World(nullptr) : ID(entityID)
, ID(EntityID_Invalid)
{ } { }
EntityWrapper(::World* world, EntityID id) EntityID ID;
: World(world)
, ID(id)
{ }
::World* World;
EntityID ID;
static const EntityWrapper Invalid;
const std::string Name() const;
bool HasComponent(const std::string& componentType);
void AttachComponent(const char* componentName);
EntityWrapper Parent();
EntityWrapper FirstParentByName(const std::string& parentEntityName);
EntityWrapper FirstChildByName(const std::string& name);
EntityWrapper FirstLevelChildByName(const std::string& name);
EntityWrapper FirstParentWithComponent(const std::string& componentType);
EntityWrapper Clone(EntityWrapper parent = EntityWrapper::Invalid);
std::vector<EntityWrapper> ChildrenWithComponent(const std::string& componentType);
void DeleteChildren();
bool IsChildOf(EntityWrapper potentialParent);
bool Valid() const;
ComponentWrapper operator[](const char* componentName);
ComponentWrapper operator[](const std::string& 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);
void childrenWithComponentRecursive(const std::string& componentType, EntityWrapper& entity, std::vector<EntityWrapper>& childrenWithComponent);
static void fillRelationships(std::unordered_multimap<EntityWrapper, EntityWrapper>& relationMap, EntityWrapper entity);
static void recreateRelationships(const std::unordered_multimap<EntityWrapper, EntityWrapper>& relationMap, EntityWrapper templateEntity, EntityWrapper parent = EntityWrapper::Invalid);
}; };
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 #endif
-164
View File
@@ -1,164 +0,0 @@
#ifndef EntityXMLFile_h__
#define EntityXMLFile_h__
#include <stack>
#include <boost/lexical_cast.hpp>
#include <xercesc/util/XercesDefs.hpp>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/sax2/SAX2XMLReader.hpp>
#include <xercesc/sax2/XMLReaderFactory.hpp>
#include <xercesc/sax2/DefaultHandler.hpp>
#include <xercesc/sax2/Attributes.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/util/XMLChar.hpp>
#include <xercesc/sax2/DefaultHandler.hpp>
#include <xercesc/framework/XMLDocumentHandler.hpp>
#include <xercesc/framework/psvi/XSElementDeclaration.hpp>
#include <xercesc/framework/psvi/XSComplexTypeDefinition.hpp>
#include <xercesc/framework/psvi/XSParticle.hpp>
#include <xercesc/framework/psvi/XSModelGroup.hpp>
#include <xercesc/framework/psvi/XSAnnotation.hpp>
#include <xercesc/framework/psvi/XSValue.hpp>
#include <xercesc/framework/XMLGrammarPoolImpl.hpp>
#include <xercesc/dom/DOM.hpp>
#include <xercesc/dom/DOMLSInput.hpp>
#include <xercesc/dom/DOMElement.hpp>
#include "../GLM.h"
#include "Util/XercesString.h"
#include "ResourceManager.h"
#include "Entity.h"
#include "ComponentInfo.h"
class EntityFileHandler
{
friend class EntityFileSAXHandler;
public:
// @param EntityID The entity found
// @param EntityID The parent of the entity
typedef std::function<void(EntityID, EntityID, const std::string&)> OnStartEntityCallback;
void SetStartEntityCallback(OnStartEntityCallback c) { m_OnStartEntityCallback = c; }
// @param EntityID The entity the component corresponds to
// @param std::string Type name of the component
typedef std::function<void(EntityID, const std::string&)> OnStartComponentCallback;
void SetStartComponentCallback(OnStartComponentCallback c) { m_OnStartComponentCallback = c; }
// @param EntityID Entity
// @param std::string Component name
// @param std::string Field name
// @param std::map<std::string, std::string> Field attribute names and values
typedef std::function<void(EntityID, const std::string&, const std::string&, const std::map<std::string, std::string>&)> OnStartFieldCallback;
void SetStartFieldCallback(OnStartFieldCallback c) { m_OnStartFieldCallback = c; }
// @param EntityID Entity
// @param std::string Component name
// @param std::string Field name
// @param char* Field data
typedef std::function<void(EntityID, const std::string&, const std::string&, const char*)> OnStartFieldDataCallback;
void SetStartFieldDataCallback(OnStartFieldDataCallback c) { m_OnStartFieldDataCallback = c; }
private:
OnStartEntityCallback m_OnStartEntityCallback = nullptr;
OnStartComponentCallback m_OnStartComponentCallback = nullptr;
OnStartFieldCallback m_OnStartFieldCallback = nullptr;
OnStartFieldDataCallback m_OnStartFieldDataCallback = nullptr;
};
class EntityFileSAXHandler : public xercesc::DefaultHandler
{
public:
enum class State
{
Unknown,
Entity,
Component,
ComponentField
};
EntityFileSAXHandler(const EntityFileHandler* handler, xercesc::SAX2XMLReader* reader);
void startElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname, const xercesc::Attributes& attrs) override;
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;
void warning(const xercesc::SAXParseException& e);
void error(const xercesc::SAXParseException& e);
void fatalError(const xercesc::SAXParseException& e);
private:
const EntityFileHandler* m_Handler;
xercesc::XMLGrammarPool* m_GrammarPool;
xercesc::SAX2XMLReader* m_Reader;
//State m_CurrentScope = State::Unknown;
std::stack<State> m_StateStack;
unsigned int m_NextEntityID = 0;
std::stack<EntityID> m_EntityStack;
std::string m_CurrentComponent;
std::string m_CurrentField;
std::map<std::string, std::string> m_CurrentAttributes;
void onStartEntity(const xercesc::Attributes& attrs);
void onEndEntity();
void onStartEntityRef(const xercesc::Attributes& attrs);
void onStartComponent(const std::string& name);
void onEndComponent(const std::string& name);
void onStartComponentField(const std::string& field, const xercesc::Attributes& attrs);
void onEndComponentField(const std::string& field);
void onFieldData(char* data);
};
class EntityFileXMLErrorHandler : public xercesc::ErrorHandler
{
public:
void warning(const xercesc::SAXParseException& e) override
{
reportParseException("Warning", e);
}
void error(const xercesc::SAXParseException& e) override
{
reportParseException("Error", e);
}
void fatalError(const xercesc::SAXParseException& e) override
{
reportParseException("FATAL ERROR", e);
}
void resetErrors() override { }
private:
void reportParseException(std::string type, const xercesc::SAXParseException& e)
{
char* message = xercesc::XMLString::transcode(e.getMessage());
char* systemID = xercesc::XMLString::transcode(e.getSystemId());
std::cerr << systemID << ":" << e.getLineNumber() << ":" << e.getColumnNumber() << std::endl;
std::cerr << type << ": " << message << std::endl;
xercesc::XMLString::release(&systemID);
xercesc::XMLString::release(&message);
}
};
class EntityXMLFile : public Resource
{
friend class ResourceManager;
friend class EntityFileSAXHandler;
private:
EntityXMLFile(boost::filesystem::path path);
~EntityXMLFile();
public:
static unsigned int GetTypeStride(std::string typeName);
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);
xercesc::XMLGrammarPool* GrammarPool() const { return m_GrammarPool; }
void Parse(const EntityFileHandler* handler) const;
private:
boost::filesystem::path m_FilePath;
xercesc::XMLGrammarPool* m_GrammarPool;
xercesc::SAX2XMLReader* m_SAX2XMLReader;
//std::map<std::string, ::ComponentInfo> m_ComponentInfo;
//std::vector<std::string> m_EntityReferences;
static void setReaderFeatures(xercesc::SAX2XMLReader* reader);
};
#endif
-30
View File
@@ -1,30 +0,0 @@
#ifndef EntityXMLFileParser_h__
#define EntityXMLFileParser_h__
#include "EntityXMLFile.h"
#include "World.h"
class EntityXMLFileParser
{
friend class EntityFile;
public:
EntityXMLFileParser(const EntityXMLFile* entityFile);
private:
EntityID MergeEntities(World* world, EntityID baseParent = EntityID_Invalid);
const EntityXMLFile* m_EntityFile;
EntityFileHandler m_Handler;
World* m_World = nullptr;
EntityID m_FirstEntity = EntityID_Invalid;
// Maps EntityIDs local to the file to real IDs in the world after they've been
// created in order to resolve parent-child relationships.
std::map<EntityID, EntityID> m_EntityIDMapper;
void onStartEntity(EntityID entity, EntityID parent, const std::string& name);
void onStartComponent(EntityID entity, const std::string& component);
void onStartComponentField(EntityID entity, const std::string& componentType, const std::string& fieldName, const std::map<std::string, std::string>& attributes);
void onFieldData(EntityID entity, const std::string& componentType, const std::string& fieldName, const char* fieldData);
};
#endif
@@ -1,41 +0,0 @@
#ifndef EntityXMLFilePreprocessor_h__
#define EntityXMLFilePreprocessor_h__
#include <xercesc/framework/psvi/XSElementDeclaration.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/XSModelGroup.hpp>
#include <xercesc/framework/psvi/XSModelGroupDefinition.hpp>
#include <xercesc/framework/psvi/XSAnnotation.hpp>
#include <xercesc/framework/psvi/XSValue.hpp>
#include <xercesc/framework/MemBufFormatTarget.hpp>
#include <xercesc/framework/MemBufInputSource.hpp>
#include <xercesc/parsers/XercesDOMParser.hpp>
#include "Util/XercesString.h"
#include "ResourceManager.h"
#include "World.h"
#include "EntityXMLFile.h"
class EntityXMLFilePreprocessor
{
friend class EntityFile;
public:
EntityXMLFilePreprocessor(const EntityXMLFile* entityFile);
private:
void RegisterComponents(World* world);
const EntityXMLFile* m_EntityFile;
std::map<std::string, unsigned int> m_ComponentCounts;
std::map<std::string, ComponentInfo> m_ComponentInfo;
void onStartComponent(EntityID entity, std::string type);
void parseComponentInfo();
void parseDefaults();
std::string parseAnnotationXML(const XMLCh* xml);
};
#endif
-39
View File
@@ -1,39 +0,0 @@
#ifndef EntityXMLFileWriter_h__
#define EntityXMLFileWriter_h__
#include <boost/filesystem.hpp>
#include <xercesc/dom/DOM.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/framework/LocalFileFormatTarget.hpp>
#include "Util/XercesString.h"
#include "EntityXMLFile.h"
#include "World.h"
class EntityXMLFileWriter
{
public:
EntityXMLFileWriter(boost::filesystem::path file)
: m_FilePath(file)
{
using namespace xercesc;
m_DOMImplementation = DOMImplementationRegistry::getDOMImplementation(XS::ToXMLCh("LS"));
m_DOMLSSerializer = static_cast<DOMImplementationLS*>(m_DOMImplementation)->createLSSerializer();
m_DOMLSSerializer->getDomConfig()->setParameter(XMLUni::fgDOMWRTDiscardDefaultContent, true);
m_DOMLSSerializer->getDomConfig()->setParameter(XMLUni::fgDOMWRTFormatPrettyPrint, true);
}
void WriteWorld(World* world);
void WriteEntity(World* world, EntityID entity);
private:
boost::filesystem::path m_FilePath;
xercesc::DOMImplementation* m_DOMImplementation;
xercesc::DOMLSSerializer* m_DOMLSSerializer;
void appendEntityChildren(xercesc::DOMElement* parentElement, const World* world, EntityID entity);
void appentEntityComponents(xercesc::DOMElement* parentElemetn, const World* world, EntityID entity);
};
#endif
+67 -72
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"
@@ -14,127 +13,123 @@
relay = decltype(relay)(std::bind(handler, this, std::placeholders::_1)); \ relay = decltype(relay)(std::bind(handler, this, std::placeholders::_1)); \
m_EventBroker->Subscribe(relay); m_EventBroker->Subscribe(relay);
typedef unsigned int EventID;
class EventBroker; class EventBroker;
class BaseEventRelay class BaseEventRelay
{ {
friend class EventBroker; friend class EventBroker;
protected: protected:
BaseEventRelay(std::string contextTypeName, std::string eventTypeName) BaseEventRelay(std::string contextTypeName, std::string eventTypeName)
: m_ContextTypeName(contextTypeName) : m_ContextTypeName(contextTypeName)
, m_EventTypeName(eventTypeName) , m_EventTypeName(eventTypeName)
, m_Broker(nullptr) , m_Broker(nullptr)
{ } { }
~BaseEventRelay(); ~BaseEventRelay();
public: public:
virtual bool Receive(const std::shared_ptr<Event> event) = 0; virtual bool Receive(const std::shared_ptr<Event> event) = 0;
protected: protected:
EventID m_EventID; std::string m_ContextTypeName;
std::string m_ContextTypeName; std::string m_EventTypeName;
std::string m_EventTypeName; EventBroker* m_Broker;
EventBroker* m_Broker;
}; };
template <typename ContextType, typename EventType> 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)
, BaseEventRelay(typeid(ContextType).name(), typeid(EventType).name()) , BaseEventRelay(typeid(ContextType).name(), typeid(EventType).name())
{ } { }
EventRelay(CallbackType callback) EventRelay(CallbackType callback)
: m_Callback(callback) : m_Callback(callback)
, BaseEventRelay(typeid(ContextType).name(), typeid(EventType).name()) , BaseEventRelay(typeid(ContextType).name(), typeid(EventType).name())
{ } { }
protected: protected:
bool Receive(const std::shared_ptr<Event> event) override; bool Receive(const std::shared_ptr<Event> event) override;
private: private:
CallbackType m_Callback; CallbackType m_Callback;
}; };
template <typename ContextType, typename EventType> 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;
} }
} }
class EventBroker class EventBroker
{ {
template <typename ContextType, typename EventType> friend class EventRelay; template <typename ContextType, typename EventType> friend class EventRelay;
public: public:
EventBroker() EventBroker()
{ {
m_EventQueueRead = std::make_shared<EventQueue_t>(); m_EventQueueRead = std::make_shared<EventQueue_t>();
m_EventQueueWrite = std::make_shared<EventQueue_t>(); m_EventQueueWrite = std::make_shared<EventQueue_t>();
} }
void Subscribe(BaseEventRelay &relay); void Subscribe(BaseEventRelay &relay);
template <typename EventType> template <typename EventType>
void Publish(const EventType &event); void Publish(const EventType &event);
/* /*
Process all events in a given context. Process all events in a given context.
Returns: Number of events processed Returns: Number of events processed
*/ */
template <typename ContextType> template <typename ContextType>
int Process(); int Process();
int Process(std::string contextTypeName); int Process(std::string contextTypeName);
void Swap(); void Swap();
void Clear(); void Clear();
void Unsubscribe(BaseEventRelay &relay); void Unsubscribe(BaseEventRelay &relay);
private: private:
bool m_IsProcessing = false; bool m_IsProcessing = false;
EventID m_NextEventID = 0;
typedef std::string ContextTypeName_t; // typeid(ContextType).name() typedef std::string ContextTypeName_t; // typeid(ContextType).name()
typedef std::string EventTypeName_t; // typeid(EventType).name() typedef std::string EventTypeName_t; // typeid(EventType).name()
typedef std::unordered_multimap<EventTypeName_t, BaseEventRelay*> EventRelays_t; typedef std::unordered_multimap<EventTypeName_t, BaseEventRelay*> EventRelays_t;
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<BaseEventRelay*> 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;
std::shared_ptr<EventQueue_t> m_EventQueueWrite; std::shared_ptr<EventQueue_t> m_EventQueueWrite;
void subscribeImmediate(BaseEventRelay& relay); void subscribeImmediate(BaseEventRelay& relay);
void unsubscribeImmediate(std::tuple<EventID, ContextTypeName_t, EventTypeName_t> identifier); void unsubscribeImmediate(BaseEventRelay& relay);
}; };
template <typename EventType> template <typename EventType>
void EventBroker::Publish(const EventType &event) void EventBroker::Publish(const EventType &event)
{ {
/*auto itpair = m_Subscribers.equal_range(typeid(EventType).name()); /*auto itpair = m_Subscribers.equal_range(typeid(EventType).name());
for (auto it = itpair.first; it != itpair.second; ++it) for (auto it = itpair.first; it != itpair.second; ++it)
{ {
it->second->Receive(event); it->second->Receive(event);
}*/ }*/
m_EventQueueWrite->push_back(std::make_pair(typeid(EventType).name(), std::shared_ptr<EventType>(new EventType(event)))); m_EventQueueWrite->push_back(std::make_pair(typeid(EventType).name(), std::shared_ptr<EventType>(new EventType(event))));
} }
template <typename ContextType> template <typename ContextType>
int EventBroker::Process() int EventBroker::Process()
{ {
const std::string contextTypeName = typeid(ContextType).name(); const std::string contextTypeName = typeid(ContextType).name();
return Process(contextTypeName); return Process(contextTypeName);
} }
#endif #endif
-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
+7 -4
View File
@@ -11,22 +11,25 @@ template <typename EventContext>
class InputController class InputController
{ {
public: public:
InputController(EventBroker* eventBroker) InputController(std::shared_ptr<dd::EventBroker> eventBroker)
: m_EventBroker(eventBroker) : EventBroker(eventBroker)
{ Initialize(); } { Initialize(); }
virtual void Initialize() virtual void Initialize()
{ {
EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &InputController::OnCommand); EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &InputController::OnCommand);
EVENT_SUBSCRIBE_MEMBER(m_EMouseMove, &InputController::OnMouseMove);
} }
virtual bool OnCommand(const Events::InputCommand& e) { return false; } virtual bool OnCommand(const Events::InputCommand &event) { return false; }
virtual bool OnMouseMove(const Events::MouseMove &event) { return false; }
protected: protected:
EventBroker* m_EventBroker; std::shared_ptr<dd::EventBroker> EventBroker;
private: private:
EventRelay<EventContext, Events::InputCommand> m_EInputCommand; EventRelay<EventContext, Events::InputCommand> m_EInputCommand;
EventRelay<EventContext, Events::MouseMove> m_EMouseMove;
}; };
#endif #endif
-10
View File
@@ -8,15 +8,12 @@
#include "EventBroker.h" #include "EventBroker.h"
#include "EKeyDown.h" #include "EKeyDown.h"
#include "EKeyUp.h" #include "EKeyUp.h"
#include "EKeyboardChar.h"
#include "EMousePress.h" #include "EMousePress.h"
#include "EMouseRelease.h" #include "EMouseRelease.h"
#include "EMouseMove.h" #include "EMouseMove.h"
#include "EMouseScroll.h"
#include "ELockMouse.h" #include "ELockMouse.h"
#include "EGamepadAxis.h" #include "EGamepadAxis.h"
#include "EGamepadButton.h" #include "EGamepadButton.h"
#include "EFileDropped.h"
class InputManager class InputManager
{ {
@@ -67,13 +64,6 @@ private:
void PublishGamepadAxisIfChanged(int gamepadID, Gamepad::Axis axis); void PublishGamepadAxisIfChanged(int gamepadID, Gamepad::Axis axis);
void PublishGamepadButtonIfChanged(int gamepadID, Gamepad::Button button); void PublishGamepadButtonIfChanged(int gamepadID, Gamepad::Button button);
static std::vector<unsigned int> GLFWCharCallbackQueue;
static void GLFWCharCallback(GLFWwindow* window, unsigned int c);
static std::vector<std::pair<double, double>> GLFWScrollCallbackQueue;
static void GLFWScrollCallback(GLFWwindow* window, double xoffset, double yoffset);
static std::vector<std::string> GLFWDropCallbackQueue;
static void GLFWDropCallback(GLFWwindow* window, int count, const char* paths[]);
}; };
#endif #endif
+10 -34
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,6 +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.
LOG_WARNING("Allocated slots exceed Pool size, extra memory allocated dynamically. Pool size: %u, dynamic size: %u.", m_NumSlots, m_ExtraMemory.size());
return m_ExtraMemory.back(); return m_ExtraMemory.back();
} }
} }
@@ -132,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;
@@ -277,7 +253,7 @@ public:
} }
//Postfix increment i.e. iter++. Prefer pre-increment (++iter) for efficiency. //Postfix increment i.e. iter++. Prefer pre-increment (++iter) for efficiency.
MemoryPoolForwardIterator operator++(int) MemoryPoolForwardIterator& operator++(int)
{ {
MemoryPoolForwardIterator<T> copyIter(*this); MemoryPoolForwardIterator<T> copyIter(*this);
operator++(); operator++();
-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
-30
View File
@@ -1,30 +0,0 @@
#ifndef PerformanceTimer_h__
#define PerformanceTimer_h__
#include "../Common.h"
#ifdef DEBUG
#include <boost/timer/timer.hpp>
using boost::timer::cpu_timer;
#endif //DEBUG
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:
#ifdef DEBUG
static std::map<std::string, cpu_timer> timers;
static cpu_timer m_Timer;
static std::string currentTimerRunning;
#endif //DEBUG
};
#endif
-35
View File
@@ -1,35 +0,0 @@
#ifndef Ray_h__
#define Ray_h__
#include "../GLM.h"
#include "../Common.h"
class Ray
{
public:
Ray()
: m_Origin(glm::vec3(0.f))
, m_Direction(glm::vec3(0, 0, 1))
{}
Ray(const glm::vec3& origin, const glm::vec3& dir)
: m_Origin(origin)
, m_Direction(glm::normalize(dir))
{
DEBUG_IF(true) {
if (glm::any(glm::isnan(m_Direction))) {
LOG_WARNING("Ray Direction was set to the zero-vector, expect unknown side effects and/or crashes.");
}
}
}
const glm::vec3& Origin() const { return m_Origin; }
const glm::vec3& Direction() const { return m_Direction; }
//Sets the ray origin at parameter.
void SetOrigin(const glm::vec3& origin) { m_Origin = origin; }
//Normalizes the parameter and sets direction to it.
void SetDirection(const glm::vec3& direction) { m_Direction = glm::normalize(direction); }
private:
glm::vec3 m_Origin;
glm::vec3 m_Direction;
};
#endif // Ray_h__
+39 -138
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
{ {
@@ -19,26 +20,8 @@ class Resource
protected: protected:
Resource() { } Resource() { }
virtual ~Resource() = default;
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);
@@ -50,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
{ {
@@ -66,7 +40,6 @@ private:
ResourceManager(); ResourceManager();
public: public:
static bool UseThreading;
/*static ResourceManager& Instance() /*static ResourceManager& Instance()
{ {
static ResourceManager s; static ResourceManager s;
@@ -76,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.
@@ -84,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.
@@ -105,36 +82,22 @@ public:
*/ */
static void Reload(std::string resourceName); static void Reload(std::string resourceName);
static void Release(std::string resourceType, std::string resourceName);
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);
@@ -143,13 +106,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)
{ {
@@ -157,88 +129,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
-85
View File
@@ -1,85 +0,0 @@
#ifndef System_h__
#define System_h__
#include "EventBroker.h"
#include "World.h"
#include "EntityWrapper.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
{
friend class SystemPipeline;
protected:
System(SystemParams params)
: m_World(params.World)
, m_EventBroker(params.EventBroker)
, IsClient(params.IsClient)
, IsServer(params.IsServer)
{
if (IsClient) {
EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &System::setLocalPlayer);
}
}
virtual ~System() = default;
World* m_World;
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
{
friend class SystemPipeline;
protected:
PureSystem(std::string componentType)
: m_ComponentType(componentType)
{ }
virtual ~PureSystem() = default;
const std::string m_ComponentType;
virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cFade, double dt) = 0;
};
class ImpureSystem : public virtual System
{
friend class SystemPipeline;
protected:
ImpureSystem() = default;
virtual ~ImpureSystem() = default;
virtual void Update(double dt) = 0;
};
#endif
-131
View File
@@ -1,131 +0,0 @@
#ifndef SystemPipeline_h__
#define SystemPipeline_h__
#include "../Common.h"
#include "EventBroker.h"
#include "System.h"
#include "World.h"
#include "EPause.h"
#include "PerformanceTimer.h"
class SystemPipeline
{
public:
SystemPipeline(World* world, EventBroker* eventBroker, bool isClient, bool isServer)
: m_World(world)
, m_EventBroker(eventBroker)
, m_IsClient(isClient)
, m_IsServer(isServer)
{
EVENT_SUBSCRIBE_MEMBER(m_EPause, &SystemPipeline::OnPause);
EVENT_SUBSCRIBE_MEMBER(m_EResume, &SystemPipeline::OnResume);
}
~SystemPipeline()
{
for (UnorderedSystems& group : m_OrderedSystemGroups) {
for (auto& pair : group.Systems) {
delete pair.second;
}
}
}
template <typename T, typename... Arguments>
//All systems with orderlevel 0 will be updated first, then 1, 2, etc.
void AddSystem(int updateOrderLevel, Arguments... args)
{
if (updateOrderLevel + 1 > m_OrderedSystemGroups.size()) {
m_OrderedSystemGroups.resize(updateOrderLevel + 1);
}
UnorderedSystems& group = m_OrderedSystemGroups[updateOrderLevel];
System* system = new T(SystemParams(m_World, m_EventBroker, m_IsClient, m_IsServer), args...);
group.Systems[typeid(T).name()] = system;
PureSystem* pureSystem = dynamic_cast<PureSystem*>(system);
if (pureSystem != nullptr) {
if (!pureSystem->m_ComponentType.empty()) {
group.PureSystems[pureSystem->m_ComponentType].push_back(pureSystem);
} else {
LOG_ERROR("Failed to add pure system \"%s\": Missing component type!", typeid(T).name());
}
}
ImpureSystem* impureSystem = dynamic_cast<ImpureSystem*>(system);
if (impureSystem != nullptr) {
group.ImpureSystems.push_back(impureSystem);
}
}
void Update(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) {
// Process events
for (auto& pair : group.Systems) {
m_EventBroker->Process(pair.first);
}
// 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) {
const std::string& componentName = pair.first;
auto& systems = pair.second;
ComponentPool* pool = m_World->GetComponents(componentName);
if (pool == nullptr) {
continue;
}
for (auto& component : *pool) {
for (auto& system : systems) {
auto className = (std::string)typeid(*system).name();
PerformanceTimer::StartTimer(className);
system->UpdateComponent(EntityWrapper(m_World, component.EntityID), component, dt);
PerformanceTimer::StopTimer(className);
}
}
}
}
}
private:
World* m_World;
EventBroker* m_EventBroker;
bool m_IsClient = false;
bool m_IsServer = false;
bool m_Paused = false;
struct UnorderedSystems
{
std::map<std::string, System*> Systems;
std::map<std::string, std::vector<PureSystem*>> PureSystems;
std::vector<ImpureSystem*> ImpureSystems;
};
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
-39
View File
@@ -1,39 +0,0 @@
#ifndef Transform_h__
#define Transform_h__
#include "../GLM.h"
#include "System.h"
#include "EEntityDeleted.h"
class TransformSystem : public System
{
public:
TransformSystem(SystemParams params);
//glm::mat4 AbsoluteTransformation(EntityWrapper entity);
static glm::vec3 AbsolutePosition(EntityWrapper entity);
static glm::vec3 AbsolutePosition(World* world, EntityID entity);
static glm::vec3 AbsoluteOrientationEuler(EntityWrapper entity);
static glm::quat AbsoluteOrientation(EntityWrapper entity);
static glm::quat AbsoluteOrientation(World* world, EntityID entity);
static glm::vec3 AbsoluteScale(EntityWrapper entity);
static glm::vec3 AbsoluteScale(World* world, EntityID entity);
static glm::mat4 ModelMatrix(EntityWrapper entity);
static glm::mat4 ModelMatrix(EntityID entity, World* world);
static glm::vec3 TransformPoint(const glm::vec3& point, const glm::mat4& matrix);
static int RecalculatedPositions;
static int RecalculatedOrientations;
static int RecalculatedScales;
private:
static std::unordered_map<EntityWrapper, glm::vec3> PositionCache;
static std::unordered_map<EntityWrapper, glm::quat> OrientationCache;
static std::unordered_map<EntityWrapper, glm::vec3> ScaleCache;
static std::unordered_map<EntityWrapper, glm::mat4> MatrixCache;
EventRelay<TransformSystem, Events::EntityDeleted> m_EEntityDeleted;
bool OnEntityDeleted(const Events::EntityDeleted& e);
};
#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;
}; };
-12
View File
@@ -1,12 +0,0 @@
// Example:
// DEBUG_IF(condition) {
// // This code is executed only in debug mode and if condition is true.
// }
// NOTE: condition statement is not executed at all in release mode.
#ifndef DEBUG_IF
#ifdef DEBUG
#define DEBUG_IF(c) if(c)
#else
#define DEBUG_IF(c) if(false)
#endif
#endif
+34 -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,7 @@ 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, ...)
#endif
#endif // Logging_h__ #endif // Logging_h__
-46
View File
@@ -1,46 +0,0 @@
#ifndef Util_XercesString_h__
#define Util_XercesString_h__
#include <string>
#include <xercesc/util/XercesDefs.hpp>
#include <xercesc/util/XMLString.hpp>
namespace XS
{
class ToString
{
public:
ToString(const XMLCh* const str) { m_AsChar = xercesc::XMLString::transcode(str); }
~ToString()
{
if (m_AsChar != nullptr) {
xercesc::XMLString::release(&m_AsChar);
}
}
operator std::string() const { return std::string(m_AsChar); }
private:
char* m_AsChar = nullptr;
};
class ToXMLCh
{
public:
ToXMLCh(const std::string str) { m_Transcoded = xercesc::XMLString::transcode(str.c_str()); }
ToXMLCh(const char* str) { m_Transcoded = xercesc::XMLString::transcode(str); }
~ToXMLCh()
{
if (m_Transcoded != nullptr) {
xercesc::XMLString::release(&m_Transcoded);
}
}
operator const XMLCh*() const { return m_Transcoded; }
private:
XMLCh* m_Transcoded = nullptr;
};
}
#endif
+7 -45
View File
@@ -2,73 +2,35 @@
#define World_h__ #define World_h__
#include "../Common.h" #include "../Common.h"
#include "Entity.h" #include "EntityWrapper.h"
#include "ObjectPool.h" #include "ObjectPool.h"
#include "ComponentPool.h" #include "ComponentPool.h"
#include "EventBroker.h"
struct EntityWrapper;
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 EntityID CreateEntity(EntityID parent = 0);
EntityID CreateEntity(EntityID parent = EntityID_Invalid);
// Delete entity and all components within
void DeleteEntity(EntityID entity);
// Check if an entity exists
bool ValidEntity(EntityID entity) const;
// Register a component type and allocate space for it // Register a component type and allocate space for it
void RegisterComponent(const 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
bool HasComponent(EntityID entity, const std::string& componentType) const;
// Get a component of an entity // Get a component of an entity
ComponentWrapper GetComponent(EntityID entity, const std::string& componentType); ComponentWrapper GetComponent(EntityID entity, std::string componentType);
// Delete a component off an entity
void DeleteComponent(EntityID entity, const std::string& componentType);
// Get all components of the specified type // Get all components of the specified type
ComponentPool* GetComponents(const std::string& componentType); const ComponentPool& GetComponents(std::string componentType);
// Get entity parent
EntityID GetParent(EntityID entity);
// Change the parent of an entity
void SetParent(EntityID entity, EntityID parent);
// Get children of an entity
const std::pair<std::unordered_multimap<EntityID, EntityID>::const_iterator, std::unordered_multimap<EntityID, EntityID>::const_iterator> GetDirectChildren(EntityID entity);
// Get all component pools
const std::unordered_map<std::string, ComponentPool*>& GetComponentPools() const { return m_ComponentPools; }
// Get the entity children map
const std::unordered_multimap<EntityID, EntityID>& GetEntityChildren() const { return m_EntityChildren; }
// Set the textual name of an entity
void SetName(EntityID entity, const std::string& name);
// Get the textual name of an entity
std::string GetName(EntityID entity) const;
// Get the first entity in the world with the name.
EntityWrapper GetFirstEntityByName(const std::string& name);
// Merge another world into this one
// Returns a map that maps entities from the other world to their copies in this one
std::unordered_map<EntityID, EntityID> Merge(const World* other);
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;
// TODO: This should be a more effective structure
std::unordered_multimap<EntityID, EntityID> m_EntityChildren; std::unordered_multimap<EntityID, EntityID> m_EntityChildren;
std::unordered_map<std::string, ComponentPool*> m_ComponentPools; std::unordered_map<std::string, ComponentPool*> m_ComponentPools;
std::unordered_map<EntityID, std::string> m_EntityNames;
EntityID generateEntityID(); EntityID generateEntityID();
void deleteEntityRecursive(EntityID entity, bool cascaded = false);
}; };
#endif #endif
@@ -1,120 +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, EntityWrapper playerEntity)
: FirstPersonInputController(eventBroker, playerID, playerEntity)
{
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;
}
ImGuiIO& io = ImGui::GetIO();
if (io.WantCaptureMouse || io.WantCaptureKeyboard) {
return false;
}
m_SpeedMultiplier += e.DeltaY * (0.1 * m_SpeedMultiplier);
m_Config->Set("Editor.CameraSpeed", m_SpeedMultiplier);
m_Config->SaveToDisk();
return true;
}
};
#endif
-192
View File
@@ -1,192 +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"
#include "Game/Events/ESpawnerSpawn.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 pastes an entity previously "copied"
// @param EntityWrapper The entity to copy
// @param EntityWrapper The entity to parent the new copy to
// @return The new copy of the entity
typedef std::function<EntityWrapper(EntityWrapper, EntityWrapper)> OnEntityPaste_t;
void SetEntityPasteCallback(OnEntityPaste_t f) { m_OnEntityPaste = 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;
EntityWrapper m_CopyTarget = EntityWrapper::Invalid;
// 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;
OnEntityPaste_t m_OnEntityPaste = 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);
};
-73
View File
@@ -1,73 +0,0 @@
#include "../Core/System.h"
#include "../Rendering/IRenderer.h"
#include "../Rendering/Camera.h"
#include "../Rendering/ESetCamera.h"
#include "../Core/World.h"
#include "../Core/SystemPipeline.h"
#include "../Core/ResourceManager.h"
#include "../Core/EntityFile.h"
#include "../Core/EntityXMLFileWriter.h"
#include "../Core/EMousePress.h"
#include "../Input/EInputCommand.h"
#include "EditorGUI.h"
#include "EditorStats.h"
#include "EditorCameraInputController.h"
class EditorSystem : public ImpureSystem
{
public:
EditorSystem(SystemParams params, IRenderer* renderer, RenderFrame* renderFrame);
~EditorSystem();
void Update(double dt);
void Enable();
void Disable();
private:
IRenderer* m_Renderer;
RenderFrame* m_RenderFrame;
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
double m_LastTime = 0.f;
bool m_Enabled = true;
EditorGUI::WidgetMode m_WidgetMode = EditorGUI::WidgetMode::Translate;
EditorGUI::WidgetSpace m_WidgetSpace = EditorGUI::WidgetSpace::Global;
EntityWrapper m_Widget = EntityWrapper::Invalid;
EntityWrapper m_CurrentSelection = EntityWrapper::Invalid;
// Utility functions
EntityWrapper importEntity(EntityWrapper parent, boost::filesystem::path filePath);
void setWidgetMode(EditorGUI::WidgetMode mode);
bool isAnyParentMissingTransform(EntityID entityID);
// GUI callbacks
void OnEntitySelected(EntityWrapper entity);
void OnEntitySave(EntityWrapper entity, boost::filesystem::path filePath);
EntityWrapper OnEntityCreate(EntityWrapper parent);
void OnEntityDelete(EntityWrapper entity);
void OnEntityChangeParent(EntityWrapper entity, EntityWrapper parent);
void OnEntityChangeName(EntityWrapper entity, const std::string& name);
EntityWrapper OnEntityPaste(EntityWrapper entityToCopy, EntityWrapper parent);
void OnComponentAttach(EntityWrapper entity, const std::string& componentType);
void OnComponentDelete(EntityWrapper entity, const std::string& componentType);
void OnWidgetSpace(EditorGUI::WidgetSpace widgetSpace);
// 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;
bool OnInputCommand(const Events::InputCommand& e);
EventRelay<EditorSystem, Events::SetCamera> m_ESetCamera;
bool OnSetCamera(const Events::SetCamera& e);
};
@@ -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
+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
+24
View File
@@ -0,0 +1,24 @@
#ifndef Events_BindGamepadAxis_h__
#define Events_BindGamepadAxis_h__
#include "Core/EventBroker.h"
#include "Core/EGamepadAxis.h"
namespace Events
{
/** Called to bind a gamepad axis to an input command. */
struct BindGamepadAxis : Event
{
/** The axis to bind. */
Gamepad::Axis Axis;
/** The command to send. */
std::string Command;
/** The value to send for positive stimulation.
Multiplied by the 0-1 clamped value of the axis.
*/
float Value;
};
}
+26
View File
@@ -0,0 +1,26 @@
#ifndef Events_BindGamepadButton_h__
#define Events_BindGamepadButton_h__
#include "Core/EventBroker.h"
#include "Core/EGamepadButton.h"
namespace Events
{
/** Called to bind a gamepad button to an input command. */
struct BindGamepadButton : Event
{
/** The gamepad button to bind. */
Gamepad::Button Button;
/** The command to send. */
std::string Command;
/** The value to send for positive stimulation.
Multiplied by the 0-1 clamped value of the button.
*/
float Value;
};
}
#endif
+25
View File
@@ -0,0 +1,25 @@
#ifndef Events_BindKey_h__
#define Events_BindKey_h__
#include "Core/EventBroker.h"
namespace Events
{
/** Called to bind a keyboard key to an input command. */
struct BindKey : Event
{
/** The GLFW key code to bind. */
int KeyCode;
/** The command to send. */
std::string Command;
/** The value to send for positive stimulation.
Multiplied by the 0-1 clamped value of the key.
*/
float Value;
};
}
#endif
+25
View File
@@ -0,0 +1,25 @@
#ifndef Events_BindMouseButton_h__
#define Events_BindMouseButton_h__
#include "Core/EventBroker.h"
namespace Events
{
/** Called to bind a mouse button to an input command. */
struct BindMouseButton : Event
{
/** The GLFW mouse button code to bind. */
int Button;
/** The command to send. */
std::string Command;
/** The value to send for positive stimulation.
Multiplied by the 0-1 clamped value of the button.
*/
float Value;
};
}
#endif
-22
View File
@@ -1,22 +0,0 @@
#ifndef Events_BindOrigin_h__
#define Events_BindOrigin_h__
#include "Core/EventBroker.h"
namespace Events
{
/** Called to bind an input origin to an input command. */
struct BindOrigin : Event
{
/** The input origin to bind. */
std::string Origin;
/** The command to send. */
std::string Command;
/** The value to send for positive stimulation. */
float Value = 1.f;
};
}
#endif
+2 -4
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,12 +9,11 @@ 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. */
float Value = 0; float Value;
}; };
} }
@@ -1,441 +0,0 @@
#ifndef FirstPersonInputController_h__
#define FirstPersonInputController_h__
#include "../GLM.h"
#include "../Core/InputController.h"
#include "../Core/ELockMouse.h"
#include "../Game/Events/EDashAbility.h"
#include "InputHandler.h"
#include "Rendering/EAutoAnimationBlend.h"
#include "Rendering/ESetBlendWeight.h"
template <typename EventContext>
class FirstPersonInputController : public InputController<EventContext>
{
public:
FirstPersonInputController(EventBroker* eventBroker, int playerID, EntityWrapper playerEntity);
virtual const glm::vec3 Movement() const { return m_Movement; }
virtual const glm::vec3 Rotation() const { return m_Rotation; }
virtual bool Jumping() const { return m_Jumping; }
virtual bool Crouching() const { return m_Crouching; }
virtual bool CrouchingLastFrame() const { return m_CrouchingLastFrame; }
virtual bool DoubleJumping() const { return m_DoubleJumping; }
virtual void SetDoubleJumping(bool isDoubleJumping) {
m_DoubleJumping = isDoubleJumping;
}
void LockMouse();
void UnlockMouse();
virtual bool OnCommand(const Events::InputCommand& e) override;
virtual void Reset();
void AssaultDashCheck(double dt, bool isJumping, double assaultDashCoolDownMaxTimer, Field<double> assaultDashCoolDownTimer, EntityID playerID);
virtual bool AssaultDashDoubleTapped() const { return m_AssaultDashDoubleTapped; }
virtual bool PlayerIsDashing() const { return m_PlayerIsDashing; }
bool SpecialAbilityKeyDown() const { return m_SpecialAbilityKeyDown; }
protected:
const int m_PlayerID;
EntityWrapper m_PlayerEntity;
bool m_MouseLocked = false;
glm::vec3 m_Rotation;
glm::vec3 m_Movement;
bool m_Jumping = false;
bool m_DoubleJumping = false;
bool m_Crouching = false;
bool m_CrouchingLastFrame = false;
//assault dash membervariables - needed to calculate the doubletap- and dashlogic
double m_AssaultDashDoubleTapDeltaTime = 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;
//specialabilities
bool m_MovementKeyDown = false;
bool m_SpecialAbilityKeyDown = false;
int m_NumberOfMovementKeysDown = 0;
EventRelay<EventContext, Events::LockMouse> m_ELockMouse;
bool OnLockMouse(const Events::LockMouse& e);
EventRelay<EventContext, Events::UnlockMouse> m_EUnlockMouse;
bool OnUnlockMouse(const Events::UnlockMouse& e);
};
template <typename EventContext>
FirstPersonInputController<EventContext>::FirstPersonInputController(EventBroker* eventBroker, int playerID, EntityWrapper playerEntity)
: InputController(eventBroker)
, m_PlayerID(playerID)
, m_PlayerEntity(playerEntity)
{
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;
m_CrouchingLastFrame = m_Crouching;
}
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;
}
if (e.Command == "Pitch") {
float val = glm::radians(e.Value);
m_Rotation.x += -val;
}
if (e.Command == "Yaw") {
float val = glm::radians(e.Value);
m_Rotation.y += -val;
}
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;
//Animation
if (m_PlayerEntity.Valid()) {
EntityWrapper playerModel = m_PlayerEntity.FirstChildByName("PlayerModel");
if (playerModel.Valid()) {
if (val > 0) { // Walk/Run
Events::AutoAnimationBlend aeb;
aeb.Duration = 0.1;
if (m_Crouching) {
aeb.NodeName = "Walk";
} else {
aeb.NodeName = "Run";
}
aeb.RootNode = playerModel;
aeb.Start = true;
aeb.SingleLevelBlend = true;
m_EventBroker->Publish(aeb);
} else if (val < 0) { // Walk/run Backwards
Events::AutoAnimationBlend aeb;
aeb.Duration = 0.1;
if (m_Crouching) {
aeb.NodeName = "Walk";
} else {
aeb.NodeName = "Run";
}
aeb.RootNode = playerModel;
aeb.Start = true;
aeb.SingleLevelBlend = true;
aeb.Reverse = true;
m_EventBroker->Publish(aeb);
}
}
EntityWrapper firstPersonModel = m_PlayerEntity.FirstChildByName("Hands");
if (firstPersonModel.Valid()) {
if (val > 0) { // Walk/Run
if (!m_Crouching) {
Events::AutoAnimationBlend aeb;
aeb.Duration = 0.1;
aeb.NodeName = "Run";
aeb.RootNode = firstPersonModel;
aeb.SingleLevelBlend = true;
aeb.Start = true;
m_EventBroker->Publish(aeb);
}
} else if (val < 0) { // Walk/run Backwards
if (!m_Crouching) {
Events::AutoAnimationBlend aeb;
aeb.Duration = 0.1;
aeb.NodeName = "Run";
aeb.RootNode = firstPersonModel;
aeb.SingleLevelBlend = true;
aeb.Start = true;
aeb.Reverse = true;
m_EventBroker->Publish(aeb);
}
}
}
}
}
if (e.Command == "Right") {
float val = glm::clamp(e.Value, -1.f, 1.f);
m_Movement.x = val;
//Animation
if (m_PlayerEntity.Valid()) {
EntityWrapper playerModel = m_PlayerEntity.FirstChildByName("PlayerModel");
if (playerModel.Valid()) { //Right Strafe
if (val > 0) {
Events::AutoAnimationBlend aeb;
aeb.Duration = 0.1;
aeb.NodeName = "Right";
aeb.RootNode = playerModel;
aeb.SingleLevelBlend = true;
aeb.Start = true;
m_EventBroker->Publish(aeb);
} else if (val < 0) { //LeftStrafe
Events::AutoAnimationBlend aeb;
aeb.Duration = 0.1;
aeb.NodeName = "Left";
aeb.RootNode = playerModel;
aeb.SingleLevelBlend = true;
aeb.Start = true;
m_EventBroker->Publish(aeb);
}
}
EntityWrapper firstPersonModel = m_PlayerEntity.FirstChildByName("Hands");
if (firstPersonModel.Valid()) {
if (val > 0) { // Walk/Run
if (!m_Crouching) {
Events::AutoAnimationBlend aeb;
aeb.Duration = 0.1;
aeb.NodeName = "Run";
aeb.RootNode = firstPersonModel;
aeb.SingleLevelBlend = true;
aeb.Start = true;
m_EventBroker->Publish(aeb);
}
} else if (val < 0) { // Walk/run Backwards
if (!m_Crouching) {
Events::AutoAnimationBlend aeb;
aeb.Duration = 0.1;
aeb.NodeName = "Run";
aeb.RootNode = firstPersonModel;
aeb.SingleLevelBlend = true;
aeb.Start = true;
aeb.Reverse = true;
m_EventBroker->Publish(aeb);
}
}
}
}
}
}
if (m_PlayerEntity.Valid()) {
glm::vec2 movementXZ = glm::vec2(m_Movement.x, m_Movement.z);
if (glm::length(movementXZ) < 0.1f) {
//Blend to Idle
EntityWrapper playerModel = m_PlayerEntity.FirstChildByName("PlayerModel");
if (playerModel.Valid()) {
Events::AutoAnimationBlend aeb;
aeb.Duration = 0.1;
aeb.NodeName = "Idle";
aeb.RootNode = playerModel;
aeb.Start = true;
m_EventBroker->Publish(aeb);
}
EntityWrapper firstPersonModel = m_PlayerEntity.FirstChildByName("Hands");
if (firstPersonModel.Valid()) {
Events::AutoAnimationBlend aeb;
aeb.Duration = 0.1;
aeb.NodeName = "Idle";
aeb.RootNode = firstPersonModel;
aeb.Start = true;
m_EventBroker->Publish(aeb);
}
} else {
//Blend to movement
EntityWrapper playerModel = m_PlayerEntity.FirstChildByName("PlayerModel");
if (playerModel.Valid()) {
Events::AutoAnimationBlend aeb;
aeb.Duration = 0.1;
aeb.NodeName = "DirectionBlend";
aeb.RootNode = playerModel;
m_EventBroker->Publish(aeb);
}
}
}
if (glm::length(m_Movement) > 0) {
m_Movement = glm::normalize(m_Movement);
//Animation
// movement direction blend
if (m_PlayerEntity.Valid()) {
EntityWrapper playerModel = m_PlayerEntity.FirstChildByName("PlayerModel");
if (playerModel.Valid()) {
glm::vec2 direction = glm::normalize(glm::vec2(m_Movement.x, m_Movement.z));
double weight = glm::abs(glm::dot(glm::vec2(1, 0), direction));
Events::SetBlendWeight sbw;
sbw.NodeName = "DirectionBlend";
sbw.Weight = weight;
sbw.RootNode = playerModel;
m_EventBroker->Publish(sbw);
}
}
}
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;
//Animation
if (m_PlayerEntity.Valid()) {
EntityWrapper playerModel = m_PlayerEntity.FirstChildByName("PlayerModel");
if (playerModel.Valid()) {
if (e.Value == 0.f) {
Events::AutoAnimationBlend aeb;
aeb.Duration = 0.3;
aeb.NodeName = "StandMovement";
aeb.RootNode = playerModel;
aeb.Start = true;
aeb.Restart = true;
aeb.SingleLevelBlend = true;
m_EventBroker->Publish(aeb);
} else if(e.Value == 1.0f) {
Events::AutoAnimationBlend aeb;
aeb.Duration = 0.3;
aeb.NodeName = "CrouchMovement";
aeb.RootNode = playerModel;
aeb.Start = true;
aeb.Restart = true;
aeb.SingleLevelBlend = true;
m_EventBroker->Publish(aeb);
}
}
}
}
if (e.Command == "SpecialAbility") {
m_SpecialAbilityKeyDown = e.Value > 0;
}
m_ShiftDashing = m_SpecialAbilityKeyDown && m_MovementKeyDown;
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, Field<double> assaultDashCoolDownTimer, EntityID playerID) {
m_AssaultDashDoubleTapDeltaTime += dt;
assaultDashCoolDownTimer -= dt;
//cooldown = assaultDashCoolDownMaxTimer sec, pretend the dash lasts 0.25 sec (for friction to do its work)
if (assaultDashCoolDownTimer > (assaultDashCoolDownMaxTimer - 0.25f)) {
m_PlayerIsDashing = true;
} else {
m_PlayerIsDashing = false;
}
//dashing with shift
if (m_ShiftDashing && 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!
assaultDashCoolDownTimer = assaultDashCoolDownMaxTimer;
m_AssaultDashDoubleTapped = true;
m_AssaultDashDoubleTapDeltaTime = 0.f;
Events::DashAbility e;
e.Player = playerID;
m_EventBroker->Publish(e);
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 (!(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;
assaultDashCoolDownTimer = assaultDashCoolDownMaxTimer;
Events::DashAbility e;
e.Player = playerID;
m_EventBroker->Publish(e);
}
#endif
-25
View File
@@ -1,25 +0,0 @@
#ifndef InputHandler_h__
#define InputHandler_h__
#include "../Common.h"
#include "../Core/EventBroker.h"
#include "InputProxy.h"
class InputHandler
{
public:
InputHandler(EventBroker* eventBroker, InputProxy* inputProxy)
: m_EventBroker(eventBroker)
, m_InputProxy(inputProxy)
{ }
virtual bool BindOrigin(std::string origin, std::string command, float value) = 0;
virtual void Update(double dt) { }
virtual float GetCommandValue(std::string command) = 0;
protected:
EventBroker* m_EventBroker;
InputProxy* m_InputProxy;
};
#endif
-47
View File
@@ -1,47 +0,0 @@
#ifndef InputProxy_h__
#define InputProxy_h__
#include <boost/tokenizer.hpp>
#include "../Common.h"
#include "../Core/ResourceManager.h"
#include "../Core/ConfigFile.h"
#include "EInputCommand.h"
#include "EBindOrigin.h"
class InputHandler;
class InputProxy
{
public:
InputProxy(EventBroker* eventBroker);
~InputProxy();
void LoadBindings(std::string file);
void Update(double dt);
void Process(bool suppressNewEvents = false);
template <typename T>
void AddHandler();
void Publish(const Events::InputCommand& e);
protected:
EventBroker* m_EventBroker;
std::vector<InputHandler*> m_Handlers;
std::map<std::string, std::set<InputHandler*>> m_CommandHandlers;
// Represents every unique command (has of PlayerID & Command) and all values reported for that command this frame
std::map<std::pair<unsigned int, std::string>, std::vector<float>> m_CommandQueue;
std::map<std::string, float> m_CurrentCommandValues;
std::map<std::string, float> m_LastCommandValues;
EventRelay<InputProxy, Events::BindOrigin> m_EBindOrigin;
bool OnBindOrigin(const Events::BindOrigin& e);
};
template <typename T>
void InputProxy::AddHandler()
{
m_Handlers.push_back(new T(m_EventBroker, this));
}
#endif
+78
View File
@@ -0,0 +1,78 @@
#ifndef InputSystem_h__
#define InputSystem_h__
#include <array>
#include <unordered_map>
#include "Core/System.h"
#include "Core/EKeyUp.h"
#include "Core/EKeyDown.h"
#include "Core/EMousePress.h"
#include "Core/EMouseRelease.h"
#include "Core/EGamepadAxis.h"
#include "Core/EGamepadButton.h"
#include "Core/Util/EnumClassHash.h"
#include "EBindKey.h"
#include "EBindMouseButton.h"
#include "EBindGamepadAxis.h"
#include "EBindGamepadButton.h"
#include "EInputCommand.h"
namespace Systems
{
class InputSystem : public System
{
public:
InputSystem(World* world, std::shared_ptr<dd::EventBroker> eventBroker)
: System(world, eventBroker)
{ }
void RegisterComponents(ComponentFactory* cf) override;
void Initialize() override;
void Update(double dt) override;
private:
std::unordered_map<std::string, std::unordered_map<int, float>> m_CommandKeyboardValues; // command string -> keyboard key value for command
std::unordered_map<std::string, std::unordered_map<int, float>> m_CommandMouseButtonValues; // command string -> mouse button value for command
std::unordered_map<std::string, std::unordered_map<Gamepad::Axis, float, EnumClassHash>> m_CommandGamepadAxisValues; // command string -> gamepad axis value for command
std::unordered_map<std::string, std::unordered_map<Gamepad::Button, float, EnumClassHash>> m_CommandGamepadButtonValues; // command string -> gamepad button value for command
// Input binding tables
std::unordered_multimap<int, std::tuple<std::string, float>> m_KeyBindings; // GLFW_KEY... -> command string & value
std::unordered_multimap<int, std::tuple<std::string, float>> m_MouseButtonBindings; // GLFW_MOUSE_BUTTON... -> command string
std::unordered_multimap<Gamepad::Axis, std::tuple<std::string, float>, EnumClassHash> m_GamepadAxisBindings; // Gamepad::Axis -> command string & value
std::unordered_multimap<Gamepad::Button, std::tuple<std::string, float>, EnumClassHash> m_GamepadButtonBindings; // Gamepad::Button -> command string
// Input events
EventRelay<InputSystem, Events::KeyDown> m_EKeyDown;
bool OnKeyDown(const Events::KeyDown &event);
EventRelay<InputSystem, Events::KeyUp> m_EKeyUp;
bool OnKeyUp(const Events::KeyUp &event);
EventRelay<InputSystem, Events::MousePress> m_EMousePress;
bool OnMousePress(const Events::MousePress &event);
EventRelay<InputSystem, Events::MouseRelease> m_EMouseRelease;
bool OnMouseRelease(const Events::MouseRelease &event);
EventRelay<InputSystem, Events::GamepadAxis> m_EGamepadAxis;
bool OnGamepadAxis(const Events::GamepadAxis &event);
EventRelay<InputSystem, Events::GamepadButtonDown> m_EGamepadButtonDown;
bool OnGamepadButtonDown(const Events::GamepadButtonDown &event);
EventRelay<InputSystem, Events::GamepadButtonUp> m_EGamepadButtonUp;
bool OnGamepadButtonUp(const Events::GamepadButtonUp &event);
// Input binding events
EventRelay<InputSystem, Events::BindKey> m_EBindKey;
bool OnBindKey(const Events::BindKey &event);
EventRelay<InputSystem, Events::BindMouseButton> m_EBindMouseButton;
bool OnBindMouseButton(const Events::BindMouseButton &event);
EventRelay<InputSystem, Events::BindGamepadAxis> m_EBindGamepadAxis;
bool OnBindGamepadAxis(const Events::BindGamepadAxis &event);
EventRelay<InputSystem, Events::BindGamepadButton> m_EBindGamepadButton;
bool OnBindGamepadButton(const Events::BindGamepadButton &event);
float GetCommandTotalValue(std::string command);
void PublishCommand(int playerID, std::string command, float value);
};
}
#endif
@@ -1,28 +0,0 @@
#ifndef KeyboardInputHandler_h__
#define KeyboardInputHandler_h__
#include <GLFW/glfw3.h>
#include "InputHandler.h"
#include "Core/EKeyDown.h"
#include "Core/EKeyUp.h"
class KeyboardInputHandler : public InputHandler
{
public:
KeyboardInputHandler(EventBroker* eventBroker, InputProxy* inputProxy);
bool BindOrigin(std::string origin, std::string command, float value) override;
virtual float GetCommandValue(std::string command) override;
private:
std::unordered_map<std::string, int> m_OriginKeyCodes;
std::unordered_map<int, std::tuple<std::string, float>> m_KeyBindings; // GLFW_KEY... -> command string & value
std::unordered_map<std::string, float> m_CommandValues;
EventRelay<InputHandler, Events::KeyDown> m_EKeyDown;
bool OnKeyDown(const Events::KeyDown& e);
EventRelay<InputHandler, Events::KeyUp> m_EKeyUp;
bool OnKeyUp(const Events::KeyUp& e);
};
#endif
-38
View File
@@ -1,38 +0,0 @@
#ifndef MouseInputHandler_h__
#define MouseInputHandler_h__
#include <GLFW/glfw3.h>
#include "InputHandler.h"
#include "Core/EMousePress.h"
#include "Core/EMouseRelease.h"
#include "Core/EMouseMove.h"
class MouseInputHandler : public InputHandler
{
public:
MouseInputHandler(EventBroker* eventBroker, InputProxy* inputProxy);
bool BindOrigin(std::string origin, std::string command, float value) override;
virtual float GetCommandValue(std::string command) override;
private:
std::unordered_map<std::string, int> m_OriginCodes;
std::unordered_map<std::string, char> m_OriginAxes;
std::unordered_map<int, std::tuple<std::string, float>> m_Bindings; // GLFW_MOUSE_BUTTON... -> command string & value
std::unordered_map<char, std::tuple<std::string, float>> m_Axes; // Axis -> command string & value
std::unordered_map<std::string, float> m_CommandValues;
std::unordered_map<std::string, float> m_ContinuousCommandValues;
EventRelay<InputHandler, Events::MousePress> m_EMousePress;
bool OnMousePress(const Events::MousePress& e);
EventRelay<InputHandler, Events::MouseRelease> m_EMouseRelease;
bool OnMouseRelease(const Events::MouseRelease& e);
EventRelay<InputHandler, Events::MouseMove> m_EMouseMove;
bool OnMouseMove(const Events::MouseMove& e);
bool hasOrigin(std::string origin);
};
#endif
+4 -143
View File
@@ -1,153 +1,14 @@
#ifndef Client_h__ #ifndef Client_h__
#define Client_h__ #define Client_h__
#include <string> #include <boost\asio.hpp>
#include <ctime>
#include <limits>
#include <queue>
#include <glm/common.hpp> class Client
#include <boost/asio.hpp>
#include <boost/shared_array.hpp>
#include "Network/EKillDeath.h"
#include "Core/World.h"
#include "Core/EntityFile.h"
#include "Core/EventBroker.h"
#include "Core/ConfigFile.h"
#include "Core/EPlayerDeath.h"
#include "Core/EPlayerDamage.h"
#include "Core/EPlayerSpawned.h"
#include "Core/EAmmoPickup.h"
#include "Game/Events/EDoubleJump.h"
#include "Game/Events/EDashAbility.h"
#include "Game/Events/EReset.h"
#include "Input/EInputCommand.h"
#include "imgui/imgui.h"
#include "Network/Network.h"
#include "Network/MessageType.h"
#include "Network/PlayerDefinition.h"
#include "Network/UDPClient.h"
#include "Network/TCPClient.h"
#include "Network/SnapshotDefinitions.h"
#include "Network/EDisplayServerlist.h"
#include "Network/EConnectRequest.h"
#include "Network/EPlayerDisconnected.h"
#include "Network/ESearchForServers.h"
#include "Network/EInterpolate.h"
#include "Network/SnapshotFilter.h"
#include "Core/EWin.h"
class Client : public Network
{ {
public: Client();
Client(World* world, EventBroker* eventBroker); ~Client();
Client(World* world, EventBroker* eventBroker, std::unique_ptr<SnapshotFilter> snapshotFilter);
~Client();
void Connect(std::string address, int port);
void Update(double dt) override;
private:
UDPClient m_Unreliable;
TCPClient m_Reliable;
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
size_t bytesRead = 0;
// Packet loss logic
PacketID m_PacketID = 0;
PacketID m_PreviousPacketID = 0;
PacketID m_SendPacketID = 0;
// Game logic
std::string m_PlayerName;
PlayerID 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
PlayerDefinition m_PlayerDefinitions[8];
SnapshotDefinitions m_NextSnapshot;
double m_DurationOfPingTime = 0;
double m_StartPingTime = 0;
double m_TimeSinceSentInputs = 0;
double m_SendInputInterval = 0.033;
std::vector<Events::InputCommand> m_InputCommandBuffer;
// Private member functions
size_t receive(char* data);
void disconnect();
void parseMessageType(Packet& packet);
void updateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID);
SharedComponentWrapper createSharedComponent(Packet& packet, EntityID entityID, const ComponentInfo& componentInfo);
void ignoreFields(Packet& packet, const ComponentInfo& componentInfo);
void parseUDPConnect(Packet& packet);
void parseTCPConnect(Packet& packet);
void parsePlayerConnected(Packet& packet);
void parsePing();
void parseServerlist(Packet& packet);
void parseKick();
void parsePlayersSpawned(Packet& packet);
void parseEntityDeletion(Packet& packet);
void parsePlayerDamage(Packet& packet);
void parseComponentDeletion(Packet& packet);
void parseDoubleJump(Packet& packet);
void parseDashEffect(Packet& packet);
void parseAmmoPickup(Packet& packet);
void parseRemoveWorld(Packet& packet);
void parseKDEvent(Packet& packet);
void parseWin(Packet& packet);
void InterpolateFields(Packet& packet, const ComponentInfo & componentInfo, const EntityID & entityID, const std::string & componentType);
void parseSnapshot(Packet& packet);
void identifyPacketLoss();
void hasServerTimedOut();
EntityID createPlayer();
void sendInputCommands();
void sendLocalPlayerTransform();
void becomePlayer();
void displayServerlist();
void createMainMenu();
// 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
EventRelay<Client, Events::InputCommand> m_EInputCommand;
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;
EventRelay<Client, Events::DoubleJump> m_EDoubleJump;
bool OnDoubleJump(Events::DoubleJump & e);
EventRelay<Client, Events::DashAbility> m_EDashAbility;
bool OnDashAbility(const Events::DashAbility& e);
EventRelay<Client, Events::ConnectRequest> m_EConnectRequest;
bool OnConnectRequest(const Events::ConnectRequest& e);
bool OnSearchForServers(const Events::SearchForServers& e);
UDPClient m_ServerlistRequest;
std::vector<ServerInfo> m_Serverlist;
bool m_SearchingForServers = false;
double m_TimeSearched = 0;
double m_SearchingTime = 0.2; // Config I guess
}; };
#endif #endif
-17
View File
@@ -1,17 +0,0 @@
#ifndef Events_ConnectRequest_h__
#define Events_ConnectRequest_h__
#include "Core/EventBroker.h"
namespace Events
{
struct ConnectRequest : public Event
{
std::string IP = "";
int Port = 0;
};
}
#endif
@@ -1,29 +0,0 @@
#ifndef Events_DisplayServerlist_h__
#define Events_DisplayServerlist_h__
#include <string>
#include <vector>
#include "Core/Event.h"
struct ServerInfo
{
ServerInfo(std::string address, int port, std::string name, int players)
{
Address = address; Port = port; Name = name; PlayersConnected = players;
}
std::string Address = "";
int Port = 0;
std::string Name = "";
int PlayersConnected = 0;
};
namespace Events
{
struct DisplayServerlist : public Event
{
std::vector<ServerInfo> Serverlist;
};
}
#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
-30
View File
@@ -1,30 +0,0 @@
#ifndef Events_KillDeath_h__
#define Events_KillDeath_h__
#include "Core/EventBroker.h"
typedef unsigned int PlayerID;
namespace Events
{
struct KillDeath : public Event
{
int CasualtyTeam;
PlayerID Casualty = -1;
std::string CasualtyName;
//1 = assault, 2 = defender, 3 = sniper
int CasualtyClass;
int KillerTeam;
PlayerID Killer = -1;
std::string KillerName;
//1 = assault, 2 = defender, 3 = sniper
int KillerClass;
};
}
#endif

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