Compare commits

..

5 Commits

435 changed files with 5143 additions and 27406 deletions
-11
View File
@@ -4,14 +4,3 @@ bin/
lib/
# Because apparently nobody has any self control
*.orig
*.suo
*.sdf
tools/MayaExporter/MayaExporter/x64/Debug/
tools/MayaExporter/x64/Debug/
tools/MayaExporter/MayaExporter/Debug/
tools/MayaExporter/MayaExporter/GeneratedFiles/
tools/MayaExporter/MayaExporter/x64/*
tools/MayaExporter/x64/*
-9
View File
@@ -14,9 +14,6 @@ endif()
if(CMAKE_COMPILER_IS_GNUCXX)
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()
#set(BUILD_SHARED_LIBS FALSE)
@@ -37,12 +34,6 @@ foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES})
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY})
endforeach(OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES)
# DEBUG definition
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS
$<$<CONFIG:Debug>:DEBUG>
$<$<CONFIG:RelWithDebInfo>:DEBUG>
)
include(cotire)
add_subdirectory(src/Engine)
add_subdirectory(src/Game)
+1 -2
View File
@@ -11,8 +11,7 @@ Libraries bundled along with binaries for Windows (MSVC14), available as a submo
| **[libpng](http://www.libpng.org/pub/png/libpng.html)** | 1.6.19 | [libpng License](http://www.libpng.org/pub/png/src/libpng-LICENSE.txt) |
| **[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)
| **[nativefiledialog](https://github.com/mlabbe/nativefiledialog) | 2016-01-08 | https://github.com/mlabbe/nativefiledialog/blob/master/LICENSE |
#### External libraries
Libraries that are too big to be bundled with the project.
+1 -1
Submodule assets updated: 7531e441fe...c8e631f449
+8 -36
View File
@@ -6,16 +6,11 @@
//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/Transform.h"
#include "../Core/Entity.h"
#include "../Core/EntityWrapper.h"
#include "EntityAABB.h"
#include "Core/Ray.h"
#include "Core/AABB.h"
#include "Engine/Rendering/RawModel.h"
#include "Core/Entity.h"
class World;
struct ComponentWrapper;
@@ -28,21 +23,6 @@ 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<RawModel::Vertex>& modelVertices,
@@ -63,24 +43,16 @@ bool RayVsModel(const Ray& ray,
float& outUCoord,
float& outVCoord);
bool AABBvsTriangles(const AABB& box,
const RawModel::Vertex* modelVertices,
const std::vector<unsigned int>& modelIndices,
const glm::mat4& modelMatrix,
glm::vec3& boxVelocity,
float verticalStepHeight,
bool& isOnGround,
glm::vec3& outResolutionVector);
//Return true if the boxes are intersecting.
bool AABBVsAABB(const AABB& a, const AABB& b);
//Return true if the boxes are intersecting.
//Also outputs the minimum translation that box [a] would need in order to resolve collision.
bool AABBVsAABB(const AABB& a, const AABB& b, glm::vec3& minimumTranslation);
bool IsSameBoxProbably(const AABB& first, const AABB& second, const float epsilon = 0.0001f);
// Calculates an absolute AABB from an entity AABB component
boost::optional<EntityAABB> EntityAbsoluteAABB(EntityWrapper& entity, bool takeModelBox = false);
boost::optional<EntityAABB> AbsoluteAABBExplosionEffect(EntityWrapper& entity);
//Returns true if the entity has a boundingbox. Outputs the aabb in [outBox].
bool GetEntityBox(World* world, EntityID entity, AABB& outBox, bool forceBoxFromModel = false);
bool GetEntityBox(World* world, ComponentWrapper& AABBComponent, AABB& outBox);
}
+15 -13
View File
@@ -4,26 +4,28 @@
#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"
#include "Common.h"
#include "Core/System.h"
#include "Core/EventBroker.h"
#include "Core/EKeyUp.h"
class CollisionSystem : public PureSystem
{
public:
CollisionSystem(World* world, EventBroker* eventBroker, Octree<EntityAABB>* octree)
: System(world, eventBroker)
, PureSystem("Collidable")
, m_Octree(octree)
{ }
CollisionSystem(EventBroker* eventBroker)
: PureSystem(eventBroker, "AABB")
, zPress(false)
{
//TODO: Debug stuff, remove later.
EVENT_SUBSCRIBE_MEMBER(m_EKeyUp, &CollisionSystem::OnKeyUp);
}
virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) override;
virtual void UpdateComponent(World* world, ComponentWrapper& cAABB, double dt) override;
private:
Octree<EntityAABB>* m_Octree;
std::vector<EntityAABB> m_OctreeResult;
bool zPress;
EventRelay<CollisionSystem, Events::KeyUp> m_EKeyUp;
bool OnKeyUp(const Events::KeyUp &event);
};
#endif
+7 -7
View File
@@ -2,7 +2,7 @@
#define Events_TriggerEnter_h__
#include "../Core/EventBroker.h"
#include "../Core/EntityWrapper.h"
#include "../Core/Entity.h"
namespace Events
{
@@ -11,27 +11,27 @@ namespace Events
struct TriggerTouch : Event
{
/** The id of the entity that touches the trigger. */
EntityWrapper Entity;
EntityID Entity;
/** The id of the trigger entity. */
EntityWrapper Trigger;
EntityID 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;
EntityID Entity;
/** The id of the trigger entity. */
EntityWrapper Trigger;
EntityID Trigger;
};
/** Thrown once, when an entity is completely contained inside a trigger. */
struct TriggerEnter : Event
{
/** The id of the entity that entered the trigger. */
EntityWrapper Entity;
EntityID Entity;
/** The id of the trigger entity. */
EntityWrapper Trigger;
EntityID Trigger;
};
}
-22
View File
@@ -1,22 +0,0 @@
#ifndef EntityAABB_h__
#define EntityAABB_h__
#include "../Core/AABB.h"
#include "../Core/EntityWrapper.h"
struct EntityAABB : AABB
{
EntityAABB() = default;
EntityAABB(const glm::vec3& minPos, const glm::vec3& maxPos)
: AABB(minPos, maxPos)
{ }
EntityAABB(const AABB& aabb)
: AABB(aabb)
{ }
EntityWrapper Entity;
};
#endif
@@ -1,25 +0,0 @@
#ifndef FillFrustumOctreeSystem_h__
#define FillFrustumOctreeSystem_h__
#include "../Core/System.h"
#include "../Core/Octree.h"
#include "Collision.h"
#include "EntityAABB.h"
class FillFrustumOctreeSystem : public ImpureSystem, public PureSystem
{
public:
FillFrustumOctreeSystem(World* world, EventBroker* eventBroker, Octree<EntityAABB>* octree)
: System(world, eventBroker)
, 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(World* world, EventBroker* eventBroker, Octree<EntityAABB>* octree, const std::string& fillComponentType)
: System(world, eventBroker)
, PureSystem(fillComponentType)
, m_Octree(octree)
{ }
virtual void Update(double dt) override;
virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) override;
private:
Octree<EntityAABB>* m_Octree;
};
#endif
+12 -30
View File
@@ -4,51 +4,33 @@
#include <glm/common.hpp>
#include <unordered_set>
#include "../Core/System.h"
#include "../Core/EventBroker.h"
#include "../Core/Octree.h"
#include "Core/System.h"
#include "Core/EventBroker.h"
#include "ETrigger.h"
#include "EntityAABB.h"
class AABB;
class TriggerSystem : public PureSystem
{
public:
TriggerSystem(World* world, EventBroker* eventBroker, Octree<EntityAABB>* octree)
: System(world, eventBroker)
, PureSystem("Trigger")
, m_Octree(octree)
{
EVENT_SUBSCRIBE_MEMBER(m_ETouch, &TriggerSystem::OnTouch);
EVENT_SUBSCRIBE_MEMBER(m_EEnter, &TriggerSystem::OnEnter);
EVENT_SUBSCRIBE_MEMBER(m_ELeave, &TriggerSystem::OnLeave);
}
TriggerSystem(EventBroker* eventBroker)
: PureSystem(eventBroker, "Trigger")
{}
virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) override;
virtual void UpdateComponent(World* world, ComponentWrapper& collision, 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);
std::unordered_map<EntityID, std::unordered_set<EntityID>> m_EntitiesTouchingTrigger;
std::unordered_map<EntityID, std::unordered_set<EntityID>> m_EntitiesCompletelyInTrigger;
//True if leave event was thrown.
bool throwLeaveIfWasInTrigger(std::unordered_set<EntityWrapper>& triggerSet, EntityWrapper colliderENtity, EntityWrapper triggerEntity);
bool throwLeaveIfWasInTrigger(std::unordered_set<EntityID>& triggerSet, EntityID pId, EntityID tId);
template<typename Event>
void publish(EntityWrapper collider, EntityWrapper trigger)
void publish(EntityID pId, EntityID tId)
{
Event e;
e.Trigger = trigger;
e.Entity = collider;
e.Trigger = tId;
e.Entity = pId;
m_EventBroker->Publish(e);
}
};
-3
View File
@@ -1,11 +1,8 @@
#include <memory>
#include <string>
#include <sstream>
#include <vector>
#include <map>
#include <unordered_map>
#include <algorithm>
#include <array>
#include "Core/Util/Logging.h"
#include "Core/Util/IfDebug.h"
+4 -3
View File
@@ -9,19 +9,20 @@ public:
AABB() = default;
//No checks are made. Values in minPos must be less than values in maxPos, i.e. min.x < max.x, etc.
AABB(const glm::vec3& minPos, const glm::vec3& maxPos);
AABB(const glm::vec4& minPos, const glm::vec4& maxPos);
//No checks are made. Size must consist of non-negative numbers.
static AABB FromOriginSize(const glm::vec3& origin, const glm::vec3& size);
virtual void CreateFromCenter(const glm::vec3& center, 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& Center() const { return m_Center; }
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_Center;
glm::vec3 m_HalfSize;
};
+3 -8
View File
@@ -5,19 +5,15 @@
struct ComponentInfo
{
typedef int EnumType;
struct Meta_t
{
std::string Annotation;
unsigned int Allocation = 0;
std::map<std::string, std::string> FieldAnnotations;
std::map<std::string, std::map<std::string, EnumType>> FieldEnumDefinitions;
unsigned int Stride = 0;
};
struct Field_t
{
std::string Name;
std::string Type;
unsigned int Offset;
unsigned int Stride;
@@ -25,10 +21,9 @@ struct ComponentInfo
std::string Name;
std::unordered_map<std::string, Field_t> Fields;
std::vector<std::string> FieldsInOrder;
unsigned int Stride = 0;
std::vector<const Field_t*> FieldsInOrder;
Meta_t Meta;
std::shared_ptr<char> Defaults = nullptr;
std::shared_ptr<Meta_t> Meta = nullptr;
};
template<>
+1 -2
View File
@@ -43,7 +43,7 @@ public:
ComponentPool(const ::ComponentInfo& ci)
: m_ComponentInfo(ci)
, m_Pool(ci.Meta->Allocation, sizeof(EntityID) + ci.Stride)
, m_Pool(ci.Meta.Allocation, sizeof(EntityID) + ci.Meta.Stride)
{ }
ComponentPool(const ComponentPool& other) = delete;
ComponentPool(const ComponentPool&& other) = delete;
@@ -61,7 +61,6 @@ public:
iterator begin() const;
iterator end() const;
size_t size() const;
//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<<)
+19 -37
View File
@@ -18,37 +18,22 @@ struct ComponentWrapper
const ::EntityID EntityID;
char* Data;
ComponentInfo::EnumType Enum(const char* fieldName, const char* enumKey)
template <typename T>
T& Property(std::string name)
{
return Info.Meta->FieldEnumDefinitions.at(fieldName).at(enumKey);
unsigned int offset = Info.Fields.at(name).Offset;
return *reinterpret_cast<T*>(&Data[offset]);
}
template <typename T>
T& Field(std::string name)
{
const ComponentInfo::Field_t& field = Info.Fields.at(name);
if (sizeof(T) > field.Stride) {
std::stringstream message;
message << "Type size of \"" << typeid(T).name() << "\" doesn't match size of component field \"" << Info.Name << "." << name << "\"!";
throw new std::runtime_error(message.str().c_str());
}
return *reinterpret_cast<T*>(&Data[field.Offset]);
}
template <typename T>
void SetField(std::string name, const T value) { Field<T>(name) = value; }
void SetProperty(std::string name, const T value) { Property<T>(name) = value; }
//template <typename T>
//void SetField(std::string name, T& value) { Field<T>(name) = value; }
//void SetProperty(std::string name, T& value) { Property<T>(name) = value; }
// Specialization for string literals
template <std::size_t N>
void SetField(std::string name, const char(&value)[N]) { Field<std::string>(name) = std::string(value); }
void SetProperty(std::string name, const char(&value)[N]) { Property<std::string>(name) = std::string(value); }
void Copy(ComponentWrapper& destination)
{
memcpy(destination.Data, this->Data, Info.Stride);
}
struct SubscriptProxy
{
friend struct ComponentWrapper;
@@ -62,21 +47,18 @@ struct ComponentWrapper
std::string m_PropertyName;
public:
// Return the integer value of an enum type key for this field
ComponentInfo::EnumType Enum(const char* enumKey) { return m_Component->Enum(m_PropertyName.c_str(), enumKey); }
template <typename T>
operator T&() { return m_Component->Property<T>(m_PropertyName); }
template <typename T>
operator T&() { return m_Component->Field<T>(m_PropertyName); }
template <typename T>
void operator=(const T val) { m_Component->SetField<T>(m_PropertyName, val); }
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->SetField<T>(m_PropertyName, val); }
//void operator=(T& val) { m_Component->SetProperty<T>(m_PropertyName, val); }
// Specialization for string literals
template <std::size_t N>
void operator=(const char(&val)[N]) { m_Component->SetField<N>(m_PropertyName, val); }
template<std::size_t N>
void operator=(const char(&val)[N]) { m_Component->SetProperty<N>(m_PropertyName, val); }
};
SubscriptProxy operator[](std::string propertyName) { return SubscriptProxy(this, propertyName); }
};
@@ -86,25 +68,25 @@ class ComponentWrapperFactory
{
public:
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.Meta->Allocation = allocation;
m_ComponentInfo.Meta.Allocation = allocation;
}
template <typename T>
void AddProperty(std::string fieldName, T defaultValue)
{
m_DefaultValues.push_back(defaultValue);
m_ComponentInfo.Fields[fieldName].Type = typeid(T).name();
m_ComponentInfo.Fields[fieldName].Offset = m_ComponentInfo.Stride;
m_ComponentInfo.Fields[fieldName].Name = typeid(T).name();
m_ComponentInfo.Fields[fieldName].Offset = m_ComponentInfo.Meta.Stride;
m_ComponentInfo.Fields[fieldName].Stride = sizeof(T);
m_ComponentInfo.Stride += sizeof(T);
m_ComponentInfo.Meta.Stride += sizeof(T);
}
ComponentInfo& Finalize()
{
m_ComponentInfo.Defaults = std::shared_ptr<char>(new char[m_ComponentInfo.Stride]);
m_ComponentInfo.Defaults = std::shared_ptr<char>(new char[m_ComponentInfo.Meta.Stride]);
std::size_t offset = 0;
for (auto& val : m_DefaultValues) {
memcpy(m_ComponentInfo.Defaults.get() + offset, val.Data.get(), val.Size);
+31 -25
View File
@@ -3,10 +3,10 @@
#include <string>
#include <boost/filesystem.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/range/adaptors.hpp>
#include <ini_file/ini_file.hpp>
#include "../Common.h"
#include "ResourceManager.h"
@@ -20,46 +20,52 @@ private:
public:
template <typename T>
T Get(std::string key, T defaultValue);
template <typename T>
std::vector<std::pair<std::string, T>> GetAll(std::string key);
template <typename T>
void Set(std::string key, T value);
const ini_file::section* GetSection(std::string section);
const ini_file::section_map& GetSections() { return m_Merged; }
const ini_file::param* GetParam(std::string key);
void SaveToDisk();
private:
boost::filesystem::path m_Path;
boost::property_tree::ptree m_PTreeDefaults;
boost::property_tree::ptree m_PTreeOverrides;
boost::property_tree::ptree m_PTreeMerged;
ini_file::section_map m_Defaults;
ini_file::section_map m_Overrides;
ini_file::section_map m_Merged;
// Merge ini file section map b into a
void mergeINI(ini_file::section_map& a, const ini_file::section_map& b);
// Convert an ini key delimited by periods to a section and a param
boost::optional<std::pair<std::string, std::string>> tokenizeKey(std::string key);
};
template <typename T>
T ConfigFile::Get(std::string key, T defaultValue)
{
return m_PTreeMerged.get<T>(key, defaultValue);
}
auto param = GetParam(key);
if (param == nullptr) {
return defaultValue;
}
template <typename T>
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;
return boost::lexical_cast<T>(param->get_value());
}
template <typename T>
void ConfigFile::Set(std::string key, T value)
{
m_PTreeOverrides.put<T>(key, value);
m_PTreeMerged.put<T>(key, value);
std::string section;
std::string param;
if (auto tokens = tokenizeKey(key)) {
std::tie(section, param) = *tokens;
} else {
LOG_WARNING("%s: Malformed config key \"%s\"", m_Path.string().c_str(), key.c_str());
return;
}
m_Overrides[section][param] = boost::lexical_cast<std::string>(value);
m_Merged[section][param] = boost::lexical_cast<std::string>(value);
}
#endif
+157
View File
@@ -0,0 +1,157 @@
#ifndef DeveloperConsole_h__
#define DeveloperConsole_h__
#include <iostream>
#include <boost/lexical_cast.hpp>
#include <boost/tokenizer.hpp>
#include "../Common.h"
#include "ConfigFile.h"
class DeveloperConsole
{
public:
DeveloperConsole() = delete;
static void MergeConfig(std::string configFile)
{
auto config = ResourceManager::Load<ConfigFile>("Config.ini");
LOG_DEBUG("Debug.LogLevel %i", config->Get<int>("Debug.LogLevel", -1));
config->Set("Debug.LogLevel", 8);
LOG_DEBUG("Debug.LogLevel %i", config->Get<int>("Debug.LogLevel", -1));
config->Set("Test.TesTest.Testies", "Hello");
config->SaveToDisk();
for (auto& section : config->GetSections()) {
for (auto& param : *section.second) {
std::cout << "// " << param.second->get_comment() << std::endl;
std::cout << section.first << "." << param.first << " " << param.second->get_value() << std::endl;
}
}
for (auto& section : config->GetSections()) {
for (auto& param : *section.second) {
std::string key = section.first + "." + param.first;
m_VariableBindingSetters[key] = [config, key](std::string value) {
config->Set<std::string>(key, value);
};
m_VariableBindingGetters[key] = [config, key]() {
return config->Get<std::string>(key, "");
};
}
}
}
template <typename T>
static typename std::enable_if<std::is_enum<T>::value, void>::type
BindVariable(std::string path, T& variable)
{
BindVariable<T, std::underlying_type<T>::type>(path, variable);
}
template <typename T, typename R = T>
static typename std::enable_if<!std::is_enum<R>::value, void>::type
BindVariable(std::string path, T& variable)
{
m_VariableBindingSetters[path] = [&variable](std::string value) {
variable = static_cast<T>(boost::lexical_cast<R>(value));
};
m_VariableBindingGetters[path] = [&variable]() {
return boost::lexical_cast<std::string>(static_cast<R>(variable));
};
}
static void Consume(const std::string& command)
{
if (command.empty()) {
return;
}
boost::char_separator<char> argumentSeparator(" ");
tokenizer tokens(command, argumentSeparator);
for (tokenizer::const_iterator it = tokens.begin(); it != tokens.end(); it++) {
consumeToken(it, tokens.end());
}
}
static void Consume(std::istream& stream)
{
std::string input;
std::getline(stream, input);
Consume(input);
/*if (stream.peek() == '\n') {
printValue(key);
} else {
std::string newValue;
stream >> newValue;
if (m_VariableBindingSetters.find(key) != m_VariableBindingSetters.end()) {
m_VariableBindingSetters.at(key)(newValue);
} else {
std::cout << "Unknown path: " << key << std::endl;
}
return;
for (auto& config : m_ConfigFiles) {
config->Set(key, newValue);
config->SaveToDisk();
LOG_DEBUG("Key %s set to new value %s and saved to disk.", key.c_str(), newValue.c_str());
}
} */
}
private:
typedef boost::tokenizer<boost::char_separator<char>> tokenizer;
static std::map<std::string, std::function<std::string()>> m_VariableBindingGetters;
static std::map<std::string, std::function<void(std::string)>> m_VariableBindingSetters;
static std::map<std::string, std::function<std::string(std::string)>> m_VariableBindingMappers;
static std::map<std::string, std::string> m_VariableDocumentation;
static void consumeToken(tokenizer::iterator& token, const tokenizer::iterator end)
{
tokenizer::iterator next = token;
next++;
if (next == end) {
printValue(token);
} else {
setValue(token, end);
}
}
static void printValue(tokenizer::iterator token)
{
std::string key = *token;
std::string value;
if (m_VariableBindingGetters.find(key) != m_VariableBindingGetters.end()) {
std::cout << key << " = " << m_VariableBindingGetters.at(key)() << std::endl;
} else {
std::cout << "Unknown path: " << key << std::endl;
}
return;
if (!value.empty()) {
std::cout << key << " = " << value << std::endl;
} else {
std::cerr << "Unknown path: " << key << std::endl;
}
}
static void setValue(tokenizer::iterator& token, const tokenizer::iterator end)
{
std::string key = *token;
std::string value = *(++token);
if (m_VariableBindingSetters.find(key) != m_VariableBindingSetters.end()) {
m_VariableBindingSetters.at(key)(value);
} else {
std::cout << "Unknown path: " << key << std::endl;
}
}
};
#endif
-20
View File
@@ -1,20 +0,0 @@
#ifndef ECaptured_h__
#define ECaptured_h__
#include "EventBroker.h"
#include "../Core/Entity.h"
#include "Engine/GLM.h"
namespace Events
{
//triggers when a capturePoint has been taken over
struct Captured : Event
{
int TeamNumberThatCapturedCapturePoint;
EntityID CapturePointID;
};
}
#endif
-20
View File
@@ -1,20 +0,0 @@
#ifndef EComponentAttached_h__
#define EComponentAttached_h__
#include "EventBroker.h"
#include "World.h"
#include "Entity.h"
#include "ComponentWrapper.h"
namespace Events
{
struct ComponentAttached : Event
{
EntityWrapper Entity;
ComponentWrapper Component;
};
}
#endif
-21
View File
@@ -1,21 +0,0 @@
#ifndef EComponentDeleted_h__
#define EComponentDeleted_h__
#include "../Common.h"
#include "Event.h"
#include "Entity.h"
namespace Events
{
struct ComponentDeleted : Event
{
EntityID Entity;
std::string ComponentType;
// True if the component was deleted as a result of the entity it was attached to being deleted
bool Cascaded;
};
}
#endif
-19
View File
@@ -1,19 +0,0 @@
#ifndef EEntityDeleted_h__
#define EEntityDeleted_h__
#include "Event.h"
#include "Entity.h"
namespace Events
{
struct EntityDeleted : Event
{
EntityID DeletedEntity;
// True if the entity deletion was triggered because the entity's parent was deleted before it
bool Cascaded;
};
}
#endif
-3
View File
@@ -11,9 +11,6 @@ struct KeyDown : Event
{
/** GLFW key code */
int KeyCode;
bool ModCtrl;
bool ModAlt;
bool ModShift;
};
}
-3
View File
@@ -11,9 +11,6 @@ struct KeyUp : Event
{
/** GLFW key code */
int KeyCode;
bool ModCtrl;
bool ModAlt;
bool ModShift;
};
}
-22
View File
@@ -1,22 +0,0 @@
#ifndef EPause_h__
#define EPause_h__
#include "EventBroker.h"
#include "World.h"
namespace Events
{
struct Pause : Event
{
::World* World;
};
struct Resume : Event
{
::World* World;
};
}
#endif
-17
View File
@@ -1,17 +0,0 @@
#ifndef EPickupSpawned_h__
#define EPickupSpawned_h__
#include "Core/Event.h"
#include "Core/EntityWrapper.h"
namespace Events
{
struct PickupSpawned : Event
{
EntityWrapper Pickup;
};
}
#endif
+5 -4
View File
@@ -2,16 +2,17 @@
#define EPlayerDamage_h__
#include "EventBroker.h"
#include "../Core/EntityWrapper.h"
#include "../Core/Entity.h"
namespace Events
{
struct PlayerDamage : Event
{
//NOTE: this struct is missing information on what the damageSource is
EntityWrapper Player;
double Damage;
double DamageAmount;
EntityID PlayerDamagedID;
//optional TypeOfDamage
std::string TypeOfDamage;
};
}
+3 -2
View File
@@ -2,7 +2,7 @@
#define EPlayerDeath_h__
#include "EventBroker.h"
#include "../Core/EntityWrapper.h"
#include "../Core/Entity.h"
namespace Events
{
@@ -10,7 +10,8 @@ namespace Events
struct PlayerDeath : Event
{
//KilledBy,KilledByWhat is optional for now. It might be used later in the playerlog-system
EntityWrapper Player;
EntityID KilledBy;
EntityID PlayerID;
std::string KilledByWhat;
};
+6 -6
View File
@@ -2,16 +2,16 @@
#define EPlayerHealthPickup_h__
#include "EventBroker.h"
#include "../Core/EntityWrapper.h"
#include "../Core/Entity.h"
namespace Events
{
struct PlayerHealthPickup : Event
{
EntityWrapper Player;
double HealthAmount;
};
struct PlayerHealthPickup : Event
{
double HealthAmount;
EntityID PlayerHealedID;
};
}
-20
View File
@@ -1,20 +0,0 @@
#ifndef EPlayerSpawned_h__
#define EPlayerSpawned_h__
#include "Core/Event.h"
#include "Core/EntityWrapper.h"
namespace Events
{
struct PlayerSpawned : Event
{
int PlayerID;
EntityWrapper Player;
EntityWrapper Spawner;
std::string PlayerName;
};
}
#endif
-17
View File
@@ -1,17 +0,0 @@
#ifndef EShoot_h__
#define EShoot_h__
#include "EventBroker.h"
#include "../Core/EntityWrapper.h"
namespace Events
{
struct Shoot : Event
{
EntityWrapper Player;
};
}
#endif
-20
View File
@@ -1,20 +0,0 @@
#ifndef EWin_h__
#define EWin_h__
#include "EventBroker.h"
#include "../Core/Entity.h"
#include "Engine/GLM.h"
namespace Events
{
//triggers when a team has captured all capturePoints
struct Win : Event
{
//can be 0 = none, 1,2
int TeamThatWon;
};
}
#endif
-1
View File
@@ -4,5 +4,4 @@
typedef unsigned int EntityID;
const static unsigned int EntityID_Invalid = -1;
#endif
+8 -8
View File
@@ -285,7 +285,7 @@ private:
XSValue::Status status;
XSValue* val = XSValue::getActualValue(child->getNodeValue(), XSValue::dt_integer, status);
compInfo.Meta->Allocation += val->fData.fValue.f_int;
compInfo.Meta.Allocation += val->fData.fValue.f_int;
}
// Save documentation string
@@ -293,11 +293,11 @@ private:
if (documentationTags->getLength() != 0) {
auto child = documentationTags->item(0)->getFirstChild();
if (child != nullptr) {
compInfo.Meta->Annotation = XSTR(child->getNodeValue());
compInfo.Meta.Annotation = XSTR(child->getNodeValue());
}
}
// TODO: Parse annotation string XML
// compInfo.Meta->Allocation = ...
// compInfo.Meta.Allocation = ...
} else {
std::cout << "Warning: Component is missing an annotation!" << std::endl;
}
@@ -344,7 +344,7 @@ private:
fieldOffset += getTypeStride(type);
}
compInfo.Stride = fieldOffset;
compInfo.Meta.Stride = fieldOffset;
m_ComponentInfo[compInfo.Name] = compInfo;
}
}
@@ -367,14 +367,14 @@ private:
std::string componentName = XSTR(component->getLocalName());
auto& compInfo = m_ComponentInfo.at(componentName);
compInfo.Meta->Allocation += 1;
compInfo.Meta.Allocation += 1;
}
std::cout << "COMPONENT INFO" << std::endl;
for (auto& pair : m_ComponentInfo) {
ComponentInfo& ci = pair.second;
std::cout << "Component: " << ci.Name << " (" << ci.Meta->Annotation << ")" << std::endl;
std::cout << " Allocation: " << ci.Meta->Allocation << std::endl;
std::cout << "Component: " << ci.Name << " (" << ci.Meta.Annotation << ")" << std::endl;
std::cout << " Allocation: " << ci.Meta.Allocation << std::endl;
std::cout << " Fields:" << std::endl;
// Calculate component size
@@ -393,7 +393,7 @@ private:
cs.ComponentName = ci.Name;
cs.Stride = stride;
cs.Info = ci;
cs.Data = new char[stride*ci.Meta->Allocation];
cs.Data = new char[stride*ci.Meta.Allocation];
m_ComponentStore[cs.ComponentName] = cs;
}
}
+148 -19
View File
@@ -73,15 +73,88 @@ public:
ComponentField
};
EntityFileSAXHandler(const EntityFileHandler* handler, xercesc::SAX2XMLReader* reader);
EntityFileSAXHandler(const EntityFileHandler* handler, xercesc::SAX2XMLReader* reader)
: m_Handler(handler)
, m_Reader(reader)
{
// 0 is imaginary world entity
m_EntityStack.push(0);
m_StateStack.push(State::Unknown);
}
void startElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname, const xercesc::Attributes& attrs) override;
void 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 startElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname, const xercesc::Attributes& attrs) override
{
std::string name = XS::ToString(_localName);
void warning(const xercesc::SAXParseException& e);
void error(const xercesc::SAXParseException& e);
void fatalError(const xercesc::SAXParseException& e);
if (m_StateStack.top() == State::Unknown || m_StateStack.top() == State::Entity) {
if (name == "Entity") {
m_StateStack.push(State::Entity);
onStartEntity(attrs);
return;
}
if (name == "EntityRef") {
onStartEntityRef(attrs);
return;
}
}
std::string uri = XS::ToString(_uri);
if (m_StateStack.top() == State::Entity) {
if (uri == "components") {
m_StateStack.push(State::Component);
onStartComponent(name);
return;
}
}
if (m_StateStack.top() == State::Component) {
m_StateStack.push(State::ComponentField);
onStartComponentField(name, attrs);
return;
}
}
void characters(const XMLCh* const chars, const XMLSize_t length) override
{
if (m_StateStack.top() == State::ComponentField) {
char* transcoded = xercesc::XMLString::transcode(chars);
onFieldData(transcoded);
}
}
void endElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname) override
{
std::string name = XS::ToString(_localName);
if (m_StateStack.top() == State::Entity) {
if (name == "Entity") {
m_StateStack.pop();
onEndEntity();
return;
}
}
std::string uri = XS::ToString(_uri);
if (m_StateStack.top() == State::Component) {
//if (uri == "components") {
m_StateStack.pop();
onEndComponent(name);
return;
//}
}
if (m_StateStack.top() == State::ComponentField) {
m_StateStack.pop();
onEndComponentField(name);
return;
}
}
void fatalError(const xercesc::SAXParseException& e)
{
XS::ToString s(e.getMessage());
LOG_ERROR("SAXParseException: %s", ((std::string)s).c_str());
//throw e;
}
private:
const EntityFileHandler* m_Handler;
@@ -95,14 +168,73 @@ private:
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);
void onStartEntity(const xercesc::Attributes& attrs)
{
EntityID parent = m_EntityStack.top();
if (m_Handler->m_OnStartEntityCallback) {
std::string name;
auto xName = attrs.getValue(XS::ToXMLCh("name"));
if (xName != nullptr) {
name = XS::ToString(xName);
}
m_Handler->m_OnStartEntityCallback(m_NextEntityID, parent, name);
}
m_EntityStack.push(m_NextEntityID);
m_NextEntityID++;
}
void onEndEntity()
{
m_EntityStack.pop();
}
void onStartEntityRef(const xercesc::Attributes& attrs)
{
std::string path = XS::ToString(attrs.getValue(XS::ToXMLCh("file")));
xercesc::SAX2XMLReader* parser = xercesc::XMLReaderFactory::createXMLReader();
parser->setContentHandler(this);
parser->setErrorHandler(this);
parser->parse(path.c_str());
delete parser;
}
void onStartComponent(const std::string& name)
{
//LOG_DEBUG(" Component: %s", name.c_str());
m_CurrentComponent = name;
if (m_Handler->m_OnStartComponentCallback) {
m_Handler->m_OnStartComponentCallback(m_EntityStack.top(), name);
}
}
void onEndComponent(const std::string& name) { }
void onStartComponentField(const std::string& field, const xercesc::Attributes& attrs)
{
//LOG_DEBUG(" Field: %s", field.c_str());
m_CurrentField = field;
m_CurrentAttributes.clear();
for (int i = 0; i < attrs.getLength(); i++) {
auto name = attrs.getQName(i);
auto value = attrs.getValue(name);
//LOG_DEBUG(" %s = %s", (char*)XS::ToString(name), (char*)XS::ToString(value));
m_CurrentAttributes[XS::ToString(name).operator std::string()] = XS::ToString(value).operator std::string();
}
if (m_Handler->m_OnStartFieldCallback) {
m_Handler->m_OnStartFieldCallback(m_EntityStack.top(), m_CurrentComponent, field, m_CurrentAttributes);
}
}
void onEndComponentField(const std::string& field) { }
void onFieldData(char* data)
{
//LOG_DEBUG(" Data: %s", data);
if (m_Handler->m_OnStartFieldDataCallback) {
m_Handler->m_OnStartFieldDataCallback(m_EntityStack.top(), m_CurrentComponent, m_CurrentField, data);
}
xercesc::XMLString::release(&data);
}
};
class EntityFileXMLErrorHandler : public xercesc::ErrorHandler
@@ -137,13 +269,12 @@ private:
class EntityFile : public Resource
{
friend class ResourceManager;
friend class EntityFileSAXHandler;
private:
EntityFile(boost::filesystem::path path);
~EntityFile();
public:
static unsigned int GetTypeStride(std::string typeName);
static std::size_t GetTypeStride(std::string typeName);
static void WriteAttributeData(char* outData, const ComponentInfo::Field_t& field, const std::map<std::string, std::string>& attributes);
static void WriteValueData(char* outData, const ComponentInfo::Field_t& field, const char* valueData);
@@ -157,8 +288,6 @@ private:
xercesc::SAX2XMLReader* m_SAX2XMLReader;
//std::map<std::string, ::ComponentInfo> m_ComponentInfo;
//std::vector<std::string> m_EntityReferences;
static void setReaderFeatures(xercesc::SAX2XMLReader* reader);
};
#endif
+1 -2
View File
@@ -9,13 +9,12 @@ class EntityFileParser
public:
EntityFileParser(const EntityFile* entityFile);
EntityID MergeEntities(World* world, EntityID baseParent = EntityID_Invalid);
void MergeEntities(World* world);
private:
const EntityFile* m_EntityFile;
EntityFileHandler m_Handler;
World* m_World = nullptr;
EntityID m_FirstEntity = EntityID_Invalid;
// Maps EntityIDs local to the file to real IDs in the world after they've been
// created in order to resolve parent-child relationships.
std::map<EntityID, EntityID> m_EntityIDMapper;
@@ -5,7 +5,6 @@
#include <xercesc/framework/psvi/XSComplexTypeDefinition.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>
@@ -32,7 +31,6 @@ private:
void onStartComponent(EntityID entity, std::string type);
void parseComponentInfo();
void parseDefaults();
std::string parseAnnotationXML(const XMLCh* xml);
};
#endif
-58
View File
@@ -1,58 +0,0 @@
#ifndef EntityWrapper_h__
#define EntityWrapper_h__
#include <boost/optional.hpp>
#include <boost/functional/hash.hpp>
#include "ComponentWrapper.h"
class World;
struct EntityWrapper
{
EntityWrapper()
: World(nullptr)
, ID(EntityID_Invalid)
{ }
EntityWrapper(::World* world, EntityID id)
: World(world)
, ID(id)
{ }
::World* World;
EntityID ID;
static const EntityWrapper Invalid;
const std::string Name();
bool HasComponent(const std::string& componentType);
void AttachComponent(const char* componentName);
EntityWrapper Parent();
EntityWrapper FirstChildByName(const std::string& name);
EntityWrapper FirstParentWithComponent(const std::string& componentType);
bool IsChildOf(EntityWrapper potentialParent);
bool Valid();
ComponentWrapper operator[](const char* componentName);
bool operator==(const EntityWrapper& e) const;
bool operator!=(const EntityWrapper& e) const;
explicit operator EntityID() const;
private:
EntityWrapper firstChildByNameRecursive(const std::string& name, EntityID parent);
};
namespace std
{
template<> struct hash<EntityWrapper>
{
std::size_t operator()(const EntityWrapper& e) const
{
std::size_t seed = 0;
boost::hash_combine(seed, e.World);
boost::hash_combine(seed, e.ID);
return seed;
}
};
}
#endif
+2 -2
View File
@@ -43,7 +43,7 @@ template <typename ContextType, typename EventType>
class EventRelay : public BaseEventRelay
{
public:
typedef std::function<bool(EventType&)> CallbackType;
typedef std::function<bool(const EventType&)> CallbackType;
EventRelay()
: m_Callback(nullptr)
@@ -65,7 +65,7 @@ template <typename ContextType, typename EventType>
bool EventRelay<ContextType, EventType>::Receive(const std::shared_ptr<Event> event)
{
if (m_Callback != nullptr) {
return m_Callback(*static_cast<EventType*>(event.get()));
return m_Callback(*static_cast<const EventType*>(event.get()));
} else {
return false;
}
-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
+4 -14
View File
@@ -5,14 +5,6 @@
template <typename T>
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).
//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.
@@ -88,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".
char* Allocate()
{
for (; m_CurrentAllocSlot < m_NumSlots && m_SlotIsAllocated[m_CurrentAllocSlot] && !DisableMemoryPool::Value; ++m_CurrentAllocSlot);
if (m_CurrentAllocSlot < m_NumSlots && !DisableMemoryPool::Value) {
for (; m_CurrentAllocSlot < m_NumSlots && m_SlotIsAllocated[m_CurrentAllocSlot]; ++m_CurrentAllocSlot);
if (m_CurrentAllocSlot < m_NumSlots) {
if (m_LowestAllocatedSlot > m_CurrentAllocSlot)
m_LowestAllocatedSlot = m_CurrentAllocSlot;
//Mark the slot as allocated.
@@ -101,9 +93,7 @@ public:
else {
m_ExtraMemory.push_back((char*)malloc(m_Stride));
//We should preferably not enter here to avoid performance issues. Set more numMaxElements in constructor instead.
if (!DisableMemoryPool::Value) {
LOG_DEBUG("Allocated slots exceed Pool size, extra memory allocated dynamically. Pool size: %u, dynamic size: %u.", m_NumSlots, m_ExtraMemory.size());
}
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();
}
}
@@ -118,7 +108,7 @@ public:
//(i.e. IsAllocatedInPool may give false positives)
//if it was malloc():ed
//so, we may enter here even if we shouldn't.
if (!DisableMemoryPool::Value && IsAllocatedInPool(obj)) {
if (IsAllocatedInPool(obj)) {
--m_NumAllocatedSlots;
const size_t freeSlot = (obj - m_StartAddress) / m_Stride;
m_SlotIsAllocated[freeSlot] = false;
+104
View File
@@ -0,0 +1,104 @@
#ifndef OctTree_h__
#define OctTree_h__
#include "Core/AABB.h"
class Ray;
class OctTree
{
public:
struct Output
{
float CollideDistance;
};
OctTree();
~OctTree();
//For the root OctTree, [octTreeBounds] should be a box containing the entire level.
OctTree(const AABB& octTreeBounds, int subDivisions);
//We cannot copy the OctTree as of now, because of the recursive dynamic allocation.
//Define these if the OctTree suddenly needs to be copied, think of the children OctChild* ptrs.
OctTree(const OctTree& other) = delete;
OctTree(const OctTree&& other) = delete;
OctTree& operator= (const OctTree& other) = delete;
//Add a dynamic object (one that moves around) into the tree.
void AddDynamicObject(const AABB& box);
//Add a static object (that does not move) into the tree.
void AddStaticObject(const AABB& box);
//Get the boxes that are in the same area as the input [box], the boxes are put in [outBoxes].
void BoxesInSameRegion(const AABB& box, std::vector<AABB>& outBoxes);
//Empty the tree of all objects, static and dynamic.
void ClearObjects();
//Empty the tree of all dynamic objects. Static objects remain in the tree.
void ClearDynamicObjects();
//Returns true if the ray collides with something in the tree. Result is written to [data].
bool RayCollides(const Ray& ray, Output& data);
//Returns true if the box collides with something in the tree.
//On collision with a box, that box is written to [outBoxIntersected].
//Note: More efficient than calling BoxesInSameRegion from outside and testing there.
bool BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected);
private:
struct OctChild; //Fwd declaration;
struct ContainedObject
{
ContainedObject()
: Box(AABB())
, Checked(false)
{}
ContainedObject(AABB box)
: Box(box)
, Checked(false)
{}
AABB Box;
bool Checked;
};
OctChild* m_Root;
std::vector<ContainedObject> m_StaticObjects;
std::vector<ContainedObject> m_DynamicObjects;
bool m_UpdatedOnce;
unsigned int m_BoxID;
glm::vec3 m_PrevPos;
glm::quat m_PrevOri;
void falsifyObjectChecks();
struct OctChild
{
~OctChild();
OctChild(const AABB& octTreeBounds,
int subDivisions,
std::vector<OctTree::ContainedObject>& staticObjects,
std::vector<OctTree::ContainedObject>& dynamicObjects);
OctChild(const OctChild& other) = delete;
OctChild(const OctChild&& other) = delete;
OctChild& operator= (const OctChild& other) = delete;
void AddDynamicObject(const AABB& box);
void AddStaticObject(const AABB& box);
void BoxesInSameRegion(const AABB& box, std::vector<AABB>& outBoxes) const;
void ClearObjects();
void ClearDynamicObjects();
bool RayCollides(const Ray& ray, Output& data) const;
bool BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const;
OctChild* m_Children[8];
//Indices into the lists in OctTree.
std::vector<int> m_StaticObjIndices;
std::vector<int> m_DynamicObjIndices;
AABB m_Box;
//Reference to the lists in OctTree.
std::vector<OctTree::ContainedObject>& m_StaticObjectsRef;
std::vector<OctTree::ContainedObject>& m_DynamicObjectsRef;
inline bool hasChildren() const;
int childIndexContainingPoint(const glm::vec3& point) const;
std::vector<int> childIndicesContainingBox(const AABB& box) const;
};
};
#endif
-287
View File
@@ -1,287 +0,0 @@
#ifndef Octree_h__
#define Octree_h__
#include <type_traits>
#include "../Common.h"
#include "AABB.h"
#include "Frustum.h"
//Fwd declarations.
class Ray;
namespace OctSpace
{
struct Output;
struct ContainedObject;
struct Child;
}
//T needs to be AABB, or inherit from AABB.
//T also needs to have a default constructor.
template<typename T>
class Octree
{
public:
Octree() = delete;
~Octree();
//For the root Octree, [octreeBounds] should be a box containing the entire level.
Octree(const AABB& octreeBounds, int subDivisions);
//We cannot copy the Octree as of now, because of the recursive dynamic allocation.
//Define these if the Octree suddenly needs to be copied, think of the children Child* ptrs.
Octree(const Octree& other) = delete;
Octree(const Octree&& other) = delete;
Octree& operator= (const Octree& other) = delete;
//Add a dynamic object (one that moves around) into the tree.
void AddDynamicObject(const T& object);
//Add a static object (that does not move) into the tree.
void AddStaticObject(const T& object);
//Get the objects that are in the same area as the input [box], the objects are put in [outObjects].
//The type Box must be AABB, or inherit from AABB.
template<typename Box>
void ObjectsInSameRegion(const Box& box, std::vector<T>& outObjects);
//Get the objects that are inside the frustum, the objects are put in outObjects.
void ObjectsInFrustum(const Frustum& frustum, 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;
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;
};
}
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>::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();
}
}
}
#endif
+1 -5
View File
@@ -2,15 +2,11 @@
#define Ray_h__
#include "../GLM.h"
#include "../Common.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))
+39 -135
View File
@@ -12,6 +12,7 @@
/** Base Resource class.
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
{
@@ -21,23 +22,6 @@ protected:
Resource() { }
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
// FIXME: Why did we do this again instead of just using the constructor?
// static Resource* Create(std::string resourceName);
@@ -49,15 +33,6 @@ public:
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 */
class ResourceManager
{
@@ -65,7 +40,6 @@ private:
ResourceManager();
public:
static bool UseThreading;
/*static ResourceManager& Instance()
{
static ResourceManager s;
@@ -75,6 +49,15 @@ public:
template <typename T>
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
@param resourceType Resource type as string.
@@ -82,20 +65,15 @@ public:
*/
// TODO: Templateify
static bool IsResourceLoaded(std::string resourceType, std::string resourceName);
/** Return value should always be a valid pointer, will throw an exception on error.
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.
/** Hot-loads a resource and caches it for future use
@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.
*/
template <typename T, bool async = false>
static T* Load(const std::string& resourceName, Resource* parent = nullptr);
template <typename T>
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.
@@ -109,31 +87,19 @@ public:
static void Update();
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::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::string, Resource*> m_ResourceFromName; // name -> 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
static unsigned int m_CurrentResourceTypeID;
static std::unordered_map<std::string, unsigned int> m_ResourceTypeIDs;
// Number of resources of a type. Doubles as local ID.
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 void fileWatcherCallback(std::string path, FileWatcher::FileEventFlags flags);
@@ -142,13 +108,22 @@ private:
static unsigned int GetNewResourceID(unsigned int typeID);
// Internal: Create a resource and cache it
static Resource* createResourceThrowing(const std::string& resourceType, const 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();
static Resource* CreateResource(std::string resourceType, std::string resourceName, Resource* parent);
};
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>
void ResourceManager::RegisterType(std::string typeName)
{
@@ -156,88 +131,17 @@ void ResourceManager::RegisterType(std::string typeName)
m_FactoryFunctions[typeName] = [](std::string resourceName) { return new T(resourceName); };
}
template <typename T, bool async>
static T* ResourceManager::Load(const std::string& resourceName, Resource* parent /* = nullptr */)
template <typename T>
void ResourceManager::Preload(std::string resourceName)
{
auto resourceTypename = typeid(T).name();
auto iter = m_CompilerTypenameToResourceType.find(resourceTypename);
if (iter == m_CompilerTypenameToResourceType.end()) {
LOG_ERROR("Failed to load resource \"%s\" of type \"%s\": type not registered", resourceName.c_str(), resourceTypename);
throw Resource::FailedLoadingException();
}
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;
}
std::string resourceType = iter->second;
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;
}
}
}
Preload(it->second, resourceName);
}
#endif
+12 -13
View File
@@ -3,7 +3,6 @@
#include "EventBroker.h"
#include "World.h"
#include "EntityWrapper.h"
#include "ComponentWrapper.h"
class System
@@ -11,41 +10,41 @@ class System
friend class SystemPipeline;
protected:
System(World* world, EventBroker) { }
System(World* world, EventBroker* eventBroker)
: m_World(world)
, m_EventBroker(eventBroker)
System(EventBroker* eventBroker)
: m_EventBroker(eventBroker)
{ }
virtual ~System() = default;
World* m_World;
EventBroker* m_EventBroker;
};
class PureSystem : public virtual System
class PureSystem : public System
{
friend class SystemPipeline;
protected:
PureSystem(std::string componentType)
: m_ComponentType(componentType)
PureSystem(EventBroker* eventBroker, std::string componentType)
: System(eventBroker)
, m_ComponentType(componentType)
{ }
virtual ~PureSystem() = default;
const std::string m_ComponentType;
virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cComponent, double dt) = 0;
virtual void UpdateComponent(World* world, ComponentWrapper& component, double dt) = 0;
};
class ImpureSystem : public virtual System
class ImpureSystem : public System
{
friend class SystemPipeline;
protected:
ImpureSystem() = default;
ImpureSystem(EventBroker* eventBroker)
: System(eventBroker)
{ }
virtual ~ImpureSystem() = default;
virtual void Update(double dt) = 0;
virtual void Update(World* world, double dt) = 0;
};
#endif
+14 -42
View File
@@ -5,19 +5,13 @@
#include "EventBroker.h"
#include "System.h"
#include "World.h"
#include "EPause.h"
class SystemPipeline
{
public:
SystemPipeline(World* world, EventBroker* eventBroker)
: m_World(world)
, m_EventBroker(eventBroker)
{
EVENT_SUBSCRIBE_MEMBER(m_EPause, &SystemPipeline::OnPause);
EVENT_SUBSCRIBE_MEMBER(m_EResume, &SystemPipeline::OnResume);
}
SystemPipeline(EventBroker* eventBroker)
: m_EventBroker(eventBroker)
{ }
~SystemPipeline()
{
for (UnorderedSystems& group : m_OrderedSystemGroups) {
@@ -35,11 +29,11 @@ public:
m_OrderedSystemGroups.resize(updateOrderLevel + 1);
}
UnorderedSystems& group = m_OrderedSystemGroups[updateOrderLevel];
System* system = new T(m_World, m_EventBroker, args...);
System* system = new T(m_EventBroker, args...);
group.Systems[typeid(T).name()] = system;
PureSystem* pureSystem = dynamic_cast<PureSystem*>(system);
if (pureSystem != nullptr) {
if (std::is_base_of<PureSystem, T>::value) {
PureSystem* pureSystem = static_cast<PureSystem*>(system);
if (!pureSystem->m_ComponentType.empty()) {
group.PureSystems[pureSystem->m_ComponentType].push_back(pureSystem);
} else {
@@ -47,18 +41,14 @@ public:
}
}
ImpureSystem* impureSystem = dynamic_cast<ImpureSystem*>(system);
if (impureSystem != nullptr) {
if (std::is_base_of<ImpureSystem, T>::value) {
ImpureSystem* impureSystem = static_cast<ImpureSystem*>(system);
group.ImpureSystems.push_back(impureSystem);
}
}
void Update(double dt)
void Update(World* world, double dt)
{
if (m_Paused) {
dt = 0.0;
}
for (UnorderedSystems& group : m_OrderedSystemGroups) {
// Process events
for (auto& pair : group.Systems) {
@@ -66,30 +56,27 @@ public:
}
// Update
for (auto& system : group.ImpureSystems) {
system->Update(dt);
}
for (auto& pair : group.PureSystems) {
const std::string& componentName = pair.first;
auto& systems = pair.second;
const ComponentPool* pool = m_World->GetComponents(componentName);
const ComponentPool* pool = world->GetComponents(componentName);
if (pool == nullptr) {
continue;
}
for (auto& component : *pool) {
for (auto& system : systems) {
system->UpdateComponent(EntityWrapper(m_World, component.EntityID), component, dt);
system->UpdateComponent(world, component, dt);
}
}
}
for (auto& system : group.ImpureSystems) {
system->Update(world, dt);
}
}
}
private:
World* m_World;
EventBroker* m_EventBroker;
bool m_Paused = false;
struct UnorderedSystems
{
std::map<std::string, System*> Systems;
@@ -97,21 +84,6 @@ private:
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
-25
View File
@@ -1,25 +0,0 @@
#ifndef Transform_h__
#define Transform_h__
#include "../GLM.h"
#include "World.h"
#include "EntityWrapper.h"
namespace Transform
{
glm::mat4 AbsoluteTransformation(EntityWrapper entity);
glm::vec3 AbsolutePosition(EntityWrapper entity);
glm::vec3 AbsolutePosition(World* world, EntityID entity);
glm::vec3 AbsoluteOrientationEuler(EntityWrapper entity);
glm::quat AbsoluteOrientation(EntityWrapper entity);
glm::quat AbsoluteOrientation(World* world, EntityID entity);
glm::vec3 AbsoluteScale(EntityWrapper entity);
glm::vec3 AbsoluteScale(World* world, EntityID entity);
glm::mat4 ModelMatrix(EntityWrapper entity);
glm::mat4 ModelMatrix(EntityID entity, World* world);
glm::vec3 TransformPoint(const glm::vec3& point, const glm::mat4& matrix);
}
#endif
-22
View File
@@ -1,22 +0,0 @@
#ifndef UniformScaleSystem_h__
#define UniformScaleSystem_h__
#include "../GLM.h"
#include "System.h"
#include "../Rendering/ESetCamera.h"
class UniformScaleSystem : public PureSystem
{
public:
UniformScaleSystem(World* world, EventBroker* eventBroker);
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
+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 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
{
@@ -54,7 +54,7 @@ public:
private:
struct FileInfo
{
std::size_t Size;
int Size;
std::time_t Timestamp;
};
+1 -1
View File
@@ -4,7 +4,7 @@
// }
// NOTE: condition statement is not executed at all in release mode.
#ifndef DEBUG_IF
#ifdef DEBUG
#ifndef DEBUG
#define DEBUG_IF(c) if(c)
#else
#define DEBUG_IF(c) if(false)
+57 -6
View File
@@ -29,9 +29,41 @@ enum _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, ...) \
_LOG(logLevel, __BASE_FILE__, __func__, __LINE__, format, ##__VA_ARGS__)
@@ -45,11 +77,30 @@ extern void _LOG(_LOG_LEVEL logLevel, const char* file, const char* func, unsign
#define LOG_INFO(format, ...) \
LOG(LOG_LEVEL_INFO, format, ##__VA_ARGS__)
#ifdef DEBUG
#define LOG_DEBUG(format, ...) \
LOG(LOG_LEVEL_DEBUG, format, ##__VA_ARGS__)
#else
#define LOG_DEBUG(format, ...)
#endif
// Set the log level temporarily for the current scope
#define LOG_LEVEL_SCOPE(logLevel) \
_LOG_LEVEL_SCOPED_HELPER<logLevel> _logLevelScopedHelper;
template <_LOG_LEVEL LEVEL>
class _LOG_LEVEL_SCOPED_HELPER
{
public:
_LOG_LEVEL_SCOPED_HELPER()
{
m_OriginalLogLevel = LOG_LEVEL;
LOG_LEVEL = LEVEL;
}
~_LOG_LEVEL_SCOPED_HELPER()
{
LOG_LEVEL = m_OriginalLogLevel;
}
private:
_LOG_LEVEL m_OriginalLogLevel;
};
#endif // Logging_h__
+5 -13
View File
@@ -5,15 +5,11 @@
#include "Entity.h"
#include "ObjectPool.h"
#include "ComponentPool.h"
#include "EventBroker.h"
class World
{
public:
World() = default;
World(EventBroker* eventBroker)
: m_EventBroker(eventBroker)
{ }
~World();
// Create empty entity
@@ -25,21 +21,19 @@ public:
// Register a component type and allocate space for it
void RegisterComponent(ComponentInfo& ci);
// Attach a component to an entity and fill it with default values
ComponentWrapper AttachComponent(EntityID entity, 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;
bool HasComponent(EntityID entity, std::string componentType) const;
// 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);
void DeleteComponent(EntityID entity, std::string componentType);
// Get all components of the specified type
const 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> GetChildren(EntityID entity);
// Get all component pools
const std::unordered_map<std::string, ComponentPool*>& GetComponentPools() const { return m_ComponentPools; }
// Get the entity children map
@@ -50,7 +44,6 @@ public:
std::string GetName(EntityID entity) const;
private:
EventBroker* m_EventBroker = nullptr;
EntityID m_CurrentEntityID = 0;
std::unordered_map<EntityID, EntityID> m_EntityParents;
@@ -60,7 +53,6 @@ private:
std::unordered_map<EntityID, std::string> m_EntityNames;
EntityID generateEntityID();
void deleteEntityRecursive(EntityID entity, bool cascaded = false);
};
#endif
@@ -1,115 +0,0 @@
#ifndef EditorCameraInputController_h__
#define EditorCameraInputController_h__
#include <imgui/imgui.h>
#include "../Input/FirstPersonInputController.h"
#include "../Core/EMousePress.h"
#include "../Core/EMouseRelease.h"
#include "../Core/EMouseScroll.h"
#include "../Core/ConfigFile.h"
template <typename EventContext>
class EditorCameraInputController : public FirstPersonInputController<EventContext>
{
public:
EditorCameraInputController(EventBroker* eventBroker, unsigned int playerID)
: FirstPersonInputController(eventBroker, playerID)
{
EVENT_SUBSCRIBE_MEMBER(m_EMousePress, &EditorCameraInputController::OnMousePress);
EVENT_SUBSCRIBE_MEMBER(m_EMouseRelease, &EditorCameraInputController::OnMouseRelease);
EVENT_SUBSCRIBE_MEMBER(m_EMouseScroll, &EditorCameraInputController::OnMouseScroll);
m_Config = ResourceManager::Load<ConfigFile>("Config.ini");
m_SpeedMultiplier = m_Config->Get<float>("Editor.CameraSpeed", 3.f);
}
virtual const glm::vec3 Movement() const override { return m_Movement * static_cast<float>(m_SpeedMultiplier); }
void Enable() { m_Enabled = true; }
void Disable() { m_Enabled = false; }
virtual bool OnCommand(const Events::InputCommand& e) override
{
if (glm::abs(e.Value) > 0 && !m_MouseLocked) {
return false;
}
ImGuiIO& io = ImGui::GetIO();
if (glm::abs(e.Value) > 0 && (io.WantCaptureKeyboard || io.WantCaptureMouse)) {
return false;
}
if (e.Command == "Jump") {
if (e.Value > 0) {
m_Movement.y = glm::max(e.Value, 1.f);
} else {
m_Movement.y = 0.f;
}
}
if (e.Command == "Crouch") {
if (e.Value > 0) {
m_Movement.y = glm::min(-e.Value, -1.f);
} else {
m_Movement.y = 0.f;
}
}
if (e.Command == "Sprint") {
if (e.Value > 0) {
m_SpeedMultiplier *= 2.f;
} else {
m_SpeedMultiplier /= 2.f;
}
}
return FirstPersonInputController::OnCommand(e);
}
protected:
ConfigFile* m_Config;
bool m_Enabled = false;
double m_SpeedMultiplier = 1.f;
EventRelay<EventContext, Events::MousePress> m_EMousePress;
bool OnMousePress(const Events::MousePress& e)
{
if (!m_Enabled) {
return false;
}
if (e.Button == GLFW_MOUSE_BUTTON_2) {
ImGuiIO& io = ImGui::GetIO();
if (!io.WantCaptureMouse) {
LockMouse();
}
}
return true;
}
EventRelay<EventContext, Events::MouseRelease> m_EMouseRelease;
bool OnMouseRelease(const Events::MouseRelease& e)
{
if (!m_Enabled) {
return false;
}
if (e.Button == GLFW_MOUSE_BUTTON_2) {
UnlockMouse();
}
return true;
}
EventRelay<EventContext, Events::MouseScroll> m_EMouseScroll;
bool OnMouseScroll(const Events::MouseScroll& e)
{
if (!m_Enabled) {
return false;
}
m_SpeedMultiplier += e.DeltaY * (0.1 * m_SpeedMultiplier);
m_Config->Set("Editor.CameraSpeed", m_SpeedMultiplier);
m_Config->SaveToDisk();
return true;
}
};
#endif
-183
View File
@@ -1,183 +0,0 @@
#ifndef EditorGUI_h__
#define EditorGUI_h__
#include <imgui/imgui.h>
#define IMGUI_DEFINE_MATH_OPERATORS
#include <imgui/imgui_internal.h>
#include <nativefiledialog/nfd.h>
#include <boost/filesystem.hpp>
#include <boost/any.hpp>
#include <boost/algorithm/string/replace.hpp>
#include "../Common.h"
#include "../GLM.h"
#include <glm/gtx/common.hpp>
#include "EditorWidgetSystem.h"
#include "../Core/EventBroker.h"
#include "../Core/World.h"
#include "../Core/EntityWrapper.h"
#include "../Core/ResourceManager.h"
#include "../Core/EPause.h"
#include "../Core/EKeyDown.h"
#include "../Core/ELockMouse.h"
#include "../Core/EFileDropped.h"
#include "../Rendering/Texture.h"
class EditorGUI
{
public:
EditorGUI(World* world, EventBroker* eventBroker);
enum class WidgetMode
{
Translate,
Rotate,
Scale
};
enum class WidgetSpace
{
Global,
Local
};
void Draw();
void SelectEntity(EntityWrapper entity);
void SetDirty(EntityWrapper entity);
// Called when an entity is selected in the entity tree
typedef std::function<void(EntityWrapper)> OnEntitySelectedCallback_t;
void SetEntitySelectedCallback(OnEntitySelectedCallback_t f) { m_OnEntitySelected = f; }
// Called when the user means to import an entity file.
// @param EntityWrapper The entity to parent the imported entity to. The entity will be imported into the world of this entity.
// @param boost::filesystem::path The path to the entity to import
// @return EntityWrapper The newly created entity
typedef std::function<EntityWrapper(EntityWrapper, boost::filesystem::path)> OnEntityImport_t;
void SetEntityImportCallback(OnEntityImport_t f) { m_OnEntityImport = f; }
// Called when the user means to save an entity to file.
// Permitted to throw exceptions on save failure.
typedef std::function<void(EntityWrapper, boost::filesystem::path)> OnEntitySave_t;
void SetEntitySaveCallback(OnEntitySave_t f) { m_OnEntitySave = f; }
// Called when the user means to create a new entity.
// @param EntityWrapper The parent of the entity to be created
// @return EntityWrapper The newly created entity
typedef std::function<EntityWrapper(EntityWrapper)> OnEntityCreate_t;
void SetEntityCreateCallback(OnEntityCreate_t f) { m_OnEntityCreate = f; }
// Called when the user means to delete an entity.
typedef std::function<void(EntityWrapper)> OnEntityDelete_t;
void SetEntityDeleteCallback(OnEntityDelete_t f) { m_OnEntityDelete = f; }
// Called when the user means to change the parent of an entity.
typedef std::function<void(EntityWrapper, EntityWrapper)> OnEntityChangeParent_t;
void SetEntityChangeParentCallback(OnEntityChangeParent_t f) { m_OnEntityChangeParent = f; }
// Called when the user means to rename an entity.
typedef std::function<void(EntityWrapper, const std::string&)> OnEntityChangeName_t;
void SetEntityChangeNameCallback(OnEntityChangeName_t f) { m_OnEntityChangeName = f; }
// Called when the user means to attach a new component to an entity.
typedef std::function<void(EntityWrapper, const std::string&)> OnComponentAttach_t;
void SetComponentAttachCallback(OnComponentAttach_t f) { m_OnComponentAttach = f; }
// Called when the user means to delete a component off an entity.
typedef std::function<void(EntityWrapper, const std::string&)> OnComponentDelete_t;
void SetComponentDeleteCallback(OnComponentDelete_t f) { m_OnComponentDelete = f; }
// Called when the user selects a widget mode.
typedef std::function<void(WidgetMode)> OnWidgetMode_t;
void SetWidgetModeCallback(OnWidgetMode_t f) { m_OnWidgetMode = f; }
// Called when the user selects a widget space.
typedef std::function<void(WidgetSpace)> OnWidgetSpace_t;
void SetWidgetSpaceCallback(OnWidgetSpace_t f) { m_OnWidgetSpace = f; }
private:
World* m_World;
EventBroker* m_EventBroker;
struct EntityFileInfo
{
boost::filesystem::path Path;
bool Dirty = false;
};
// Config variables
const boost::filesystem::path m_DefaultEntityPath = boost::filesystem::path("Schema") / boost::filesystem::path("Entities");
// State
EntityWrapper m_CurrentSelection = EntityWrapper::Invalid;
std::unordered_map<EntityWrapper, EntityFileInfo> m_EntityFiles;
EntityWrapper m_CurrentlyDragging = EntityWrapper::Invalid;
std::string m_LastErrorMessage;
WidgetMode m_CurrentWidgetMode = WidgetMode::Translate;
WidgetSpace m_CurrentWidgetSpace = WidgetSpace::Global;
std::set<std::string> m_ModalsToOpen;
std::map<std::string, boost::any> m_ModalData;
std::string m_DroppedFile = "";
bool m_Paused = false;
bool m_MouseLocked = false;
// Callbacks
OnEntitySelectedCallback_t m_OnEntitySelected = nullptr;
OnEntityImport_t m_OnEntityImport = nullptr;
OnEntitySave_t m_OnEntitySave = nullptr;
OnEntityCreate_t m_OnEntityCreate = nullptr;
OnEntityDelete_t m_OnEntityDelete = nullptr;
OnEntityChangeParent_t m_OnEntityChangeParent = nullptr;
OnEntityChangeName_t m_OnEntityChangeName = nullptr;
OnComponentAttach_t m_OnComponentAttach = nullptr;
OnComponentDelete_t m_OnComponentDelete = nullptr;
OnWidgetMode_t m_OnWidgetMode = nullptr;
OnWidgetSpace_t m_OnWidgetSpace = nullptr;
// Events
EventRelay<EditorGUI, Events::KeyDown> m_EKeyDown;
bool OnKeyDown(const Events::KeyDown& e);
EventRelay<EditorGUI, Events::FileDropped> m_EFileDropped;
bool OnFileDropped(const Events::FileDropped& e);
EventRelay<EditorGUI, Events::Pause> m_EPause;
bool OnPause(const Events::Pause& e);
EventRelay<EditorGUI, Events::Resume> m_EResume;
bool OnResume(const Events::Resume& e);
EventRelay<EditorGUI, Events::LockMouse> m_ELockMouse;
bool OnLockMouse(const Events::LockMouse& e);
EventRelay<EditorGUI, Events::UnlockMouse> m_EUnlockMouse;
bool OnUnlockMouse(const Events::UnlockMouse& e);
// Utility functions
boost::filesystem::path fileOpenDialog();
boost::filesystem::path fileSaveDialog();
const std::string formatEntityName(EntityWrapper entity);
GLuint tryLoadTexture(std::string filePath);
void openModal(const std::string& modal);
void setWidgetMode(WidgetMode mode);
void toggleWidgetSpace();
static bool compareCharArray(const char* c1, const char* c2);
// Entity file handling methods
void entityImport(World* world);
void entitySave(EntityWrapper entity, bool saveAs = false);
void entityCreate(World* world, EntityWrapper parent);
void entityDelete(EntityWrapper entity);
void entityChangeParent(EntityWrapper entity, EntityWrapper parent);
// UI drawing methods
void drawMenu();
void drawTools();
void drawEntities(World* world);
void drawEntitiesRecursive(World* world, EntityID parent);
bool drawEntityNode(EntityWrapper entity);
void drawComponents(EntityWrapper entity);
bool drawComponentNode(EntityWrapper entity, const ComponentInfo& componentType);
bool drawComponentField(ComponentWrapper& c, const ComponentInfo::Field_t& field);
bool drawComponentField_Vector(ComponentWrapper &c, const ComponentInfo::Field_t &field);
bool drawComponentField_Color(ComponentWrapper &c, const ComponentInfo::Field_t &field);
bool drawComponentField_int(ComponentWrapper &c, const ComponentInfo::Field_t &field);
bool drawComponentField_enum(ComponentWrapper &c, const ComponentInfo::Field_t &field);
bool drawComponentField_float(ComponentWrapper &c, const ComponentInfo::Field_t &field);
bool drawComponentField_double(ComponentWrapper &c, const ComponentInfo::Field_t &field);
bool drawComponentField_bool(ComponentWrapper &c, const ComponentInfo::Field_t &field);
bool drawComponentField_string(ComponentWrapper &c, const ComponentInfo::Field_t &field);
void drawModals();
// Custom UI elements
bool createDeleteButton(const std::string& componentType);
void createWidgetToolButton(WidgetMode mode);
};
#endif
@@ -1,27 +0,0 @@
#ifndef EditorRenderSystem_h__
#define EditorRenderSystem_h__
#include "../Core/System.h"
#include "../Rendering/IRenderer.h"
#include "../Rendering/ModelJob.h"
#include "../Rendering/Camera.h"
#include "../Rendering/ESetCamera.h"
class EditorRenderSystem : public ImpureSystem
{
public:
EditorRenderSystem(World* world, EventBroker* eventBroker, IRenderer* renderer, RenderFrame* renderFrame);
virtual void Update(double dt) override;
private:
IRenderer* m_Renderer;
RenderFrame* m_RenderFrame;
Camera* m_EditorCamera;
EntityWrapper m_CurrentCamera = EntityWrapper::Invalid;
EventRelay<EditorRenderSystem, Events::SetCamera> m_ESetCamera;
bool OnSetCamera(Events::SetCamera& e);
};
#endif
-29
View File
@@ -1,29 +0,0 @@
#include <numeric>
#include <iomanip>
#include <imgui/imgui.h>
#include "../Common.h"
#include "../GLM.h"
#include "../OpenGL.h"
class EditorStats
{
public:
EditorStats();
void Draw(double dt);
private:
// FPS graph
const unsigned int m_SampleSize = 100;
unsigned int m_FrameCount = 0;
std::vector<double> m_FrameTimes;
double m_TimeAccumulator = 0.0;
double m_AveragedSamplesPerSecond = 10.0;
const unsigned int m_AveragedSampleSize = 100;
unsigned int m_CurrentAveragedSampleIndex = 0;
std::vector<double> m_AveragedSamples;
void drawFPSGraph(double dt);
void drawRAMUsage(double dt);
void drawVRAMStats(double dt);
};
+74 -52
View File
@@ -1,72 +1,94 @@
#include <imgui/imgui.h>
#include <glm/gtx/common.hpp>
#include <boost/filesystem/path.hpp>
#include <nativefiledialog/nfd.h>
#include "../Core/System.h"
#include "../Core/EMousePress.h"
#include "../Core/EMouseRelease.h"
#include "../Core/EMouseMove.h"
#include "../Core/ConfigFile.h"
#include "../Input/EInputCommand.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 "../Rendering/EPicking.h"
#include "../Core/EFileDropped.h"
#include "../Rendering/RenderQueueFactory.h"
#include "../Core/EntityFilePreprocessor.h"
#include "../Core/EntityFileParser.h"
#include "../Core/EntityFileWriter.h"
#include "../Core/EMousePress.h"
#include "../Input/EInputCommand.h"
#include "EditorGUI.h"
#include "EditorStats.h"
#include "EditorCameraInputController.h"
class EditorSystem : public ImpureSystem
{
public:
EditorSystem(World* world, EventBroker* eventBroker, IRenderer* renderer, RenderFrame* renderFrame);
~EditorSystem();
EditorSystem(EventBroker* eventBroker, IRenderer* renderer);
void Update(double dt);
void Enable();
void Disable();
virtual void Update(World* world, double dt) override;
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;
World* m_World = nullptr;
// 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;
bool m_Enabled;
bool m_Visible;
boost::filesystem::path m_DefaultEntityDir;
boost::filesystem::path m_CurrentFile;
std::vector<glm::vec2> m_PickingQueue;
// Utility functions
EntityWrapper importEntity(EntityWrapper parent, boost::filesystem::path filePath);
void setWidgetMode(EditorGUI::WidgetMode mode);
enum class WidgetMode
{
None,
Translate,
Rotate,
Scale
} m_WidgetMode = WidgetMode::None;
// 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);
void OnComponentAttach(EntityWrapper entity, const std::string& componentType);
void OnComponentDelete(EntityWrapper entity, const std::string& componentType);
void OnWidgetSpace(EditorGUI::WidgetSpace widgetSpace);
enum class WidgetSpace
{
Local,
Global
} m_WidgetSpace = WidgetSpace::Global;
EntityID m_Widget = EntityID_Invalid;
EntityID m_WidgetX = EntityID_Invalid;
EntityID m_WidgetPlaneX = EntityID_Invalid;
EntityID m_WidgetY = EntityID_Invalid;
EntityID m_WidgetPlaneY = EntityID_Invalid;
EntityID m_WidgetZ = EntityID_Invalid;
EntityID m_WidgetPlaneZ = EntityID_Invalid;
EntityID m_WidgetOrigin = EntityID_Invalid;
glm::vec3 m_WidgetCurrentAxis;
float m_WidgetPickingDepth = 0.f;
EntityID m_Selection = EntityID_Invalid;
EntityID m_LastSelection = EntityID_Invalid;
EntityID m_UIDraggingEntity = EntityID_Invalid;
glm::vec3 m_Position;
std::string m_LastDroppedFile;
static boost::filesystem::path openDialog(boost::filesystem::path defaultPath);
static boost::filesystem::path saveDialog(boost::filesystem::path defaultPath);
// Events
EventRelay<EditorSystem, Events::MousePress> m_EMousePress;
bool OnMousePress(const Events::MousePress& e);
EventRelay<EditorSystem, Events::WidgetDelta> m_EWidgetDelta;
bool OnWidgetDelta(const Events::WidgetDelta& e);
EventRelay<EditorSystem, Events::InputCommand> m_EInputCommand;
bool OnInputCommand(const Events::InputCommand& e);
EventRelay<EditorSystem, Events::SetCamera> m_ESetCamera;
bool OnSetCamera(const Events::SetCamera& e);
EventRelay<EditorSystem, Events::MouseRelease> m_EMouseRelease;
bool OnMouseRelease(const Events::MouseRelease& e);
EventRelay<EditorSystem, Events::MousePress> m_EMousePress;
bool OnMousePress(const Events::MousePress& e);
EventRelay<EditorSystem, Events::MouseMove> m_EMouseMove;
bool OnMouseMove(const Events::MouseMove& e);
EventRelay<EditorSystem, Events::Picking> m_EPicking;
bool OnPicking(const Events::Picking& e);
EventRelay<EditorSystem, Events::FileDropped> m_EFileDropped;
bool OnFileDropped(const Events::FileDropped& e);
void createWidget();
void updateWidget();
void setWidgetMode(WidgetMode newMode);
void setWidgetSpace(WidgetSpace space);
void drawUI(World* world, double dt);
bool createDeleteButton(std::string componentType);
bool createEntityNode(World* world, EntityID entity);
void changeParent(EntityID entity, EntityID newParent);
void fileImport(World* world);
void fileSave(World* world);
void fileSaveAs(World* world);
};
@@ -1,49 +0,0 @@
#ifndef EditorWidgetSystem_h__
#define EditorWidgetSystem_h__
#include <imgui/imgui.h>
#include "../GLM.h"
#include "../Core/System.h"
#include "../Rendering/IRenderer.h"
#include "../Rendering/Util/ScreenCoords.h"
#include "../Core/EMouseMove.h"
#include "../Core/EMousePress.h"
#include "../Core/EMouseRelease.h"
namespace Events
{
struct WidgetDelta : Event
{
glm::vec3 Translation;
glm::vec3 Rotation;
glm::vec3 Scale;
};
}
class EditorWidgetSystem : public ImpureSystem, PureSystem
{
public:
EditorWidgetSystem(World* world, EventBroker* eventBroker, 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 -2
View File
@@ -7,5 +7,4 @@
#include <glm/gtx/rotate_vector.hpp>
#include <glm/gtc/quaternion.hpp>
#include <glm/gtx/quaternion.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/projection.hpp>
#include <glm/gtc/type_ptr.hpp>
+1 -1
View File
@@ -40,7 +40,7 @@ public:
m_TexturePressed = resourceName;
}
void Draw(RenderScene& rq) override
void Draw(RenderQueueCollection& rq) override
{
if (m_Texture == nullptr && !m_TextureReleased.empty()) {
SetTexture(m_TextureReleased);
+2 -2
View File
@@ -212,7 +212,7 @@ public:
virtual void Update(double dt) { }
void DrawLayered(RenderScene& rq)
void DrawLayered(RenderQueueCollection& rq)
{
if (this->Hidden())
return;
@@ -232,7 +232,7 @@ public:
}
}
virtual void Draw(RenderScene& rq) { }
virtual void Draw(RenderQueueCollection& rq) { }
protected:
::EventBroker* m_EventBroker;
+1 -1
View File
@@ -16,7 +16,7 @@ public:
void EnableScissor() { m_ScissorEnabled = true; }
void DisableScissor() { m_ScissorEnabled = false; }
void Draw(RenderScene& rq) override
void Draw(RenderQueueCollection& rq) override
{
if (m_Texture == nullptr)
return;
+1 -3
View File
@@ -2,7 +2,6 @@
#define Events_InputCommand_h__
#include "Core/EventBroker.h"
#include "Core/EntityWrapper.h"
namespace Events
{
@@ -10,8 +9,7 @@ namespace Events
struct InputCommand : Event
{
/** Numerical ID of the player. */
int PlayerID;
EntityWrapper Player;
unsigned int PlayerID;
/** The command that was sent. */
std::string Command;
/** The value of the command. */
+47 -216
View File
@@ -4,236 +4,67 @@
#include "../GLM.h"
#include "../Core/InputController.h"
#include "../Core/ELockMouse.h"
#include "../Game/Events/EDashAbility.h"
#include "InputHandler.h"
template <typename EventContext>
class FirstPersonInputController : public InputController<EventContext>
{
public:
FirstPersonInputController(EventBroker* eventBroker, int playerID);
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 DoubleJumping() const { return m_DoubleJumping; }
virtual void SetDoubleJumping(bool isDoubleJumping) {
m_DoubleJumping = isDoubleJumping;
FirstPersonInputController(EventBroker* eventBroker, unsigned int playerID)
: InputController(eventBroker)
, m_PlayerID(playerID)
{
EVENT_SUBSCRIBE_MEMBER(m_ELockMouse, &FirstPersonInputController::OnLockMouse);
EVENT_SUBSCRIBE_MEMBER(m_EUnlockMouse, &FirstPersonInputController::OnUnlockMouse);
}
void LockMouse();
void UnlockMouse();
virtual bool OnCommand(const Events::InputCommand& e) override;
virtual void Reset();
const glm::quat Orientation() const { return m_Orientation; }
void LockMouse()
{
Events::LockMouse e;
m_EventBroker->Publish(e);
m_MouseLocked = true;
}
void AssaultDashCheck(double dt, bool isJumping, double assaultDashCoolDownMaxTimer);
virtual bool AssaultDashDoubleTapped() const { return m_AssaultDashDoubleTapped; }
virtual bool PlayerIsDashing() const { return m_PlayerIsDashing; }
void UnlockMouse()
{
Events::UnlockMouse e;
m_EventBroker->Publish(e);
m_MouseLocked = false;
}
protected:
const int m_PlayerID;
bool m_MouseLocked = false;
glm::vec3 m_Rotation;
glm::vec3 m_Movement;
bool m_Jumping = false;
bool m_DoubleJumping = false;
bool m_Crouching = false;
//assault dash membervariables - needed to calculate the doubletap- and dashlogic
double m_AssaultDashDoubleTapDeltaTime = 0.0;
double m_AssaultDashCoolDownTimer = 0.0;
//i will let m_AssaultDashDoubleTapSensitivityTimer stay hardcoded, its not really a gamevariable (more an inputvariable),
//and its very unlikely that someone wants to change that value
const float m_AssaultDashDoubleTapSensitivityTimer = 0.25f;
std::string m_AssaultDashTapDirection = "";
std::string m_CurrentDirectionVector = "";
bool m_AssaultDashDoubleTapped = false;
bool m_PlayerIsDashing = false;
bool m_ShiftDashing = false;
bool m_ValidDoubleTap = false;
virtual bool OnCommand(const Events::InputCommand& e) override
{
if (m_PlayerID != e.PlayerID) {
return false;
}
//specialabilitys
bool m_MovementKeyDown = false;
bool m_SpecialAbilityKeyDown = false;
if (m_MouseLocked) {
if (e.Command == "Pitch") {
float val = glm::radians(e.Value);
m_Orientation = m_Orientation * glm::angleAxis<float>(-val, glm::vec3(1, 0, 0));
return true;
}
EventRelay<EventContext, Events::LockMouse> m_ELockMouse;
bool OnLockMouse(const Events::LockMouse& e);
EventRelay<EventContext, Events::UnlockMouse> m_EUnlockMouse;
bool OnUnlockMouse(const Events::UnlockMouse& e);
};
if (e.Command == "Yaw") {
float val = glm::radians(e.Value);
m_Orientation = glm::angleAxis<float>(-val, glm::vec3(0, 1, 0)) * m_Orientation;
return true;
}
}
template <typename EventContext>
FirstPersonInputController<EventContext>::FirstPersonInputController(EventBroker* eventBroker, int playerID)
: InputController(eventBroker)
, m_PlayerID(playerID)
{
EVENT_SUBSCRIBE_MEMBER(m_ELockMouse, &FirstPersonInputController::OnLockMouse);
EVENT_SUBSCRIBE_MEMBER(m_EUnlockMouse, &FirstPersonInputController::OnUnlockMouse);
}
template <typename EventContext>
void FirstPersonInputController<EventContext>::Reset()
{
m_Rotation = glm::vec3(0.f, 0.f, 0.f);
m_Jumping = false;
}
template <typename EventContext>
void FirstPersonInputController<EventContext>::LockMouse()
{
Events::LockMouse e;
m_EventBroker->Publish(e);
m_MouseLocked = true;
}
template <typename EventContext>
void FirstPersonInputController<EventContext>::UnlockMouse()
{
Events::UnlockMouse e;
m_EventBroker->Publish(e);
m_MouseLocked = false;
}
template <typename EventContext>
bool FirstPersonInputController<EventContext>::OnCommand(const Events::InputCommand& e)
{
if (m_PlayerID != e.PlayerID) {
return false;
}
if (e.Command == "Pitch") {
float val = glm::radians(e.Value);
m_Rotation.x += -val;
//m_Rotation.x = glm::clamp(m_Rotation.x, -glm::half_pi<float>(), glm::half_pi<float>());
}
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;
}
if (e.Command == "Right") {
float val = glm::clamp(e.Value, -1.f, 1.f);
m_Movement.x = val;
}
if (glm::length2(m_Movement) > 0) {
m_Movement = glm::normalize(m_Movement);
}
}
if (e.Command == "Forward" || e.Command == "Right") {
if (e.Value != 0) {
m_CurrentDirectionVector = e.Command == "Right" ? (e.Value > 0 ? "Right" : "Left") : (e.Value > 0 ? "Forward" : "Backward");
}
//if value = 0 then you have just released this key
if (e.Value != 0) {
m_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_MovementKeyDown = false;
//you have just released the key, store what key it was and reset the doubletap-sensitivity-timer
m_AssaultDashTapDirection = m_CurrentDirectionVector;
m_AssaultDashDoubleTapDeltaTime = 0.f;
}
}
if (e.Command == "Jump") {
m_Jumping = e.Value > 0;
}
if (e.Command == "Crouch") {
m_Crouching = e.Value > 0;
}
if (e.Command == "SpecialAbility") {
if (e.Value > 0) {
m_SpecialAbilityKeyDown = true;
} else {
m_SpecialAbilityKeyDown = false;
}
}
if (m_SpecialAbilityKeyDown && m_MovementKeyDown) {
m_ShiftDashing = true;
} else {
m_ShiftDashing = false;
}
return true;
}
template <typename EventContext>
bool FirstPersonInputController<EventContext>::OnUnlockMouse(const Events::UnlockMouse& e)
{
m_MouseLocked = false;
return true;
}
template <typename EventContext>
bool FirstPersonInputController<EventContext>::OnLockMouse(const Events::LockMouse& e)
{
m_MouseLocked = true;
return true;
}
template <typename EventContext>
void FirstPersonInputController<EventContext>::AssaultDashCheck(double dt, bool isJumping, double assaultDashCoolDownMaxTimer) {
m_AssaultDashDoubleTapDeltaTime += dt;
m_AssaultDashCoolDownTimer -= dt;
//cooldown = assaultDashCoolDownMaxTimer sec, pretend the dash lasts 0.25 sec (for friction to do its work)
if (m_AssaultDashCoolDownTimer > (assaultDashCoolDownMaxTimer - 0.25f)) {
m_PlayerIsDashing = true;
} else {
m_PlayerIsDashing = false;
}
//dashing with shift
if (m_ShiftDashing && m_AssaultDashCoolDownTimer <= 0.0f && !isJumping) {
//player is dashing with shift
//the wanted-direction is set in playermovement already so we dont need to check what direction we want to dash in!
m_AssaultDashCoolDownTimer = assaultDashCoolDownMaxTimer;
m_AssaultDashDoubleTapped = true;
m_AssaultDashDoubleTapDeltaTime = 0.f;
//moving to the side has priority
return;
}
//dashing with doubletap - check if doubletap to dash enabled
if (ResourceManager::Load<ConfigFile>("Input.ini")->Get<bool>("Keyboard.DoubleTapToDash", false)) {
return;
}
//reset the DoubleTapped state in case we recently doubleTapped (doubletap will only happen during 1 frame)
if (m_AssaultDashDoubleTapped) {
m_AssaultDashDoubleTapped = false;
}
//check if we have received a valid doubletap
if (!m_ValidDoubleTap) {
return;
}
m_ValidDoubleTap = false;
if (!(m_AssaultDashCoolDownTimer <= 0.0f && !isJumping)) {
//if we cant dash at the moment, then just reset the tap-sensitivity-timer
m_AssaultDashDoubleTapDeltaTime = 0.f;
return;
}
//ok, we have a valid tap, lets do it
m_AssaultDashDoubleTapped = true;
m_AssaultDashDoubleTapDeltaTime = 0.f;
m_AssaultDashCoolDownTimer = assaultDashCoolDownMaxTimer;
Events::DashAbility e;
m_EventBroker->Publish(e);
}
protected:
const unsigned int m_PlayerID;
glm::quat m_Orientation;
bool m_MouseLocked = false;
EventRelay<EventContext, Events::LockMouse> m_ELockMouse;
bool OnLockMouse(const Events::LockMouse& e) { m_MouseLocked = true; return true; }
EventRelay<EventContext, Events::UnlockMouse> m_EUnlockMouse;
bool OnUnlockMouse(const Events::UnlockMouse& e) { m_MouseLocked = false; return true; }
};
#endif
-1
View File
@@ -1,7 +1,6 @@
#ifndef InputProxy_h__
#define InputProxy_h__
#include <boost/tokenizer.hpp>
#include "../Common.h"
#include "../Core/ResourceManager.h"
#include "../Core/ConfigFile.h"
+22 -49
View File
@@ -3,12 +3,9 @@
#include <string>
#include <ctime>
#include <limits>
#include <queue>
#include <glm/common.hpp>
#include <boost/asio.hpp>
#include <boost/shared_array.hpp>
#include "Network/Network.h"
#include "Network/MessageType.h"
@@ -18,9 +15,6 @@
#include "Core/EventBroker.h"
#include "Core/ConfigFile.h"
#include "Input/EInputCommand.h"
#include "Core/EPlayerDamage.h"
#include "Network/EInterpolate.h"
#include "Core/EPlayerSpawned.h"
class Client : public Network
{
@@ -29,6 +23,7 @@ public:
~Client();
void Start(World* world, EventBroker* eventBroker) override;
void Update() override;
void Close();
private:
// Assio UDP logic
boost::asio::ip::udp::endpoint m_ReceiverEndpoint;
@@ -36,76 +31,54 @@ private:
boost::asio::ip::udp::socket m_Socket;
// Sending message to server logic
size_t bytesRead = 0;
char readBuf[INPUTSIZE] = { 0 };
int bytesRead = -1;
char readBuf[1024] = { 0 };
int snapshotInterval = 33;
std::clock_t previousSnapshotMessage = std::clock();
// Packet loss logic
PacketID m_PacketID = 0;
PacketID m_PreviousPacketID = 0;
PacketID m_SendPacketID = 0;
unsigned int m_PacketID = 0;
unsigned int m_PreviousPacketID = 0;
unsigned int m_SendPacketID = 0;
// Game logic
World* m_World;
std::string m_PlayerName;
PlayerID m_PlayerID = -1;
EntityID m_ServerEntityID = std::numeric_limits<EntityID>::max();
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;
int m_PlayerID = -1;
// Network logic
PlayerDefinition m_PlayerDefinitions[8];
PlayerDefinition m_PlayerDefinitions[MAXCONNECTIONS];
SnapshotDefinitions m_NextSnapshot;
bool m_ThreadIsRunning = true;
double m_DurationOfPingTime;
std::clock_t m_StartPingTime;
std::clock_t m_TimeSinceSentInputs;
unsigned int m_SendInputIntervalMs;
std::vector<Events::InputCommand> m_InputCommandBuffer;
// Use to check if we should send disconnect message
// if game is turned of by closing window.
bool m_WasStarted = false;
// Private member functions
void readFromServer();
size_t receive(char* data);
void sendSnapshotToServer();
int receive(char* data, size_t length);
void send(Packet& packet);
void connect();
void disconnect();
void ping();
void moveMessageHead(char*& data, size_t& length, size_t stepSize);
void parseMessageType(Packet& packet);
void updateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID, const std::string& componentType);
void parseEventMessage(Packet& packet);
void parseConnect(Packet& packet);
void parsePlayerConnected(Packet& packet);
void parsePing();
void parseKick();
void parsePlayersSpawned(Packet& packet);
void parseEntityDeletion(Packet& packet);
void parseComponentDeletion(Packet& packet);
void InterpolateFields(Packet & packet, const ComponentInfo & componentInfo, const EntityID & entityID, const std::string & componentType);
void parseServerPing();
void parseSnapshot(Packet& packet);
void identifyPacketLoss();
bool hasServerTimedOut();
bool isConnected();
EntityID createPlayer();
void sendInputCommands();
void sendLocalPlayerTransform();
void becomePlayer();
// 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
EventBroker* m_EventBroker;
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);
bool OnInputCommand(const Events::InputCommand &e);
};
#endif
-20
View File
@@ -1,20 +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
{
EntityID Entity;
boost::shared_array<char> DataArray;
};
}
#endif
@@ -1,18 +0,0 @@
#ifndef Events_PlayerDisconnected
#define Events_PlayerDisconnected
#include "Core/EventBroker.h"
#include "Core/Entity.h"
namespace Events
{
struct PlayerDisconnected : public Event
{
unsigned int PlayerID;
EntityID Entity;
};
}
#endif
+7 -14
View File
@@ -5,20 +5,13 @@
// Used to determine what type of message was sent.
enum class MessageType
{
Connect,
Disconnect,
Ping,
Message,
Snapshot,
OnInputCommand,
OnPlayerDamage,
PlayerConnected,
BecomePlayer,
Kick,
OnPlayerSpawned,
EntityDeleted,
ComponentDeleted,
PlayerTransform
Connect,
Disconnect,
ClientPing,
ServerPing,
Message,
Snapshot,
Event,
};
#endif
+2 -21
View File
@@ -1,20 +1,12 @@
#ifndef Network_h__
#define Network_h__
#include <ctime>
#include "Core/World.h"
#include "Core/EventBroker.h"
#include "Network/Packet.h"
#include "Network/NetworkData.h"
#include "Core/ResourceManager.h"
#include "Core/ConfigFile.h"
#include <fstream>
#include <iostream>
#define INPUTSIZE 32000
typedef unsigned int PlayerID;
typedef unsigned int PacketID;
#define MAXCONNECTIONS 8
#define INPUTSIZE 128
class Network
{
@@ -22,17 +14,6 @@ public:
virtual ~Network() { };
virtual void Start(World* m_world, EventBroker *eventBroker) = 0;
virtual void Update() = 0;
protected:
// For Debug
bool isReadingData = false;
NetworkData m_NetworkData;
unsigned int m_SaveDataIntervalMs = 1000;
std::clock_t m_SaveDataTimer;
unsigned int m_MaxConnections;
double m_TimeoutMs;
void saveToFile();
void updateNetworkData();
void initialize();
};
#endif
-18
View File
@@ -1,18 +0,0 @@
#ifndef NetworkData_h__
#define NetworkData_h__
#include <vector>
struct NetworkData {
double TotalTime = 0;
size_t TotalDataReceived = 0;
size_t TotalDataSent = 0;
size_t AmountOfMessagesReceived = 0;
unsigned int AmountOfMessagesSent = 0;
// Interval based
size_t DataReceivedThisInterval = 0;
size_t DataSentThisInterval = 0;
// pair: first=reveived, second=send
std::vector<std::pair<size_t, size_t>> BandwidthBytes;
};
#endif
+9 -17
View File
@@ -13,19 +13,16 @@ public:
// arg2: PacketID for identifying packet loss.
Packet(MessageType type, unsigned int& packetID);
// Used to create packet from already existing data buffer.
Packet(char* data, const size_t sizeOfPacket);
Packet(MessageType type);
Packet(char* data, const int sizeOfPacket);
~Packet();
void Init(MessageType type, unsigned int& packetID);
// Add primitive types like int, float, char...
template<typename T>
void WritePrimitive(T val)
{
// Check if we are trying to add more than the package can fit.
if (m_MaxPacketSize < m_Offset + sizeof(T)) {
LOG_WARNING("Packet AddPrimitive(): You are trying to add more than we have allocated for! New size is %i bytes\n", m_MaxPacketSize*2);
resizeData();
LOG_WARNING("Packet AddPrimitive(): You are trying to add more than we have allocated for!");
}
memcpy(m_Data + m_Offset, &val, sizeof(T));
m_Offset += sizeof(T);
@@ -44,26 +41,21 @@ public:
return returnValue;
}
// Add a string to the message
void WriteString(const std::string& str);
void WriteString(std::string str);
// Add data to the message
void WriteData(char* data, int sizeOfData);
// Pops the first element as if it was a string.
std::string ReadString();
char* ReadData(int SizeOfData);
void ChangePacketID(unsigned int& packetID);
size_t Size() { return m_Offset; };
int Size() { return m_Offset; };
char* Data() { return m_Data; };
size_t DataReadSize() { return m_ReturnDataOffset; }
size_t MaxSize() { return m_MaxPacketSize; }
size_t HeaderSize() { return m_HeaderSize; }
private:
char* m_Data;
size_t m_ReturnDataOffset = 0;
size_t m_Offset = 0;
size_t m_MaxPacketSize = 512;
size_t m_HeaderSize = 0;
void resizeData();
unsigned int m_ReturnDataOffset = 0;
int m_Offset = 0;
unsigned int m_MaxPacketSize = 128;
};
#endif
+1 -4
View File
@@ -1,14 +1,11 @@
#ifndef PlayerDefinition_h__
#define PlayerDefinition_h__
#include <string>
#include "../Core/Entity.h"
struct PlayerDefinition {
::EntityID EntityID = EntityID_Invalid;
int EntityID = -1;
std::string Name = "";
boost::asio::ip::udp::endpoint Endpoint;
unsigned int PacketID;
std::clock_t StopTime;
};
#endif
+26 -35
View File
@@ -11,13 +11,7 @@
#include "Network/PlayerDefinition.h"
#include "Core/World.h"
#include "Core/EventBroker.h"
#include "../Network/Network.h"
#include "Input/EInputCommand.h"
#include "Core/EPlayerDamage.h"
#include "Network/EPlayerDisconnected.h"
#include "Core/EPlayerSpawned.h"
#include "Core/EEntityDeleted.h"
#include "Core/EComponentDeleted.h"
#include "Network/Network.h"
class Server : public Network
{
@@ -26,69 +20,66 @@ public:
~Server();
void Start(World* m_world, EventBroker *eventBroker) override;
void Update() override;
void Close();
private:
// UDP logic
boost::asio::ip::udp::endpoint m_ReceiverEndpoint;
boost::asio::io_service m_IOService;
boost::asio::ip::udp::socket m_Socket;
PlayerDefinition m_PlayerDefinitions[MAXCONNECTIONS];
// Sending messages to client logic
std::map<PlayerID, PlayerDefinition> m_ConnectedPlayers;
// HACK: Fix INPUTSIZE
char readBuffer[INPUTSIZE] = { 0 };
size_t bytesRead = 0;
char readBuffer[1024] = { 0 };
int bytesRead = 0;
// time for previouse message
std::clock_t previousePingMessage = std::clock();
std::clock_t previousSnapshotMessage = std::clock();
std::clock_t timOutTimer = std::clock();
// How often we send messages (milliseconds)
float pingIntervalMs;
float snapshotInterval;
int intervalMs = 1000;
int snapshotInterval = 50;
int checkTimeOutInterval = 100;
int m_NextPlayerID = 0;
//Timers
std::clock_t m_StartPingTime;
std::clock_t m_StopTimes[8];
// Game logic
World* m_World;
EventBroker* m_EventBroker;
// vec.size() = ammount of players to create, stores playerID's
std::vector<unsigned int> m_PlayersToCreate;
// Packet loss logic
PacketID m_PacketID = 0;
PacketID m_PreviousPacketID = 0;
unsigned int m_PacketID;
unsigned int m_PreviousPacketID;
unsigned int m_SendPacketID;
// Close logic
bool m_ThreadIsRunning = true;
// Private member functions
size_t receive(char* data);
int receive(char* data, size_t length);
void readFromClients();
void send(PlayerID player, Packet& packet);
void send(Packet& packet, int playerID);
void send(Packet& packet);
void moveMessageHead(char*& data, size_t& length, size_t stepSize);
void broadcast(std::string message);
void broadcast(Packet& packet);
void sendSnapshot();
void addChildrenToPacket(Packet& packet, EntityID entityID);
void sendPing();
void checkForTimeOuts();
void disconnect(PlayerID playerID);
void disconnect(int i);
void parseMessageType(Packet& packet);
void parseOnInputCommand(Packet& packet);
void parseOnPlayerDamage(Packet& packet);
void parseEvent(Packet& packet);
void parseConnect(Packet& packet);
void parseDisconnect();
void parseClientPing();
void parsePing();
void parseServerPing();
void parseSnapshot(Packet& packet);
void identifyPacketLoss();
void kick(PlayerID player);
PlayerID GetPlayerIDFromEndpoint(boost::asio::ip::udp::endpoint endpoint);
// Debug event
EventRelay<Server, Events::InputCommand> m_EInputCommand;
bool OnInputCommand(const Events::InputCommand& e);
EventRelay<Server, Events::PlayerSpawned> m_EPlayerSpawned;
bool OnPlayerSpawned(const Events::PlayerSpawned& e);
EventRelay<Server, Events::EntityDeleted> m_EEntityDeleted;
bool OnEntityDeleted(const Events::EntityDeleted& e);
EventRelay<Server, Events::ComponentDeleted> m_EComponentDeleted;
bool OnComponentDeleted(const Events::ComponentDeleted& e);
void parsePlayerTransform(Packet& packet);
EntityID createPlayer();
};
#endif
@@ -1,31 +0,0 @@
#ifndef AnimationSystem_h__
#define AnimationSystem_h__
#include "GLM.h"
#include "Common.h"
#include "Core/System.h"
#include "Core/ResourceManager.h"
#include "Rendering/Model.h"
#include "Rendering/EAnimationComplete.h"
#include "Rendering/Skeleton.h"
#include <imgui/imgui.h>
class AnimationSystem : public PureSystem
{
public:
AnimationSystem(World* world, EventBroker* eventBroker)
: System(world, eventBroker)
, PureSystem("Animation")
{
}
~AnimationSystem() { }
virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& animationComponent, double dt) override;
private:
float angle = 0.f;
bool b_forward = false;
char bone[100];
};
#endif
+1 -1
View File
@@ -3,7 +3,7 @@
#include "../Core/ResourceManager.h"
class BaseTexture : public ThreadUnsafeResource
class BaseTexture : public Resource
{
friend class ResourceManager;
@@ -1,29 +0,0 @@
#ifndef BoneAttachmentSystem_h__
#define BoneAttachmentSystem_h__
#include "GLM.h"
#include "Common.h"
#include "Core/System.h"
#include "Core/ResourceManager.h"
#include "Rendering/Model.h"
#include "Rendering/Skeleton.h"
//Needs to be a higher orderlevel than AnimationSystem
class BoneAttachmentSystem : public PureSystem
{
public:
BoneAttachmentSystem(World* world, EventBroker* eventBroker)
: System(world, eventBroker)
, PureSystem("BoneAttachment")
{
}
~BoneAttachmentSystem() { }
virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& BoneAttachmentComponent, double dt) override;
private:
};
#endif
+8 -8
View File
@@ -2,7 +2,6 @@
#define Camera_h__
#include "../GLM.h"
#include "../Core/Util/Rectangle.h"
class Camera
{
@@ -27,11 +26,13 @@ public:
glm::quat Orientation() const { return m_Orientation; }
void SetOrientation(glm::quat val);
glm::mat4 ProjectionMatrix() const { return m_ProjectionMatrix; }
void SetProjectionMatrix(glm::mat4 val);
/*float Pitch() const { return m_Pitch; }
void Pitch(float val);
float Yaw() const { return m_Yaw; }
void Yaw(float val);*/
glm::mat4 ProjectionMatrix() const { return m_ProjectionMatrix; }
glm::mat4 ViewMatrix() const { return m_ViewMatrix; }
void SetViewMatrix(glm::mat4 val);
float AspectRatio() const { return m_AspectRatio; }
void SetAspectRatio(float val);
@@ -45,12 +46,11 @@ public:
float FarClip() const { return m_FarClip; }
void SetFarClip(float val);
void UpdateViewMatrix();
void UpdateProjectionMatrix();
glm::vec2 WorldToScreen(glm::vec3 worldCoord, Rectangle resolution);
private:
void UpdateViewMatrix();
void UpdateProjectionMatrix();
glm::vec3 m_Position;
glm::quat m_Orientation;
@@ -0,0 +1,63 @@
#include <imgui/imgui.h>
#include "../Input/FirstPersonInputController.h"
template <typename EventContext>
class DebugCameraInputController : public FirstPersonInputController<EventContext>
{
public:
DebugCameraInputController(EventBroker* eventBroker, unsigned int playerID)
: FirstPersonInputController(eventBroker, playerID)
{ }
const glm::vec3 Position() const { return m_Position; }
void SetBaseSpeed(float speed) { m_BaseSpeed = speed; }
virtual bool OnCommand(const Events::InputCommand& e) override
{
ImGuiIO& io = ImGui::GetIO();
if (e.Command == "PrimaryFire") {
if (e.Value > 0) {
if (!io.WantCaptureMouse) {
LockMouse();
}
} else {
UnlockMouse();
}
return false;
}
if (!io.WantCaptureKeyboard) {
if (e.Command == "Right") {
float value = std::max(-1.f, std::min(e.Value, 1.f));
m_Velocity.x = value;
}
if (e.Command == "Forward") {
float value = std::max(-1.f, std::min(e.Value, 1.f));
m_Velocity.z = -value;
}
if (e.Command == "Sprint") {
if (e.Value > 0.f) {
m_Speed = m_BaseSpeed * 2.f * (e.Value);
} else {
m_Speed = m_BaseSpeed;
}
}
}
return FirstPersonInputController::OnCommand(e);
}
void Update(double dt)
{
if (glm::length2(m_Velocity) > 0) {
m_Position += m_Orientation * (glm::normalize(m_Velocity) * m_Speed * (float)dt);
}
}
protected:
glm::vec3 m_Position = glm::vec3(0, 0, 0);
glm::vec3 m_Velocity = glm::vec3(0, 0, 0);
float m_BaseSpeed = 2.0f;
float m_Speed = m_BaseSpeed;
};
@@ -1,35 +0,0 @@
#ifndef DirectionalLightJob_h__
#define DirectionalLightJob_h__
#include <cstdint>
#include "../Common.h"
#include "../GLM.h"
#include "../Core/ComponentWrapper.h"
#include "RenderJob.h"
#include "../Core/Transform.h"
#include "../Core/World.h"
struct DirectionalLightJob : RenderJob
{
DirectionalLightJob(ComponentWrapper transformComponent, ComponentWrapper directionalLightComponent, World* m_World)
: RenderJob()
{
Direction = glm::vec4(0,0,-1,0) * glm::inverse(Transform::AbsoluteOrientation(m_World, transformComponent.EntityID));
//Direction = glm::vec4((glm::vec3)directionalLightComponent["Direction"], 0.f);
Color = (glm::vec4)directionalLightComponent["Color"];
Intensity = (double)directionalLightComponent["Intensity"];
};
glm::vec4 Direction;
glm::vec4 Color;
float Intensity;
void CalculateHash() override
{
Hash = 0;
}
};
#endif
-53
View File
@@ -1,53 +0,0 @@
#ifndef DrawBloomPass_h__
#define DrawBloomPass_h__
#include "IRenderer.h"
#include "DrawBloomPassState.h"
//#include "LightCullingPass.h" Finalpass om den skall skickas in
#include "FrameBuffer.h"
#include "ShaderProgram.h"
//#include "Util/UnorderedMapVec2.h"
#include "Texture.h"
class DrawBloomPass
{
public:
DrawBloomPass(IRenderer* renderer /* ,Texture or finalpass*/ );
~DrawBloomPass() { }
void InitializeTextures();
void InitializeFrameBuffers();
void InitializeShaderPrograms();
void InitializeBuffers();
void ClearBuffer();
void FillGaussianBuffer(FrameBuffer* fb);
void Draw(GLuint texture);
//Getters
//Return the blurred result of the texture that was sent into draw
GLuint GaussianTexture() const { return m_GaussianTexture_vert; }
private:
void GenerateTexture(GLuint* texture, GLenum wrapping, GLenum filtering, glm::vec2 dimensions, GLint internalFormat, GLint format, GLenum type) const;
Texture* m_WhiteTexture;
Model* m_ScreenQuad;
const IRenderer* m_Renderer;
//const LightCullingPass* m_LightCullingPass
GLuint m_iterations = 9;
GLuint m_GaussianTexture_horiz;
GLuint m_GaussianTexture_vert;
FrameBuffer m_GaussianFrameBuffer_horiz;
FrameBuffer m_GaussianFrameBuffer_vert;
ShaderProgram* m_GaussianProgram_horiz;
ShaderProgram* m_GaussianProgram_vert;
};
#endif
@@ -1,15 +0,0 @@
#ifndef DrawBloomPassState_h__
#define DrawBloomPassState_h__
#include "Rendering/RenderState.h"
class DrawBloomPassState : public RenderState
{
public:
DrawBloomPassState();
~DrawBloomPassState();
private:
};
#endif
@@ -1,29 +0,0 @@
#ifndef DrawColorCorrectionPass_h__
#define DrawColorCorrectionPass_h__
#include "IRenderer.h"
#include "DrawScreenQuadPassState.h"
#include "FrameBuffer.h"
#include "ShaderProgram.h"
//#include "Util/UnorderedMapVec2.h"
#include "Texture.h"
#include "imgui/imgui.h"
class DrawColorCorrectionPass
{
public:
DrawColorCorrectionPass(IRenderer* renderer);
~DrawColorCorrectionPass() { }
void InitializeFrameBuffers();
void InitializeShaderPrograms();
void Draw(GLuint sceneTexture, GLuint bloomTexture, GLuint sceneTextureLowRes, GLuint bloomTextureLowRes, GLfloat gamma, GLfloat exposure);
private:
const IRenderer* m_Renderer;
ShaderProgram* m_ColorCorrectionProgram;
Model* m_ScreenQuad;
};
#endif
-85
View File
@@ -1,85 +0,0 @@
#ifndef DrawFinalPass_h__
#define DrawFinalPass_h__
#include "IRenderer.h"
#include "DrawFinalPassState.h"
#include "LightCullingPass.h"
#include "FrameBuffer.h"
#include "ShaderProgram.h"
#include "Util/UnorderedMapVec2.h"
#include "Texture.h"
class DrawFinalPass
{
public:
DrawFinalPass(IRenderer* renderer, LightCullingPass* lightCullingPass);
~DrawFinalPass() { }
void InitializeTextures();
void InitializeFrameBuffers();
void InitializeShaderPrograms();
void Draw(RenderScene& scene);
void ClearBuffer();
//Return the texture that is used in later stages to apply the bloom effect
GLuint BloomTexture() const { return m_BloomTexture; }
GLuint BloomTextureLowRes() const { return m_BloomTextureLowRes; }
//Return the texture with diffuse and lighting of the scene.
GLuint SceneTexture() const { return m_SceneTexture; }
GLuint SceneTextureLowRes() const { return m_SceneTextureLowRes; }
//Return the framebuffer used in the scene rendering stage.
FrameBuffer* FinalPassFrameBuffer() { return &m_FinalPassFrameBuffer; }
FrameBuffer* FinalPassFrameBufferLowRes() { return &m_FinalPassFrameBufferLowRes; }
private:
void GenerateTexture(GLuint* texture, GLenum wrapping, GLenum filtering, glm::vec2 dimensions, GLint internalFormat, GLint format, GLenum type) const;
void GenerateMipMapTexture(GLuint* texture, GLenum wrapping, glm::vec2 dimensions, GLint format, GLenum type, GLint numMipMaps) const;
void DrawModelRenderQueues(std::list<std::shared_ptr<RenderJob>>& jobs, RenderScene& scene);
void DrawShieldToStencilBuffer(std::list<std::shared_ptr<RenderJob>>& jobs, RenderScene& scene);
void DrawShieldedModelRenderQueue(std::list<std::shared_ptr<RenderJob>>& jobs, RenderScene& scene);
void DrawToDepthBuffer(std::list<std::shared_ptr<RenderJob>>& jobs, RenderScene& scene);
void BindExplosionUniforms(GLuint shaderHandle, std::shared_ptr<ExplosionEffectJob>& job, RenderScene& scene);
void BindModelUniforms(GLuint shaderHandle, std::shared_ptr<ModelJob>& job, RenderScene& scene);
void BindExplosionTextures(GLuint shaderHandle, std::shared_ptr<ExplosionEffectJob>& job);
void BindModelTextures(GLuint shaderHandle, std::shared_ptr<ModelJob>& job);
Texture* m_WhiteTexture;
Texture* m_BlackTexture;
Texture* m_NeutralNormalTexture;
Texture* m_GreyTexture;
FrameBuffer m_FinalPassFrameBuffer;
FrameBuffer m_FinalPassFrameBufferLowRes;
GLuint m_BloomTexture;
GLuint m_SceneTexture;
GLuint m_BloomTextureLowRes;
GLuint m_SceneTextureLowRes;
GLuint m_DepthBuffer;
GLuint m_DepthBufferLowRes;
//maqke this component based i guess?
GLuint m_ShieldPixelRate = 16;
const IRenderer* m_Renderer;
const LightCullingPass* m_LightCullingPass;
ShaderProgram* m_ForwardPlusProgram;
ShaderProgram* m_ExplosionEffectProgram;
ShaderProgram* m_ExplosionEffectSplatMapProgram;
ShaderProgram* m_ForwardPlusSplatMapProgram;
ShaderProgram* m_ShieldToStencilProgram;
ShaderProgram* m_FillDepthBufferProgram;
ShaderProgram* m_ForwardPlusSkinnedProgram;
ShaderProgram* m_ExplosionEffectSkinnedProgram;
ShaderProgram* m_ExplosionEffectSplatMapSkinnedProgram;
ShaderProgram* m_ForwardPlusSplatMapSkinnedProgram;
ShaderProgram* m_ShieldToStencilSkinnedProgram;
ShaderProgram* m_FillDepthBufferSkinnedProgram;
};
#endif
@@ -1,22 +0,0 @@
#ifndef DrawFinalPassState_h__
#define DrawFinalPassState_h__
#include "Rendering/RenderState.h"
class DrawFinalPassState : public RenderState
{
public:
DrawFinalPassState(GLuint frameBuffer);
~DrawFinalPassState();
private:
};
class DrawStencilState : public RenderState
{
public:
DrawStencilState(GLuint frameBuffer);
~DrawStencilState();
};
#endif
+36
View File
@@ -0,0 +1,36 @@
#ifndef DrawScenePass_h__
#define DrawScenePass_h__
#include "IRenderer.h"
#include "DrawScenePassState.h"
#include "FrameBuffer.h"
#include "ShaderProgram.h"
#include "Util/UnorderedMapVec2.h"
#include "Texture.h"
class DrawScenePass
{
public:
DrawScenePass(IRenderer* renderer);
~DrawScenePass() { }
void InitializeTextures();
void InitializeFrameBuffers();
void InitializeShaderPrograms();
void Draw(RenderQueueCollection& rq);
//Getters
private:
void GenerateTexture(GLuint* texture, GLenum wrapping, GLenum filtering, glm::vec2 dimensions, GLint internalFormat, GLint format, GLenum type) const;
Texture* m_WhiteTexture;
const IRenderer* m_Renderer;
ShaderProgram* m_BasicForwardProgram;
};
#endif
@@ -0,0 +1,15 @@
#ifndef DrawScenePassState_h__
#define DrawScenePassState_h__
#include "Rendering/RenderState.h"
class DrawScenePassState : public RenderState
{
public:
DrawScenePassState();
~DrawScenePassState();
private:
};
#endif
@@ -1,28 +0,0 @@
#ifndef DrawScreenQuadPass_h__
#define DrawScreenQuadPass_h__
#include "IRenderer.h"
#include "DrawScreenQuadPassState.h"
#include "FrameBuffer.h"
#include "ShaderProgram.h"
//#include "Util/UnorderedMapVec2.h"
#include "Texture.h"
class DrawScreenQuadPass
{
public:
DrawScreenQuadPass(IRenderer* renderer);
~DrawScreenQuadPass() { }
void InitializeFrameBuffers();
void InitializeShaderPrograms();
void Draw(GLuint texture);
private:
const IRenderer* m_Renderer;
ShaderProgram* m_DrawQuadProgram;
Model* m_ScreenQuad;
};
#endif
@@ -1,15 +0,0 @@
#ifndef DrawScreenQuadPassState_h__
#define DrawScreenQuadPassState_h__
#include "Rendering/RenderState.h"
class DrawScreenQuadPassState : public RenderState
{
public:
DrawScreenQuadPassState();
~DrawScreenQuadPassState();
private:
};
#endif
+1 -1
View File
@@ -9,7 +9,7 @@ class DummyRenderer : public IRenderer
{
public:
virtual void Initialize() override;
virtual void Draw(RenderFrame& rq) override;
virtual void Draw(RenderQueueCollection& rq) override;
};
#endif
@@ -1,18 +0,0 @@
#ifndef Events_AnimationComplete_h__
#define Events_AnimationComplete_h__
#include "../Core/EventBroker.h"
#include "../Core/EntityWrapper.h"
namespace Events
{
struct AnimationComplete : Event
{
EntityWrapper Entity;
std::string Name;
};
}
#endif
+74
View File
@@ -0,0 +1,74 @@
#ifndef Events_Picking_h__
#define Events_Picking_h__
#include "../OpenGL.h"
#include "../GLM.h"
#include "../Core/EventBroker.h"
#include "Util/ScreenCoords.h"
#include "FrameBuffer.h"
#include "../Core/Entity.h"
#include "Util/UnorderedMapVec2.h"
namespace Events
{
/** Thrown Every frame, use functions to pick*/
struct Picking : Event
{
public:
Picking(FrameBuffer* pickingBuffer, GLuint* depthBuffer, glm::mat4 projectionMatrix, glm::mat4 viewMatrix, Rectangle resolution, const std::unordered_map<glm::vec2, EntityID>* pickingColorsToEntity)
: PickingBuffer(pickingBuffer)
, DepthBuffer(depthBuffer)
, ProjectionMatrix(projectionMatrix)
, ViewMatrix(viewMatrix)
, Resolution(resolution)
, PickingColorsToEntity(pickingColorsToEntity)
{ }
struct PickData
{
//Picked Entity
EntityID Entity;
//World position of the "pick"
glm::vec3 Position;
// Depth
float Depth;
};
PickData Pick(glm::vec2 screenCoord) const
{
PickData pickData;
// Invert screen y coordinate
screenCoord.y = Resolution.Height - screenCoord.y;
ScreenCoords::PixelData data = ScreenCoords::ToPixelData(screenCoord, PickingBuffer, *DepthBuffer);
pickData.Depth = data.Depth;
auto it = PickingColorsToEntity->find(glm::vec2(data.Color[0], data.Color[1]));
if (it != PickingColorsToEntity->end()) {
pickData.Entity = it->second;
} else {
pickData.Entity = EntityID_Invalid;
}
pickData.Position = ScreenCoords::ToWorldPos(screenCoord.x, screenCoord.y, data.Depth, Resolution, ProjectionMatrix, ViewMatrix);
return pickData;
}
private:
FrameBuffer* PickingBuffer;
GLuint* DepthBuffer;
const glm::mat4 ProjectionMatrix;
const glm::mat4 ViewMatrix;
const Rectangle Resolution;
const std::unordered_map<glm::vec2, EntityID>* PickingColorsToEntity;
};
}
#endif
-17
View File
@@ -1,17 +0,0 @@
#ifndef Events_SetCamera_h__
#define Events_SetCamera_h__
#include "../Core/EventBroker.h"
#include "../Core/EntityWrapper.h"
namespace Events
{
struct SetCamera : Event
{
EntityWrapper CameraEntity;
};
}
#endif
@@ -1,106 +0,0 @@
#ifndef ExplosionEffectJob_h__
#define ExplosionEffectJob_h__
#include <cstdint>
#include "../Common.h"
#include "../GLM.h"
#include "../Core/ComponentWrapper.h"
#include "Texture.h"
#include "Model.h"
#include "RenderJob.h"
#include "../Core/ResourceManager.h"
#include "Camera.h"
#include "../Core/World.h"
struct ExplosionEffectJob : ModelJob
{
ExplosionEffectJob(ComponentWrapper explosionEffectComponent, ::Model* model, Camera* camera, glm::mat4 matrix, ::RawModel::MaterialProperties matGroup, ComponentWrapper modelComponent, ::World* world, glm::vec4 fillColor, float fillPercentage)
: ModelJob(model, camera, matrix, matGroup, modelComponent, world, fillColor, fillPercentage)
{
ExplosionOrigin = (glm::vec3)explosionEffectComponent["ExplosionOrigin"];
TimeSinceDeath = (double)explosionEffectComponent["TimeSinceDeath"];
ExplosionDuration = (double)explosionEffectComponent["ExplosionDuration"];
EndColor = (glm::vec4)explosionEffectComponent["EndColor"];
Randomness = (bool)explosionEffectComponent["Randomness"];
RandomnessScalar = (double)explosionEffectComponent["RandomnessScalar"];
Velocity = (glm::vec2)explosionEffectComponent["Velocity"];
ColorByDistance = (bool)explosionEffectComponent["ColorByDistance"];
ExponentialAccelaration = (bool)explosionEffectComponent["ExponentialAccelaration"];
};
glm::vec3 ExplosionOrigin;
double TimeSinceDeath = 0.f; //Seconds
double ExplosionDuration = 2.f;
//bool Gravity = true;
//double GravityForce = 1.f; // Speed
//double ObjectRadius = 2.f; // TODO: Change this for object radius when it's available
glm::vec4 EndColor;
bool Randomness = false;
float RandomnessScalar = 1.f;
glm::vec2 Velocity;
bool ColorByDistance = false;
//bool ReverseAnimation = false;
//bool Wireframe = false;
bool ExponentialAccelaration = false;
std::array<float, 50> RandomNumbers = {
0.3257552917701f,
0.07601508315467f,
0.57408909014151f,
0.0f,
0.8618231368539f,
0.074957156588769f,
0.39413607511396f,
0.54579346698979f,
0.83222648353885f,
0.83635707285086f,
0.34473986148124f,
0.98092448710507f,
0.46346380070944f,
0.7308761201477f,
0.70832470371776f,
0.28268750909841f,
0.26291620883295f,
0.07685032816457f,
0.30760929515008f,
0.2781575388639f ,
0.016950582161988f ,
0.25787915254844f ,
0.76293767279151f ,
0.67730279903733f ,
0.49042877018937f ,
0.13002237823327f ,
0.62803373841012f ,
0.94525353747665f ,
0.32893980076953f ,
0.95952951719962f ,
0.056386206790985f ,
0.012030893476694f ,
0.93090049220757f,
0.83579883064879f,
0.79733513938139f,
0.8796381046435f ,
0.94160434600972f ,
0.76901855588379f ,
0.50253688101775f ,
0.82457069578793f ,
0.80157403359263f ,
0.87291810189975f ,
0.64679548919517f ,
0.42664138899494f ,
0.77171308303797f ,
0.75567959237643f ,
0.45190826265696f ,
0.59844922628181f ,
0.56534937655802f ,
0.195656257307f};
void CalculateHash() override
{
Hash = 0;
}
};
#endif
-36
View File
@@ -1,36 +0,0 @@
#ifndef Font_h__
#define Font_h__
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
#include <boost/tokenizer.hpp>
#include <boost/lexical_cast.hpp>
#include "../OpenGL.h"
#include "../GLM.h"
#include "../Core/ResourceManager.h"
class Font : public Resource
{
friend class ResourceManager;
private:
Font(std::string path);
public:
struct Character {
GLuint TextureID; // ID handle of the glyph texture
glm::ivec2 Size; // Size of glyph
glm::ivec2 Bearing; // Offset from baseline to left/top of glyph
GLuint Advance; // Offset to advance to next glyph
};
int FontSize = 16;
~Font();
std::map<GLchar, Character> m_Characters;
};
#endif
+16 -20
View File
@@ -9,43 +9,39 @@
#include "Camera.h"
#include "RenderQueue.h"
#include "Model.h"
#include "../Core/World.h" //So temp
struct PickData
{
EntityID Entity;
glm::vec3 Position; //World position
float Depth;
::Camera* Camera;
const ::World* World;
};
class IRenderer
{
public:
GLFWwindow* Window() const { return m_Window; }
//Returns screen size including window border and header
Rectangle Resolution() const { return m_Resolution; }
virtual void SetResolution(const Rectangle& resolution) { m_Resolution = resolution; }
void SetResolution(const Rectangle& resolution) { m_Resolution = resolution; }
bool Fullscreen() { return m_Fullscreen; }
virtual void SetFullscreen(bool fullscreen) { m_Fullscreen = fullscreen; }
void SetFullscreen(bool fullscreen) { m_Fullscreen = fullscreen; }
bool VSYNC() const { return m_VSYNC; }
virtual void SetVSYNC(bool vsync) { m_VSYNC = vsync; }
//Returns screen size excluding window border and header
Rectangle GetViewportSize() const { return m_ViewportSize; }
void SetVSYNC(bool vsync) { m_VSYNC = vsync; }
::Camera* Camera() const { return m_Camera; }
void SetCamera(::Camera* camera)
{
if (camera == nullptr) {
m_Camera = m_DefaultCamera;
} else {
m_Camera = camera;
}
}
virtual void Initialize() = 0;
virtual void Update(double dt) = 0;
virtual void Draw(RenderFrame& rq) = 0;
virtual PickData Pick(glm::vec2 screenCord) = 0;
virtual void Draw(RenderQueueCollection& rq) = 0;
protected:
Rectangle m_Resolution = Rectangle::Rectangle(1280, 720);
Rectangle m_ViewportSize = Rectangle::Rectangle(1280, 720);
bool m_Fullscreen = false;
bool m_VSYNC = false;
int m_GLVersion[2];
std::string m_GLVendor;
::Camera* m_DefaultCamera;
::Camera* m_Camera = nullptr;
GLFWwindow* m_Window = nullptr;
};
@@ -1,84 +0,0 @@
#ifndef LightCullingPass_h__
#define LightCullingPass_h__
#define TILE_SIZE 16
#define MAX_LIGHTS_PER_TILE 200
#include "IRenderer.h"
#include "LightCullingPassState.h"
#include "ShaderProgram.h"
#include "RenderQueue.h"
class LightCullingPass
{
public:
LightCullingPass(IRenderer* renderer);
~LightCullingPass();
void GenerateNewFrustum(RenderScene& scene);
void OnResolutionChange();
void SetSSBOSizes();
void CullLights(RenderScene& scene);
void FillLightList(RenderScene& scene);
GLuint FrustumSSBO() const { return m_FrustumSSBO; }
GLuint LightSSBO() const { return m_LightSSBO; }
GLuint LightGridSSBO() const { return m_LightGridSSBO; }
GLuint LightOffsetSSBO() const { return m_LightOffsetSSBO; }
GLuint LightIndexSSBO() const { return m_LightIndexSSBO; }
private:
void InitializeSSBOs();
void InitializeShaderPrograms();
const IRenderer* m_Renderer;
GLuint m_FrustumSSBO = 0;
GLuint m_LightSSBO = 0;
GLuint m_LightGridSSBO = 0;
GLuint m_LightOffsetSSBO = 0;
GLuint m_LightIndexSSBO = 0;
ShaderProgram* m_CalculateFrustumProgram;
ShaderProgram* m_LightCullProgram;
int m_NumberOfTiles = 0;
struct Plane {
glm::vec3 Normal = glm::vec3(0.f);
float d = 0;
};
struct Frustum {
Plane Planes[4];
};
Frustum* m_Frustums;
//This should be a component
struct LightSource {
glm::vec4 Position = glm::vec4(0.f);
glm::vec4 Direction = glm::vec4(10.f);
glm::vec4 Color = glm::vec4(1.f);
float Radius = 5.f;
float Intensity = 0.8f;
float Falloff = 0.3f;
enum Type_t { Zero, Point, Directional, Spot } Type;
};
std::vector<LightSource> m_LightSources;
struct LightGrid {
float Start = 0;
float Amount = 0;
glm::vec2 Padding = glm::vec2(1.f, 2.f);
};
LightGrid* m_LightGrid;
int m_LightOffset = 0;
float* m_LightIndex;
};
#endif
+5 -13
View File
@@ -1,12 +1,10 @@
#ifndef Model_h__
#define Model_h__
#include "Rendering/RawModelCustom.h"
//#include "Rendering/RawModelAssimp.h"
#include "RawModel.h"
#include "../OpenGL.h"
#include "Core/AABB.h"
class Model : public ThreadUnsafeResource
class Model : public RawModel
{
friend class ResourceManager;
@@ -15,20 +13,14 @@ private:
public:
~Model();
const std::vector<RawModel::MaterialProperties>& MaterialGroups() const { return m_RawModel->m_Materials; }
const glm::mat4& Matrix() const { return m_RawModel->m_Matrix; }
const RawModel::Vertex* Vertices() const { return m_RawModel->Vertices(); }
unsigned int NumberOfVertices() const { return m_RawModel->NumVertices(); }
const AABB& Box() const { return m_Box; }
bool IsSkinned() const { return m_RawModel->IsSkinned(); }
GLuint VAO;
GLuint ElementBuffer;
RawModel* m_RawModel;
private:
AABB m_Box;
GLuint VertexBuffer;
GLuint DiffuseVertexColorBuffer;
GLuint SpecularVertexColorBuffer;
GLuint NormalBuffer;
GLuint TangentNormalsBuffer;
GLuint BiTangentNormalsBuffer;

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