Merge remote-tracking branch 'origin/Networking' into Networking
# Conflicts: # src/Engine/Network/Client.cpp # src/Engine/Network/Server.cpp # src/Game/Game.cpp
This commit is contained in:
@@ -1,16 +1,17 @@
|
|||||||
#### Bundled libraries
|
#### Bundled libraries
|
||||||
Libraries bundled along with binaries for Windows (MSVC14), available as a submodule in the *deps* directory of the source tree.
|
Libraries bundled along with binaries for Windows (MSVC14), available as a submodule in the *deps* directory of the source tree.
|
||||||
|
|
||||||
| Project | Version | License |
|
| Project | Version | License |
|
||||||
| ------------------------------------------------------------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ---------------------------------------------------------------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| **[GLFW](http://www.glfw.org)** | 3.1.2 | [zlib/libpng License](http://www.glfw.org/license.html) |
|
| **[GLFW](http://www.glfw.org)** | 3.1.2 | [zlib/libpng License](http://www.glfw.org/license.html) |
|
||||||
| **[GLM](http://glm.g-truc.net/0.9.5/index.html)** | 0.9.7.1 | [MIT License](http://glm.g-truc.net/copying.txt) |
|
| **[GLM](http://glm.g-truc.net/0.9.5/index.html)** | 0.9.7.1 | [MIT License](http://glm.g-truc.net/copying.txt) |
|
||||||
| **[GLEW](http://glew.sourceforge.net)** | 1.13.0 | [Modified BSD License](http://glew.sourceforge.net/glew.txt), [Mesa 3-D License](http://glew.sourceforge.net/mesa.txt), [Khronos License](http://glew.sourceforge.net/khronos.txt) |
|
| **[GLEW](http://glew.sourceforge.net)** | 1.13.0 | [Modified BSD License](http://glew.sourceforge.net/glew.txt), [Mesa 3-D License](http://glew.sourceforge.net/mesa.txt), [Khronos License](http://glew.sourceforge.net/khronos.txt) |
|
||||||
| **[Assimp](http://assimp.sourceforge.net)** | 3.1.1 | [BSD 3-Clause License](http://assimp.sourceforge.net/main_license.html) |
|
| **[Assimp](http://assimp.sourceforge.net)** | 3.1.1 | [BSD 3-Clause License](http://assimp.sourceforge.net/main_license.html) |
|
||||||
| **[zlib](http://www.zlib.net)** | 1.28 | [zlib License](http://www.zlib.net/zlib_license.html) |
|
| **[zlib](http://www.zlib.net)** | 1.28 | [zlib License](http://www.zlib.net/zlib_license.html) |
|
||||||
| **[libpng](http://www.libpng.org/pub/png/libpng.html)** | 1.6.19 | [libpng License](http://www.libpng.org/pub/png/src/libpng-LICENSE.txt) |
|
| **[libpng](http://www.libpng.org/pub/png/libpng.html)** | 1.6.19 | [libpng License](http://www.libpng.org/pub/png/src/libpng-LICENSE.txt) |
|
||||||
| **[Xerces-C++](https://xerces.apache.org/xerces-c)** | 3.1.2 | [Apache License Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) |
|
| **[Xerces-C++](https://xerces.apache.org/xerces-c)** | 3.1.2 | [Apache License Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) |
|
||||||
| **[ImGui](https://github.com/ocornut/imgui)** | 2015-12-12 | [MIT License](https://github.com/ocornut/imgui/blob/de3a154f3801de22c8e0bd2aeabf663a70c05972/LICENSE) |
|
| **[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 | https://github.com/mlabbe/nativefiledialog/blob/master/LICENSE |
|
||||||
|
|
||||||
#### External libraries
|
#### External libraries
|
||||||
Libraries that are too big to be bundled with the project.
|
Libraries that are too big to be bundled with the project.
|
||||||
|
|||||||
+1
-1
Submodule assets updated: 673d4a4e4c...6cbf2365d4
+1
-1
Submodule deps updated: 1ae6ba5b12...bf83f099ba
@@ -12,9 +12,17 @@ struct ComponentInfo
|
|||||||
unsigned int Stride = 0;
|
unsigned int Stride = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Field_t
|
||||||
|
{
|
||||||
|
std::string Name;
|
||||||
|
std::string Type;
|
||||||
|
unsigned int Offset;
|
||||||
|
unsigned int Stride;
|
||||||
|
};
|
||||||
|
|
||||||
std::string Name;
|
std::string Name;
|
||||||
std::unordered_map<std::string, std::string> FieldTypes;
|
std::unordered_map<std::string, Field_t> Fields;
|
||||||
std::unordered_map<std::string, unsigned int> FieldOffsets;
|
std::vector<std::string> FieldsInOrder;
|
||||||
Meta_t Meta;
|
Meta_t Meta;
|
||||||
std::shared_ptr<char> Defaults = nullptr;
|
std::shared_ptr<char> Defaults = nullptr;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ struct ComponentWrapper
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
T& Property(std::string name)
|
T& Property(std::string name)
|
||||||
{
|
{
|
||||||
unsigned int offset = Info.FieldOffsets.at(name);
|
unsigned int offset = Info.Fields.at(name).Offset;
|
||||||
return *reinterpret_cast<T*>(&Data[offset]);
|
return *reinterpret_cast<T*>(&Data[offset]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,8 +78,9 @@ public:
|
|||||||
void AddProperty(std::string fieldName, T defaultValue)
|
void AddProperty(std::string fieldName, T defaultValue)
|
||||||
{
|
{
|
||||||
m_DefaultValues.push_back(defaultValue);
|
m_DefaultValues.push_back(defaultValue);
|
||||||
m_ComponentInfo.FieldTypes[fieldName] = typeid(T).name();
|
m_ComponentInfo.Fields[fieldName].Name = typeid(T).name();
|
||||||
m_ComponentInfo.FieldOffsets[fieldName] = m_ComponentInfo.Meta.Stride;
|
m_ComponentInfo.Fields[fieldName].Offset = m_ComponentInfo.Meta.Stride;
|
||||||
|
m_ComponentInfo.Fields[fieldName].Stride = sizeof(T);
|
||||||
m_ComponentInfo.Meta.Stride += sizeof(T);
|
m_ComponentInfo.Meta.Stride += sizeof(T);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#ifndef EPlayerDamage_h__
|
||||||
|
#define EPlayerDamage_h__
|
||||||
|
|
||||||
|
#include "EventBroker.h"
|
||||||
|
#include "../Core/Entity.h"
|
||||||
|
|
||||||
|
namespace Events
|
||||||
|
{
|
||||||
|
|
||||||
|
struct PlayerDamage : Event
|
||||||
|
{
|
||||||
|
double DamageAmount;
|
||||||
|
EntityID PlayerDamagedID;
|
||||||
|
//optional TypeOfDamage
|
||||||
|
std::string TypeOfDamage;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#ifndef EPlayerDeath_h__
|
||||||
|
#define EPlayerDeath_h__
|
||||||
|
|
||||||
|
#include "EventBroker.h"
|
||||||
|
#include "../Core/Entity.h"
|
||||||
|
|
||||||
|
namespace Events
|
||||||
|
{
|
||||||
|
|
||||||
|
struct PlayerDeath : Event
|
||||||
|
{
|
||||||
|
//KilledBy,KilledByWhat is optional for now. It might be used later in the playerlog-system
|
||||||
|
EntityID KilledBy;
|
||||||
|
EntityID PlayerID;
|
||||||
|
std::string KilledByWhat;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#ifndef EPlayerHealthPickup_h__
|
||||||
|
#define EPlayerHealthPickup_h__
|
||||||
|
|
||||||
|
#include "EventBroker.h"
|
||||||
|
#include "../Core/Entity.h"
|
||||||
|
|
||||||
|
namespace Events
|
||||||
|
{
|
||||||
|
|
||||||
|
struct PlayerHealthPickup : Event
|
||||||
|
{
|
||||||
|
double HealthAmount;
|
||||||
|
EntityID PlayerHealedID;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -2,5 +2,6 @@
|
|||||||
#define Entity_h__
|
#define Entity_h__
|
||||||
|
|
||||||
typedef unsigned int EntityID;
|
typedef unsigned int EntityID;
|
||||||
|
const static unsigned int EntityID_Invalid = -1;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -0,0 +1,293 @@
|
|||||||
|
#ifndef EntityFile_h__
|
||||||
|
#define EntityFile_h__
|
||||||
|
|
||||||
|
#include <stack>
|
||||||
|
#include <boost/lexical_cast.hpp>
|
||||||
|
#include <xercesc/util/XercesDefs.hpp>
|
||||||
|
#include <xercesc/util/PlatformUtils.hpp>
|
||||||
|
#include <xercesc/sax2/SAX2XMLReader.hpp>
|
||||||
|
#include <xercesc/sax2/XMLReaderFactory.hpp>
|
||||||
|
#include <xercesc/sax2/DefaultHandler.hpp>
|
||||||
|
#include <xercesc/sax2/Attributes.hpp>
|
||||||
|
#include <xercesc/util/XMLString.hpp>
|
||||||
|
#include <xercesc/util/XMLChar.hpp>
|
||||||
|
#include <xercesc/sax2/DefaultHandler.hpp>
|
||||||
|
#include <xercesc/framework/XMLDocumentHandler.hpp>
|
||||||
|
#include <xercesc/framework/psvi/XSElementDeclaration.hpp>
|
||||||
|
#include <xercesc/framework/psvi/XSComplexTypeDefinition.hpp>
|
||||||
|
#include <xercesc/framework/psvi/XSParticle.hpp>
|
||||||
|
#include <xercesc/framework/psvi/XSModelGroup.hpp>
|
||||||
|
#include <xercesc/framework/psvi/XSAnnotation.hpp>
|
||||||
|
#include <xercesc/framework/psvi/XSValue.hpp>
|
||||||
|
#include <xercesc/framework/XMLGrammarPoolImpl.hpp>
|
||||||
|
#include <xercesc/dom/DOM.hpp>
|
||||||
|
#include <xercesc/dom/DOMLSInput.hpp>
|
||||||
|
#include <xercesc/dom/DOMElement.hpp>
|
||||||
|
|
||||||
|
#include "../GLM.h"
|
||||||
|
#include "Util/XercesString.h"
|
||||||
|
#include "ResourceManager.h"
|
||||||
|
#include "Entity.h"
|
||||||
|
#include "ComponentInfo.h"
|
||||||
|
|
||||||
|
class EntityFileHandler
|
||||||
|
{
|
||||||
|
friend class EntityFileSAXHandler;
|
||||||
|
public:
|
||||||
|
// @param EntityID The entity found
|
||||||
|
// @param EntityID The parent of the entity
|
||||||
|
typedef std::function<void(EntityID, EntityID, const std::string&)> OnStartEntityCallback;
|
||||||
|
void SetStartEntityCallback(OnStartEntityCallback c) { m_OnStartEntityCallback = c; }
|
||||||
|
// @param EntityID The entity the component corresponds to
|
||||||
|
// @param std::string Type name of the component
|
||||||
|
typedef std::function<void(EntityID, const std::string&)> OnStartComponentCallback;
|
||||||
|
void SetStartComponentCallback(OnStartComponentCallback c) { m_OnStartComponentCallback = c; }
|
||||||
|
// @param EntityID Entity
|
||||||
|
// @param std::string Component name
|
||||||
|
// @param std::string Field name
|
||||||
|
// @param std::map<std::string, std::string> Field attribute names and values
|
||||||
|
typedef std::function<void(EntityID, const std::string&, const std::string&, const std::map<std::string, std::string>&)> OnStartFieldCallback;
|
||||||
|
void SetStartFieldCallback(OnStartFieldCallback c) { m_OnStartFieldCallback = c; }
|
||||||
|
// @param EntityID Entity
|
||||||
|
// @param std::string Component name
|
||||||
|
// @param std::string Field name
|
||||||
|
// @param char* Field data
|
||||||
|
typedef std::function<void(EntityID, const std::string&, const std::string&, const char*)> OnStartFieldDataCallback;
|
||||||
|
void SetStartFieldDataCallback(OnStartFieldDataCallback c) { m_OnStartFieldDataCallback = c; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
OnStartEntityCallback m_OnStartEntityCallback = nullptr;
|
||||||
|
OnStartComponentCallback m_OnStartComponentCallback = nullptr;
|
||||||
|
OnStartFieldCallback m_OnStartFieldCallback = nullptr;
|
||||||
|
OnStartFieldDataCallback m_OnStartFieldDataCallback = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EntityFileSAXHandler : public xercesc::DefaultHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class State
|
||||||
|
{
|
||||||
|
Unknown,
|
||||||
|
Entity,
|
||||||
|
Component,
|
||||||
|
ComponentField
|
||||||
|
};
|
||||||
|
|
||||||
|
EntityFileSAXHandler(const EntityFileHandler* handler, xercesc::SAX2XMLReader* reader)
|
||||||
|
: 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
|
||||||
|
{
|
||||||
|
std::string name = XS::ToString(_localName);
|
||||||
|
|
||||||
|
if (m_StateStack.top() == State::Unknown || m_StateStack.top() == State::Entity) {
|
||||||
|
if (name == "Entity") {
|
||||||
|
m_StateStack.push(State::Entity);
|
||||||
|
onStartEntity(attrs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (name == "EntityRef") {
|
||||||
|
onStartEntityRef(attrs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string uri = XS::ToString(_uri);
|
||||||
|
if (m_StateStack.top() == State::Entity) {
|
||||||
|
if (uri == "components") {
|
||||||
|
m_StateStack.push(State::Component);
|
||||||
|
onStartComponent(name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_StateStack.top() == State::Component) {
|
||||||
|
m_StateStack.push(State::ComponentField);
|
||||||
|
onStartComponentField(name, attrs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void 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;
|
||||||
|
xercesc::XMLGrammarPool* m_GrammarPool;
|
||||||
|
xercesc::SAX2XMLReader* m_Reader;
|
||||||
|
//State m_CurrentScope = State::Unknown;
|
||||||
|
std::stack<State> m_StateStack;
|
||||||
|
unsigned int m_NextEntityID = 0;
|
||||||
|
std::stack<EntityID> m_EntityStack;
|
||||||
|
std::string m_CurrentComponent;
|
||||||
|
std::string m_CurrentField;
|
||||||
|
std::map<std::string, std::string> m_CurrentAttributes;
|
||||||
|
|
||||||
|
void onStartEntity(const xercesc::Attributes& attrs)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void warning(const xercesc::SAXParseException& e) override
|
||||||
|
{
|
||||||
|
reportParseException("Warning", e);
|
||||||
|
}
|
||||||
|
void error(const xercesc::SAXParseException& e) override
|
||||||
|
{
|
||||||
|
reportParseException("Error", e);
|
||||||
|
}
|
||||||
|
void fatalError(const xercesc::SAXParseException& e) override
|
||||||
|
{
|
||||||
|
reportParseException("FATAL ERROR", e);
|
||||||
|
}
|
||||||
|
void resetErrors() override { }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void reportParseException(std::string type, const xercesc::SAXParseException& e)
|
||||||
|
{
|
||||||
|
char* message = xercesc::XMLString::transcode(e.getMessage());
|
||||||
|
char* systemID = xercesc::XMLString::transcode(e.getSystemId());
|
||||||
|
std::cerr << systemID << ":" << e.getLineNumber() << ":" << e.getColumnNumber() << std::endl;
|
||||||
|
std::cerr << type << ": " << message << std::endl;
|
||||||
|
xercesc::XMLString::release(&systemID);
|
||||||
|
xercesc::XMLString::release(&message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class EntityFile : public Resource
|
||||||
|
{
|
||||||
|
friend class ResourceManager;
|
||||||
|
private:
|
||||||
|
EntityFile(boost::filesystem::path path);
|
||||||
|
~EntityFile();
|
||||||
|
|
||||||
|
public:
|
||||||
|
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);
|
||||||
|
|
||||||
|
xercesc::XMLGrammarPool* GrammarPool() const { return m_GrammarPool; }
|
||||||
|
|
||||||
|
void Parse(const EntityFileHandler* handler) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
boost::filesystem::path m_FilePath;
|
||||||
|
xercesc::XMLGrammarPool* m_GrammarPool;
|
||||||
|
xercesc::SAX2XMLReader* m_SAX2XMLReader;
|
||||||
|
//std::map<std::string, ::ComponentInfo> m_ComponentInfo;
|
||||||
|
//std::vector<std::string> m_EntityReferences;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
#ifndef EntityFileParser_h__
|
||||||
|
#define EntityFileParser_h__
|
||||||
|
|
||||||
|
#include "EntityFile.h"
|
||||||
|
#include "World.h"
|
||||||
|
|
||||||
|
class EntityFileParser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
EntityFileParser(const EntityFile* entityFile);
|
||||||
|
|
||||||
|
void MergeEntities(World* world);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const EntityFile* m_EntityFile;
|
||||||
|
EntityFileHandler m_Handler;
|
||||||
|
World* m_World = nullptr;
|
||||||
|
// Maps EntityIDs local to the file to real IDs in the world after they've been
|
||||||
|
// created in order to resolve parent-child relationships.
|
||||||
|
std::map<EntityID, EntityID> m_EntityIDMapper;
|
||||||
|
|
||||||
|
void onStartEntity(EntityID entity, EntityID parent, const std::string& name);
|
||||||
|
void onStartComponent(EntityID entity, const std::string& component);
|
||||||
|
void onStartComponentField(EntityID entity, const std::string& componentType, const std::string& fieldName, const std::map<std::string, std::string>& attributes);
|
||||||
|
void onFieldData(EntityID entity, const std::string& componentType, const std::string& fieldName, const char* fieldData);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
#ifndef EntityFilePreprocessor_h__
|
||||||
|
#define EntityFilePreprocessor_h__
|
||||||
|
|
||||||
|
#include <xercesc/framework/psvi/XSElementDeclaration.hpp>
|
||||||
|
#include <xercesc/framework/psvi/XSComplexTypeDefinition.hpp>
|
||||||
|
#include <xercesc/framework/psvi/XSParticle.hpp>
|
||||||
|
#include <xercesc/framework/psvi/XSModelGroup.hpp>
|
||||||
|
#include <xercesc/framework/psvi/XSAnnotation.hpp>
|
||||||
|
#include <xercesc/framework/psvi/XSValue.hpp>
|
||||||
|
#include <xercesc/framework/MemBufFormatTarget.hpp>
|
||||||
|
#include <xercesc/framework/MemBufInputSource.hpp>
|
||||||
|
#include <xercesc/parsers/XercesDOMParser.hpp>
|
||||||
|
|
||||||
|
#include "Util/XercesString.h"
|
||||||
|
#include "ResourceManager.h"
|
||||||
|
#include "World.h"
|
||||||
|
#include "EntityFile.h"
|
||||||
|
|
||||||
|
class EntityFilePreprocessor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
EntityFilePreprocessor(const EntityFile* entityFile);
|
||||||
|
|
||||||
|
void RegisterComponents(World* world);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const EntityFile* m_EntityFile;
|
||||||
|
std::map<std::string, unsigned int> m_ComponentCounts;
|
||||||
|
std::map<std::string, ComponentInfo> m_ComponentInfo;
|
||||||
|
|
||||||
|
void onStartComponent(EntityID entity, std::string type);
|
||||||
|
void parseComponentInfo();
|
||||||
|
void parseDefaults();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
#ifndef EntityFileWriter_h__
|
||||||
|
#define EntityFileWriter_h__
|
||||||
|
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
#include <xercesc/dom/DOM.hpp>
|
||||||
|
#include <xercesc/util/XMLString.hpp>
|
||||||
|
#include <xercesc/util/PlatformUtils.hpp>
|
||||||
|
#include <xercesc/framework/LocalFileFormatTarget.hpp>
|
||||||
|
|
||||||
|
#include "Util/XercesString.h"
|
||||||
|
#include "EntityFile.h"
|
||||||
|
#include "World.h"
|
||||||
|
|
||||||
|
class EntityFileWriter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
EntityFileWriter(boost::filesystem::path file)
|
||||||
|
: m_FilePath(file)
|
||||||
|
{
|
||||||
|
using namespace xercesc;
|
||||||
|
m_DOMImplementation = DOMImplementationRegistry::getDOMImplementation(XS::ToXMLCh("LS"));
|
||||||
|
m_DOMLSSerializer = static_cast<DOMImplementationLS*>(m_DOMImplementation)->createLSSerializer();
|
||||||
|
m_DOMLSSerializer->getDomConfig()->setParameter(XMLUni::fgDOMWRTDiscardDefaultContent, true);
|
||||||
|
m_DOMLSSerializer->getDomConfig()->setParameter(XMLUni::fgDOMWRTFormatPrettyPrint, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteWorld(World* world);
|
||||||
|
void WriteEntity(World* world, EntityID entity);
|
||||||
|
|
||||||
|
private:
|
||||||
|
boost::filesystem::path m_FilePath;
|
||||||
|
xercesc::DOMImplementation* m_DOMImplementation;
|
||||||
|
xercesc::DOMLSSerializer* m_DOMLSSerializer;
|
||||||
|
|
||||||
|
void appendEntityChildren(xercesc::DOMElement* parentElement, const World* world, EntityID entity);
|
||||||
|
void appentEntityComponents(xercesc::DOMElement* parentElemetn, const World* world, EntityID entity);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,141 +0,0 @@
|
|||||||
#ifndef EntityXMLFile_h__
|
|
||||||
#define EntityXMLFile_h__
|
|
||||||
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
#include "../Common.h"
|
|
||||||
#include "../GLM.h"
|
|
||||||
#include <xercesc/dom/DOM.hpp>
|
|
||||||
#include <xercesc/dom/DOMLSInput.hpp>
|
|
||||||
#include <xercesc/dom/DOMElement.hpp>
|
|
||||||
#include <xercesc/framework/Wrapper4InputSource.hpp>
|
|
||||||
#include <xercesc/framework/LocalFileInputSource.hpp>
|
|
||||||
#include <xercesc/framework/LocalFileFormatTarget.hpp>
|
|
||||||
#include <xercesc/framework/MemBufFormatTarget.hpp>
|
|
||||||
#include <xercesc/framework/MemBufInputSource.hpp>
|
|
||||||
#include <xercesc/sax/HandlerBase.hpp>
|
|
||||||
#include <xercesc/util/PlatformUtils.hpp>
|
|
||||||
#include <xercesc/util/XMLFloat.hpp>
|
|
||||||
#include <xercesc/framework/XMLGrammarPoolImpl.hpp>
|
|
||||||
#include <xercesc/parsers/XercesDOMParser.hpp>
|
|
||||||
#include <xercesc/framework/psvi/XSElementDeclaration.hpp>
|
|
||||||
#include <xercesc/framework/psvi/XSComplexTypeDefinition.hpp>
|
|
||||||
#include <xercesc/framework/psvi/XSParticle.hpp>
|
|
||||||
#include <xercesc/framework/psvi/XSModelGroup.hpp>
|
|
||||||
#include <xercesc/framework/psvi/XSAnnotation.hpp>
|
|
||||||
#include <xercesc/framework/psvi/XSValue.hpp>
|
|
||||||
#include <xercesc/framework/XMLValidator.hpp>
|
|
||||||
|
|
||||||
#include "ResourceManager.h"
|
|
||||||
#include "Entity.h"
|
|
||||||
#include "ComponentInfo.h"
|
|
||||||
class World;
|
|
||||||
|
|
||||||
class EntityPreprocessorXMLErrorHandler : public xercesc::DOMErrorHandler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
bool handleError(const xercesc::DOMError &e) override
|
|
||||||
{
|
|
||||||
char* message = xercesc::XMLString::transcode(e.getMessage());
|
|
||||||
std::cerr << "Preprocessor DOMError: " << message << std::endl;
|
|
||||||
xercesc::XMLString::release(&message);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class EntityParserXMLErrorHandler : public xercesc::ErrorHandler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void warning(const xercesc::SAXParseException& e) override
|
|
||||||
{
|
|
||||||
reportParseException("Warning", e);
|
|
||||||
}
|
|
||||||
void error(const xercesc::SAXParseException& e) override
|
|
||||||
{
|
|
||||||
reportParseException("Error", e);
|
|
||||||
}
|
|
||||||
void fatalError(const xercesc::SAXParseException& e) override
|
|
||||||
{
|
|
||||||
reportParseException("FATAL ERROR", e);
|
|
||||||
}
|
|
||||||
void resetErrors() override { }
|
|
||||||
|
|
||||||
private:
|
|
||||||
void reportParseException(std::string type, const xercesc::SAXParseException& e)
|
|
||||||
{
|
|
||||||
char* message = xercesc::XMLString::transcode(e.getMessage());
|
|
||||||
char* systemID = xercesc::XMLString::transcode(e.getSystemId());
|
|
||||||
std::cerr << systemID << ":" << e.getLineNumber() << ":" << e.getColumnNumber() << std::endl;
|
|
||||||
std::cerr << type << ": " << message << std::endl;
|
|
||||||
xercesc::XMLString::release(&systemID);
|
|
||||||
xercesc::XMLString::release(&message);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class XSTR
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
XSTR(const XMLCh* const xmlString)
|
|
||||||
{
|
|
||||||
m_AsChar = xercesc::XMLString::transcode(xmlString);
|
|
||||||
}
|
|
||||||
|
|
||||||
XSTR(const char* normalString)
|
|
||||||
{
|
|
||||||
m_AsXMLCh = xercesc::XMLString::transcode(normalString);
|
|
||||||
}
|
|
||||||
|
|
||||||
~XSTR()
|
|
||||||
{
|
|
||||||
if (m_AsChar != nullptr) {
|
|
||||||
xercesc::XMLString::release(&m_AsChar);
|
|
||||||
}
|
|
||||||
if (m_AsXMLCh != nullptr) {
|
|
||||||
xercesc::XMLString::release(&m_AsXMLCh);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
operator const char*() const { return m_AsChar; }
|
|
||||||
operator const XMLCh*() const { return m_AsXMLCh; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
char* m_AsChar = nullptr;
|
|
||||||
XMLCh* m_AsXMLCh = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
class EntityXMLFile : public Resource
|
|
||||||
{
|
|
||||||
friend class ResourceManager;
|
|
||||||
|
|
||||||
private:
|
|
||||||
EntityXMLFile(std::string path);
|
|
||||||
|
|
||||||
public:
|
|
||||||
~EntityXMLFile();
|
|
||||||
|
|
||||||
void PopulateWorld(World* world);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static unsigned int InstanceCount;
|
|
||||||
|
|
||||||
std::string m_EntityFile;
|
|
||||||
xercesc::XMLGrammarPool* m_GrammarPool = nullptr;
|
|
||||||
EntityParserXMLErrorHandler* m_ErrorHandler = nullptr;
|
|
||||||
xercesc::XercesDOMParser* m_DOMParser = nullptr;
|
|
||||||
xercesc::DOMDocument* m_DOMDocument = nullptr;
|
|
||||||
std::map<std::string, ComponentInfo> m_ComponentInfo;
|
|
||||||
|
|
||||||
// Preprocesses the entity file to insert include-by-copy child entities
|
|
||||||
// TODO: Make this work in memory instead of saving to file
|
|
||||||
void preprocess(std::string inPath, std::string outPath);
|
|
||||||
|
|
||||||
void parseComponentInfo();
|
|
||||||
void parseDefaults();
|
|
||||||
void predictComponentAllocation();
|
|
||||||
void parseEntityGraph(World* world, xercesc::DOMElement* parent, EntityID parentEntity);
|
|
||||||
std::size_t getTypeStride(std::string typeName);
|
|
||||||
float getFloatAttribute(const xercesc::DOMElement* element, const char* attribute) const;
|
|
||||||
void writeData(const xercesc::DOMElement* element, std::string typeName, char* outData);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -13,6 +13,8 @@
|
|||||||
relay = decltype(relay)(std::bind(handler, this, std::placeholders::_1)); \
|
relay = decltype(relay)(std::bind(handler, this, std::placeholders::_1)); \
|
||||||
m_EventBroker->Subscribe(relay);
|
m_EventBroker->Subscribe(relay);
|
||||||
|
|
||||||
|
typedef unsigned int EventID;
|
||||||
|
|
||||||
class EventBroker;
|
class EventBroker;
|
||||||
|
|
||||||
class BaseEventRelay
|
class BaseEventRelay
|
||||||
@@ -31,6 +33,7 @@ public:
|
|||||||
virtual bool Receive(const std::shared_ptr<Event> event) = 0;
|
virtual bool Receive(const std::shared_ptr<Event> event) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
EventID m_EventID;
|
||||||
std::string m_ContextTypeName;
|
std::string m_ContextTypeName;
|
||||||
std::string m_EventTypeName;
|
std::string m_EventTypeName;
|
||||||
EventBroker* m_Broker;
|
EventBroker* m_Broker;
|
||||||
@@ -95,6 +98,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_IsProcessing = false;
|
bool m_IsProcessing = false;
|
||||||
|
EventID m_NextEventID = 0;
|
||||||
|
|
||||||
typedef std::string ContextTypeName_t; // typeid(ContextType).name()
|
typedef std::string ContextTypeName_t; // typeid(ContextType).name()
|
||||||
typedef std::string EventTypeName_t; // typeid(EventType).name()
|
typedef std::string EventTypeName_t; // typeid(EventType).name()
|
||||||
@@ -103,14 +107,14 @@ private:
|
|||||||
typedef std::unordered_map<ContextTypeName_t, EventRelays_t> ContextRelays_t;
|
typedef std::unordered_map<ContextTypeName_t, EventRelays_t> ContextRelays_t;
|
||||||
ContextRelays_t m_ContextRelays;
|
ContextRelays_t m_ContextRelays;
|
||||||
std::vector<BaseEventRelay*> m_RelaysToSubscribe;
|
std::vector<BaseEventRelay*> m_RelaysToSubscribe;
|
||||||
std::vector<BaseEventRelay*> m_RelaysToUnsubscribe;
|
std::vector<std::tuple<EventID, ContextTypeName_t, EventTypeName_t>> m_RelaysToUnsubscribe;
|
||||||
|
|
||||||
typedef std::list<std::pair<EventTypeName_t, std::shared_ptr<Event>>> EventQueue_t;
|
typedef std::list<std::pair<EventTypeName_t, std::shared_ptr<Event>>> EventQueue_t;
|
||||||
std::shared_ptr<EventQueue_t> m_EventQueueRead;
|
std::shared_ptr<EventQueue_t> m_EventQueueRead;
|
||||||
std::shared_ptr<EventQueue_t> m_EventQueueWrite;
|
std::shared_ptr<EventQueue_t> m_EventQueueWrite;
|
||||||
|
|
||||||
void subscribeImmediate(BaseEventRelay& relay);
|
void subscribeImmediate(BaseEventRelay& relay);
|
||||||
void unsubscribeImmediate(BaseEventRelay& relay);
|
void unsubscribeImmediate(std::tuple<EventID, ContextTypeName_t, EventTypeName_t> identifier);
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename EventType>
|
template <typename EventType>
|
||||||
|
|||||||
@@ -7,10 +7,13 @@
|
|||||||
|
|
||||||
class System
|
class System
|
||||||
{
|
{
|
||||||
|
friend class SystemPipeline;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
System(EventBroker* eventBroker)
|
System(EventBroker* eventBroker)
|
||||||
: m_EventBroker(eventBroker)
|
: m_EventBroker(eventBroker)
|
||||||
{ }
|
{ }
|
||||||
|
virtual ~System() = default;
|
||||||
|
|
||||||
EventBroker* m_EventBroker;
|
EventBroker* m_EventBroker;
|
||||||
};
|
};
|
||||||
@@ -24,6 +27,7 @@ protected:
|
|||||||
: System(eventBroker)
|
: System(eventBroker)
|
||||||
, m_ComponentType(componentType)
|
, m_ComponentType(componentType)
|
||||||
{ }
|
{ }
|
||||||
|
virtual ~PureSystem() = default;
|
||||||
|
|
||||||
const std::string m_ComponentType;
|
const std::string m_ComponentType;
|
||||||
|
|
||||||
@@ -38,6 +42,7 @@ protected:
|
|||||||
ImpureSystem(EventBroker* eventBroker)
|
ImpureSystem(EventBroker* eventBroker)
|
||||||
: System(eventBroker)
|
: System(eventBroker)
|
||||||
{ }
|
{ }
|
||||||
|
virtual ~ImpureSystem() = default;
|
||||||
|
|
||||||
virtual void Update(World* world, double dt) = 0;
|
virtual void Update(World* world, double dt) = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,23 +14,28 @@ public:
|
|||||||
{ }
|
{ }
|
||||||
~SystemPipeline()
|
~SystemPipeline()
|
||||||
{
|
{
|
||||||
for (auto& pair : m_PureSystems) {
|
for (UnorderedSystems& group : m_OrderedSystemGroups) {
|
||||||
for (auto& system : pair.second) {
|
for (auto& pair : group.Systems) {
|
||||||
delete system;
|
delete pair.second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename... Arguments>
|
template <typename T, typename... Arguments>
|
||||||
void AddSystem(Arguments... args)
|
//All systems with orderlevel 0 will be updated first, then 1, 2, etc.
|
||||||
|
void AddSystem(int updateOrderLevel, Arguments... args)
|
||||||
{
|
{
|
||||||
|
if (updateOrderLevel + 1 > m_OrderedSystemGroups.size()) {
|
||||||
|
m_OrderedSystemGroups.resize(updateOrderLevel + 1);
|
||||||
|
}
|
||||||
|
UnorderedSystems& group = m_OrderedSystemGroups[updateOrderLevel];
|
||||||
System* system = new T(m_EventBroker, args...);
|
System* system = new T(m_EventBroker, args...);
|
||||||
m_Systems[typeid(T).name()] = system;
|
group.Systems[typeid(T).name()] = system;
|
||||||
|
|
||||||
if (std::is_base_of<PureSystem, T>::value) {
|
if (std::is_base_of<PureSystem, T>::value) {
|
||||||
PureSystem* pureSystem = static_cast<PureSystem*>(system);
|
PureSystem* pureSystem = static_cast<PureSystem*>(system);
|
||||||
if (!pureSystem->m_ComponentType.empty()) {
|
if (!pureSystem->m_ComponentType.empty()) {
|
||||||
m_PureSystems[pureSystem->m_ComponentType].push_back(pureSystem);
|
group.PureSystems[pureSystem->m_ComponentType].push_back(pureSystem);
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR("Failed to add pure system \"%s\": Missing component type!", typeid(T).name());
|
LOG_ERROR("Failed to add pure system \"%s\": Missing component type!", typeid(T).name());
|
||||||
}
|
}
|
||||||
@@ -38,41 +43,47 @@ public:
|
|||||||
|
|
||||||
if (std::is_base_of<ImpureSystem, T>::value) {
|
if (std::is_base_of<ImpureSystem, T>::value) {
|
||||||
ImpureSystem* impureSystem = static_cast<ImpureSystem*>(system);
|
ImpureSystem* impureSystem = static_cast<ImpureSystem*>(system);
|
||||||
m_ImpureSystems.push_back(impureSystem);
|
group.ImpureSystems.push_back(impureSystem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Update(World* world, double dt)
|
void Update(World* world, double dt)
|
||||||
{
|
{
|
||||||
// Process events
|
for (UnorderedSystems& group : m_OrderedSystemGroups) {
|
||||||
for (auto& pair : m_Systems) {
|
// Process events
|
||||||
m_EventBroker->Process(pair.first);
|
for (auto& pair : group.Systems) {
|
||||||
}
|
m_EventBroker->Process(pair.first);
|
||||||
|
|
||||||
// Update
|
|
||||||
for (auto& pair : m_PureSystems) {
|
|
||||||
const std::string& componentName = pair.first;
|
|
||||||
auto& systems = pair.second;
|
|
||||||
const ComponentPool* pool = world->GetComponents(componentName);
|
|
||||||
if (pool == nullptr) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
for (auto& component : *pool) {
|
|
||||||
for (auto& system : systems) {
|
// Update
|
||||||
system->UpdateComponent(world, component, dt);
|
for (auto& pair : group.PureSystems) {
|
||||||
|
const std::string& componentName = pair.first;
|
||||||
|
auto& systems = pair.second;
|
||||||
|
const ComponentPool* pool = world->GetComponents(componentName);
|
||||||
|
if (pool == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (auto& component : *pool) {
|
||||||
|
for (auto& system : systems) {
|
||||||
|
system->UpdateComponent(world, component, dt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
for (auto& system : group.ImpureSystems) {
|
||||||
for (auto& system : m_ImpureSystems) {
|
system->Update(world, dt);
|
||||||
system->Update(world, dt);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EventBroker* m_EventBroker;
|
EventBroker* m_EventBroker;
|
||||||
std::map<std::string, System*> m_Systems;
|
struct UnorderedSystems
|
||||||
std::map<std::string, std::vector<PureSystem*>> m_PureSystems;
|
{
|
||||||
std::vector<ImpureSystem*> m_ImpureSystems;
|
std::map<std::string, System*> Systems;
|
||||||
|
std::map<std::string, std::vector<PureSystem*>> PureSystems;
|
||||||
|
std::vector<ImpureSystem*> ImpureSystems;
|
||||||
|
};
|
||||||
|
std::vector<UnorderedSystems> m_OrderedSystemGroups;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#ifndef Transform_h__
|
||||||
|
#define Transform_h__
|
||||||
|
|
||||||
|
#include "../GLM.h"
|
||||||
|
#include "World.h"
|
||||||
|
|
||||||
|
namespace Transform
|
||||||
|
{
|
||||||
|
|
||||||
|
glm::vec3 AbsolutePosition(World* world, EntityID entity);
|
||||||
|
glm::quat AbsoluteOrientation(World* world, EntityID entity);
|
||||||
|
glm::vec3 AbsoluteScale(World* world, EntityID entity);
|
||||||
|
glm::mat4 ModelMatrix(EntityID entity, World* world);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
#ifndef Util_XercesString_h__
|
||||||
|
#define Util_XercesString_h__
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <xercesc/util/XercesDefs.hpp>
|
||||||
|
#include <xercesc/util/XMLString.hpp>
|
||||||
|
|
||||||
|
namespace XS
|
||||||
|
{
|
||||||
|
|
||||||
|
class ToString
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ToString(const XMLCh* const str) { m_AsChar = xercesc::XMLString::transcode(str); }
|
||||||
|
~ToString()
|
||||||
|
{
|
||||||
|
if (m_AsChar != nullptr) {
|
||||||
|
xercesc::XMLString::release(&m_AsChar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
operator std::string() const { return std::string(m_AsChar); }
|
||||||
|
private:
|
||||||
|
char* m_AsChar = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ToXMLCh
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ToXMLCh(const std::string str) { m_Transcoded = xercesc::XMLString::transcode(str.c_str()); }
|
||||||
|
ToXMLCh(const char* str) { m_Transcoded = xercesc::XMLString::transcode(str); }
|
||||||
|
~ToXMLCh()
|
||||||
|
{
|
||||||
|
if (m_Transcoded != nullptr) {
|
||||||
|
xercesc::XMLString::release(&m_Transcoded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
operator const XMLCh*() const { return m_Transcoded; }
|
||||||
|
private:
|
||||||
|
XMLCh* m_Transcoded = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -16,13 +16,14 @@ public:
|
|||||||
EntityID CreateEntity(EntityID parent = 0);
|
EntityID CreateEntity(EntityID parent = 0);
|
||||||
// Delete entity and all components within
|
// Delete entity and all components within
|
||||||
void DeleteEntity(EntityID entity);
|
void DeleteEntity(EntityID entity);
|
||||||
|
// Check if an entity exists
|
||||||
|
bool ValidEntity(EntityID entity) const;
|
||||||
// Register a component type and allocate space for it
|
// Register a component type and allocate space for it
|
||||||
void RegisterComponent(ComponentInfo& ci);
|
void RegisterComponent(ComponentInfo& ci);
|
||||||
// Attach a component to an entity and fill it with default values
|
// Attach a component to an entity and fill it with default values
|
||||||
ComponentWrapper AttachComponent(EntityID entity, std::string componentType);
|
ComponentWrapper AttachComponent(EntityID entity, std::string componentType);
|
||||||
// Check if an entity has a component
|
// Check if an entity has a component
|
||||||
bool HasComponent(EntityID entity, std::string componentType);
|
bool HasComponent(EntityID entity, std::string componentType) const;
|
||||||
// Get a component of an entity
|
// Get a component of an entity
|
||||||
ComponentWrapper GetComponent(EntityID entity, std::string componentType);
|
ComponentWrapper GetComponent(EntityID entity, std::string componentType);
|
||||||
// Delete a component off an entity
|
// Delete a component off an entity
|
||||||
@@ -37,14 +38,19 @@ public:
|
|||||||
const std::unordered_map<std::string, ComponentPool*>& GetComponentPools() const { return m_ComponentPools; }
|
const std::unordered_map<std::string, ComponentPool*>& GetComponentPools() const { return m_ComponentPools; }
|
||||||
// Get the entity children map
|
// Get the entity children map
|
||||||
const std::unordered_multimap<EntityID, EntityID>& GetEntityChildren() const { return m_EntityChildren; }
|
const std::unordered_multimap<EntityID, EntityID>& GetEntityChildren() const { return m_EntityChildren; }
|
||||||
|
// Set the textual name of an entity
|
||||||
|
void SetName(EntityID entity, const std::string& name);
|
||||||
|
// Get the textual name of an entity
|
||||||
|
std::string GetName(EntityID entity) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EntityID m_CurrentEntityID = 1;
|
EntityID m_CurrentEntityID = 0;
|
||||||
|
|
||||||
std::unordered_map<EntityID, EntityID> m_EntityParents;
|
std::unordered_map<EntityID, EntityID> m_EntityParents;
|
||||||
// TODO: This should be a more effective structure
|
// TODO: This should be a more effective structure
|
||||||
std::unordered_multimap<EntityID, EntityID> m_EntityChildren;
|
std::unordered_multimap<EntityID, EntityID> m_EntityChildren;
|
||||||
std::unordered_map<std::string, ComponentPool*> m_ComponentPools;
|
std::unordered_map<std::string, ComponentPool*> m_ComponentPools;
|
||||||
|
std::unordered_map<EntityID, std::string> m_EntityNames;
|
||||||
|
|
||||||
EntityID generateEntityID();
|
EntityID generateEntityID();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include <imgui/imgui.h>
|
#include <imgui/imgui.h>
|
||||||
#include <glm/gtx/common.hpp>
|
#include <glm/gtx/common.hpp>
|
||||||
#include <boost/filesystem/path.hpp>
|
#include <boost/filesystem/path.hpp>
|
||||||
|
#include <nativefiledialog/nfd.h>
|
||||||
#include "../Core/System.h"
|
#include "../Core/System.h"
|
||||||
#include "../Core/EMousePress.h"
|
#include "../Core/EMousePress.h"
|
||||||
#include "../Core/EMouseRelease.h"
|
#include "../Core/EMouseRelease.h"
|
||||||
@@ -8,9 +9,11 @@
|
|||||||
#include "../Core/ConfigFile.h"
|
#include "../Core/ConfigFile.h"
|
||||||
#include "../Input/EInputCommand.h"
|
#include "../Input/EInputCommand.h"
|
||||||
#include "../Rendering/IRenderer.h"
|
#include "../Rendering/IRenderer.h"
|
||||||
#include "../Rendering/EPicking.h"
|
#include "../Core/Transform.h"
|
||||||
#include "../Core/EFileDropped.h"
|
#include "../Core/EFileDropped.h"
|
||||||
#include "../Rendering/RenderQueueFactory.h"
|
#include "../Core/EntityFilePreprocessor.h"
|
||||||
|
#include "../Core/EntityFileParser.h"
|
||||||
|
#include "../Core/EntityFileWriter.h"
|
||||||
|
|
||||||
class EditorSystem : public ImpureSystem
|
class EditorSystem : public ImpureSystem
|
||||||
{
|
{
|
||||||
@@ -22,9 +25,12 @@ public:
|
|||||||
private:
|
private:
|
||||||
IRenderer* m_Renderer;
|
IRenderer* m_Renderer;
|
||||||
World* m_World = nullptr;
|
World* m_World = nullptr;
|
||||||
|
Camera* m_Camera = nullptr;
|
||||||
|
|
||||||
bool m_Enabled;
|
bool m_Enabled;
|
||||||
bool m_Visible;
|
bool m_Visible;
|
||||||
|
boost::filesystem::path m_DefaultEntityDir;
|
||||||
|
boost::filesystem::path m_CurrentFile;
|
||||||
std::vector<glm::vec2> m_PickingQueue;
|
std::vector<glm::vec2> m_PickingQueue;
|
||||||
|
|
||||||
enum class WidgetMode
|
enum class WidgetMode
|
||||||
@@ -41,22 +47,27 @@ private:
|
|||||||
Global
|
Global
|
||||||
} m_WidgetSpace = WidgetSpace::Global;
|
} m_WidgetSpace = WidgetSpace::Global;
|
||||||
|
|
||||||
EntityID m_Widget = 0;
|
EntityID m_Widget = EntityID_Invalid;
|
||||||
EntityID m_WidgetX = 0;
|
EntityID m_WidgetX = EntityID_Invalid;
|
||||||
EntityID m_WidgetPlaneX = 0;
|
EntityID m_WidgetPlaneX = EntityID_Invalid;
|
||||||
EntityID m_WidgetY = 0;
|
EntityID m_WidgetY = EntityID_Invalid;
|
||||||
EntityID m_WidgetPlaneY = 0;
|
EntityID m_WidgetPlaneY = EntityID_Invalid;
|
||||||
EntityID m_WidgetZ = 0;
|
EntityID m_WidgetZ = EntityID_Invalid;
|
||||||
EntityID m_WidgetPlaneZ = 0;
|
EntityID m_WidgetPlaneZ = EntityID_Invalid;
|
||||||
EntityID m_WidgetOrigin = 0;
|
EntityID m_WidgetOrigin = EntityID_Invalid;
|
||||||
glm::vec3 m_WidgetCurrentAxis;
|
glm::vec3 m_WidgetCurrentAxis;
|
||||||
float m_WidgetPickingDepth = 0.f;
|
float m_WidgetPickingDepth = 0.f;
|
||||||
|
glm::vec3 m_WidgetPickingPosition = glm::vec3(0);
|
||||||
|
|
||||||
EntityID m_Selection = 0;
|
EntityID m_Selection = EntityID_Invalid;
|
||||||
EntityID m_LastSelection = 0;
|
EntityID m_LastSelection = EntityID_Invalid;
|
||||||
|
EntityID m_UIDraggingEntity = EntityID_Invalid;
|
||||||
glm::vec3 m_Position;
|
glm::vec3 m_Position;
|
||||||
std::string m_LastDroppedFile;
|
std::string m_LastDroppedFile;
|
||||||
|
|
||||||
|
static boost::filesystem::path openDialog(boost::filesystem::path defaultPath);
|
||||||
|
static boost::filesystem::path saveDialog(boost::filesystem::path defaultPath);
|
||||||
|
|
||||||
EventRelay<EditorSystem, Events::InputCommand> m_EInputCommand;
|
EventRelay<EditorSystem, Events::InputCommand> m_EInputCommand;
|
||||||
bool OnInputCommand(const Events::InputCommand& e);
|
bool OnInputCommand(const Events::InputCommand& e);
|
||||||
EventRelay<EditorSystem, Events::MouseRelease> m_EMouseRelease;
|
EventRelay<EditorSystem, Events::MouseRelease> m_EMouseRelease;
|
||||||
@@ -65,15 +76,19 @@ private:
|
|||||||
bool OnMousePress(const Events::MousePress& e);
|
bool OnMousePress(const Events::MousePress& e);
|
||||||
EventRelay<EditorSystem, Events::MouseMove> m_EMouseMove;
|
EventRelay<EditorSystem, Events::MouseMove> m_EMouseMove;
|
||||||
bool OnMouseMove(const Events::MouseMove& e);
|
bool OnMouseMove(const Events::MouseMove& e);
|
||||||
EventRelay<EditorSystem, Events::Picking> m_EPicking;
|
|
||||||
bool OnPicking(const Events::Picking& e);
|
|
||||||
EventRelay<EditorSystem, Events::FileDropped> m_EFileDropped;
|
EventRelay<EditorSystem, Events::FileDropped> m_EFileDropped;
|
||||||
bool OnFileDropped(const Events::FileDropped& e);
|
bool OnFileDropped(const Events::FileDropped& e);
|
||||||
|
|
||||||
|
void Picking();
|
||||||
|
void createWidget();
|
||||||
void updateWidget();
|
void updateWidget();
|
||||||
void setWidgetMode(WidgetMode newMode);
|
void setWidgetMode(WidgetMode newMode);
|
||||||
void setWidgetSpace(WidgetSpace space);
|
void setWidgetSpace(WidgetSpace space);
|
||||||
void drawUI(World* world, double dt);
|
void drawUI(World* world, double dt);
|
||||||
bool createDeleteButton(std::string componentType);
|
bool createDeleteButton(std::string componentType);
|
||||||
|
bool createEntityNode(World* world, EntityID entity);
|
||||||
void changeParent(EntityID entity, EntityID newParent);
|
void changeParent(EntityID entity, EntityID newParent);
|
||||||
|
void fileImport(World* world);
|
||||||
|
void fileSave(World* world);
|
||||||
|
void fileSaveAs(World* world);
|
||||||
};
|
};
|
||||||
@@ -40,7 +40,7 @@ public:
|
|||||||
m_TexturePressed = resourceName;
|
m_TexturePressed = resourceName;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Draw(RenderQueueCollection& rq) override
|
void Draw(RenderScene& rq) override
|
||||||
{
|
{
|
||||||
if (m_Texture == nullptr && !m_TextureReleased.empty()) {
|
if (m_Texture == nullptr && !m_TextureReleased.empty()) {
|
||||||
SetTexture(m_TextureReleased);
|
SetTexture(m_TextureReleased);
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ public:
|
|||||||
|
|
||||||
virtual void Update(double dt) { }
|
virtual void Update(double dt) { }
|
||||||
|
|
||||||
void DrawLayered(RenderQueueCollection& rq)
|
void DrawLayered(RenderScene& rq)
|
||||||
{
|
{
|
||||||
if (this->Hidden())
|
if (this->Hidden())
|
||||||
return;
|
return;
|
||||||
@@ -232,7 +232,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Draw(RenderQueueCollection& rq) { }
|
virtual void Draw(RenderScene& rq) { }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
::EventBroker* m_EventBroker;
|
::EventBroker* m_EventBroker;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ public:
|
|||||||
void EnableScissor() { m_ScissorEnabled = true; }
|
void EnableScissor() { m_ScissorEnabled = true; }
|
||||||
void DisableScissor() { m_ScissorEnabled = false; }
|
void DisableScissor() { m_ScissorEnabled = false; }
|
||||||
|
|
||||||
void Draw(RenderQueueCollection& rq) override
|
void Draw(RenderScene& rq) override
|
||||||
{
|
{
|
||||||
if (m_Texture == nullptr)
|
if (m_Texture == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
#include <glm/common.hpp>
|
#include <glm/common.hpp>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
@@ -15,6 +16,7 @@
|
|||||||
#include "Core/EventBroker.h"
|
#include "Core/EventBroker.h"
|
||||||
#include "Core/ConfigFile.h"
|
#include "Core/ConfigFile.h"
|
||||||
#include "Input/EInputCommand.h"
|
#include "Input/EInputCommand.h"
|
||||||
|
#include "Core/EPlayerDamage.h"
|
||||||
|
|
||||||
class Client : public Network
|
class Client : public Network
|
||||||
{
|
{
|
||||||
@@ -23,7 +25,6 @@ public:
|
|||||||
~Client();
|
~Client();
|
||||||
void Start(World* world, EventBroker* eventBroker) override;
|
void Start(World* world, EventBroker* eventBroker) override;
|
||||||
void Update() override;
|
void Update() override;
|
||||||
void Close();
|
|
||||||
private:
|
private:
|
||||||
// Assio UDP logic
|
// Assio UDP logic
|
||||||
boost::asio::ip::udp::endpoint m_ReceiverEndpoint;
|
boost::asio::ip::udp::endpoint m_ReceiverEndpoint;
|
||||||
@@ -32,9 +33,7 @@ private:
|
|||||||
|
|
||||||
// Sending message to server logic
|
// Sending message to server logic
|
||||||
int bytesRead = -1;
|
int bytesRead = -1;
|
||||||
char readBuf[1024] = { 0 };
|
char readBuf[INPUTSIZE] = { 0 };
|
||||||
int snapshotInterval = 33;
|
|
||||||
std::clock_t previousSnapshotMessage = std::clock();
|
|
||||||
|
|
||||||
// Packet loss logic
|
// Packet loss logic
|
||||||
unsigned int m_PacketID = 0;
|
unsigned int m_PacketID = 0;
|
||||||
@@ -45,40 +44,50 @@ private:
|
|||||||
World* m_World;
|
World* m_World;
|
||||||
std::string m_PlayerName;
|
std::string m_PlayerName;
|
||||||
int m_PlayerID = -1;
|
int m_PlayerID = -1;
|
||||||
|
EntityID m_ServerEntityID = std::numeric_limits<EntityID>::max();
|
||||||
|
// Server Client Lookup map
|
||||||
|
// Assumes that root node for client and server is EntityID 0.
|
||||||
|
|
||||||
|
// Don't Add items to these two maps with insert, use insertIntoServerClientMaps(EntityID, EntityID)!!!!
|
||||||
|
std::unordered_map<EntityID, EntityID> m_ServerIDToClientID;
|
||||||
|
std::unordered_map<EntityID, EntityID> m_ClientIDToServerID;
|
||||||
|
|
||||||
// Network logic
|
// Network logic
|
||||||
PlayerDefinition m_PlayerDefinitions[MAXCONNECTIONS];
|
PlayerDefinition m_PlayerDefinitions[MAXCONNECTIONS];
|
||||||
SnapshotDefinitions m_NextSnapshot;
|
SnapshotDefinitions m_NextSnapshot;
|
||||||
bool m_ThreadIsRunning = true;
|
|
||||||
double m_DurationOfPingTime;
|
double m_DurationOfPingTime;
|
||||||
std::clock_t m_StartPingTime;
|
std::clock_t m_StartPingTime;
|
||||||
// Use to check if we should send disconnect message
|
|
||||||
// if game is turned of by closing window.
|
|
||||||
bool m_WasStarted = false;
|
|
||||||
|
|
||||||
// Private member functions
|
// Private member functions
|
||||||
void readFromServer();
|
void readFromServer();
|
||||||
void sendSnapshotToServer();
|
int receive(char* data, size_t length);
|
||||||
int receive(char* data, size_t length);
|
|
||||||
void send(Packet& packet);
|
void send(Packet& packet);
|
||||||
void connect();
|
void connect();
|
||||||
void disconnect();
|
void disconnect();
|
||||||
void ping();
|
void ping();
|
||||||
void moveMessageHead(char*& data, size_t& length, size_t stepSize);
|
|
||||||
void parseMessageType(Packet& packet);
|
void parseMessageType(Packet& packet);
|
||||||
void parseEventMessage(Packet& packet);
|
void updateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID, const std::string& componentType);
|
||||||
void parseConnect(Packet& packet);
|
void parseConnect(Packet& packet);
|
||||||
|
void parsePlayerConnected(Packet& packet);
|
||||||
void parsePing();
|
void parsePing();
|
||||||
void parseServerPing();
|
void parseServerPing();
|
||||||
void parseSnapshot(Packet& packet);
|
void parseSnapshot(Packet& packet);
|
||||||
void identifyPacketLoss();
|
void identifyPacketLoss();
|
||||||
bool isConnected();
|
bool isConnected();
|
||||||
EntityID createPlayer();
|
EntityID createPlayer();
|
||||||
|
// 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);
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
EventBroker* m_EventBroker;
|
EventBroker* m_EventBroker;
|
||||||
EventRelay<Client, Events::InputCommand> m_EInputCommand;
|
EventRelay<Client, Events::InputCommand> m_EInputCommand;
|
||||||
bool OnInputCommand(const Events::InputCommand &e);
|
bool OnInputCommand(const Events::InputCommand& e);
|
||||||
|
EventRelay<Client, Events::PlayerDamage> m_EPlayeDamage;
|
||||||
|
bool OnPlayerDamage(const Events::PlayerDamage& e);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -11,7 +11,9 @@ enum class MessageType
|
|||||||
ServerPing,
|
ServerPing,
|
||||||
Message,
|
Message,
|
||||||
Snapshot,
|
Snapshot,
|
||||||
Event,
|
OnInputCommand,
|
||||||
|
OnPlayerDamage,
|
||||||
|
PlayerConnected
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
#include "Network/Packet.h"
|
#include "Network/Packet.h"
|
||||||
|
|
||||||
#define MAXCONNECTIONS 8
|
#define MAXCONNECTIONS 8
|
||||||
#define INPUTSIZE 128
|
#define INPUTSIZE 4097
|
||||||
|
|
||||||
class Network
|
class Network
|
||||||
{
|
{
|
||||||
@@ -14,7 +14,6 @@ public:
|
|||||||
virtual ~Network() { };
|
virtual ~Network() { };
|
||||||
virtual void Start(World* m_world, EventBroker *eventBroker) = 0;
|
virtual void Start(World* m_world, EventBroker *eventBroker) = 0;
|
||||||
virtual void Update() = 0;
|
virtual void Update() = 0;
|
||||||
virtual void Close() = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -14,15 +14,17 @@ public:
|
|||||||
Packet(MessageType type, unsigned int& packetID);
|
Packet(MessageType type, unsigned int& packetID);
|
||||||
// Used to create packet from already existing data buffer.
|
// Used to create packet from already existing data buffer.
|
||||||
Packet(char* data, const int sizeOfPacket);
|
Packet(char* data, const int sizeOfPacket);
|
||||||
|
|
||||||
~Packet();
|
~Packet();
|
||||||
|
void Init(MessageType type, unsigned int& packetID);
|
||||||
|
|
||||||
// Add primitive types like int, float, char...
|
// Add primitive types like int, float, char...
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void WritePrimitive(T val)
|
void WritePrimitive(T val)
|
||||||
{
|
{
|
||||||
// Check if we are trying to add more than the package can fit.
|
// Check if we are trying to add more than the package can fit.
|
||||||
if (m_MaxPacketSize < m_Offset + sizeof(T)) {
|
if (m_MaxPacketSize < m_Offset + sizeof(T)) {
|
||||||
LOG_WARNING("Packet AddPrimitive(): You are trying to add more than we have allocated for!");
|
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();
|
||||||
}
|
}
|
||||||
memcpy(m_Data + m_Offset, &val, sizeof(T));
|
memcpy(m_Data + m_Offset, &val, sizeof(T));
|
||||||
m_Offset += sizeof(T);
|
m_Offset += sizeof(T);
|
||||||
@@ -41,7 +43,7 @@ public:
|
|||||||
return returnValue;
|
return returnValue;
|
||||||
}
|
}
|
||||||
// Add a string to the message
|
// Add a string to the message
|
||||||
void WriteString(std::string str);
|
void WriteString(const std::string& str);
|
||||||
// Add data to the message
|
// Add data to the message
|
||||||
void WriteData(char* data, int sizeOfData);
|
void WriteData(char* data, int sizeOfData);
|
||||||
// Pops the first element as if it was a string.
|
// Pops the first element as if it was a string.
|
||||||
@@ -50,12 +52,15 @@ public:
|
|||||||
|
|
||||||
int Size() { return m_Offset; };
|
int Size() { return m_Offset; };
|
||||||
char* Data() { return m_Data; };
|
char* Data() { return m_Data; };
|
||||||
|
unsigned int DataReadSize() { return m_ReturnDataOffset; }
|
||||||
|
unsigned int MaxSize() { return m_MaxPacketSize; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char* m_Data;
|
char* m_Data;
|
||||||
unsigned int m_ReturnDataOffset = 0;
|
unsigned int m_ReturnDataOffset = 0;
|
||||||
int m_Offset = 0;
|
int m_Offset = 0;
|
||||||
unsigned int m_MaxPacketSize = 128;
|
unsigned int m_MaxPacketSize = 512;
|
||||||
|
void resizeData();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -12,6 +12,8 @@
|
|||||||
#include "Core/World.h"
|
#include "Core/World.h"
|
||||||
#include "Core/EventBroker.h"
|
#include "Core/EventBroker.h"
|
||||||
#include "Network/Network.h"
|
#include "Network/Network.h"
|
||||||
|
#include "Input/EInputCommand.h"
|
||||||
|
#include "Core/EPlayerDamage.h"
|
||||||
|
|
||||||
class Server : public Network
|
class Server : public Network
|
||||||
{
|
{
|
||||||
@@ -20,8 +22,6 @@ public:
|
|||||||
~Server();
|
~Server();
|
||||||
void Start(World* m_world, EventBroker *eventBroker) override;
|
void Start(World* m_world, EventBroker *eventBroker) override;
|
||||||
void Update() override;
|
void Update() override;
|
||||||
void Close();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// UDP logic
|
// UDP logic
|
||||||
boost::asio::ip::udp::endpoint m_ReceiverEndpoint;
|
boost::asio::ip::udp::endpoint m_ReceiverEndpoint;
|
||||||
@@ -30,7 +30,7 @@ private:
|
|||||||
PlayerDefinition m_PlayerDefinitions[MAXCONNECTIONS];
|
PlayerDefinition m_PlayerDefinitions[MAXCONNECTIONS];
|
||||||
|
|
||||||
// Sending messages to client logic
|
// Sending messages to client logic
|
||||||
char readBuffer[1024] = { 0 };
|
char readBuffer[INPUTSIZE] = { 0 };
|
||||||
int bytesRead = 0;
|
int bytesRead = 0;
|
||||||
// time for previouse message
|
// time for previouse message
|
||||||
std::clock_t previousePingMessage = std::clock();
|
std::clock_t previousePingMessage = std::clock();
|
||||||
@@ -48,36 +48,29 @@ private:
|
|||||||
// Game logic
|
// Game logic
|
||||||
World* m_World;
|
World* m_World;
|
||||||
EventBroker* m_EventBroker;
|
EventBroker* m_EventBroker;
|
||||||
// vec.size() = ammount of players to create, stores playerID's
|
|
||||||
std::vector<unsigned int> m_PlayersToCreate;
|
|
||||||
|
|
||||||
// Packet loss logic
|
// Packet loss logic
|
||||||
unsigned int m_PacketID;
|
unsigned int m_PacketID;
|
||||||
unsigned int m_PreviousPacketID;
|
unsigned int m_PreviousPacketID;
|
||||||
unsigned int m_SendPacketID;
|
unsigned int m_SendPacketID;
|
||||||
|
|
||||||
// Close logic
|
|
||||||
bool m_ThreadIsRunning = true;
|
|
||||||
|
|
||||||
// Private member functions
|
// Private member functions
|
||||||
int receive(char* data, size_t length);
|
int receive(char* data, size_t length);
|
||||||
void readFromClients();
|
void readFromClients();
|
||||||
void send(Packet& packet, int playerID);
|
void send(Packet& packet, int playerID);
|
||||||
void send(Packet& packet);
|
void send(Packet& packet);
|
||||||
void moveMessageHead(char*& data, size_t& length, size_t stepSize);
|
|
||||||
void broadcast(std::string message);
|
|
||||||
void broadcast(Packet& packet);
|
void broadcast(Packet& packet);
|
||||||
void sendSnapshot();
|
void sendSnapshot();
|
||||||
void sendPing();
|
void sendPing();
|
||||||
void checkForTimeOuts();
|
void checkForTimeOuts();
|
||||||
void disconnect(int i);
|
void disconnect(int i);
|
||||||
void parseMessageType(Packet& packet);
|
void parseMessageType(Packet& packet);
|
||||||
void parseEvent(Packet& packet);
|
void parseOnInputCommand(Packet& packet);
|
||||||
|
void parseOnPlayerDamage(Packet& packet);
|
||||||
void parseConnect(Packet& packet);
|
void parseConnect(Packet& packet);
|
||||||
void parseDisconnect();
|
void parseDisconnect();
|
||||||
void parseClientPing();
|
void parseClientPing();
|
||||||
void parseServerPing();
|
void parseServerPing();
|
||||||
void parseSnapshot(Packet& packet);
|
|
||||||
void identifyPacketLoss();
|
void identifyPacketLoss();
|
||||||
EntityID createPlayer();
|
EntityID createPlayer();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -26,13 +26,12 @@ public:
|
|||||||
glm::quat Orientation() const { return m_Orientation; }
|
glm::quat Orientation() const { return m_Orientation; }
|
||||||
void SetOrientation(glm::quat val);
|
void SetOrientation(glm::quat val);
|
||||||
|
|
||||||
/*float Pitch() const { return m_Pitch; }
|
|
||||||
void Pitch(float val);
|
|
||||||
float Yaw() const { return m_Yaw; }
|
|
||||||
void Yaw(float val);*/
|
|
||||||
|
|
||||||
glm::mat4 ProjectionMatrix() const { return m_ProjectionMatrix; }
|
glm::mat4 ProjectionMatrix() const { return m_ProjectionMatrix; }
|
||||||
|
void SetProjectionMatrix(glm::mat4 val);
|
||||||
|
|
||||||
glm::mat4 ViewMatrix() const { return m_ViewMatrix; }
|
glm::mat4 ViewMatrix() const { return m_ViewMatrix; }
|
||||||
|
void SetViewMatrix(glm::mat4 val);
|
||||||
|
|
||||||
|
|
||||||
float AspectRatio() const { return m_AspectRatio; }
|
float AspectRatio() const { return m_AspectRatio; }
|
||||||
void SetAspectRatio(float val);
|
void SetAspectRatio(float val);
|
||||||
@@ -46,11 +45,10 @@ public:
|
|||||||
float FarClip() const { return m_FarClip; }
|
float FarClip() const { return m_FarClip; }
|
||||||
void SetFarClip(float val);
|
void SetFarClip(float val);
|
||||||
|
|
||||||
|
void UpdateViewMatrix();
|
||||||
|
void UpdateProjectionMatrix();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void UpdateViewMatrix();
|
|
||||||
void UpdateProjectionMatrix();
|
|
||||||
|
|
||||||
glm::vec3 m_Position;
|
glm::vec3 m_Position;
|
||||||
glm::quat m_Orientation;
|
glm::quat m_Orientation;
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ public:
|
|||||||
: FirstPersonInputController(eventBroker, playerID)
|
: FirstPersonInputController(eventBroker, playerID)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
void SetPosition(const glm::vec3 position) { m_Position = position; }
|
||||||
|
void SetOrientation(const glm::quat orientation) { m_Orientation = orientation; }
|
||||||
|
|
||||||
const glm::vec3 Position() const { return m_Position; }
|
const glm::vec3 Position() const { return m_Position; }
|
||||||
void SetBaseSpeed(float speed) { m_BaseSpeed = speed; }
|
void SetBaseSpeed(float speed) { m_BaseSpeed = speed; }
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ public:
|
|||||||
void InitializeFrameBuffers();
|
void InitializeFrameBuffers();
|
||||||
void InitializeShaderPrograms();
|
void InitializeShaderPrograms();
|
||||||
|
|
||||||
void Draw(RenderQueueCollection& rq);
|
void Draw(RenderScene& scene);
|
||||||
|
|
||||||
//Getters
|
//Getters
|
||||||
|
|
||||||
@@ -25,12 +25,18 @@ public:
|
|||||||
private:
|
private:
|
||||||
void GenerateTexture(GLuint* texture, GLenum wrapping, GLenum filtering, glm::vec2 dimensions, GLint internalFormat, GLint format, GLenum type) const;
|
void GenerateTexture(GLuint* texture, GLenum wrapping, GLenum filtering, glm::vec2 dimensions, GLint internalFormat, GLint format, GLenum type) const;
|
||||||
|
|
||||||
|
static bool DepthSort(const std::shared_ptr<RenderJob> &i, const std::shared_ptr<RenderJob> &j)
|
||||||
|
{
|
||||||
|
return (i->Depth < j->Depth);
|
||||||
|
};
|
||||||
|
|
||||||
Texture* m_WhiteTexture;
|
Texture* m_WhiteTexture;
|
||||||
|
|
||||||
const IRenderer* m_Renderer;
|
const IRenderer* m_Renderer;
|
||||||
|
|
||||||
ShaderProgram* m_BasicForwardProgram;
|
ShaderProgram* m_BasicForwardProgram;
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -9,7 +9,7 @@ class DummyRenderer : public IRenderer
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void Initialize() override;
|
virtual void Initialize() override;
|
||||||
virtual void Draw(RenderQueueCollection& rq) override;
|
virtual void Draw(RenderFrame& rq) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
#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 = 0;
|
|
||||||
}
|
|
||||||
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
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#ifndef Events_SetCamera_h__
|
||||||
|
#define Events_SetCamera_h__
|
||||||
|
|
||||||
|
#include "../Core/EventBroker.h"
|
||||||
|
#include "../Core/Entity.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
namespace Events
|
||||||
|
{
|
||||||
|
|
||||||
|
struct SetCamera : Event
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SetCamera() { };
|
||||||
|
std::string Name;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -10,6 +10,15 @@
|
|||||||
#include "RenderQueue.h"
|
#include "RenderQueue.h"
|
||||||
#include "Model.h"
|
#include "Model.h"
|
||||||
|
|
||||||
|
struct PickData
|
||||||
|
{
|
||||||
|
EntityID Entity;
|
||||||
|
glm::vec3 Position; //World position
|
||||||
|
float Depth;
|
||||||
|
::Camera* Camera;
|
||||||
|
const ::World* World;
|
||||||
|
};
|
||||||
|
|
||||||
class IRenderer
|
class IRenderer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -20,19 +29,19 @@ public:
|
|||||||
void SetFullscreen(bool fullscreen) { m_Fullscreen = fullscreen; }
|
void SetFullscreen(bool fullscreen) { m_Fullscreen = fullscreen; }
|
||||||
bool VSYNC() const { return m_VSYNC; }
|
bool VSYNC() const { return m_VSYNC; }
|
||||||
void SetVSYNC(bool vsync) { m_VSYNC = vsync; }
|
void SetVSYNC(bool vsync) { m_VSYNC = vsync; }
|
||||||
::Camera* Camera() const { return m_Camera; }
|
::Camera* Camera() const { return m_Camera; }
|
||||||
void SetCamera(::Camera* camera)
|
void SetCamera(::Camera* camera)
|
||||||
{
|
{
|
||||||
if (camera == nullptr) {
|
if (camera == nullptr) {
|
||||||
m_Camera = m_DefaultCamera;
|
m_Camera = m_DefaultCamera;
|
||||||
} else {
|
} else {
|
||||||
m_Camera = camera;
|
m_Camera = camera;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Initialize() = 0;
|
virtual void Initialize() = 0;
|
||||||
virtual void Update(double dt) = 0;
|
virtual void Update(double dt) = 0;
|
||||||
virtual void Draw(RenderQueueCollection& rq) = 0;
|
virtual void Draw(RenderFrame& rq) = 0;
|
||||||
|
virtual PickData Pick(glm::vec2 screenCord) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Rectangle m_Resolution = Rectangle::Rectangle(1280, 720);
|
Rectangle m_Resolution = Rectangle::Rectangle(1280, 720);
|
||||||
@@ -40,9 +49,9 @@ protected:
|
|||||||
bool m_VSYNC = false;
|
bool m_VSYNC = false;
|
||||||
int m_GLVersion[2];
|
int m_GLVersion[2];
|
||||||
std::string m_GLVendor;
|
std::string m_GLVendor;
|
||||||
::Camera* m_DefaultCamera;
|
|
||||||
::Camera* m_Camera = nullptr;
|
|
||||||
GLFWwindow* m_Window = nullptr;
|
GLFWwindow* m_Window = nullptr;
|
||||||
|
::Camera* m_DefaultCamera;
|
||||||
|
::Camera* m_Camera = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // Renderer_h__
|
#endif // Renderer_h__
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
#ifndef ModelJob_h__
|
||||||
|
#define ModelJob_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 ModelJob : RenderJob
|
||||||
|
{
|
||||||
|
ModelJob(Model* model, Camera* camera, glm::mat4 matrix, ::Model::MaterialGroup texGroup, ComponentWrapper modelComponent, World* world)
|
||||||
|
: RenderJob()
|
||||||
|
{
|
||||||
|
Model = model;
|
||||||
|
TextureID = (texGroup.Texture) ? texGroup.Texture->ResourceID : 0;
|
||||||
|
DiffuseTexture = texGroup.Texture.get();
|
||||||
|
NormalTexture = texGroup.NormalMap.get();
|
||||||
|
SpecularTexture = texGroup.SpecularMap.get();
|
||||||
|
StartIndex = texGroup.StartIndex;
|
||||||
|
EndIndex = texGroup.EndIndex;
|
||||||
|
Matrix = matrix;
|
||||||
|
Color = modelComponent["Color"];
|
||||||
|
Entity = modelComponent.EntityID;
|
||||||
|
World = world;
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned int TextureID;
|
||||||
|
unsigned int ShaderID;
|
||||||
|
|
||||||
|
EntityID Entity;
|
||||||
|
glm::mat4 Matrix;
|
||||||
|
const Texture* DiffuseTexture;
|
||||||
|
const Texture* NormalTexture;
|
||||||
|
const Texture* SpecularTexture;
|
||||||
|
float Shininess = 0.f;
|
||||||
|
glm::vec4 Color;
|
||||||
|
const ::Model* Model = nullptr;
|
||||||
|
unsigned int StartIndex = 0;
|
||||||
|
unsigned int EndIndex = 0;
|
||||||
|
const World* World;
|
||||||
|
|
||||||
|
void CalculateHash() override
|
||||||
|
{
|
||||||
|
Hash = TextureID;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -5,9 +5,9 @@
|
|||||||
#include "PickingPassState.h"
|
#include "PickingPassState.h"
|
||||||
#include "FrameBuffer.h"
|
#include "FrameBuffer.h"
|
||||||
#include "ShaderProgram.h"
|
#include "ShaderProgram.h"
|
||||||
#include "Util/UnorderedMapVec2.h"
|
#include "Util/UnorderedMapiVec2.h"
|
||||||
#include "../Core/EventBroker.h"
|
#include "../Core/EventBroker.h"
|
||||||
#include "EPicking.h"
|
#include "../Core/World.h"
|
||||||
|
|
||||||
class PickingPass
|
class PickingPass
|
||||||
{
|
{
|
||||||
@@ -18,16 +18,19 @@ public:
|
|||||||
void InitializeFrameBuffers();
|
void InitializeFrameBuffers();
|
||||||
void InitializeShaderPrograms();
|
void InitializeShaderPrograms();
|
||||||
|
|
||||||
void Draw(RenderQueueCollection& rq);
|
void Draw(RenderScene& scene);
|
||||||
|
void ClearPicking();
|
||||||
|
|
||||||
|
|
||||||
//Getters
|
//Getters
|
||||||
const ShaderProgram& PickingProgram() const { return *m_PickingProgram; }
|
const ShaderProgram& PickingProgram() const { return *m_PickingProgram; }
|
||||||
const std::unordered_map<glm::vec2, EntityID>& PickingColorsToEntity() const { return m_PickingColorsToEntity; }
|
//const std::unordered_map<glm::ivec2, EntityID>& PickingColorsToEntity() const { return m_PickingColorsToEntity; }
|
||||||
GLuint PickingTexture() const { return m_PickingTexture; }
|
GLuint PickingTexture() const { return m_PickingTexture; }
|
||||||
GLuint DepthBuffer() const { return m_DepthBuffer; }
|
GLuint DepthBuffer() const { return m_DepthBuffer; }
|
||||||
const FrameBuffer& PickingBuffer() const { return m_PickingBuffer; }
|
const FrameBuffer& PickingBuffer() const { return m_PickingBuffer; }
|
||||||
|
|
||||||
|
|
||||||
|
PickData Pick(glm::vec2 screenCoord);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void GenerateTexture(GLuint* texture, GLenum wrapping, GLenum filtering, glm::vec2 dimensions, GLint internalFormat, GLint format, GLenum type) const;
|
void GenerateTexture(GLuint* texture, GLenum wrapping, GLenum filtering, glm::vec2 dimensions, GLint internalFormat, GLint format, GLenum type) const;
|
||||||
@@ -37,13 +40,24 @@ private:
|
|||||||
const IRenderer* m_Renderer;
|
const IRenderer* m_Renderer;
|
||||||
|
|
||||||
ShaderProgram* m_PickingProgram;
|
ShaderProgram* m_PickingProgram;
|
||||||
|
Camera* m_Camera;
|
||||||
|
|
||||||
std::unordered_map<glm::vec2, EntityID> m_PickingColorsToEntity;
|
struct PickingInfo
|
||||||
|
{
|
||||||
|
EntityID Entity;
|
||||||
|
const ::World* World;
|
||||||
|
::Camera* Camera;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unordered_map<glm::ivec2, PickingInfo> m_PickingColorsToEntity;
|
||||||
|
|
||||||
GLuint m_PickingTexture;
|
GLuint m_PickingTexture;
|
||||||
GLuint m_DepthBuffer;
|
GLuint m_DepthBuffer;
|
||||||
|
|
||||||
FrameBuffer m_PickingBuffer;
|
FrameBuffer m_PickingBuffer;
|
||||||
|
|
||||||
|
int m_ColorCounter[2];
|
||||||
|
std::map<std::tuple<EntityID, const World*, Camera*>, glm::ivec2> m_EntityColors;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -46,6 +46,7 @@ public:
|
|||||||
struct MaterialGroup
|
struct MaterialGroup
|
||||||
{
|
{
|
||||||
float Shininess;
|
float Shininess;
|
||||||
|
float Transparency;
|
||||||
std::shared_ptr<::Texture> Texture;
|
std::shared_ptr<::Texture> Texture;
|
||||||
std::shared_ptr<::Texture> NormalMap;
|
std::shared_ptr<::Texture> NormalMap;
|
||||||
std::shared_ptr<::Texture> SpecularMap;
|
std::shared_ptr<::Texture> SpecularMap;
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
#ifndef RenderJob_h__
|
||||||
|
#define RenderJob_h__
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "../Common.h"
|
||||||
|
#include "../GLM.h"
|
||||||
|
#include "../Core/ComponentWrapper.h"
|
||||||
|
#include "RenderQueue.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct RenderJob
|
||||||
|
{
|
||||||
|
friend class RenderQueue;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
float Depth;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint64_t Hash;
|
||||||
|
|
||||||
|
virtual void CalculateHash() = 0;
|
||||||
|
|
||||||
|
bool operator<(const RenderJob& rhs)
|
||||||
|
{
|
||||||
|
return this->Hash < rhs.Hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -8,61 +8,13 @@
|
|||||||
#include "../GLM.h"
|
#include "../GLM.h"
|
||||||
#include "../Core/Util/Rectangle.h"
|
#include "../Core/Util/Rectangle.h"
|
||||||
#include "../Core/Entity.h"
|
#include "../Core/Entity.h"
|
||||||
|
#include "Camera.h"
|
||||||
|
#include "RenderJob.h"
|
||||||
|
#include "ModelJob.h"
|
||||||
|
|
||||||
class Model;
|
|
||||||
class Skeleton;
|
|
||||||
class Texture;
|
|
||||||
class RenderQueue;
|
|
||||||
|
|
||||||
//TODO: Render: Remove obsolete RenderJobs and fix standard values on variables.
|
|
||||||
|
|
||||||
struct RenderJob
|
|
||||||
{
|
|
||||||
friend class RenderQueue;
|
|
||||||
|
|
||||||
float Depth;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
uint64_t Hash;
|
|
||||||
|
|
||||||
virtual void CalculateHash() = 0;
|
|
||||||
|
|
||||||
bool operator<(const RenderJob& rhs)
|
|
||||||
{
|
|
||||||
return this->Hash < rhs.Hash;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ModelJob : RenderJob
|
|
||||||
{
|
|
||||||
unsigned int ShaderID = 0;
|
|
||||||
unsigned int TextureID = 0;
|
|
||||||
|
|
||||||
//TODO: RENDERER: Not sure if the best solution for pickingColor to entity link is this
|
|
||||||
EntityID Entity;
|
|
||||||
|
|
||||||
glm::mat4 ModelMatrix;
|
|
||||||
const Texture* DiffuseTexture;
|
|
||||||
const Texture* NormalTexture;
|
|
||||||
const Texture* SpecularTexture;
|
|
||||||
float Shininess = 0.f;
|
|
||||||
glm::vec4 Color;
|
|
||||||
const Model* Model = nullptr;
|
|
||||||
unsigned int StartIndex = 0;
|
|
||||||
unsigned int EndIndex = 0;
|
|
||||||
|
|
||||||
// Animation
|
|
||||||
Skeleton* Skeleton = nullptr;
|
|
||||||
bool NoRootMotion = true;
|
|
||||||
std::string AnimationName;
|
|
||||||
double AnimationTime = 0;
|
|
||||||
|
|
||||||
void CalculateHash() override
|
|
||||||
{
|
|
||||||
Hash = TextureID;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
/*
|
||||||
struct SpriteJob : RenderJob
|
struct SpriteJob : RenderJob
|
||||||
{
|
{
|
||||||
unsigned int ShaderID = 0;
|
unsigned int ShaderID = 0;
|
||||||
@@ -93,62 +45,53 @@ struct PointLightJob : RenderJob
|
|||||||
Hash = 0;
|
Hash = 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
class RenderQueue
|
struct RenderScene
|
||||||
{
|
{
|
||||||
public:
|
::Camera* Camera;
|
||||||
template <typename T>
|
std::list<std::shared_ptr<RenderJob>> ForwardJobs;
|
||||||
void Add(T &job)
|
std::list<std::shared_ptr<RenderJob>> LightJobs;
|
||||||
{
|
Rectangle Viewport;
|
||||||
job.CalculateHash();
|
|
||||||
Jobs.push_back(std::shared_ptr<T>(new T(job)));
|
|
||||||
m_Size++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Sort()
|
|
||||||
{
|
|
||||||
Jobs.sort();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Clear()
|
void Clear()
|
||||||
{
|
{
|
||||||
Jobs.clear();
|
ForwardJobs.clear();
|
||||||
m_Size = 0;
|
LightJobs.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
int Size() const { return m_Size; }
|
|
||||||
std::list<std::shared_ptr<RenderJob>>::const_iterator begin()
|
|
||||||
{
|
|
||||||
return Jobs.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::list<std::shared_ptr<RenderJob>>::const_iterator end()
|
|
||||||
{
|
|
||||||
return Jobs.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::list<std::shared_ptr<RenderJob>> Jobs;
|
|
||||||
|
|
||||||
private:
|
|
||||||
int m_Size = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RenderQueueCollection
|
struct RenderFrame
|
||||||
{
|
{
|
||||||
RenderQueue Forward;
|
public:
|
||||||
RenderQueue Lights;
|
|
||||||
|
|
||||||
void Clear()
|
void Add(RenderScene &scene)
|
||||||
{
|
{
|
||||||
Forward.Clear();
|
RenderScenes.push_back(std::shared_ptr<RenderScene>(new RenderScene(scene)));
|
||||||
Lights.Clear();
|
m_Size++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sort()
|
void Clear()
|
||||||
{
|
{
|
||||||
Forward.Sort();
|
RenderScenes.clear();
|
||||||
Lights.Sort();
|
m_Size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Size() const { return m_Size; }
|
||||||
|
std::list<std::shared_ptr<RenderScene>>::const_iterator begin()
|
||||||
|
{
|
||||||
|
return RenderScenes.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<std::shared_ptr<RenderScene>>::const_iterator end()
|
||||||
|
{
|
||||||
|
return RenderScenes.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<std::shared_ptr<RenderScene>> RenderScenes;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_Size = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
#ifndef RenderQueueFactory_h__
|
|
||||||
#define RenderQueueFactory_h__
|
|
||||||
|
|
||||||
#include "../Core/World.h"
|
|
||||||
#include "RenderQueue.h"
|
|
||||||
#include "../Core/ResourceManager.h"
|
|
||||||
#include "Model.h"
|
|
||||||
#include "../GLM.h"
|
|
||||||
|
|
||||||
class RenderQueueFactory
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
RenderQueueFactory();
|
|
||||||
void Update(World* world);
|
|
||||||
|
|
||||||
RenderQueueCollection RenderQueues() const { return m_RenderQueues; }
|
|
||||||
|
|
||||||
static glm::vec3 AbsolutePosition(World* world, EntityID entity);
|
|
||||||
static glm::quat AbsoluteOrientation(World* world, EntityID entity);
|
|
||||||
static glm::vec3 AbsoluteScale(World* world, EntityID entity);
|
|
||||||
|
|
||||||
private:
|
|
||||||
RenderQueueCollection m_RenderQueues;
|
|
||||||
|
|
||||||
void FillModels(World* world, RenderQueue* renderQueue);
|
|
||||||
void FillLights(World* world, RenderQueue* renderQueue);
|
|
||||||
|
|
||||||
glm::mat4 ModelMatrix(World* world, EntityID entity);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
#ifndef RenderSystem_h__
|
||||||
|
#define RenderSystem_h__
|
||||||
|
|
||||||
|
#include "../Core/System.h"
|
||||||
|
#include "RenderQueue.h"
|
||||||
|
#include "../GLM.h"
|
||||||
|
#include "../OpenGL.h"
|
||||||
|
#include "../Core/ResourceManager.h"
|
||||||
|
#include "ESetCamera.h"
|
||||||
|
#include "Model.h"
|
||||||
|
#include "../Core/EKeyDown.h"
|
||||||
|
#include "../Input/EInputCommand.h"
|
||||||
|
#include "Camera.h"
|
||||||
|
#include "ModelJob.h"
|
||||||
|
#include "Renderer.h"
|
||||||
|
#include "../Core/Transform.h"
|
||||||
|
#include "DebugCameraInputController.h"
|
||||||
|
|
||||||
|
class RenderSystem : public ImpureSystem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RenderSystem(EventBroker* eventBrokerer, const IRenderer* renderer, RenderFrame* renderFrame);
|
||||||
|
~RenderSystem();
|
||||||
|
|
||||||
|
virtual void Update(World* world, double dt) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
World* m_World = nullptr;
|
||||||
|
const IRenderer* m_Renderer;
|
||||||
|
|
||||||
|
RenderFrame* m_RenderFrame;
|
||||||
|
bool m_SwitchCamera = false;
|
||||||
|
Camera* m_Camera;
|
||||||
|
DebugCameraInputController<RenderSystem>* m_DebugCameraInputController;
|
||||||
|
|
||||||
|
std::list<ComponentWrapper> m_CameraComponents;
|
||||||
|
|
||||||
|
EventRelay<RenderSystem, Events::SetCamera> m_ESetCamera;
|
||||||
|
bool OnSetCamera(const Events::SetCamera &event);
|
||||||
|
EntityID m_CurrentCamera = EntityID_Invalid;
|
||||||
|
|
||||||
|
void switchCamera(EntityID entity);
|
||||||
|
|
||||||
|
void updateCamera(World* world, double dt);
|
||||||
|
void updateProjectionMatrix(ComponentWrapper& cameraComponent);
|
||||||
|
|
||||||
|
void fillModels(std::list<std::shared_ptr<RenderJob>>& jobs, World* world);
|
||||||
|
|
||||||
|
EventRelay<RenderSystem, Events::InputCommand> m_EInputCommand;
|
||||||
|
bool OnInputCommand(const Events::InputCommand& e);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -12,42 +12,31 @@
|
|||||||
#include "../Core/World.h"
|
#include "../Core/World.h"
|
||||||
#include "PickingPass.h"
|
#include "PickingPass.h"
|
||||||
#include "DrawScenePass.h"
|
#include "DrawScenePass.h"
|
||||||
|
|
||||||
|
|
||||||
#define TILE_SIZE 16
|
|
||||||
#define NUM_LIGHTS 3
|
|
||||||
|
|
||||||
|
|
||||||
enum lightType
|
|
||||||
{
|
|
||||||
Point,
|
|
||||||
Spot,
|
|
||||||
Directional,
|
|
||||||
Area
|
|
||||||
};
|
|
||||||
|
|
||||||
#include "../Core/EventBroker.h"
|
#include "../Core/EventBroker.h"
|
||||||
#include "EPicking.h"
|
|
||||||
#include "ImGuiRenderPass.h"
|
#include "ImGuiRenderPass.h"
|
||||||
|
#include "Camera.h"
|
||||||
|
|
||||||
class Renderer : public IRenderer
|
class Renderer : public IRenderer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Renderer(EventBroker* eventBroker)
|
Renderer(EventBroker* eventBroker, World* world)
|
||||||
: m_EventBroker(eventBroker)
|
: m_EventBroker(eventBroker)
|
||||||
|
, m_World(world)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
virtual void Initialize() override;
|
virtual void Initialize() override;
|
||||||
virtual void Update(double dt) override;
|
virtual void Update(double dt) override;
|
||||||
virtual void Draw(RenderQueueCollection& rq) override;
|
virtual void Draw(RenderFrame& frame) override;
|
||||||
|
|
||||||
|
virtual PickData Pick(glm::vec2 screenCoord) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//----------------------Variables----------------------//
|
//----------------------Variables----------------------//
|
||||||
EventBroker* m_EventBroker;
|
EventBroker* m_EventBroker;
|
||||||
|
World* m_World;
|
||||||
|
|
||||||
Texture* m_ErrorTexture;
|
Texture* m_ErrorTexture;
|
||||||
Texture* m_WhiteTexture;
|
Texture* m_WhiteTexture;
|
||||||
float m_CameraMoveSpeed;
|
|
||||||
|
|
||||||
Model* m_ScreenQuad;
|
Model* m_ScreenQuad;
|
||||||
Model* m_UnitQuad;
|
Model* m_UnitQuad;
|
||||||
@@ -68,56 +57,10 @@ private:
|
|||||||
//void PickingPass(RenderQueueCollection& rq);
|
//void PickingPass(RenderQueueCollection& rq);
|
||||||
void DrawScreenQuad(GLuint textureToDraw);
|
void DrawScreenQuad(GLuint textureToDraw);
|
||||||
|
|
||||||
//----------------------Forward+-----------------------//
|
|
||||||
void CalculateFrustum();
|
|
||||||
void CullLights();
|
|
||||||
//Frustum
|
|
||||||
struct Plane {
|
|
||||||
glm::vec3 Normal;
|
|
||||||
float d;
|
|
||||||
};
|
|
||||||
struct Frustum {
|
|
||||||
Plane Planes[4];
|
|
||||||
};
|
|
||||||
Frustum m_Frustums[80*45]; //TODO: Renderer: Make this change with resolution
|
|
||||||
|
|
||||||
//Lights
|
|
||||||
void TEMPCreateLights();
|
|
||||||
//TODO: Renderer: Add Directionllights, spotlights and area lights to this as type.
|
|
||||||
struct PointLight {
|
|
||||||
glm::vec4 Position = glm::vec4(0.f);
|
|
||||||
glm::vec4 Color = glm::vec4(1.f);
|
|
||||||
float Radius = 5.f;
|
|
||||||
float Intensity = 0.8f;
|
|
||||||
float Falloff = 0.3f;
|
|
||||||
float Padding = 1337;
|
|
||||||
};
|
|
||||||
PointLight m_PointLights[NUM_LIGHTS];
|
|
||||||
|
|
||||||
struct LightGrid {
|
|
||||||
int Amount;
|
|
||||||
int Start;
|
|
||||||
glm::vec2 Padding;
|
|
||||||
};
|
|
||||||
LightGrid m_LightGrid[80*45];
|
|
||||||
|
|
||||||
int m_LightOffset = 0;
|
|
||||||
|
|
||||||
int m_LightIndex[80*45*200];
|
|
||||||
|
|
||||||
//-------------------------SSBO------------------------//
|
|
||||||
GLuint m_FrustumSSBO = 0;
|
|
||||||
GLuint m_LightSSBO = 1;
|
|
||||||
GLuint m_LightGridSSBO = 2;
|
|
||||||
GLuint m_LightOffsetSSBO = 3;
|
|
||||||
GLuint m_LightIndexSSBO = 4;
|
|
||||||
|
|
||||||
void GenerateTexture(GLuint* texture, GLenum wrapping, GLenum filtering, glm::vec2 dimensions, GLint internalFormat, GLint format, GLenum type);
|
void GenerateTexture(GLuint* texture, GLenum wrapping, GLenum filtering, glm::vec2 dimensions, GLint internalFormat, GLint format, GLenum type);
|
||||||
//--------------------ShaderPrograms-------------------//
|
//--------------------ShaderPrograms-------------------//
|
||||||
ShaderProgram* m_BasicForwardProgram;
|
ShaderProgram* m_BasicForwardProgram;
|
||||||
ShaderProgram* m_DrawScreenQuadProgram;
|
ShaderProgram* m_DrawScreenQuadProgram;
|
||||||
ShaderProgram* m_CalculateFrustumProgram;
|
|
||||||
ShaderProgram* m_LightCullProgram;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
#ifndef UnorderedMapiVec2_h__
|
||||||
|
#define UnorderedMapiVec2_h__
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <boost/functional/hash.hpp>
|
||||||
|
#include <glm/vec2.hpp>
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct std::hash<glm::ivec2>
|
||||||
|
{
|
||||||
|
inline std::size_t operator()(const glm::ivec2 &v) const
|
||||||
|
{
|
||||||
|
return boost::hash<float>()(v.x) ^ boost::hash<float>()(v.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator()(const glm::ivec2& a, const glm::ivec2& b)const
|
||||||
|
{
|
||||||
|
return a.x == b.x && a.y == b.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
+5
-3
@@ -8,16 +8,18 @@
|
|||||||
#include "Core/InputManager.h"
|
#include "Core/InputManager.h"
|
||||||
#include "GUI/Frame.h"
|
#include "GUI/Frame.h"
|
||||||
#include "Core/World.h"
|
#include "Core/World.h"
|
||||||
#include "Rendering/RenderQueueFactory.h"
|
|
||||||
#include "Input/InputProxy.h"
|
#include "Input/InputProxy.h"
|
||||||
#include "Input/KeyboardInputHandler.h"
|
#include "Input/KeyboardInputHandler.h"
|
||||||
#include "Input/MouseInputHandler.h"
|
#include "Input/MouseInputHandler.h"
|
||||||
#include "Core/EKeyDown.h"
|
#include "Core/EKeyDown.h"
|
||||||
#include "Core/EntityXMLFile.h"
|
#include "Core/EntityFilePreprocessor.h"
|
||||||
#include "Core/SystemPipeline.h"
|
#include "Core/SystemPipeline.h"
|
||||||
#include "RaptorCopterSystem.h"
|
#include "RaptorCopterSystem.h"
|
||||||
#include "PlayerSystem.h"
|
#include "PlayerSystem.h"
|
||||||
#include "Editor/EditorSystem.h"
|
#include "Editor/EditorSystem.h"
|
||||||
|
#include "Core/EntityFile.h"
|
||||||
|
#include "Rendering/RenderSystem.h"
|
||||||
|
#include "Core/EntityFileParser.h"
|
||||||
|
|
||||||
// Network
|
// Network
|
||||||
#include <boost/thread.hpp>
|
#include <boost/thread.hpp>
|
||||||
@@ -45,7 +47,7 @@ private:
|
|||||||
GUI::Frame* m_FrameStack;
|
GUI::Frame* m_FrameStack;
|
||||||
World* m_World;
|
World* m_World;
|
||||||
SystemPipeline* m_SystemPipeline;
|
SystemPipeline* m_SystemPipeline;
|
||||||
RenderQueueFactory* m_RenderQueueFactory;
|
RenderFrame* m_RenderFrame;
|
||||||
// Network variables
|
// Network variables
|
||||||
boost::thread m_NetworkThread;
|
boost::thread m_NetworkThread;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
#ifndef HealthSystem_h__
|
||||||
|
#define HealthSystem_h__
|
||||||
|
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
#include <glm/common.hpp>
|
||||||
|
|
||||||
|
#include "Common.h"
|
||||||
|
#include "Core/System.h"
|
||||||
|
#include "Core\EPlayerDamage.h";
|
||||||
|
#include "Core\EPlayerHealthPickup.h";
|
||||||
|
#include "Core\EPlayerDeath.h";
|
||||||
|
|
||||||
|
#include <tuple>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class HealthSystem : public PureSystem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HealthSystem(EventBroker* eventBroker);
|
||||||
|
|
||||||
|
//updatecomponent
|
||||||
|
virtual void UpdateComponent(World* world, ComponentWrapper& health, double dt) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
//methods which will take care of specific events
|
||||||
|
EventRelay<HealthSystem, Events::PlayerDamage> m_EPlayerDamage;
|
||||||
|
bool HealthSystem::OnPlayerDamaged(const Events::PlayerDamage& e);
|
||||||
|
EventRelay<HealthSystem, Events::PlayerHealthPickup> m_EPlayerHealthPickup;
|
||||||
|
bool HealthSystem::OnPlayerHealthPickup(const Events::PlayerHealthPickup& e);
|
||||||
|
|
||||||
|
//vector which will keep track of health changes
|
||||||
|
std::vector<std::tuple<EntityID, double>> m_DeltaHealthVector;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -6,6 +6,8 @@
|
|||||||
<xs:include schemaLocation="Components/Test.xsd"/>
|
<xs:include schemaLocation="Components/Test.xsd"/>
|
||||||
<xs:include schemaLocation="Components/RaptorCopter.xsd"/>
|
<xs:include schemaLocation="Components/RaptorCopter.xsd"/>
|
||||||
<xs:include schemaLocation="Components/Player.xsd"/>
|
<xs:include schemaLocation="Components/Player.xsd"/>
|
||||||
|
<xs:include schemaLocation="Components/Camera.xsd"/>
|
||||||
<xs:include schemaLocation="Components/AABB.xsd"/>
|
<xs:include schemaLocation="Components/AABB.xsd"/>
|
||||||
<xs:include schemaLocation="Components/Trigger.xsd"/>
|
<xs:include schemaLocation="Components/Trigger.xsd"/>
|
||||||
|
<xs:include schemaLocation="Components/Health.xsd"/>
|
||||||
</xs:schema>
|
</xs:schema>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<c:Camera>
|
||||||
|
<Name>cam</Name>
|
||||||
|
<FOV>60.0</FOV>
|
||||||
|
<NearClip>0.01</NearClip>
|
||||||
|
<FarClip>5000</FarClip>
|
||||||
|
</c:Camera>
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
|
||||||
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:t="types">
|
||||||
|
<xs:import schemaLocation="../Types.xsd" namespace="types"/>
|
||||||
|
|
||||||
|
<xs:element name="Camera">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>It's a camera thingy!</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:all>
|
||||||
|
<xs:element name="Name" type="t:string" minOccurs="0"/>
|
||||||
|
<xs:element name="FOV" type="t:double" minOccurs="0"/>
|
||||||
|
<xs:element name="NearClip" type="t:double" minOccurs="0"/>
|
||||||
|
<xs:element name="FarClip" type="t:double" minOccurs="0"/>
|
||||||
|
</xs:all>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
</xs:schema>
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
<c:Health>
|
||||||
|
<Health>100</Health>
|
||||||
|
<MaxHealth>100</MaxHealth>
|
||||||
|
</c:Health>
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
|
||||||
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:t="types">
|
||||||
|
<xs:import schemaLocation="../Types.xsd" namespace="types"/>
|
||||||
|
|
||||||
|
<xs:element name="Health">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:all>
|
||||||
|
<xs:element name="Health" type="t:double" minOccurs="0"/>
|
||||||
|
<xs:element name="MaxHealth" type="t:double" minOccurs="0"/>
|
||||||
|
</xs:all>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
</xs:schema>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
|
||||||
|
<Entity xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../Types/Entity.xsd" xmlns:c="components">
|
||||||
|
<Components>
|
||||||
|
<c:Transform/>
|
||||||
|
</Components>
|
||||||
|
</Entity>
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<Entity xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xi="http://www.w3.org/2001/XInclude" xsi:noNamespaceSchemaLocation="../Types/Entity.xsd" xmlns:c="components" name="RaptorCopter">
|
||||||
|
<Components>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="0" Y="0"/>
|
||||||
|
<Orientation X="0.0" Y="0" Z="0.0"/>
|
||||||
|
</c:Transform>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>Models/Core/UnitRaptor.obj</Resource>
|
||||||
|
<Color R="1" G="0.4" B="0.8"/>
|
||||||
|
</c:Model>
|
||||||
|
</Components>
|
||||||
|
<Children>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="0" Y="0"/>
|
||||||
|
<Orientation X="0" Y="0" Z="0"/>
|
||||||
|
</c:Transform>
|
||||||
|
<c:RaptorCopter>
|
||||||
|
<Speed>20</Speed>
|
||||||
|
<Axis Y="1"/>
|
||||||
|
</c:RaptorCopter>
|
||||||
|
</Components>
|
||||||
|
<Children>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="0" Y="0.4"/>
|
||||||
|
<Scale X="0.1" Y="0.4" Z="0.1"/>
|
||||||
|
</c:Transform>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>Models/Core/UnitCylinder.obj</Resource>
|
||||||
|
<Color R="1" G="0.4" B="0.8"/>
|
||||||
|
</c:Model>
|
||||||
|
</Components>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="0" Y="0.6"/>
|
||||||
|
<Scale X="1.7" Y="0.03" Z="0.1"/>
|
||||||
|
<Orientation X="0" Y="0" Z="0"/>
|
||||||
|
</c:Transform>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>Models/Core/UnitCube.obj</Resource>
|
||||||
|
<Color R="1" G="0.4" B="0.8"/>
|
||||||
|
</c:Model>
|
||||||
|
</Components>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="0" Y="0.6"/>
|
||||||
|
<Scale X="1.7" Y="0.03" Z="0.1"/>
|
||||||
|
<Orientation X="0" Y="1.57" Z="0"/>
|
||||||
|
</c:Transform>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>Models/Core/UnitCube.obj</Resource>
|
||||||
|
<Color R="1" G="0.4" B="0.8"/>
|
||||||
|
</c:Model>
|
||||||
|
</Components>
|
||||||
|
</Entity>
|
||||||
|
</Children>
|
||||||
|
</Entity>
|
||||||
|
</Children>
|
||||||
|
</Entity>
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
|
||||||
|
<Entity xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../Types/Entity.xsd" xmlns:c="components">
|
||||||
|
<Components>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="0" Y="0" Z="0"/>
|
||||||
|
<Orientation X="0" Y="0" Z="0"/>
|
||||||
|
</c:Transform>
|
||||||
|
</Components>
|
||||||
|
<Children>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="0" Y="1" Z="10"/>
|
||||||
|
</c:Transform>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>Models/Camera.obj</Resource>
|
||||||
|
</c:Model>
|
||||||
|
<c:Camera>
|
||||||
|
<Name>MainCamera</Name>
|
||||||
|
</c:Camera>
|
||||||
|
</Components>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="5" Y="1" Z="5"/>
|
||||||
|
</c:Transform>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>Models/Camera.obj</Resource>
|
||||||
|
</c:Model>
|
||||||
|
<c:Camera>
|
||||||
|
<Name>ActionCamera</Name>
|
||||||
|
</c:Camera>
|
||||||
|
</Components>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="0" Y="-1" Z="0"/>
|
||||||
|
<Scale X="100" Y="1" Z="100"/>
|
||||||
|
</c:Transform>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>Models/Core/UnitPlane.obj</Resource>
|
||||||
|
</c:Model>
|
||||||
|
</Components>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="0" Y="0" Z="0"/>
|
||||||
|
</c:Transform>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>An error</Resource>
|
||||||
|
</c:Model>
|
||||||
|
</Components>
|
||||||
|
</Entity>
|
||||||
|
</Children>
|
||||||
|
</Entity>
|
||||||
@@ -9,114 +9,19 @@
|
|||||||
<Resource>Models/DummyScene.obj</Resource>
|
<Resource>Models/DummyScene.obj</Resource>
|
||||||
</c:Model>
|
</c:Model>
|
||||||
</Components>
|
</Components>
|
||||||
|
</Entity>
|
||||||
<Children>
|
<Children>
|
||||||
<Entity>
|
|
||||||
<Components>
|
|
||||||
<c:Transform>
|
|
||||||
<Position X="-1.5"/>
|
|
||||||
<Scale X="1" Y="1" Z="1"/>
|
|
||||||
</c:Transform>
|
|
||||||
<c:Model>
|
|
||||||
<Resource>Models/ScaleWidget.obj</Resource>
|
|
||||||
</c:Model>
|
|
||||||
</Components>
|
|
||||||
</Entity>
|
|
||||||
<Entity>
|
|
||||||
<Components>
|
|
||||||
<c:Transform>
|
|
||||||
<Position X="1.5"/>
|
|
||||||
<Scale X="2" Y="2" Z="2"/>
|
|
||||||
</c:Transform>
|
|
||||||
<c:Model>
|
|
||||||
<Resource>Models/RotationWidget.obj</Resource>
|
|
||||||
</c:Model>
|
|
||||||
<c:Trigger>
|
|
||||||
</c:Trigger>
|
|
||||||
</Components>
|
|
||||||
</Entity>
|
|
||||||
<!--<Entity>
|
|
||||||
<Components>
|
|
||||||
<c:Player>
|
|
||||||
<Velocity X="0" Y="0" Z="0"/>
|
|
||||||
</c:Player>
|
|
||||||
<c:Transform>
|
|
||||||
<Position X="2.5"/>
|
|
||||||
</c:Transform>
|
|
||||||
<c:Model>
|
|
||||||
<Resource>Models/Core/UnitCube.obj</Resource>
|
|
||||||
</c:Model>
|
|
||||||
<c:AABB>
|
|
||||||
</c:AABB>
|
|
||||||
</Components>
|
|
||||||
</Entity>-->
|
|
||||||
<Entity>
|
<Entity>
|
||||||
<Components>
|
<Components>
|
||||||
<c:Transform>
|
<c:Transform>
|
||||||
<Position X="0" Y="-0"/>
|
<Position X="0" Y="-0"/>
|
||||||
<Scale X="1" Y="1" Z="1"/>
|
<Scale X="1" Y="1" Z="1"/>
|
||||||
</c:Transform>
|
</c:Transform>
|
||||||
<!--<c:Move>
|
<c:Camera>
|
||||||
<Speed>1</Speed>
|
</c:Camera>
|
||||||
<Direction X="-1"/>
|
<c:Model>
|
||||||
<Rotation Y="3.14"/>
|
<Resource>Models/Camera.obj</Resource>
|
||||||
</c:Move>-->
|
</c:Model>
|
||||||
</Components>
|
</Components>
|
||||||
<Children>
|
|
||||||
<Entity>
|
|
||||||
<Components>
|
|
||||||
<c:Transform>
|
|
||||||
<Position X="0" Y="0"/>
|
|
||||||
<Orientation X="0.0" Y="0" Z="1.0"/>
|
|
||||||
</c:Transform>
|
|
||||||
<c:Model>
|
|
||||||
<Resource>Models/Core/UnitRaptor.obj</Resource>
|
|
||||||
<Color R="1" G="0.4" B="0.8"/>
|
|
||||||
</c:Model>
|
|
||||||
</Components>
|
|
||||||
<Children>
|
|
||||||
<Entity>
|
|
||||||
<Components>
|
|
||||||
<c:Transform>
|
|
||||||
<Position X="-0.01" Y="0.55"/>
|
|
||||||
<Orientation X="0" Y="0" Z="-1"/>
|
|
||||||
</c:Transform>
|
|
||||||
<c:RaptorCopter>
|
|
||||||
<Speed>20</Speed>
|
|
||||||
<Axis Y="1"/>
|
|
||||||
</c:RaptorCopter>
|
|
||||||
</Components>
|
|
||||||
<Children>
|
|
||||||
<Entity>
|
|
||||||
<Components>
|
|
||||||
<c:Transform>
|
|
||||||
<Position X="0" Y="0"/>
|
|
||||||
<Scale X="1.7" Y="0.03" Z="0.1"/>
|
|
||||||
<Orientation X="0" Y="0" Z="0"/>
|
|
||||||
</c:Transform>
|
|
||||||
<c:Model>
|
|
||||||
<Resource>Models/Core/UnitCube.obj</Resource>
|
|
||||||
<Color R="1" G="0.4" B="0.8"/>
|
|
||||||
</c:Model>
|
|
||||||
</Components>
|
|
||||||
</Entity>
|
|
||||||
<Entity>
|
|
||||||
<Components>
|
|
||||||
<c:Transform>
|
|
||||||
<Position X="0" Y="0"/>
|
|
||||||
<Scale X="1.7" Y="0.03" Z="0.1"/>
|
|
||||||
<Orientation X="0" Y="1.57" Z="0"/>
|
|
||||||
</c:Transform>
|
|
||||||
<c:Model>
|
|
||||||
<Resource>Models/Core/UnitCube.obj</Resource>
|
|
||||||
<Color R="1" G="0.4" B="0.8"/>
|
|
||||||
</c:Model>
|
|
||||||
</Components>
|
|
||||||
</Entity>
|
|
||||||
</Children>
|
|
||||||
</Entity>
|
|
||||||
</Children>
|
|
||||||
</Entity>
|
|
||||||
</Children>
|
|
||||||
</Entity>
|
</Entity>
|
||||||
</Children>
|
</Children>
|
||||||
</Entity>
|
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
<xs:element ref="c:Test" minOccurs="0"/>
|
<xs:element ref="c:Test" minOccurs="0"/>
|
||||||
<xs:element ref="c:RaptorCopter" minOccurs="0"/>
|
<xs:element ref="c:RaptorCopter" minOccurs="0"/>
|
||||||
<xs:element ref="c:Player" minOccurs="0"/>
|
<xs:element ref="c:Player" minOccurs="0"/>
|
||||||
|
<xs:element ref="c:Health" minOccurs="0"/>
|
||||||
</xs:all>
|
</xs:all>
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
</xs:element>
|
</xs:element>
|
||||||
@@ -23,11 +24,19 @@
|
|||||||
<xs:complexType>
|
<xs:complexType>
|
||||||
<xs:sequence>
|
<xs:sequence>
|
||||||
<xs:element ref="Entity" minOccurs="0" maxOccurs="unbounded"/>
|
<xs:element ref="Entity" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
<xs:element name="EntityRef" minOccurs="0" maxOccurs="unbounded">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:all>
|
||||||
|
<xs:attribute name="file" type="xs:string" minOccurs="0"/>
|
||||||
|
</xs:all>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
</xs:sequence>
|
</xs:sequence>
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
</xs:element>
|
</xs:element>
|
||||||
</xs:all>
|
</xs:all>
|
||||||
<xs:attribute ref="xml:base"/>
|
<xs:attribute ref="xml:base"/>
|
||||||
|
<xs:attribute name="name" type="xs:string" minOccurs="0" default=""/>
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
</xs:element>
|
</xs:element>
|
||||||
</xs:schema>
|
</xs:schema>
|
||||||
@@ -1,8 +1,5 @@
|
|||||||
#version 430
|
#version 430
|
||||||
|
|
||||||
uniform mat4 M;
|
|
||||||
uniform mat4 V;
|
|
||||||
uniform mat4 P;
|
|
||||||
uniform vec4 Color;
|
uniform vec4 Color;
|
||||||
|
|
||||||
uniform sampler2D texture0;
|
uniform sampler2D texture0;
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ out VertexData{
|
|||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
gl_Position = P*V*M * vec4(Position, 1.0);
|
gl_Position = P * V * M * vec4(Position, 1.0);
|
||||||
|
|
||||||
Output.Position = Position;
|
Output.Position = Position;
|
||||||
Output.TextureCoordinate = TextureCoords;
|
Output.TextureCoordinate = TextureCoords;
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
#version 430
|
#version 430
|
||||||
|
|
||||||
uniform mat4 M;
|
|
||||||
uniform mat4 V;
|
|
||||||
uniform mat4 P;
|
|
||||||
uniform vec2 PickingColor;
|
uniform vec2 PickingColor;
|
||||||
|
|
||||||
in VertexData{
|
in VertexData{
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ out VertexData{
|
|||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
gl_Position = P*V*M * vec4(Position, 1.0);
|
gl_Position = P * V* M * vec4(Position, 1.0);
|
||||||
|
|
||||||
Output.Position = Position;
|
Output.Position = Position;
|
||||||
}
|
}
|
||||||
@@ -90,12 +90,27 @@ set(SOURCE_FILES
|
|||||||
${SOURCE_FILES_Rendering}
|
${SOURCE_FILES_Rendering}
|
||||||
${SOURCE_FILES_Rendering_Util}
|
${SOURCE_FILES_Rendering_Util}
|
||||||
${SOURCE_FILES_Collision}
|
${SOURCE_FILES_Collision}
|
||||||
|
${SOURCE_FILES_Editor}
|
||||||
${CMAKE_SOURCE_DIR}/deps/include/imgui/imgui.cpp
|
${CMAKE_SOURCE_DIR}/deps/include/imgui/imgui.cpp
|
||||||
${CMAKE_SOURCE_DIR}/deps/include/imgui/imgui_draw.cpp
|
${CMAKE_SOURCE_DIR}/deps/include/imgui/imgui_draw.cpp
|
||||||
${CMAKE_SOURCE_DIR}/deps/include/imgui/imgui_demo.cpp
|
${CMAKE_SOURCE_DIR}/deps/include/imgui/imgui_demo.cpp
|
||||||
${SOURCE_FILES_Editor}
|
${CMAKE_SOURCE_DIR}/deps/include/nativefiledialog/nfd_common.c
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# nativefiledialog
|
||||||
|
if(WIN32)
|
||||||
|
set(SOURCE_FILES ${SOURCE_FILES}
|
||||||
|
${CMAKE_SOURCE_DIR}/deps/include/nativefiledialog/nfd_win.cpp
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
if(UNIX)
|
||||||
|
set(SOURCE_FILES ${SOURCE_FILES}
|
||||||
|
${CMAKE_SOURCE_DIR}/deps/include/nativefiledialog/nfd_gtk.c
|
||||||
|
# TODO: Link with GTK+ here!
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
set(LIBRARIES
|
set(LIBRARIES
|
||||||
${OPENGL_LIBRARIES}
|
${OPENGL_LIBRARIES}
|
||||||
${GLEW_LIBRARIES}
|
${GLEW_LIBRARIES}
|
||||||
|
|||||||
+178
-178
@@ -8,196 +8,196 @@
|
|||||||
namespace Collision
|
namespace Collision
|
||||||
{
|
{
|
||||||
|
|
||||||
//note: this one hasnt been delta adjusted like RayVsAABB has
|
//note: this one hasnt been delta adjusted like RayVsAABB has
|
||||||
bool RayAABBIntr(const Ray& ray, const AABB& box)
|
bool RayAABBIntr(const Ray& ray, const AABB& box)
|
||||||
{
|
{
|
||||||
glm::vec3 w = 75.0f * ray.Direction();
|
glm::vec3 w = 75.0f * ray.Direction();
|
||||||
glm::vec3 v = glm::abs(w);
|
glm::vec3 v = glm::abs(w);
|
||||||
glm::vec3 c = ray.Origin() - box.Center() + w;
|
glm::vec3 c = ray.Origin() - box.Center() + w;
|
||||||
glm::vec3 half = box.HalfSize();
|
glm::vec3 half = box.HalfSize();
|
||||||
|
|
||||||
if (abs(c.x) > v.x + half.x) {
|
if (abs(c.x) > v.x + half.x) {
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
if (abs(c.y) > v.y + half.y) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (abs(c.z) > v.z + half.z) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (abs(c.y*w.z - c.z*w.y) > half.y*v.z + half.z*v.y) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (abs(c.x*w.z - c.z*w.x) > half.x*v.z + half.z*v.x) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return !(abs(c.x*w.y - c.y*w.x) > half.x*v.y + half.y*v.x);
|
|
||||||
}
|
}
|
||||||
|
if (abs(c.y) > v.y + half.y) {
|
||||||
bool RayVsAABB(const Ray& ray, const AABB& box)
|
return false;
|
||||||
{
|
|
||||||
float dummy;
|
|
||||||
return RayVsAABB(ray, box, dummy);
|
|
||||||
}
|
}
|
||||||
|
if (abs(c.z) > v.z + half.z) {
|
||||||
bool RayVsAABB(const Ray& ray, const AABB& box, float& outDistance)
|
|
||||||
{
|
|
||||||
glm::vec3 invdir = 1.0f / ray.Direction();
|
|
||||||
glm::vec3 origin = ray.Origin();
|
|
||||||
|
|
||||||
float t1 = (box.MinCorner().x - origin.x)*invdir.x;
|
|
||||||
float t2 = (box.MaxCorner().x - origin.x)*invdir.x;
|
|
||||||
float t3 = (box.MinCorner().y - origin.y)*invdir.y;
|
|
||||||
float t4 = (box.MaxCorner().y - origin.y)*invdir.y;
|
|
||||||
float t5 = (box.MinCorner().z - origin.z)*invdir.z;
|
|
||||||
float t6 = (box.MaxCorner().z - origin.z)*invdir.z;
|
|
||||||
|
|
||||||
float tmin = std::max(std::max(std::min(t1, t2), std::min(t3, t4)), std::min(t5, t6));
|
|
||||||
float tmax = std::min(std::min(std::max(t1, t2), std::max(t3, t4)), std::max(t5, t6));
|
|
||||||
|
|
||||||
//if (tmax < 0 || tmin > tmax)
|
|
||||||
//if tmin,tmax are almost the same (i.e. hitting exactly in the corner) then tmin might be slightly
|
|
||||||
//greater than tmax becuase of floating-precision problems. fixed by adding a small delta to tmax
|
|
||||||
if (tmax < 0 || tmin>(tmax + 0.0001f))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
outDistance = (tmin > 0) ? tmin : tmax;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AABBVsAABB(const AABB& a, const AABB& b)
|
|
||||||
{
|
|
||||||
const glm::vec3& aCenter = a.Center();
|
|
||||||
const glm::vec3& bCenter = b.Center();
|
|
||||||
const glm::vec3& aHSize = a.HalfSize();
|
|
||||||
const glm::vec3& bHSize = b.HalfSize();
|
|
||||||
//Test will probably exit because of the X and Z axes more often, so test them first.
|
|
||||||
if (abs(aCenter[0] - bCenter[0]) > (aHSize[0] + bHSize[0])) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (abs(aCenter[2] - bCenter[2]) > (aHSize[2] + bHSize[2])) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return (abs(aCenter[1] - bCenter[1]) <= (aHSize[1] + bHSize[1]));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AABBVsAABB(const AABB& a, const AABB& b, glm::vec3& minimumTranslation)
|
|
||||||
{
|
|
||||||
minimumTranslation = glm::vec3(0, 0, 0);
|
|
||||||
const glm::vec3& aMax = a.MaxCorner();
|
|
||||||
const glm::vec3& bMax = b.MaxCorner();
|
|
||||||
const glm::vec3& aMin = a.MinCorner();
|
|
||||||
const glm::vec3& bMin = b.MinCorner();
|
|
||||||
const glm::vec3& bSize = b.Size();
|
|
||||||
const glm::vec3& aSize = a.Size();
|
|
||||||
float minOffset = INFINITY;
|
|
||||||
float off;
|
|
||||||
auto axisesIntersecting = glm::tvec3<bool, glm::highp>(false, false, false);
|
|
||||||
for (int i = 0; i < 3; ++i) {
|
|
||||||
off = bMax[i] - aMin[i];
|
|
||||||
if (off > 0 && off < bSize[i] + aSize[i]) {
|
|
||||||
if (off < minOffset) {
|
|
||||||
minimumTranslation = glm::vec3();
|
|
||||||
minimumTranslation[i] = minOffset = off;
|
|
||||||
}
|
|
||||||
axisesIntersecting[i] = true;
|
|
||||||
}
|
|
||||||
off = aMax[i] - bMin[i];
|
|
||||||
if (off > 0 && off < bSize[i] + aSize[i]) {
|
|
||||||
if (off < minOffset) {
|
|
||||||
minOffset = off;
|
|
||||||
minimumTranslation = glm::vec3();
|
|
||||||
minimumTranslation[i] = -off;
|
|
||||||
}
|
|
||||||
axisesIntersecting[i] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return glm::all(axisesIntersecting);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RayVsModel(const Ray& ray,
|
|
||||||
const std::vector<RawModel::Vertex>& modelVertices,
|
|
||||||
const std::vector<unsigned int>& modelIndices)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < modelIndices.size(); ++i) {
|
|
||||||
glm::vec3 v0 = modelVertices[modelIndices[i]].Position;
|
|
||||||
glm::vec3 e1 = modelVertices[modelIndices[++i]].Position - v0; //v1 - v0
|
|
||||||
glm::vec3 e2 = modelVertices[modelIndices[++i]].Position - v0; //v2 - v0
|
|
||||||
glm::vec3 m = ray.Origin() - v0;
|
|
||||||
glm::vec3 MxE1 = glm::cross(m, e1);
|
|
||||||
glm::vec3 DxE2 = glm::cross(ray.Direction(), e2);
|
|
||||||
float DetInv = glm::dot(e1, DxE2);
|
|
||||||
if (std::abs(DetInv) < FLT_EPSILON) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
DetInv = 1.0f / DetInv;
|
|
||||||
float u = glm::dot(m, DxE2) * DetInv;
|
|
||||||
float v = glm::dot(ray.Direction(), MxE1) * DetInv;
|
|
||||||
//u,v can be very close to 0 but still negative sometimes. added a deltafactor to compensate for that problem
|
|
||||||
if ((u + 0.001f) < 0 || (v + 0.001f) < 0 || 1 < u + v) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
//Here, u and v are positive, u+v <= 1, and if distance is positive - triangle is hit.
|
|
||||||
if (0 <= glm::dot(e2, MxE1) * DetInv) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RayVsModel(const Ray& ray,
|
if (abs(c.y*w.z - c.z*w.y) > half.y*v.z + half.z*v.y) {
|
||||||
const std::vector<RawModel::Vertex>& modelVertices,
|
return false;
|
||||||
const std::vector<unsigned int>& modelIndices,
|
}
|
||||||
float& outDistance,
|
if (abs(c.x*w.z - c.z*w.x) > half.x*v.z + half.z*v.x) {
|
||||||
float& outUCoord,
|
return false;
|
||||||
float& outVCoord)
|
}
|
||||||
{
|
return !(abs(c.x*w.y - c.y*w.x) > half.x*v.y + half.y*v.x);
|
||||||
outDistance = INFINITY;
|
}
|
||||||
bool hit = false;
|
|
||||||
for (int i = 0; i < modelIndices.size(); ++i) {
|
|
||||||
glm::vec3 v0 = modelVertices[modelIndices[i]].Position;
|
|
||||||
glm::vec3 e1 = modelVertices[modelIndices[++i]].Position - v0; //v1 - v0
|
|
||||||
glm::vec3 e2 = modelVertices[modelIndices[++i]].Position - v0; //v2 - v0
|
|
||||||
glm::vec3 m = ray.Origin() - v0;
|
|
||||||
glm::vec3 MxE1 = glm::cross(m, e1);
|
|
||||||
glm::vec3 DxE2 = glm::cross(ray.Direction(), e2);//pVec
|
|
||||||
float DetInv = glm::dot(e1, DxE2);
|
|
||||||
if (std::abs(DetInv) < FLT_EPSILON) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
DetInv = 1.0f / DetInv;
|
|
||||||
float dist = glm::dot(e2, MxE1) * DetInv;
|
|
||||||
if (dist >= outDistance) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
float u = glm::dot(m, DxE2) * DetInv;
|
|
||||||
float v = glm::dot(ray.Direction(), MxE1) * DetInv;
|
|
||||||
|
|
||||||
//u,v can be very close to 0 but still negative sometimes. added a deltafactor to compensate for that problem
|
bool RayVsAABB(const Ray& ray, const AABB& box)
|
||||||
//If u and v are positive, u+v <= 1, dist is positive, and less than closest.
|
{
|
||||||
if (0 <= (u + 0.001f) && 0 <= (v + 0.001f) && u + v <= 1 && 0 <= dist) {
|
float dummy;
|
||||||
outDistance = dist;
|
return RayVsAABB(ray, box, dummy);
|
||||||
outUCoord = u;
|
}
|
||||||
outVCoord = v;
|
|
||||||
hit = true;
|
bool RayVsAABB(const Ray& ray, const AABB& box, float& outDistance)
|
||||||
|
{
|
||||||
|
glm::vec3 invdir = 1.0f / ray.Direction();
|
||||||
|
glm::vec3 origin = ray.Origin();
|
||||||
|
|
||||||
|
float t1 = (box.MinCorner().x - origin.x)*invdir.x;
|
||||||
|
float t2 = (box.MaxCorner().x - origin.x)*invdir.x;
|
||||||
|
float t3 = (box.MinCorner().y - origin.y)*invdir.y;
|
||||||
|
float t4 = (box.MaxCorner().y - origin.y)*invdir.y;
|
||||||
|
float t5 = (box.MinCorner().z - origin.z)*invdir.z;
|
||||||
|
float t6 = (box.MaxCorner().z - origin.z)*invdir.z;
|
||||||
|
|
||||||
|
float tmin = std::max(std::max(std::min(t1, t2), std::min(t3, t4)), std::min(t5, t6));
|
||||||
|
float tmax = std::min(std::min(std::max(t1, t2), std::max(t3, t4)), std::max(t5, t6));
|
||||||
|
|
||||||
|
//if (tmax < 0 || tmin > tmax)
|
||||||
|
//if tmin,tmax are almost the same (i.e. hitting exactly in the corner) then tmin might be slightly
|
||||||
|
//greater than tmax becuase of floating-precision problems. fixed by adding a small delta to tmax
|
||||||
|
if (tmax < 0 || tmin>(tmax + 0.0001f))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
outDistance = (tmin > 0) ? tmin : tmax;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AABBVsAABB(const AABB& a, const AABB& b)
|
||||||
|
{
|
||||||
|
const glm::vec3& aCenter = a.Center();
|
||||||
|
const glm::vec3& bCenter = b.Center();
|
||||||
|
const glm::vec3& aHSize = a.HalfSize();
|
||||||
|
const glm::vec3& bHSize = b.HalfSize();
|
||||||
|
//Test will probably exit because of the X and Z axes more often, so test them first.
|
||||||
|
if (abs(aCenter[0] - bCenter[0]) > (aHSize[0] + bHSize[0])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (abs(aCenter[2] - bCenter[2]) > (aHSize[2] + bHSize[2])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return (abs(aCenter[1] - bCenter[1]) <= (aHSize[1] + bHSize[1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AABBVsAABB(const AABB& a, const AABB& b, glm::vec3& minimumTranslation)
|
||||||
|
{
|
||||||
|
minimumTranslation = glm::vec3(0, 0, 0);
|
||||||
|
const glm::vec3& aMax = a.MaxCorner();
|
||||||
|
const glm::vec3& bMax = b.MaxCorner();
|
||||||
|
const glm::vec3& aMin = a.MinCorner();
|
||||||
|
const glm::vec3& bMin = b.MinCorner();
|
||||||
|
const glm::vec3& bSize = b.Size();
|
||||||
|
const glm::vec3& aSize = a.Size();
|
||||||
|
float minOffset = INFINITY;
|
||||||
|
float off;
|
||||||
|
auto axisesIntersecting = glm::tvec3<bool, glm::highp>(false, false, false);
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
off = bMax[i] - aMin[i];
|
||||||
|
if (off > 0 && off < bSize[i] + aSize[i]) {
|
||||||
|
if (off < minOffset) {
|
||||||
|
minimumTranslation = glm::vec3();
|
||||||
|
minimumTranslation[i] = minOffset = off;
|
||||||
}
|
}
|
||||||
|
axisesIntersecting[i] = true;
|
||||||
|
}
|
||||||
|
off = aMax[i] - bMin[i];
|
||||||
|
if (off > 0 && off < bSize[i] + aSize[i]) {
|
||||||
|
if (off < minOffset) {
|
||||||
|
minOffset = off;
|
||||||
|
minimumTranslation = glm::vec3();
|
||||||
|
minimumTranslation[i] = -off;
|
||||||
|
}
|
||||||
|
axisesIntersecting[i] = true;
|
||||||
}
|
}
|
||||||
return hit;
|
|
||||||
}
|
}
|
||||||
|
return glm::all(axisesIntersecting);
|
||||||
|
}
|
||||||
|
|
||||||
bool RayVsModel(const Ray& ray,
|
bool RayVsModel(const Ray& ray,
|
||||||
const std::vector<RawModel::Vertex>& modelVertices,
|
const std::vector<RawModel::Vertex>& modelVertices,
|
||||||
const std::vector<unsigned int>& modelIndices,
|
const std::vector<unsigned int>& modelIndices)
|
||||||
glm::vec3& outHitPosition)
|
{
|
||||||
{
|
for (int i = 0; i < modelIndices.size(); ++i) {
|
||||||
float u;
|
glm::vec3 v0 = modelVertices[modelIndices[i]].Position;
|
||||||
float v;
|
glm::vec3 e1 = modelVertices[modelIndices[++i]].Position - v0; //v1 - v0
|
||||||
float dist;
|
glm::vec3 e2 = modelVertices[modelIndices[++i]].Position - v0; //v2 - v0
|
||||||
bool hit = RayVsModel(ray, modelVertices, modelIndices, dist, u, v);
|
glm::vec3 m = ray.Origin() - v0;
|
||||||
outHitPosition = ray.Origin() + dist * ray.Direction();
|
glm::vec3 MxE1 = glm::cross(m, e1);
|
||||||
return hit;
|
glm::vec3 DxE2 = glm::cross(ray.Direction(), e2);
|
||||||
|
float DetInv = glm::dot(e1, DxE2);
|
||||||
|
if (std::abs(DetInv) < FLT_EPSILON) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
DetInv = 1.0f / DetInv;
|
||||||
|
float u = glm::dot(m, DxE2) * DetInv;
|
||||||
|
float v = glm::dot(ray.Direction(), MxE1) * DetInv;
|
||||||
|
//u,v can be very close to 0 but still negative sometimes. added a deltafactor to compensate for that problem
|
||||||
|
if ((u + 0.001f) < 0 || (v + 0.001f) < 0 || 1 < u + v) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//Here, u and v are positive, u+v <= 1, and if distance is positive - triangle is hit.
|
||||||
|
if (0 <= glm::dot(e2, MxE1) * DetInv) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RayVsModel(const Ray& ray,
|
||||||
|
const std::vector<RawModel::Vertex>& modelVertices,
|
||||||
|
const std::vector<unsigned int>& modelIndices,
|
||||||
|
float& outDistance,
|
||||||
|
float& outUCoord,
|
||||||
|
float& outVCoord)
|
||||||
|
{
|
||||||
|
outDistance = INFINITY;
|
||||||
|
bool hit = false;
|
||||||
|
for (int i = 0; i < modelIndices.size(); ++i) {
|
||||||
|
glm::vec3 v0 = modelVertices[modelIndices[i]].Position;
|
||||||
|
glm::vec3 e1 = modelVertices[modelIndices[++i]].Position - v0; //v1 - v0
|
||||||
|
glm::vec3 e2 = modelVertices[modelIndices[++i]].Position - v0; //v2 - v0
|
||||||
|
glm::vec3 m = ray.Origin() - v0;
|
||||||
|
glm::vec3 MxE1 = glm::cross(m, e1);
|
||||||
|
glm::vec3 DxE2 = glm::cross(ray.Direction(), e2);//pVec
|
||||||
|
float DetInv = glm::dot(e1, DxE2);
|
||||||
|
if (std::abs(DetInv) < FLT_EPSILON) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
DetInv = 1.0f / DetInv;
|
||||||
|
float dist = glm::dot(e2, MxE1) * DetInv;
|
||||||
|
if (dist >= outDistance) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
float u = glm::dot(m, DxE2) * DetInv;
|
||||||
|
float v = glm::dot(ray.Direction(), MxE1) * DetInv;
|
||||||
|
|
||||||
|
//u,v can be very close to 0 but still negative sometimes. added a deltafactor to compensate for that problem
|
||||||
|
//If u and v are positive, u+v <= 1, dist is positive, and less than closest.
|
||||||
|
if (0 <= (u + 0.001f) && 0 <= (v + 0.001f) && u + v <= 1 && 0 <= dist) {
|
||||||
|
outDistance = dist;
|
||||||
|
outUCoord = u;
|
||||||
|
outVCoord = v;
|
||||||
|
hit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hit;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RayVsModel(const Ray& ray,
|
||||||
|
const std::vector<RawModel::Vertex>& modelVertices,
|
||||||
|
const std::vector<unsigned int>& modelIndices,
|
||||||
|
glm::vec3& outHitPosition)
|
||||||
|
{
|
||||||
|
float u;
|
||||||
|
float v;
|
||||||
|
float dist;
|
||||||
|
bool hit = RayVsModel(ray, modelVertices, modelIndices, dist, u, v);
|
||||||
|
outHitPosition = ray.Origin() + dist * ray.Direction();
|
||||||
|
return hit;
|
||||||
|
}
|
||||||
|
|
||||||
bool IsSameBoxProbably(const AABB& first, const AABB& second, const float epsilon)
|
bool IsSameBoxProbably(const AABB& first, const AABB& second, const float epsilon)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,8 +4,6 @@
|
|||||||
|
|
||||||
void CollisionSystem::UpdateComponent(World * world, ComponentWrapper & cAABB, double dt)
|
void CollisionSystem::UpdateComponent(World * world, ComponentWrapper & cAABB, double dt)
|
||||||
{
|
{
|
||||||
//TODO: Update CollisionSystem system after PlayerSystem.
|
|
||||||
|
|
||||||
//Right now, cAABB is a component attached to any entity that should be collideable.
|
//Right now, cAABB is a component attached to any entity that should be collideable.
|
||||||
AABB thisBox;
|
AABB thisBox;
|
||||||
if (!Collision::GetEntityBox(world, cAABB, thisBox)) {
|
if (!Collision::GetEntityBox(world, cAABB, thisBox)) {
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
#include "Core/EntityFile.h"
|
||||||
|
|
||||||
|
EntityFile::EntityFile(boost::filesystem::path path)
|
||||||
|
: m_FilePath(path)
|
||||||
|
{
|
||||||
|
using namespace xercesc;
|
||||||
|
XMLPlatformUtils::Initialize();
|
||||||
|
m_GrammarPool = new XMLGrammarPoolImpl();
|
||||||
|
m_SAX2XMLReader = XMLReaderFactory::createXMLReader(XMLPlatformUtils::fgMemoryManager, m_GrammarPool);
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityFile::~EntityFile()
|
||||||
|
{
|
||||||
|
delete m_SAX2XMLReader;
|
||||||
|
delete m_GrammarPool;
|
||||||
|
xercesc::XMLPlatformUtils::Terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityFile::Parse(const EntityFileHandler* handler) const
|
||||||
|
{
|
||||||
|
using namespace xercesc;
|
||||||
|
|
||||||
|
EntityFileSAXHandler saxHandler(handler, nullptr);
|
||||||
|
m_SAX2XMLReader->setFeature(XMLUni::fgXercesCacheGrammarFromParse, true);
|
||||||
|
m_SAX2XMLReader->setFeature(XMLUni::fgXercesUseCachedGrammarInParse, true);
|
||||||
|
m_SAX2XMLReader->setContentHandler(&saxHandler);
|
||||||
|
m_SAX2XMLReader->setErrorHandler(&saxHandler);
|
||||||
|
m_SAX2XMLReader->setDeclarationHandler(&saxHandler);
|
||||||
|
m_SAX2XMLReader->parse(m_FilePath.string().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t EntityFile::GetTypeStride(std::string typeName)
|
||||||
|
{
|
||||||
|
std::map<std::string, size_t> typeStrides{
|
||||||
|
{ "bool", sizeof(bool) },
|
||||||
|
{ "int", sizeof(int) },
|
||||||
|
{ "float", sizeof(float) },
|
||||||
|
{ "double", sizeof(double) },
|
||||||
|
{ "string", sizeof(std::string) },
|
||||||
|
{ "Vector", sizeof(glm::vec3) },
|
||||||
|
{ "Quaternion", sizeof(glm::quat) },
|
||||||
|
{ "Color", sizeof(glm::vec4) }
|
||||||
|
};
|
||||||
|
|
||||||
|
auto it = typeStrides.find(typeName);
|
||||||
|
return (it != typeStrides.end()) ? it->second : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityFile::WriteAttributeData(char* outData, const ComponentInfo::Field_t& field, const std::map<std::string, std::string>& attributes)
|
||||||
|
{
|
||||||
|
if (field.Type == "Vector") {
|
||||||
|
glm::vec3 vec;
|
||||||
|
vec.x = boost::lexical_cast<float>(attributes.at("X"));
|
||||||
|
vec.y = boost::lexical_cast<float>(attributes.at("Y"));
|
||||||
|
vec.z = boost::lexical_cast<float>(attributes.at("Z"));
|
||||||
|
memcpy(outData, reinterpret_cast<char*>(&vec), field.Stride);
|
||||||
|
} else if (field.Type == "Color") {
|
||||||
|
glm::vec4 vec;
|
||||||
|
vec.r = boost::lexical_cast<float>(attributes.at("R"));
|
||||||
|
vec.g = boost::lexical_cast<float>(attributes.at("G"));
|
||||||
|
vec.b = boost::lexical_cast<float>(attributes.at("B"));
|
||||||
|
vec.a = boost::lexical_cast<float>(attributes.at("A"));
|
||||||
|
memcpy(outData, reinterpret_cast<char*>(&vec), field.Stride);
|
||||||
|
} else if (field.Type == "Quaternion") {
|
||||||
|
glm::quat q;
|
||||||
|
q.x = boost::lexical_cast<float>(attributes.at("X"));
|
||||||
|
q.y = boost::lexical_cast<float>(attributes.at("Y"));
|
||||||
|
q.z = boost::lexical_cast<float>(attributes.at("Z"));
|
||||||
|
q.w = boost::lexical_cast<float>(attributes.at("W"));
|
||||||
|
memcpy(outData, reinterpret_cast<char*>(&q), field.Stride);
|
||||||
|
} else if (!attributes.empty()) {
|
||||||
|
LOG_WARNING("%i attributes not handled by any type conversion!", attributes.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityFile::WriteValueData(char* outData, const ComponentInfo::Field_t& field, const char* valueData)
|
||||||
|
{
|
||||||
|
if (field.Type == "int") {
|
||||||
|
int value = boost::lexical_cast<int>(valueData);
|
||||||
|
memcpy(outData, reinterpret_cast<char*>(&value), field.Stride);
|
||||||
|
} else if (field.Type == "float") {
|
||||||
|
float value = boost::lexical_cast<float>(valueData);
|
||||||
|
memcpy(outData, reinterpret_cast<char*>(&value), field.Stride);
|
||||||
|
} else if (field.Type == "double") {
|
||||||
|
double value = boost::lexical_cast<double>(valueData);
|
||||||
|
memcpy(outData, reinterpret_cast<char*>(&value), field.Stride);
|
||||||
|
} else if (field.Type == "bool") {
|
||||||
|
bool value = (valueData[0] == 't'); // Lazy bool evaluation
|
||||||
|
memcpy(outData, reinterpret_cast<char*>(&value), field.Stride);
|
||||||
|
} else if (field.Type == "string") {
|
||||||
|
new (outData) std::string(valueData);
|
||||||
|
} else {
|
||||||
|
LOG_WARNING("Unknown value data type: %s", field.Type.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
#include "Core/EntityFileParser.h"
|
||||||
|
|
||||||
|
EntityFileParser::EntityFileParser(const EntityFile* entityFile)
|
||||||
|
: m_EntityFile(entityFile)
|
||||||
|
{
|
||||||
|
m_Handler.SetStartEntityCallback(std::bind(&EntityFileParser::onStartEntity, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
|
||||||
|
m_Handler.SetStartComponentCallback(std::bind(&EntityFileParser::onStartComponent, this, std::placeholders::_1, std::placeholders::_2));
|
||||||
|
m_Handler.SetStartFieldCallback(std::bind(&EntityFileParser::onStartComponentField, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
|
||||||
|
m_Handler.SetStartFieldDataCallback(std::bind(&EntityFileParser::onFieldData, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityFileParser::MergeEntities(World* world)
|
||||||
|
{
|
||||||
|
m_World = world;
|
||||||
|
m_EntityIDMapper[0] = 0;
|
||||||
|
m_EntityFile->Parse(&m_Handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityFileParser::onStartEntity(EntityID entity, EntityID parent, const std::string& name)
|
||||||
|
{
|
||||||
|
EntityID realParent = m_EntityIDMapper.at(parent);
|
||||||
|
EntityID realEntity = m_World->CreateEntity(realParent);
|
||||||
|
if (!name.empty()) {
|
||||||
|
m_World->SetName(realEntity, name);
|
||||||
|
}
|
||||||
|
m_EntityIDMapper[entity] = realEntity;
|
||||||
|
LOG_DEBUG("Created entity #%i (%i) with parent %i (%i)", entity, realEntity, parent, realParent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityFileParser::onStartComponent(EntityID entity, const std::string& component)
|
||||||
|
{
|
||||||
|
EntityID realEntity = m_EntityIDMapper.at(entity);
|
||||||
|
m_World->AttachComponent(realEntity, component);
|
||||||
|
LOG_DEBUG("Attached component of type \"%s\" to entity #%i (%i)", component.c_str(), entity, realEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityFileParser::onStartComponentField(EntityID entity, const std::string& componentType, const std::string& fieldName, const std::map<std::string, std::string>& attributes)
|
||||||
|
{
|
||||||
|
EntityID realEntity = m_EntityIDMapper.at(entity);
|
||||||
|
ComponentWrapper component = m_World->GetComponent(realEntity, componentType);
|
||||||
|
auto& field = component.Info.Fields.at(fieldName);
|
||||||
|
|
||||||
|
LOG_DEBUG("Field \"%s\" type \"%s\"", fieldName.c_str(), field.Type.c_str());
|
||||||
|
LOG_DEBUG("Attributes:");
|
||||||
|
for (auto& kv : attributes) {
|
||||||
|
LOG_DEBUG("\t%s = %s", kv.first.c_str(), kv.second.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
char* data = component.Data + field.Offset;
|
||||||
|
EntityFile::WriteAttributeData(data, field, attributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityFileParser::onFieldData(EntityID entity, const std::string& componentType, const std::string& fieldName, const char* fieldData)
|
||||||
|
{
|
||||||
|
EntityID realEntity = m_EntityIDMapper.at(entity);
|
||||||
|
ComponentWrapper component = m_World->GetComponent(realEntity, componentType);
|
||||||
|
auto& field = component.Info.Fields.at(fieldName);
|
||||||
|
|
||||||
|
char* data = component.Data + field.Offset;
|
||||||
|
EntityFile::WriteValueData(data, field, fieldData);
|
||||||
|
}
|
||||||
@@ -0,0 +1,230 @@
|
|||||||
|
#include "Core/EntityFilePreprocessor.h"
|
||||||
|
|
||||||
|
EntityFilePreprocessor::EntityFilePreprocessor(const EntityFile* entityFile)
|
||||||
|
: m_EntityFile(entityFile)
|
||||||
|
{
|
||||||
|
EntityFileHandler handler;
|
||||||
|
handler.SetStartComponentCallback(std::bind(&EntityFilePreprocessor::onStartComponent, this, std::placeholders::_1, std::placeholders::_2));
|
||||||
|
m_EntityFile->Parse(&handler);
|
||||||
|
|
||||||
|
LOG_DEBUG("___ COMPONENT DEFINITIONS ___");
|
||||||
|
for (auto& kv : m_ComponentCounts) {
|
||||||
|
LOG_DEBUG("%s: %i", kv.first.c_str(), kv.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
parseComponentInfo();
|
||||||
|
|
||||||
|
for (auto& kv : m_ComponentInfo) {
|
||||||
|
auto& info = kv.second;
|
||||||
|
LOG_DEBUG("Component: %s (%s)", info.Name.c_str(), info.Meta.Annotation.c_str());
|
||||||
|
LOG_DEBUG("Stride: %i", info.Meta.Stride);
|
||||||
|
LOG_DEBUG("Allocation: %i", info.Meta.Allocation);
|
||||||
|
for (auto& kv : info.Fields) {
|
||||||
|
auto& field = kv.second;
|
||||||
|
LOG_DEBUG("\t%i\t%s %s", field.Offset, field.Type, kv.first.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parseDefaults();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityFilePreprocessor::RegisterComponents(World* world)
|
||||||
|
{
|
||||||
|
for (auto& kv : m_ComponentInfo) {
|
||||||
|
world->RegisterComponent(kv.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityFilePreprocessor::onStartComponent(EntityID entity, std::string type)
|
||||||
|
{
|
||||||
|
//LOG_DEBUG("Component: %s", type.c_str());
|
||||||
|
m_ComponentCounts[type]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityFilePreprocessor::parseComponentInfo()
|
||||||
|
{
|
||||||
|
using namespace xercesc;
|
||||||
|
EntityFileXMLErrorHandler errorHandler;
|
||||||
|
auto grammarPool = m_EntityFile->GrammarPool();
|
||||||
|
bool whateverTheFuckThisIs;
|
||||||
|
auto xsModel = grammarPool->getXSModel(whateverTheFuckThisIs);
|
||||||
|
|
||||||
|
// Find component xsd element declarations
|
||||||
|
std::cout << "Enumerating components..." << std::endl;
|
||||||
|
// <xs:element name="ComponentName">
|
||||||
|
auto topLevelElements = xsModel->getComponents(XSConstants::ELEMENT_DECLARATION);
|
||||||
|
for (unsigned int i = 0; i < topLevelElements->getLength(); ++i) {
|
||||||
|
auto element = static_cast<XSElementDeclaration*>(topLevelElements->item(i));
|
||||||
|
|
||||||
|
std::string nameSpace = XS::ToString(element->getNamespace());
|
||||||
|
if (nameSpace != "components") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ComponentInfo compInfo;
|
||||||
|
|
||||||
|
// Name
|
||||||
|
compInfo.Name = XS::ToString(element->getName());
|
||||||
|
// Known allocation
|
||||||
|
compInfo.Meta.Allocation = m_ComponentCounts[compInfo.Name];
|
||||||
|
// Annotation
|
||||||
|
auto componentAnnotation = element->getAnnotation();
|
||||||
|
if (componentAnnotation != nullptr) {
|
||||||
|
// Parse annotation XML
|
||||||
|
char* annotationString = XMLString::transcode(componentAnnotation->getAnnotationString());
|
||||||
|
MemBufInputSource annotationInput(reinterpret_cast<const XMLByte*>(annotationString), strlen(annotationString), "MemBuf: Annotation String");
|
||||||
|
XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager, grammarPool);
|
||||||
|
parser.setErrorHandler(&errorHandler);
|
||||||
|
parser.parse(annotationInput);
|
||||||
|
XMLString::release(&annotationString);
|
||||||
|
auto doc = parser.getDocument();
|
||||||
|
|
||||||
|
// TODO: Add allocation estimations from external file on map-to-map basis
|
||||||
|
// Add allocation estimation(s)
|
||||||
|
//auto allocationTags = doc->getElementsByTagName(XSTR("meta:allocation"));
|
||||||
|
//for (int i = 0; i < allocationTags->getLength(); ++i) {
|
||||||
|
// auto allocation = dynamic_cast<DOMElement*>(allocationTags->item(i));
|
||||||
|
// auto child = allocation->getFirstChild();
|
||||||
|
// if (child == nullptr) {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// XSValue::Status status;
|
||||||
|
// XSValue* val = XSValue::getActualValue(child->getNodeValue(), XSValue::dt_integer, status);
|
||||||
|
// compInfo.Meta.Allocation += val->fData.fValue.f_int;
|
||||||
|
//}
|
||||||
|
|
||||||
|
// Save documentation string
|
||||||
|
auto documentationTags = doc->getElementsByTagName(XS::ToXMLCh("xs:documentation"));
|
||||||
|
if (documentationTags->getLength() != 0) {
|
||||||
|
auto child = documentationTags->item(0)->getFirstChild();
|
||||||
|
if (child != nullptr) {
|
||||||
|
compInfo.Meta.Annotation = XS::ToString(child->getNodeValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG_WARNING("Component is missing an annotation!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// <xs:complexType>
|
||||||
|
auto typeDefinition = element->getTypeDefinition();
|
||||||
|
if (typeDefinition->getTypeCategory() != XSTypeDefinition::COMPLEX_TYPE) {
|
||||||
|
LOG_ERROR("Type definition wasn't COMPLEX_TYPE! Skipping.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto complexTypeDefinition = dynamic_cast<XSComplexTypeDefinition*>(typeDefinition);
|
||||||
|
|
||||||
|
// <xs:all>
|
||||||
|
auto modelGroupParticle = complexTypeDefinition->getParticle();
|
||||||
|
if (modelGroupParticle->getTermType() != XSParticle::TERM_MODELGROUP) {
|
||||||
|
LOG_ERROR("Model group particle wasn't TERM_MODELGROUP! Skipping.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto modelGroup = modelGroupParticle->getModelGroupTerm();
|
||||||
|
|
||||||
|
// <xs:element...
|
||||||
|
// <xs:attribute...
|
||||||
|
unsigned int fieldOffset = 0;
|
||||||
|
auto particles = modelGroup->getParticles();
|
||||||
|
for (unsigned int i = 0; i < particles->size(); ++i) {
|
||||||
|
auto particle = particles->elementAt(i);
|
||||||
|
if (particle->getTermType() != XSParticle::TERM_ELEMENT) {
|
||||||
|
LOG_ERROR("Particle wasn't TERM_ELEMENT! Skipping.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto elementDeclaration = particle->getElementTerm();
|
||||||
|
|
||||||
|
std::string name = XS::ToString(elementDeclaration->getName());
|
||||||
|
std::string type = XS::ToString(elementDeclaration->getTypeDefinition()->getName());
|
||||||
|
|
||||||
|
size_t stride = EntityFile::GetTypeStride(type);
|
||||||
|
if (stride == 0) {
|
||||||
|
std::cout << "Warning: Field \"" << name << "\" in component \"" << compInfo.Name << "\" uses unexpected field type \"" << type << "\". Skipping." << std::endl;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& field = compInfo.Fields[name];
|
||||||
|
field.Name = name;
|
||||||
|
field.Type = type;
|
||||||
|
field.Offset = fieldOffset;
|
||||||
|
field.Stride = stride;
|
||||||
|
compInfo.FieldsInOrder.push_back(name);
|
||||||
|
|
||||||
|
fieldOffset += stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
compInfo.Meta.Stride = fieldOffset;
|
||||||
|
m_ComponentInfo[compInfo.Name] = compInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityFilePreprocessor::parseDefaults()
|
||||||
|
{
|
||||||
|
using namespace xercesc;
|
||||||
|
|
||||||
|
EntityFileXMLErrorHandler errorHandler;
|
||||||
|
|
||||||
|
for (auto& ci : m_ComponentInfo) {
|
||||||
|
// Allocate memory for default values
|
||||||
|
ci.second.Defaults = std::shared_ptr<char>(new char[ci.second.Meta.Stride]);
|
||||||
|
memset(ci.second.Defaults.get(), 0, ci.second.Meta.Stride);
|
||||||
|
|
||||||
|
XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager);
|
||||||
|
parser.setErrorHandler(&errorHandler);
|
||||||
|
|
||||||
|
std::string componentName = ci.first;
|
||||||
|
LOG_DEBUG("Parsing defaults for component %s", componentName.c_str());
|
||||||
|
boost::filesystem::path defaultsFile = "Schema/Components/" + componentName + ".xml";
|
||||||
|
|
||||||
|
parser.parse(defaultsFile.string().c_str());
|
||||||
|
auto doc = parser.getDocument();
|
||||||
|
if (doc == nullptr) {
|
||||||
|
LOG_ERROR("%s not found! Skipping.", defaultsFile.string().c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the node in the components namespace matching the component name
|
||||||
|
std::string tagName = "c:" + componentName;
|
||||||
|
auto rootNodes = doc->getElementsByTagName(XS::ToXMLCh(tagName));
|
||||||
|
if (rootNodes->getLength() == 0) {
|
||||||
|
LOG_ERROR("Couldn't find defaults for component \"%s\"! Skipping.", componentName.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto componentElement = dynamic_cast<DOMElement*>(rootNodes->item(0));
|
||||||
|
|
||||||
|
// Fill the default value buffer with values
|
||||||
|
for (auto& kv : ci.second.Fields) {
|
||||||
|
std::string fieldName = kv.first;
|
||||||
|
auto& field = kv.second;
|
||||||
|
auto fieldNodes = componentElement->getElementsByTagName(XS::ToXMLCh(fieldName));
|
||||||
|
auto fieldNode = fieldNodes->item(0);
|
||||||
|
if (fieldNode == nullptr) {
|
||||||
|
LOG_ERROR("Defaults for component \"%s\" is missing field \"%s\"!", componentName.c_str(), fieldName.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto fieldElement = dynamic_cast<DOMElement*>(fieldNode);
|
||||||
|
|
||||||
|
char* data = ci.second.Defaults.get() + field.Offset;
|
||||||
|
|
||||||
|
// Handle potential field attributes
|
||||||
|
if (fieldElement->hasAttributes()) {
|
||||||
|
std::map<std::string, std::string> attributes;
|
||||||
|
auto attributeMap = fieldElement->getAttributes();
|
||||||
|
for (int i = 0; i < attributeMap->getLength(); ++i) {
|
||||||
|
auto attribItem = attributeMap->item(i);
|
||||||
|
attributes[XS::ToString(attribItem->getNodeName())] = XS::ToString(attribItem->getNodeValue());
|
||||||
|
}
|
||||||
|
EntityFile::WriteAttributeData(data, field, attributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle potential field values
|
||||||
|
auto childNode = fieldElement->getFirstChild();
|
||||||
|
if (childNode != nullptr && childNode->getNodeType() == DOMNode::TEXT_NODE) {
|
||||||
|
char* cstrValue = XMLString::transcode(childNode->getNodeValue());
|
||||||
|
EntityFile::WriteValueData(data, field, cstrValue);
|
||||||
|
XMLString::release(&cstrValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
#include "Core/EntityFileWriter.h"
|
||||||
|
|
||||||
|
#define X(str) XS::ToXMLCh(str)
|
||||||
|
|
||||||
|
void EntityFileWriter::WriteWorld(World* world)
|
||||||
|
{
|
||||||
|
WriteEntity(world, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityFileWriter::WriteEntity(World* world, EntityID entity)
|
||||||
|
{
|
||||||
|
using namespace xercesc;
|
||||||
|
DOMDocument* doc = m_DOMImplementation->createDocument(nullptr, X("Entity"), nullptr);
|
||||||
|
DOMElement* root = doc->getDocumentElement();
|
||||||
|
root->setAttribute(X("xmlns:xsi"), X("http://www.w3.org/2001/XMLSchema-instance"));
|
||||||
|
root->setAttribute(X("xsi:noNamespaceSchemaLocation"), X("../Types/Entity.xsd"));
|
||||||
|
root->setAttribute(X("xmlns:c"), X("components"));
|
||||||
|
const std::string& name = world->GetName(entity);
|
||||||
|
if (!name.empty()) {
|
||||||
|
root->setAttribute(X("name"), X(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
DOMElement* componentsElement = doc->createElement(X("Components"));
|
||||||
|
root->appendChild(componentsElement);
|
||||||
|
appentEntityComponents(componentsElement, world, entity);
|
||||||
|
|
||||||
|
DOMElement* childrenElement = doc->createElement(X("Children"));
|
||||||
|
root->appendChild(childrenElement);
|
||||||
|
appendEntityChildren(childrenElement, world, entity);
|
||||||
|
|
||||||
|
try {
|
||||||
|
LocalFileFormatTarget* target = new LocalFileFormatTarget(X(m_FilePath.string()));
|
||||||
|
DOMLSOutput* output = static_cast<DOMImplementationLS*>(m_DOMImplementation)->createLSOutput();
|
||||||
|
output->setByteStream(target);
|
||||||
|
m_DOMLSSerializer->write(doc, output);
|
||||||
|
delete target;
|
||||||
|
} catch (const std::runtime_error& e) {
|
||||||
|
LOG_ERROR("Failed to save \"%s\": %s", m_FilePath.c_str(), e.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
doc->release();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityFileWriter::appendEntityChildren(xercesc::DOMElement* parentElement, const World* world, EntityID entity)
|
||||||
|
{
|
||||||
|
using namespace xercesc;
|
||||||
|
DOMDocument* doc = parentElement->getOwnerDocument();
|
||||||
|
|
||||||
|
auto childrenRange = world->GetEntityChildren().equal_range(entity);
|
||||||
|
for (auto it = childrenRange.first; it != childrenRange.second; ++it) {
|
||||||
|
EntityID childEntity = it->second;
|
||||||
|
|
||||||
|
DOMElement* entityElement = doc->createElement(X("Entity"));
|
||||||
|
const std::string& name = world->GetName(childEntity);
|
||||||
|
if (!name.empty()) {
|
||||||
|
entityElement->setAttribute(X("name"), X(name));
|
||||||
|
}
|
||||||
|
parentElement->appendChild(entityElement);
|
||||||
|
|
||||||
|
DOMElement* componentsElement = doc->createElement(X("Components"));
|
||||||
|
entityElement->appendChild(componentsElement);
|
||||||
|
appentEntityComponents(componentsElement, world, childEntity);
|
||||||
|
|
||||||
|
DOMElement* childrenElement = doc->createElement(X("Children"));
|
||||||
|
entityElement->appendChild(childrenElement);
|
||||||
|
appendEntityChildren(childrenElement, world, childEntity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityFileWriter::appentEntityComponents(xercesc::DOMElement* parentElement, const World* world, EntityID entity)
|
||||||
|
{
|
||||||
|
using namespace xercesc;
|
||||||
|
DOMDocument* doc = parentElement->getOwnerDocument();
|
||||||
|
auto& componentPools = world->GetComponentPools();
|
||||||
|
|
||||||
|
// Step through all component pools to get an entity's components
|
||||||
|
// HACK: This is sloooow.
|
||||||
|
for (auto& kv : componentPools) {
|
||||||
|
const std::string& componentName = kv.first;
|
||||||
|
if (!world->HasComponent(entity, componentName)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
std::string qualifiedComponentName = "c:" + componentName;
|
||||||
|
DOMElement* componentElement = doc->createElement(X(qualifiedComponentName));
|
||||||
|
parentElement->appendChild(componentElement);
|
||||||
|
ComponentWrapper c = kv.second->GetByEntity(entity);
|
||||||
|
for (auto& kv : c.Info.Fields) {
|
||||||
|
std::string fieldName = kv.first;
|
||||||
|
auto& field = kv.second;
|
||||||
|
|
||||||
|
// Ignore fields that are equal to the default
|
||||||
|
// HACK: This is probably sloooooow, but it's okay.
|
||||||
|
if (memcmp(c.Data + field.Offset, c.Info.Defaults.get() + field.Offset, field.Stride) == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
DOMElement* fieldElement = doc->createElement(X(fieldName));
|
||||||
|
componentElement->appendChild(fieldElement);
|
||||||
|
|
||||||
|
if (field.Type == "Vector") {
|
||||||
|
const glm::vec3& vec = c[fieldName];
|
||||||
|
fieldElement->setAttribute(X("X"), X(boost::lexical_cast<std::string>(vec.x)));
|
||||||
|
fieldElement->setAttribute(X("Y"), X(boost::lexical_cast<std::string>(vec.y)));
|
||||||
|
fieldElement->setAttribute(X("Z"), X(boost::lexical_cast<std::string>(vec.z)));
|
||||||
|
} else if (field.Type == "Color") {
|
||||||
|
const glm::vec4& vec = c[fieldName];
|
||||||
|
fieldElement->setAttribute(X("R"), X(boost::lexical_cast<std::string>(vec.r)));
|
||||||
|
fieldElement->setAttribute(X("G"), X(boost::lexical_cast<std::string>(vec.g)));
|
||||||
|
fieldElement->setAttribute(X("B"), X(boost::lexical_cast<std::string>(vec.b)));
|
||||||
|
fieldElement->setAttribute(X("A"), X(boost::lexical_cast<std::string>(vec.a)));
|
||||||
|
} else if (field.Type == "Quaternion") {
|
||||||
|
const glm::quat& q = c[fieldName];
|
||||||
|
fieldElement->setAttribute(X("X"), X(boost::lexical_cast<std::string>(q.x)));
|
||||||
|
fieldElement->setAttribute(X("Y"), X(boost::lexical_cast<std::string>(q.y)));
|
||||||
|
fieldElement->setAttribute(X("Z"), X(boost::lexical_cast<std::string>(q.z)));
|
||||||
|
fieldElement->setAttribute(X("W"), X(boost::lexical_cast<std::string>(q.w)));
|
||||||
|
} else if (field.Type == "int") {
|
||||||
|
const int& value = c[fieldName];
|
||||||
|
fieldElement->appendChild(doc->createTextNode(X(boost::lexical_cast<std::string>(value))));
|
||||||
|
} else if (field.Type == "float") {
|
||||||
|
const float& value = c[fieldName];
|
||||||
|
fieldElement->appendChild(doc->createTextNode(X(boost::lexical_cast<std::string>(value))));
|
||||||
|
} else if (field.Type == "double") {
|
||||||
|
const double& value = c[fieldName];
|
||||||
|
fieldElement->appendChild(doc->createTextNode(X(boost::lexical_cast<std::string>(value))));
|
||||||
|
} else if (field.Type == "bool") {
|
||||||
|
const bool& value = c[fieldName];
|
||||||
|
if (value) {
|
||||||
|
fieldElement->appendChild(doc->createTextNode(X("true")));
|
||||||
|
} else {
|
||||||
|
fieldElement->appendChild(doc->createTextNode(X("false")));
|
||||||
|
}
|
||||||
|
} else if (field.Type == "string") {
|
||||||
|
const std::string& value = c[fieldName];
|
||||||
|
fieldElement->appendChild(doc->createTextNode(X(value)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,495 +0,0 @@
|
|||||||
#include "Core/EntityXMLFile.h"
|
|
||||||
#include "Core/World.h"
|
|
||||||
|
|
||||||
unsigned int EntityXMLFile::InstanceCount = 0;
|
|
||||||
|
|
||||||
EntityXMLFile::EntityXMLFile(std::string path)
|
|
||||||
: m_EntityFile(path)
|
|
||||||
{
|
|
||||||
using namespace xercesc;
|
|
||||||
|
|
||||||
if (InstanceCount == 0) {
|
|
||||||
XMLPlatformUtils::Initialize();
|
|
||||||
}
|
|
||||||
InstanceCount++;
|
|
||||||
|
|
||||||
m_GrammarPool = new XMLGrammarPoolImpl();
|
|
||||||
m_ErrorHandler = new EntityParserXMLErrorHandler();
|
|
||||||
m_DOMParser = new XercesDOMParser(nullptr, XMLPlatformUtils::fgMemoryManager, m_GrammarPool);
|
|
||||||
m_DOMParser->setErrorHandler(m_ErrorHandler);
|
|
||||||
m_DOMParser->setDoNamespaces(true);
|
|
||||||
m_DOMParser->setDoXInclude(true);
|
|
||||||
m_DOMParser->setDoSchema(true);
|
|
||||||
m_DOMParser->setValidationSchemaFullChecking(true);
|
|
||||||
m_DOMParser->setValidationScheme(xercesc::XercesDOMParser::Val_Auto);
|
|
||||||
m_DOMParser->setValidationSchemaFullChecking(true);
|
|
||||||
m_DOMParser->setValidationConstraintFatal(false);
|
|
||||||
m_DOMParser->setIncludeIgnorableWhitespace(false);
|
|
||||||
// Make sure schema grammar is kept after validation
|
|
||||||
m_DOMParser->cacheGrammarFromParse(true);
|
|
||||||
|
|
||||||
// HACK: Use Sax2 parser instead so the entire DOM doesn't have to reside in memory
|
|
||||||
m_DOMParser->parse(m_EntityFile.c_str());
|
|
||||||
m_DOMDocument = m_DOMParser->getDocument();
|
|
||||||
|
|
||||||
// 1. Fill in ComponentInfo name, fields, default values and metadata from PSVI
|
|
||||||
parseComponentInfo();
|
|
||||||
// 2. Parse default value files for those components
|
|
||||||
parseDefaults();
|
|
||||||
// 3. Allocate component structures
|
|
||||||
predictComponentAllocation();
|
|
||||||
}
|
|
||||||
|
|
||||||
EntityXMLFile::~EntityXMLFile()
|
|
||||||
{
|
|
||||||
using namespace xercesc;
|
|
||||||
|
|
||||||
if (m_DOMParser != nullptr) {
|
|
||||||
delete m_DOMParser;
|
|
||||||
}
|
|
||||||
if (m_ErrorHandler != nullptr) {
|
|
||||||
delete m_ErrorHandler;
|
|
||||||
}
|
|
||||||
if (m_GrammarPool != nullptr) {
|
|
||||||
delete m_GrammarPool;
|
|
||||||
}
|
|
||||||
|
|
||||||
InstanceCount--;
|
|
||||||
if (InstanceCount == 0) {
|
|
||||||
XMLPlatformUtils::Terminate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EntityXMLFile::PopulateWorld(World* world)
|
|
||||||
{
|
|
||||||
for (auto& pair : m_ComponentInfo) {
|
|
||||||
world->RegisterComponent(pair.second);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. Parse entity hierarchy
|
|
||||||
auto root = m_DOMDocument->getDocumentElement();
|
|
||||||
parseEntityGraph(world, root, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void EntityXMLFile::preprocess(std::string inPath, std::string outPath)
|
|
||||||
{
|
|
||||||
using namespace xercesc;
|
|
||||||
|
|
||||||
static const XMLCh gLS[] = { 'L', 'S', '\0' };
|
|
||||||
DOMImplementationLS* di = static_cast<DOMImplementationLS*>(DOMImplementationRegistry::getDOMImplementation(gLS));
|
|
||||||
|
|
||||||
// Parse the file
|
|
||||||
DOMLSParser* parser = di->createLSParser(DOMImplementationLS::MODE_SYNCHRONOUS, nullptr);
|
|
||||||
DOMConfiguration* config = parser->getDomConfig();
|
|
||||||
config->setParameter(XMLUni::fgDOMNamespaces, true);
|
|
||||||
config->setParameter(XMLUni::fgXercesSchema, true);
|
|
||||||
config->setParameter(XMLUni::fgXercesHandleMultipleImports, true);
|
|
||||||
config->setParameter(XMLUni::fgXercesSchemaFullChecking, true);
|
|
||||||
config->setParameter(XMLUni::fgXercesDoXInclude, true);
|
|
||||||
auto errHandler = new EntityPreprocessorXMLErrorHandler();
|
|
||||||
config->setParameter(XMLUni::fgDOMErrorHandler, errHandler);
|
|
||||||
|
|
||||||
auto source = new LocalFileInputSource(XSTR(inPath.c_str()));
|
|
||||||
Wrapper4InputSource* domSourceWrapper = new Wrapper4InputSource(source);
|
|
||||||
DOMDocument* doc = parser->parse(dynamic_cast<DOMLSInput*>(domSourceWrapper));
|
|
||||||
|
|
||||||
// Serialize and output the new XML
|
|
||||||
DOMLSSerializer* writer = di->createLSSerializer();
|
|
||||||
DOMLSOutput* output = di->createLSOutput();
|
|
||||||
XMLFormatTarget* formatTarget = new LocalFileFormatTarget(outPath.c_str());
|
|
||||||
// TODO: MemBufFormatTarget* formatTarget = new MemBufFormatTarget()
|
|
||||||
output->setByteStream(formatTarget);
|
|
||||||
writer->write(doc, output);
|
|
||||||
|
|
||||||
delete formatTarget;
|
|
||||||
output->release();
|
|
||||||
writer->release();
|
|
||||||
parser->release();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EntityXMLFile::parseComponentInfo()
|
|
||||||
{
|
|
||||||
using namespace xercesc;
|
|
||||||
bool wasChanged;
|
|
||||||
XSModel* xsModel = m_GrammarPool->getXSModel(wasChanged);
|
|
||||||
|
|
||||||
// Find component xsd element declarations
|
|
||||||
std::cout << "Enumerating components..." << std::endl;
|
|
||||||
// <xs:element name="ComponentName">
|
|
||||||
auto topLevelElements = xsModel->getComponents(XSConstants::ELEMENT_DECLARATION);
|
|
||||||
for (unsigned int i = 0; i < topLevelElements->getLength(); ++i) {
|
|
||||||
auto element = static_cast<XSElementDeclaration*>(topLevelElements->item(i));
|
|
||||||
|
|
||||||
std::string nameSpace(XSTR(element->getNamespace()));
|
|
||||||
if (nameSpace != "components") {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ComponentInfo compInfo;
|
|
||||||
|
|
||||||
// Name
|
|
||||||
compInfo.Name = XSTR(element->getName());
|
|
||||||
// Annotation
|
|
||||||
auto componentAnnotation = element->getAnnotation();
|
|
||||||
if (componentAnnotation != nullptr) {
|
|
||||||
// Parse annotation XML
|
|
||||||
char* annotationString = XMLString::transcode(componentAnnotation->getAnnotationString());
|
|
||||||
MemBufInputSource annotationInput(reinterpret_cast<const XMLByte*>(annotationString), strlen(annotationString), "MemBuf: Annotation String");
|
|
||||||
XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager, m_GrammarPool);
|
|
||||||
parser.setErrorHandler(m_ErrorHandler);
|
|
||||||
parser.parse(annotationInput);
|
|
||||||
XMLString::release(&annotationString);
|
|
||||||
auto doc = parser.getDocument();
|
|
||||||
|
|
||||||
// Add allocation estimation(s)
|
|
||||||
auto allocationTags = doc->getElementsByTagName(XSTR("meta:allocation"));
|
|
||||||
for (int i = 0; i < allocationTags->getLength(); ++i) {
|
|
||||||
auto allocation = dynamic_cast<DOMElement*>(allocationTags->item(i));
|
|
||||||
auto child = allocation->getFirstChild();
|
|
||||||
if (child == nullptr) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
XSValue::Status status;
|
|
||||||
XSValue* val = XSValue::getActualValue(child->getNodeValue(), XSValue::dt_integer, status);
|
|
||||||
compInfo.Meta.Allocation += val->fData.fValue.f_int;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save documentation string
|
|
||||||
auto documentationTags = doc->getElementsByTagName(XSTR("xs:documentation"));
|
|
||||||
if (documentationTags->getLength() != 0) {
|
|
||||||
auto child = documentationTags->item(0)->getFirstChild();
|
|
||||||
if (child != nullptr) {
|
|
||||||
compInfo.Meta.Annotation = XSTR(child->getNodeValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO: Parse annotation string XML
|
|
||||||
// compInfo.Meta.Allocation = ...
|
|
||||||
} else {
|
|
||||||
std::cout << "Warning: Component is missing an annotation!" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// <xs:complexType>
|
|
||||||
auto typeDefinition = element->getTypeDefinition();
|
|
||||||
if (typeDefinition->getTypeCategory() != XSTypeDefinition::COMPLEX_TYPE) {
|
|
||||||
std::cerr << "Error: Type definition wasn't COMPLEX_TYPE! Skipping." << std::endl;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
auto complexTypeDefinition = dynamic_cast<XSComplexTypeDefinition*>(typeDefinition);
|
|
||||||
|
|
||||||
// <xs:all>
|
|
||||||
auto modelGroupParticle = complexTypeDefinition->getParticle();
|
|
||||||
if (modelGroupParticle->getTermType() != XSParticle::TERM_MODELGROUP) {
|
|
||||||
std::cerr << "Error: Model group particle wasn't TERM_MODELGROUP! Skipping." << std::endl;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
auto modelGroup = modelGroupParticle->getModelGroupTerm();
|
|
||||||
|
|
||||||
// <xs:element...
|
|
||||||
// <xs:attribute...
|
|
||||||
unsigned int fieldOffset = 0;
|
|
||||||
auto particles = modelGroup->getParticles();
|
|
||||||
for (unsigned int i = 0; i < particles->size(); ++i) {
|
|
||||||
auto particle = particles->elementAt(i);
|
|
||||||
if (particle->getTermType() != XSParticle::TERM_ELEMENT) {
|
|
||||||
std::cerr << "Error: Particle wasn't TERM_ELEMENT! Skipping." << std::endl;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
auto elementDeclaration = particle->getElementTerm();
|
|
||||||
|
|
||||||
std::string name = XSTR(elementDeclaration->getName());
|
|
||||||
std::string type = XSTR(elementDeclaration->getTypeDefinition()->getName());
|
|
||||||
|
|
||||||
size_t stride = getTypeStride(type);
|
|
||||||
if (stride == 0) {
|
|
||||||
std::cout << "Warning: Field \"" << name << "\" in component \"" << compInfo.Name << "\" uses unexpected field type \"" << type << "\". Skipping." << std::endl;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
compInfo.FieldTypes[name] = type;
|
|
||||||
compInfo.FieldOffsets[name] = fieldOffset;
|
|
||||||
fieldOffset += getTypeStride(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
compInfo.Meta.Stride = fieldOffset;
|
|
||||||
m_ComponentInfo[compInfo.Name] = compInfo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EntityXMLFile::parseDefaults()
|
|
||||||
{
|
|
||||||
using namespace xercesc;
|
|
||||||
|
|
||||||
for (auto& ci : m_ComponentInfo) {
|
|
||||||
// Allocate memory for default values
|
|
||||||
ci.second.Defaults = std::shared_ptr<char>(new char[ci.second.Meta.Stride]);
|
|
||||||
memset(ci.second.Defaults.get(), 0, ci.second.Meta.Stride);
|
|
||||||
|
|
||||||
XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager);
|
|
||||||
parser.setErrorHandler(m_ErrorHandler);
|
|
||||||
|
|
||||||
std::string componentName = ci.first;
|
|
||||||
LOG_DEBUG("Parsing defaults for component %s", componentName.c_str());
|
|
||||||
boost::filesystem::path defaultsFile = "Schema/Components/" + componentName + ".xml";
|
|
||||||
|
|
||||||
parser.parse(defaultsFile.string().c_str());
|
|
||||||
auto doc = parser.getDocument();
|
|
||||||
if (doc == nullptr) {
|
|
||||||
LOG_ERROR("%s not found! Skipping.", defaultsFile.string().c_str());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the node in the components namespace matching the component name
|
|
||||||
std::string tagName = "c:" + componentName;
|
|
||||||
auto rootNodes = doc->getElementsByTagName(XSTR(tagName.c_str()));
|
|
||||||
if (rootNodes->getLength() == 0) {
|
|
||||||
LOG_ERROR("Couldn't find defaults for component \"%s\"! Skipping.", componentName.c_str());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
auto componentElement = dynamic_cast<DOMElement*>(rootNodes->item(0));
|
|
||||||
|
|
||||||
// Fill the default value buffer with values
|
|
||||||
for (auto& field : ci.second.FieldOffsets) {
|
|
||||||
std::string fieldName = field.first;
|
|
||||||
auto fieldNodes = componentElement->getElementsByTagName(XSTR(fieldName.c_str()));
|
|
||||||
auto fieldNode = fieldNodes->item(0);
|
|
||||||
if (fieldNode == nullptr) {
|
|
||||||
LOG_ERROR("Defaults for component \"%s\" is missing field \"%s\"!", componentName.c_str(), fieldName.c_str());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
auto fieldElement = dynamic_cast<DOMElement*>(fieldNode);
|
|
||||||
|
|
||||||
std::string fieldType = ci.second.FieldTypes.at(fieldName);
|
|
||||||
unsigned int fieldOffset = ci.second.FieldOffsets.at(fieldName);
|
|
||||||
writeData(fieldElement, fieldType, ci.second.Defaults.get() + fieldOffset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EntityXMLFile::predictComponentAllocation()
|
|
||||||
{
|
|
||||||
using namespace xercesc;
|
|
||||||
|
|
||||||
auto root = m_DOMDocument->getDocumentElement();
|
|
||||||
|
|
||||||
// Count static instances of components present in entity hierarchy
|
|
||||||
auto components = m_DOMDocument->getElementsByTagNameNS(XSTR("components"), XSTR("*"));
|
|
||||||
for (int i = 0; i < components->getLength(); ++i) {
|
|
||||||
auto component = dynamic_cast<DOMElement*>(components->item(i));
|
|
||||||
|
|
||||||
std::string componentName = XSTR(component->getLocalName());
|
|
||||||
auto& compInfo = m_ComponentInfo.at(componentName);
|
|
||||||
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 << " Fields:" << std::endl;
|
|
||||||
|
|
||||||
// Calculate component size
|
|
||||||
std::size_t stride = 0;
|
|
||||||
// Add size of fields
|
|
||||||
for (auto& field : ci.FieldTypes) {
|
|
||||||
std::cout << " " << field.second << " " << field.first << " (" << getTypeStride(field.second) << " byte)" << std::endl;
|
|
||||||
stride += getTypeStride(field.second);
|
|
||||||
}
|
|
||||||
std::cout << " Stride: " << ci.Meta.Stride << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EntityXMLFile::parseEntityGraph(World* world, xercesc::DOMElement* element, EntityID parentEntity)
|
|
||||||
{
|
|
||||||
using namespace xercesc;
|
|
||||||
|
|
||||||
// Create entity
|
|
||||||
EntityID entity = world->CreateEntity(parentEntity);
|
|
||||||
LOG_DEBUG("Created entity %i, parent %i", entity, parentEntity);
|
|
||||||
|
|
||||||
// Add components
|
|
||||||
auto components = m_DOMDocument->evaluate(XSTR("Components/*"), element, nullptr, DOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE, nullptr);
|
|
||||||
for (int i = 0; i < components->getSnapshotLength(); i++) {
|
|
||||||
components->snapshotItem(i);
|
|
||||||
auto componentElement = dynamic_cast<DOMElement*>(components->getNodeValue());
|
|
||||||
std::string componentName = XSTR(componentElement->getLocalName());
|
|
||||||
auto& ci = m_ComponentInfo.at(componentName);
|
|
||||||
|
|
||||||
// Attach the component
|
|
||||||
auto c = world->AttachComponent(entity, componentName);
|
|
||||||
LOG_DEBUG("Attached %s component", componentName.c_str());
|
|
||||||
|
|
||||||
// Write field data
|
|
||||||
auto fields = componentElement->getChildNodes();
|
|
||||||
for (int j = 0; j < fields->getLength(); ++j) {
|
|
||||||
auto fieldNode = fields->item(j);
|
|
||||||
auto nodeType = fieldNode->getNodeType();
|
|
||||||
if (nodeType != DOMNode::ELEMENT_NODE) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
auto field = dynamic_cast<DOMElement*>(fields->item(j));
|
|
||||||
//const XMLCh* value = fields->item(j)->getTextContent();
|
|
||||||
std::string fieldName(XSTR(field->getLocalName()));
|
|
||||||
if (ci.FieldTypes.find(fieldName) == ci.FieldTypes.end()) {
|
|
||||||
std::cout << "Warning: Component \"" << componentName << "\" contains invalid field \"" << fieldName << "\". Skipping." << std::endl;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string fieldType = ci.FieldTypes.at(fieldName);
|
|
||||||
unsigned int fieldOffset = ci.FieldOffsets.at(fieldName);
|
|
||||||
std::string fieldValue(XSTR(field->getTextContent()));
|
|
||||||
LOG_DEBUG(" %s %s = %s", fieldType.c_str(), fieldName.c_str(), fieldValue.c_str());
|
|
||||||
writeData(field, fieldType, c.Data + fieldOffset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recurse children
|
|
||||||
auto children = m_DOMDocument->evaluate(XSTR("Children/Entity"), element, nullptr, DOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE, nullptr);
|
|
||||||
for (int i = 0; i < children->getSnapshotLength(); i++) {
|
|
||||||
children->snapshotItem(i);
|
|
||||||
parseEntityGraph(world, dynamic_cast<DOMElement*>(children->getNodeValue()), entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
//auto components = m_DOMDocument->getElementsByTagNameNS(XSTR("components"), XSTR("*"));
|
|
||||||
//for (int i = 0; i < components->getLength(); ++i) {
|
|
||||||
// auto component = dynamic_cast<DOMElement*>(components->item(i));
|
|
||||||
|
|
||||||
// std::string componentName = XSTR(component->getLocalName());
|
|
||||||
// auto& compStore = m_ComponentStore.at(componentName);
|
|
||||||
// auto& compInfo = compStore.Info;
|
|
||||||
|
|
||||||
// char* data = &compStore.Data[compStore.Size*compStore.Stride];
|
|
||||||
// compStore.Size += 1;
|
|
||||||
|
|
||||||
// auto fields = component->getChildNodes();
|
|
||||||
// for (int j = 0; j < fields->getLength(); ++j) {
|
|
||||||
// auto field = fields->item(j);
|
|
||||||
// auto nodeType = field->getNodeType();
|
|
||||||
// if (nodeType != DOMNode::ELEMENT_NODE) {
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
// //auto field = dynamic_cast<DOMElement*>(fields->item(j));
|
|
||||||
// //const XMLCh* value = fields->item(j)->getTextContent();
|
|
||||||
// std::string fieldName = XSTR(field->getLocalName());
|
|
||||||
// if (compInfo.FieldTypes.find(fieldName) == compInfo.FieldTypes.end()) {
|
|
||||||
// std::cout << "Warning: Component \"" << componentName << "\" contains invalid field \"" << fieldName << "\". Skipping." << std::endl;
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// std::string fieldType = compInfo.FieldTypes.at(fieldName);
|
|
||||||
// unsigned int fieldOffset = compInfo.FieldOffsets.at(fieldName);
|
|
||||||
|
|
||||||
// XSValue::DataType dataType = XSValue::getDataType(XSTR(fieldType.c_str()));
|
|
||||||
// if (dataType == XSValue::DataType::dt_MAXCOUNT) {
|
|
||||||
// // TODO:
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
// if (dataType == XSValue::DataType::dt_string) {
|
|
||||||
// char* str = XMLString::transcode(field->getTextContent());
|
|
||||||
// std::string standardString(str);
|
|
||||||
// XMLString::release(&str);
|
|
||||||
// memcpy(&data[fieldOffset], reinterpret_cast<char*>(&standardString), getTypeStride(fieldType));
|
|
||||||
// } else {
|
|
||||||
// XSValue::Status status;
|
|
||||||
// XSValue* val = XSValue::getActualValue(field->getTextContent(), dataType, status);
|
|
||||||
// memcpy(&data[fieldOffset], reinterpret_cast<char*>(&val->fData.fValue), getTypeStride(fieldType));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
//auto entities = m_DOMDocument->getElementsByTagName(XSTR("Entity"));
|
|
||||||
//for (int i = 0; i < entities->getLength(); ++i) {
|
|
||||||
// auto entity = dynamic_cast<DOMElement*>(entities->item(i));
|
|
||||||
|
|
||||||
|
|
||||||
// //entity->setIdAttribute()
|
|
||||||
|
|
||||||
// std::cout << "ENTITY " << i + 1 << std::endl;
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t EntityXMLFile::getTypeStride(std::string typeName)
|
|
||||||
{
|
|
||||||
std::map<std::string, size_t> typeStrides{
|
|
||||||
{ "bool", sizeof(bool) },
|
|
||||||
{ "int", sizeof(int) },
|
|
||||||
{ "float", sizeof(float) },
|
|
||||||
{ "double", sizeof(double) },
|
|
||||||
{ "string", sizeof(std::string) },
|
|
||||||
{ "Vector", sizeof(glm::vec3) },
|
|
||||||
{ "Quaternion", sizeof(glm::quat) },
|
|
||||||
{ "Color", sizeof(glm::vec4) }
|
|
||||||
};
|
|
||||||
|
|
||||||
auto it = typeStrides.find(typeName);
|
|
||||||
return (it != typeStrides.end()) ? it->second : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
float EntityXMLFile::getFloatAttribute(const xercesc::DOMElement* element, const char* attribute) const
|
|
||||||
{
|
|
||||||
using namespace xercesc;
|
|
||||||
XSValue::Status status;
|
|
||||||
XSValue* val = XSValue::getActualValue(element->getAttribute(XSTR(attribute)), xercesc::XSValue::DataType::dt_double, status);
|
|
||||||
if (val == nullptr) {
|
|
||||||
LOG_ERROR("Element \"%s\" doesn't have an \"%s\" attribute!", XSTR(element->getTagName()), attribute);
|
|
||||||
return 0.f;
|
|
||||||
} else {
|
|
||||||
return static_cast<float>(val->fData.fValue.f_double);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EntityXMLFile::writeData(const xercesc::DOMElement* element, std::string typeName, char* outData)
|
|
||||||
{
|
|
||||||
using namespace xercesc;
|
|
||||||
|
|
||||||
if (typeName == "Vector") {
|
|
||||||
glm::vec3 vec;
|
|
||||||
vec.x = getFloatAttribute(element, "X");
|
|
||||||
vec.y = getFloatAttribute(element, "Y");
|
|
||||||
vec.z = getFloatAttribute(element, "Z");
|
|
||||||
memcpy(outData, reinterpret_cast<char*>(&vec), getTypeStride(typeName));
|
|
||||||
} else if (typeName == "Color") {
|
|
||||||
glm::vec4 vec;
|
|
||||||
vec.r = getFloatAttribute(element, "R");
|
|
||||||
vec.g = getFloatAttribute(element, "G");
|
|
||||||
vec.b = getFloatAttribute(element, "B");
|
|
||||||
vec.a = getFloatAttribute(element, "A");
|
|
||||||
memcpy(outData, reinterpret_cast<char*>(&vec), getTypeStride(typeName));
|
|
||||||
} else if (typeName == "Quaternion") {
|
|
||||||
glm::quat q;
|
|
||||||
q.x = getFloatAttribute(element, "X");
|
|
||||||
q.y = getFloatAttribute(element, "Y");
|
|
||||||
q.z = getFloatAttribute(element, "Z");
|
|
||||||
q.w = getFloatAttribute(element, "W");
|
|
||||||
memcpy(outData, reinterpret_cast<char*>(&q), getTypeStride(typeName));
|
|
||||||
} else if (typeName == "float") {
|
|
||||||
XSValue::Status status;
|
|
||||||
XSValue* val = XSValue::getActualValue(element->getTextContent(), xercesc::XSValue::DataType::dt_float, status);
|
|
||||||
memcpy(outData, reinterpret_cast<char*>(&val->fData.fValue.f_float), getTypeStride(typeName));
|
|
||||||
} else if (typeName == "double") {
|
|
||||||
XSValue::Status status;
|
|
||||||
XSValue* val = XSValue::getActualValue(element->getTextContent(), xercesc::XSValue::DataType::dt_double, status);
|
|
||||||
memcpy(outData, reinterpret_cast<char*>(&val->fData.fValue.f_double), getTypeStride(typeName));
|
|
||||||
} else if (typeName == "bool") {
|
|
||||||
XSValue::Status status;
|
|
||||||
XSValue* val = XSValue::getActualValue(element->getTextContent(), xercesc::XSValue::DataType::dt_boolean, status);
|
|
||||||
memcpy(outData, reinterpret_cast<char*>(&val->fData.fValue.f_bool), getTypeStride(typeName));
|
|
||||||
} else {
|
|
||||||
XSValue::DataType dataType = XSValue::getDataType(XSTR(typeName.c_str()));
|
|
||||||
if (dataType == XSValue::DataType::dt_string) {
|
|
||||||
char* str = XMLString::transcode(element->getTextContent());
|
|
||||||
std::string standardString(str);
|
|
||||||
new (outData) std::string(str);
|
|
||||||
XMLString::release(&str);
|
|
||||||
//memcpy(outData, reinterpret_cast<char*>(&standardString), getTypeStride(typeName));
|
|
||||||
} else {
|
|
||||||
//XSValue::Status status;
|
|
||||||
//XSValue* val = XSValue::getActualValue(element->getTextContent(), dataType, status);
|
|
||||||
//memcpy(outData, reinterpret_cast<char*>(&val->fData.fValue), getTypeStride(typeName));
|
|
||||||
LOG_WARNING("Unknown native data type: %s", typeName.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -2,21 +2,24 @@
|
|||||||
|
|
||||||
BaseEventRelay::~BaseEventRelay()
|
BaseEventRelay::~BaseEventRelay()
|
||||||
{
|
{
|
||||||
if (m_Broker != nullptr) {
|
if (m_Broker != nullptr) {
|
||||||
m_Broker->Unsubscribe(*this);
|
m_Broker->Unsubscribe(*this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventBroker::Unsubscribe(BaseEventRelay &relay) // ?
|
void EventBroker::Unsubscribe(BaseEventRelay& relay) // ?
|
||||||
{
|
{
|
||||||
if (m_IsProcessing) {
|
auto identifier = std::make_tuple(relay.m_EventID, relay.m_ContextTypeName, relay.m_EventTypeName);
|
||||||
m_RelaysToUnsubscribe.push_back(&relay);
|
|
||||||
} else {
|
relay.m_Broker = nullptr;
|
||||||
unsubscribeImmediate(relay);
|
if (m_IsProcessing) {
|
||||||
}
|
m_RelaysToUnsubscribe.push_back(identifier);
|
||||||
|
} else {
|
||||||
|
unsubscribeImmediate(identifier);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventBroker::Subscribe(BaseEventRelay &relay)
|
void EventBroker::Subscribe(BaseEventRelay& relay)
|
||||||
{
|
{
|
||||||
if (m_IsProcessing) {
|
if (m_IsProcessing) {
|
||||||
m_RelaysToSubscribe.push_back(&relay);
|
m_RelaysToSubscribe.push_back(&relay);
|
||||||
@@ -38,12 +41,11 @@ int EventBroker::Process(std::string contextTypeName)
|
|||||||
|
|
||||||
int eventsProcessed = 0;
|
int eventsProcessed = 0;
|
||||||
for (auto &pair : *m_EventQueueRead) {
|
for (auto &pair : *m_EventQueueRead) {
|
||||||
std::string &eventTypeName = pair.first;
|
std::string& eventTypeName = pair.first;
|
||||||
std::shared_ptr<Event> event = pair.second;
|
std::shared_ptr<Event> event = pair.second;
|
||||||
|
|
||||||
auto itpair = relays.equal_range(eventTypeName);
|
auto itpair = relays.equal_range(eventTypeName);
|
||||||
for (auto it2 = itpair.first; it2 != itpair.second; it2++)
|
for (auto it2 = itpair.first; it2 != itpair.second; it2++) {
|
||||||
{
|
|
||||||
std::string name = it2->first;
|
std::string name = it2->first;
|
||||||
BaseEventRelay* relay = it2->second;
|
BaseEventRelay* relay = it2->second;
|
||||||
relay->Receive(event);
|
relay->Receive(event);
|
||||||
@@ -60,8 +62,8 @@ int EventBroker::Process(std::string contextTypeName)
|
|||||||
m_RelaysToSubscribe.clear();
|
m_RelaysToSubscribe.clear();
|
||||||
|
|
||||||
// Process pending unsubscriptions
|
// Process pending unsubscriptions
|
||||||
for (auto& r : m_RelaysToUnsubscribe) {
|
for (auto& identifier : m_RelaysToUnsubscribe) {
|
||||||
unsubscribeImmediate(*r);
|
unsubscribeImmediate(identifier);
|
||||||
}
|
}
|
||||||
m_RelaysToUnsubscribe.clear();
|
m_RelaysToUnsubscribe.clear();
|
||||||
|
|
||||||
@@ -81,21 +83,26 @@ void EventBroker::Clear()
|
|||||||
void EventBroker::subscribeImmediate(BaseEventRelay& relay)
|
void EventBroker::subscribeImmediate(BaseEventRelay& relay)
|
||||||
{
|
{
|
||||||
relay.m_Broker = this;
|
relay.m_Broker = this;
|
||||||
|
relay.m_EventID = m_NextEventID++;
|
||||||
m_ContextRelays[relay.m_ContextTypeName].insert(std::make_pair(relay.m_EventTypeName, &relay));
|
m_ContextRelays[relay.m_ContextTypeName].insert(std::make_pair(relay.m_EventTypeName, &relay));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventBroker::unsubscribeImmediate(BaseEventRelay& relay)
|
void EventBroker::unsubscribeImmediate(std::tuple<EventID, ContextTypeName_t, EventTypeName_t> identifier)
|
||||||
{
|
{
|
||||||
auto contextIt = m_ContextRelays.find(relay.m_ContextTypeName);
|
EventID eventID;
|
||||||
|
ContextTypeName_t contextTypeName;
|
||||||
|
EventTypeName_t eventTypeName;
|
||||||
|
std::tie(eventID, contextTypeName, eventTypeName) = identifier;
|
||||||
|
|
||||||
|
auto contextIt = m_ContextRelays.find(contextTypeName);
|
||||||
if (contextIt == m_ContextRelays.end()) {
|
if (contextIt == m_ContextRelays.end()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto eventRelays = contextIt->second;
|
auto eventRelays = contextIt->second;
|
||||||
auto itpair = eventRelays.equal_range(relay.m_EventTypeName);
|
auto itpair = eventRelays.equal_range(eventTypeName);
|
||||||
for (auto it = itpair.first; it != itpair.second; ++it) {
|
for (auto it = itpair.first; it != itpair.second; ++it) {
|
||||||
if (it->second == &relay) {
|
if (it->second->m_EventID == eventID) {
|
||||||
relay.m_Broker = nullptr;
|
|
||||||
eventRelays.erase(it);
|
eventRelays.erase(it);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
#include "Core/Transform.h"
|
||||||
|
|
||||||
|
glm::vec3 Transform::AbsolutePosition(World* world, EntityID entity)
|
||||||
|
{
|
||||||
|
glm::vec3 position;
|
||||||
|
|
||||||
|
while (entity != EntityID_Invalid) {
|
||||||
|
ComponentWrapper transform = world->GetComponent(entity, "Transform");
|
||||||
|
EntityID parent = world->GetParent(entity);
|
||||||
|
position += Transform::AbsoluteOrientation(world, parent) * (glm::vec3)transform["Position"];
|
||||||
|
entity = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::quat Transform::AbsoluteOrientation(World* world, EntityID entity)
|
||||||
|
{
|
||||||
|
glm::quat orientation;
|
||||||
|
|
||||||
|
while (entity != EntityID_Invalid) {
|
||||||
|
ComponentWrapper transform = world->GetComponent(entity, "Transform");
|
||||||
|
orientation = glm::quat((glm::vec3)transform["Orientation"]) * orientation;
|
||||||
|
entity = world->GetParent(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
return orientation;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 Transform::AbsoluteScale(World* world, EntityID entity)
|
||||||
|
{
|
||||||
|
glm::vec3 scale(1.f);
|
||||||
|
|
||||||
|
while (entity != EntityID_Invalid) {
|
||||||
|
ComponentWrapper transform = world->GetComponent(entity, "Transform");
|
||||||
|
scale *= (glm::vec3)transform["Scale"];
|
||||||
|
entity = world->GetParent(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
return scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::mat4 Transform::ModelMatrix(EntityID entity, World* world)
|
||||||
|
{
|
||||||
|
glm::vec3 position = Transform::AbsolutePosition(world, entity);
|
||||||
|
glm::quat orientation = Transform::AbsoluteOrientation(world, entity);
|
||||||
|
glm::vec3 scale = Transform::AbsoluteScale(world, entity);
|
||||||
|
|
||||||
|
glm::mat4 modelMatrix = glm::translate(glm::mat4(), position) * glm::toMat4(orientation) * glm::scale(scale);
|
||||||
|
return modelMatrix;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -10,12 +10,15 @@ World::~World()
|
|||||||
EntityID World::CreateEntity(EntityID parent /*= 0*/)
|
EntityID World::CreateEntity(EntityID parent /*= 0*/)
|
||||||
{
|
{
|
||||||
EntityID newEntity = generateEntityID();
|
EntityID newEntity = generateEntityID();
|
||||||
|
if (newEntity == parent) {
|
||||||
|
LOG_WARNING("Invalid parent #%i of Entity#%i", newEntity, parent);
|
||||||
|
parent = EntityID_Invalid;
|
||||||
|
}
|
||||||
m_EntityParents[newEntity] = parent;
|
m_EntityParents[newEntity] = parent;
|
||||||
m_EntityChildren.insert(std::make_pair(parent, newEntity));
|
m_EntityChildren.insert(std::make_pair(parent, newEntity));
|
||||||
return newEntity;
|
return newEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void World::DeleteEntity(EntityID entity)
|
void World::DeleteEntity(EntityID entity)
|
||||||
{
|
{
|
||||||
// Delete components
|
// Delete components
|
||||||
@@ -46,15 +49,26 @@ void World::DeleteEntity(EntityID entity)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Erase potential name
|
||||||
|
m_EntityNames.erase(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool World::ValidEntity(EntityID entity) const
|
||||||
|
{
|
||||||
|
return m_EntityParents.find(entity) != m_EntityParents.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::RegisterComponent(ComponentInfo& ci)
|
void World::RegisterComponent(ComponentInfo& ci)
|
||||||
{
|
{
|
||||||
m_ComponentPools[ci.Name] = new ComponentPool(ci);
|
if (m_ComponentPools.find(ci.Name) == m_ComponentPools.end()) {
|
||||||
|
m_ComponentPools[ci.Name] = new ComponentPool(ci);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ComponentWrapper World::AttachComponent(EntityID entity, std::string componentType)
|
ComponentWrapper World::AttachComponent(EntityID entity, std::string componentType)
|
||||||
{
|
{
|
||||||
|
// TODO: Allocate dynamic pool if component isn't registered
|
||||||
ComponentPool* pool = m_ComponentPools.at(componentType);
|
ComponentPool* pool = m_ComponentPools.at(componentType);
|
||||||
const ComponentInfo& ci = pool->ComponentInfo();
|
const ComponentInfo& ci = pool->ComponentInfo();
|
||||||
|
|
||||||
@@ -66,8 +80,7 @@ ComponentWrapper World::AttachComponent(EntityID entity, std::string componentTy
|
|||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool World::HasComponent(EntityID entity, std::string componentType) const
|
||||||
bool World::HasComponent(EntityID entity, std::string componentType)
|
|
||||||
{
|
{
|
||||||
ComponentPool* pool = m_ComponentPools.at(componentType);
|
ComponentPool* pool = m_ComponentPools.at(componentType);
|
||||||
return pool->KnowsEntity(entity);
|
return pool->KnowsEntity(entity);
|
||||||
@@ -79,7 +92,6 @@ ComponentWrapper World::GetComponent(EntityID entity, std::string componentType)
|
|||||||
return pool->GetByEntity(entity);
|
return pool->GetByEntity(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void World::DeleteComponent(EntityID entity, std::string componentType)
|
void World::DeleteComponent(EntityID entity, std::string componentType)
|
||||||
{
|
{
|
||||||
ComponentPool* pool = m_ComponentPools.at(componentType);
|
ComponentPool* pool = m_ComponentPools.at(componentType);
|
||||||
@@ -93,13 +105,11 @@ const ComponentPool* World::GetComponents(std::string componentType)
|
|||||||
return (it != m_ComponentPools.end()) ? it->second : nullptr;
|
return (it != m_ComponentPools.end()) ? it->second : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
EntityID World::GetParent(EntityID entity)
|
EntityID World::GetParent(EntityID entity)
|
||||||
{
|
{
|
||||||
return m_EntityParents.at(entity);
|
return m_EntityParents.at(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void World::SetParent(EntityID entity, EntityID parent)
|
void World::SetParent(EntityID entity, EntityID parent)
|
||||||
{
|
{
|
||||||
EntityID lastParent = m_EntityParents.at(entity);
|
EntityID lastParent = m_EntityParents.at(entity);
|
||||||
@@ -115,6 +125,25 @@ void World::SetParent(EntityID entity, EntityID parent)
|
|||||||
m_EntityChildren.insert(std::make_pair(parent, entity));
|
m_EntityChildren.insert(std::make_pair(parent, entity));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void World::SetName(EntityID entity, const std::string& name)
|
||||||
|
{
|
||||||
|
m_EntityNames[entity] = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string World::GetName(EntityID entity) const
|
||||||
|
{
|
||||||
|
if (entity == EntityID_Invalid) {
|
||||||
|
return "EntityID_Invalid";
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it = m_EntityNames.find(entity);
|
||||||
|
if (it != m_EntityNames.end()) {
|
||||||
|
return it->second;
|
||||||
|
} else {
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
EntityID World::generateEntityID()
|
EntityID World::generateEntityID()
|
||||||
{
|
{
|
||||||
// TODO: Make EntityID generation smarter
|
// TODO: Make EntityID generation smarter
|
||||||
|
|||||||
+239
-119
@@ -9,6 +9,7 @@ EditorSystem::EditorSystem(EventBroker* eventBroker, IRenderer* renderer)
|
|||||||
auto config = ResourceManager::Load<ConfigFile>("Config.ini");
|
auto config = ResourceManager::Load<ConfigFile>("Config.ini");
|
||||||
m_Enabled = config->Get<bool>("Debug.EditorEnabled", false);
|
m_Enabled = config->Get<bool>("Debug.EditorEnabled", false);
|
||||||
m_Visible = m_Enabled;
|
m_Visible = m_Enabled;
|
||||||
|
m_DefaultEntityDir = boost::filesystem::path("Schema") / boost::filesystem::path("Entities");
|
||||||
|
|
||||||
if (!m_Enabled) {
|
if (!m_Enabled) {
|
||||||
return;
|
return;
|
||||||
@@ -18,7 +19,6 @@ EditorSystem::EditorSystem(EventBroker* eventBroker, IRenderer* renderer)
|
|||||||
EVENT_SUBSCRIBE_MEMBER(m_EMousePress, &EditorSystem::OnMousePress);
|
EVENT_SUBSCRIBE_MEMBER(m_EMousePress, &EditorSystem::OnMousePress);
|
||||||
EVENT_SUBSCRIBE_MEMBER(m_EMouseRelease, &EditorSystem::OnMouseRelease);
|
EVENT_SUBSCRIBE_MEMBER(m_EMouseRelease, &EditorSystem::OnMouseRelease);
|
||||||
EVENT_SUBSCRIBE_MEMBER(m_EMouseMove, &EditorSystem::OnMouseMove);
|
EVENT_SUBSCRIBE_MEMBER(m_EMouseMove, &EditorSystem::OnMouseMove);
|
||||||
EVENT_SUBSCRIBE_MEMBER(m_EPicking, &EditorSystem::OnPicking);
|
|
||||||
EVENT_SUBSCRIBE_MEMBER(m_EFileDropped, &EditorSystem::OnFileDropped);
|
EVENT_SUBSCRIBE_MEMBER(m_EFileDropped, &EditorSystem::OnFileDropped);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ void EditorSystem::Update(World* world, double dt)
|
|||||||
if (!m_Visible) {
|
if (!m_Visible) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Picking();
|
||||||
updateWidget();
|
updateWidget();
|
||||||
|
|
||||||
drawUI(world, dt);
|
drawUI(world, dt);
|
||||||
@@ -44,6 +44,35 @@ void EditorSystem::Update(World* world, double dt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
boost::filesystem::path EditorSystem::openDialog(boost::filesystem::path defaultPath)
|
||||||
|
{
|
||||||
|
namespace bfs = boost::filesystem;
|
||||||
|
auto absolutePath = bfs::absolute(defaultPath);
|
||||||
|
nfdchar_t* outPath = nullptr;
|
||||||
|
nfdresult_t result = NFD_OpenDialog(NULL, absolutePath.string().c_str(), &outPath);
|
||||||
|
if (result == NFD_ERROR) {
|
||||||
|
LOG_ERROR("NFD Error: %s", NFD_GetError());
|
||||||
|
return bfs::path();
|
||||||
|
}
|
||||||
|
|
||||||
|
return bfs::absolute(outPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::filesystem::path EditorSystem::saveDialog(boost::filesystem::path defaultPath)
|
||||||
|
{
|
||||||
|
namespace bfs = boost::filesystem;
|
||||||
|
auto absolutePath = bfs::absolute(defaultPath);
|
||||||
|
nfdchar_t* outPath = nullptr;
|
||||||
|
nfdresult_t result = NFD_SaveDialog(NULL, absolutePath.string().c_str(), &outPath);
|
||||||
|
if (result == NFD_ERROR) {
|
||||||
|
LOG_ERROR("NFD Error: %s", NFD_GetError());
|
||||||
|
return bfs::path();
|
||||||
|
}
|
||||||
|
|
||||||
|
return bfs::absolute(outPath);
|
||||||
|
}
|
||||||
|
|
||||||
bool EditorSystem::OnInputCommand(const Events::InputCommand& e)
|
bool EditorSystem::OnInputCommand(const Events::InputCommand& e)
|
||||||
{
|
{
|
||||||
if (e.Command == "ToggleEditor" && e.Value > 0) {
|
if (e.Command == "ToggleEditor" && e.Value > 0) {
|
||||||
@@ -81,17 +110,27 @@ bool EditorSystem::OnMousePress(const Events::MousePress& e)
|
|||||||
|
|
||||||
bool EditorSystem::OnMouseMove(const Events::MouseMove& e)
|
bool EditorSystem::OnMouseMove(const Events::MouseMove& e)
|
||||||
{
|
{
|
||||||
if (m_Widget == 0) {
|
if (m_Widget == EntityID_Invalid) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (m_Selection == EntityID_Invalid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (m_Selection == m_Widget) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// TODO: No widgets for root entity until widgets reside in thier own world,
|
||||||
|
// or the widgets will move relative to the root entity being moved, which is WEEEIRD.
|
||||||
if (m_Selection == 0) {
|
if (m_Selection == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (m_Camera == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
auto widgetTransform = m_World->GetComponent(m_Widget, "Transform");
|
auto widgetTransform = m_World->GetComponent(m_Widget, "Transform");
|
||||||
glm::vec3 widgetOrientation = widgetTransform["Orientation"];
|
glm::vec3 widgetOrientation = widgetTransform["Orientation"];
|
||||||
|
glm::quat totalOrientation = m_Camera->Orientation() * glm::inverse(glm::quat(widgetOrientation));
|
||||||
glm::quat totalOrientation = m_Renderer->Camera()->Orientation() * glm::inverse(glm::quat(widgetOrientation));
|
|
||||||
|
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
@@ -103,14 +142,14 @@ bool EditorSystem::OnMouseMove(const Events::MouseMove& e)
|
|||||||
delta2,
|
delta2,
|
||||||
m_WidgetPickingDepth,
|
m_WidgetPickingDepth,
|
||||||
res,
|
res,
|
||||||
m_Renderer->Camera()->ProjectionMatrix(),
|
m_Camera->ProjectionMatrix(),
|
||||||
glm::toMat4(glm::inverse(totalOrientation))
|
glm::toMat4(glm::inverse(totalOrientation))
|
||||||
);
|
);
|
||||||
glm::vec3 origin = ScreenCoords::ToWorldPos(
|
glm::vec3 origin = ScreenCoords::ToWorldPos(
|
||||||
glm::vec2(res.Width / 2.f, res.Height / 2.f),
|
glm::vec2(res.Width / 2.f, res.Height / 2.f),
|
||||||
m_WidgetPickingDepth,
|
m_WidgetPickingDepth,
|
||||||
res,
|
res,
|
||||||
m_Renderer->Camera()->ProjectionMatrix(),
|
m_Camera->ProjectionMatrix(),
|
||||||
glm::toMat4(glm::inverse(totalOrientation))
|
glm::toMat4(glm::inverse(totalOrientation))
|
||||||
);
|
);
|
||||||
deltaWorld = deltaWorld - origin;
|
deltaWorld = deltaWorld - origin;
|
||||||
@@ -122,9 +161,9 @@ bool EditorSystem::OnMouseMove(const Events::MouseMove& e)
|
|||||||
if (m_WidgetSpace == WidgetSpace::Global) {
|
if (m_WidgetSpace == WidgetSpace::Global) {
|
||||||
EntityID parent = m_World->GetParent(m_Selection);
|
EntityID parent = m_World->GetParent(m_Selection);
|
||||||
glm::quat inverseParentOrientation;
|
glm::quat inverseParentOrientation;
|
||||||
if (parent != 0) {
|
//if (parent != 0) {
|
||||||
inverseParentOrientation = glm::inverse(RenderQueueFactory::AbsoluteOrientation(m_World, parent));
|
inverseParentOrientation = glm::inverse(Transform::AbsoluteOrientation(m_World, parent));
|
||||||
}
|
//}
|
||||||
(glm::vec3&)m_World->GetComponent(m_Selection, "Transform")["Position"] += inverseParentOrientation * movement;
|
(glm::vec3&)m_World->GetComponent(m_Selection, "Transform")["Position"] += inverseParentOrientation * movement;
|
||||||
} else if (m_WidgetSpace == WidgetSpace::Local) {
|
} else if (m_WidgetSpace == WidgetSpace::Local) {
|
||||||
auto selectionTransform = m_World->GetComponent(m_Selection, "Transform");
|
auto selectionTransform = m_World->GetComponent(m_Selection, "Transform");
|
||||||
@@ -138,12 +177,12 @@ bool EditorSystem::OnMouseMove(const Events::MouseMove& e)
|
|||||||
if (m_WidgetSpace == WidgetSpace::Global) {
|
if (m_WidgetSpace == WidgetSpace::Global) {
|
||||||
EntityID parent = m_World->GetParent(m_Selection);
|
EntityID parent = m_World->GetParent(m_Selection);
|
||||||
glm::quat parentOrientation;
|
glm::quat parentOrientation;
|
||||||
if (parent != 0) {
|
//if (parent != 0) {
|
||||||
parentOrientation = RenderQueueFactory::AbsoluteOrientation(m_World, parent);
|
// parentOrientation = RenderSystem::AbsoluteOrientation(m_World, parent);
|
||||||
}
|
//}
|
||||||
glm::vec3& selectionOrientation = m_World->GetComponent(m_Selection, "Transform")["Orientation"];
|
glm::vec3& selectionOrientation = m_World->GetComponent(m_Selection, "Transform")["Orientation"];
|
||||||
//glm::quat currentOrientation = RenderQueueFactory::AbsoluteOrientation(m_World, m_Selection);
|
glm::quat currentOrientation = Transform::AbsoluteOrientation(m_World, m_Selection);
|
||||||
glm::quat currentOrientation = parentOrientation * glm::quat(selectionOrientation);
|
//glm::quat currentOrientation = parentOrientation * glm::quat(selectionOrientation);
|
||||||
glm::quat deltaOrientation(finalMovement);
|
glm::quat deltaOrientation(finalMovement);
|
||||||
selectionOrientation = glm::eulerAngles(glm::inverse(parentOrientation) * (deltaOrientation * currentOrientation));
|
selectionOrientation = glm::eulerAngles(glm::inverse(parentOrientation) * (deltaOrientation * currentOrientation));
|
||||||
} else if (m_WidgetSpace == WidgetSpace::Local) {
|
} else if (m_WidgetSpace == WidgetSpace::Local) {
|
||||||
@@ -198,16 +237,18 @@ bool EditorSystem::OnMouseRelease(const Events::MouseRelease& e)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EditorSystem::OnPicking(const Events::Picking& e)
|
void EditorSystem::Picking()
|
||||||
{
|
{
|
||||||
for (auto& pos : m_PickingQueue) {
|
for (auto& pos : m_PickingQueue) {
|
||||||
auto result = e.Pick(pos);
|
auto result = m_Renderer->Pick(pos);
|
||||||
EntityID entity = result.Entity;
|
EntityID entity = result.Entity;
|
||||||
if (glm::length2(m_WidgetCurrentAxis) > 0.f) {
|
if (glm::length2(m_WidgetCurrentAxis) > 0.f) {
|
||||||
|
// ???
|
||||||
} else {
|
} else {
|
||||||
LOG_INFO("Selected %i", entity);
|
LOG_INFO("Selected %i", entity);
|
||||||
if (entity != 0) {
|
if (entity != EntityID_Invalid) {
|
||||||
EntityID parent = m_World->GetParent(entity);
|
EntityID parent = m_World->GetParent(entity);
|
||||||
|
m_Camera = result.Camera;
|
||||||
if (parent == m_Widget) {
|
if (parent == m_Widget) {
|
||||||
m_WidgetCurrentAxis = glm::vec3(
|
m_WidgetCurrentAxis = glm::vec3(
|
||||||
(entity == m_WidgetX) || (entity == m_WidgetOrigin) || (entity == m_WidgetPlaneY || entity == m_WidgetPlaneZ),
|
(entity == m_WidgetX) || (entity == m_WidgetOrigin) || (entity == m_WidgetPlaneY || entity == m_WidgetPlaneZ),
|
||||||
@@ -215,22 +256,21 @@ bool EditorSystem::OnPicking(const Events::Picking& e)
|
|||||||
(entity == m_WidgetZ) || (entity == m_WidgetOrigin) || (entity == m_WidgetPlaneX || entity == m_WidgetPlaneY)
|
(entity == m_WidgetZ) || (entity == m_WidgetOrigin) || (entity == m_WidgetPlaneX || entity == m_WidgetPlaneY)
|
||||||
);
|
);
|
||||||
m_WidgetPickingDepth = result.Depth;
|
m_WidgetPickingDepth = result.Depth;
|
||||||
|
|
||||||
//auto widgetTransform = m_World->GetComponent(m_Widget, "Transform");
|
//auto widgetTransform = m_World->GetComponent(m_Widget, "Transform");
|
||||||
//auto selectionTransform = m_World->GetComponent(m_Selection, "Transform");
|
//auto selectionTransform = m_World->GetComponent(m_Selection, "Transform");
|
||||||
//widgetTransform["Position"] = (glm::vec3)selectionTransform["Position"];
|
//widgetTransform["Position"] = (glm::vec3)selectionTransform["Position"];
|
||||||
} else {
|
} else {
|
||||||
ImGui::SetActiveID(0, nullptr);
|
ImGui::SetActiveID(0, nullptr);
|
||||||
m_Selection = entity;
|
if (m_WidgetMode == WidgetMode::None) {
|
||||||
|
m_WidgetMode = WidgetMode::Translate;
|
||||||
|
}
|
||||||
setWidgetMode(m_WidgetMode);
|
setWidgetMode(m_WidgetMode);
|
||||||
|
m_Selection = entity;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
m_Selection = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_PickingQueue.clear();
|
m_PickingQueue.clear();
|
||||||
return true;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bool EditorSystem::OnFileDropped(const Events::FileDropped& e)
|
bool EditorSystem::OnFileDropped(const Events::FileDropped& e)
|
||||||
@@ -240,9 +280,9 @@ bool EditorSystem::OnFileDropped(const Events::FileDropped& e)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorSystem::updateWidget()
|
void EditorSystem::createWidget()
|
||||||
{
|
{
|
||||||
if (m_Widget == 0) {
|
if (m_Widget == EntityID_Invalid) {
|
||||||
m_Widget = m_World->CreateEntity();
|
m_Widget = m_World->CreateEntity();
|
||||||
m_World->AttachComponent(m_Widget, "Transform");
|
m_World->AttachComponent(m_Widget, "Transform");
|
||||||
m_WidgetX = m_World->CreateEntity(m_Widget);
|
m_WidgetX = m_World->CreateEntity(m_Widget);
|
||||||
@@ -269,22 +309,32 @@ void EditorSystem::updateWidget()
|
|||||||
m_WidgetOrigin = m_World->CreateEntity(m_Widget);
|
m_WidgetOrigin = m_World->CreateEntity(m_Widget);
|
||||||
m_World->AttachComponent(m_WidgetOrigin, "Transform");
|
m_World->AttachComponent(m_WidgetOrigin, "Transform");
|
||||||
m_World->AttachComponent(m_WidgetOrigin, "Model");
|
m_World->AttachComponent(m_WidgetOrigin, "Model");
|
||||||
setWidgetMode(WidgetMode::Translate);
|
setWidgetMode(WidgetMode::None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorSystem::updateWidget()
|
||||||
|
{
|
||||||
|
if (m_Widget == EntityID_Invalid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (m_Selection == m_Widget) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_Selection != 0) {
|
if (m_Selection != EntityID_Invalid) {
|
||||||
auto widgetTransform = m_World->GetComponent(m_Widget, "Transform");
|
auto widgetTransform = m_World->GetComponent(m_Widget, "Transform");
|
||||||
glm::vec3 selectionPosition = RenderQueueFactory::AbsolutePosition(m_World, m_Selection);
|
glm::vec3 selectionPosition = Transform::AbsolutePosition(m_World, m_Selection);
|
||||||
widgetTransform["Position"] = selectionPosition;
|
widgetTransform["Position"] = selectionPosition;
|
||||||
if (m_WidgetSpace == WidgetSpace::Local) {
|
if (m_WidgetSpace == WidgetSpace::Local) {
|
||||||
widgetTransform["Orientation"] = glm::eulerAngles(RenderQueueFactory::AbsoluteOrientation(m_World, m_Selection));
|
widgetTransform["Orientation"] = glm::eulerAngles(Transform::AbsoluteOrientation(m_World, m_Selection));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorSystem::setWidgetMode(WidgetMode newMode)
|
void EditorSystem::setWidgetMode(WidgetMode newMode)
|
||||||
{
|
{
|
||||||
if (m_Widget == 0) {
|
if (m_Widget == EntityID_Invalid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,10 +359,10 @@ void EditorSystem::setWidgetMode(WidgetMode newMode)
|
|||||||
m_World->GetComponent(m_WidgetPlaneY, "Model")["Visible"] = true;
|
m_World->GetComponent(m_WidgetPlaneY, "Model")["Visible"] = true;
|
||||||
m_World->GetComponent(m_WidgetPlaneZ, "Model")["Visible"] = true;
|
m_World->GetComponent(m_WidgetPlaneZ, "Model")["Visible"] = true;
|
||||||
}
|
}
|
||||||
if (m_Selection != 0) {
|
if (m_Selection != EntityID_Invalid) {
|
||||||
if (m_WidgetSpace == WidgetSpace::Local) {
|
if (m_WidgetSpace == WidgetSpace::Local) {
|
||||||
auto selectionTransform = m_World->GetComponent(m_Selection, "Transform");
|
auto selectionTransform = m_World->GetComponent(m_Selection, "Transform");
|
||||||
widgetTransform["Orientation"] = glm::eulerAngles(RenderQueueFactory::AbsoluteOrientation(m_World, m_Selection));
|
widgetTransform["Orientation"] = glm::eulerAngles(Transform::AbsoluteOrientation(m_World, m_Selection));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (newMode == WidgetMode::Scale) {
|
} else if (newMode == WidgetMode::Scale) {
|
||||||
@@ -321,25 +371,24 @@ void EditorSystem::setWidgetMode(WidgetMode newMode)
|
|||||||
m_World->GetComponent(m_WidgetZ, "Model")["Resource"] = "Models/ScaleWidgetZ.obj";
|
m_World->GetComponent(m_WidgetZ, "Model")["Resource"] = "Models/ScaleWidgetZ.obj";
|
||||||
m_World->GetComponent(m_WidgetOrigin, "Model")["Visible"] = true;
|
m_World->GetComponent(m_WidgetOrigin, "Model")["Visible"] = true;
|
||||||
m_World->GetComponent(m_WidgetOrigin, "Model")["Resource"] = "Models/ScaleWidgetOrigin.obj";
|
m_World->GetComponent(m_WidgetOrigin, "Model")["Resource"] = "Models/ScaleWidgetOrigin.obj";
|
||||||
if (m_Selection != 0) {
|
if (m_Selection != EntityID_Invalid) {
|
||||||
auto selectionTransform = m_World->GetComponent(m_Selection, "Transform");
|
auto selectionTransform = m_World->GetComponent(m_Selection, "Transform");
|
||||||
widgetTransform["Orientation"] = glm::eulerAngles(RenderQueueFactory::AbsoluteOrientation(m_World, m_Selection));
|
widgetTransform["Orientation"] = glm::eulerAngles(Transform::AbsoluteOrientation(m_World, m_Selection));
|
||||||
}
|
}
|
||||||
} else if (newMode == WidgetMode::Rotate) {
|
} else if (newMode == WidgetMode::Rotate) {
|
||||||
m_World->GetComponent(m_WidgetX, "Model")["Resource"] = "Models/RotationWidgetX.obj";
|
m_World->GetComponent(m_WidgetX, "Model")["Resource"] = "Models/RotationWidgetX.obj";
|
||||||
m_World->GetComponent(m_WidgetY, "Model")["Resource"] = "Models/RotationWidgetY.obj";
|
m_World->GetComponent(m_WidgetY, "Model")["Resource"] = "Models/RotationWidgetY.obj";
|
||||||
m_World->GetComponent(m_WidgetZ, "Model")["Resource"] = "Models/RotationWidgetZ.obj";
|
m_World->GetComponent(m_WidgetZ, "Model")["Resource"] = "Models/RotationWidgetZ.obj";
|
||||||
if (m_Selection != 0) {
|
if (m_Selection != EntityID_Invalid) {
|
||||||
auto selectionTransform = m_World->GetComponent(m_Selection, "Transform");
|
auto selectionTransform = m_World->GetComponent(m_Selection, "Transform");
|
||||||
if (m_WidgetSpace == WidgetSpace::Local) {
|
if (m_WidgetSpace == WidgetSpace::Local) {
|
||||||
widgetTransform["Orientation"] = glm::eulerAngles(RenderQueueFactory::AbsoluteOrientation(m_World, m_Selection));
|
widgetTransform["Orientation"] = glm::eulerAngles(Transform::AbsoluteOrientation(m_World, m_Selection));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_WidgetMode = newMode;
|
m_WidgetMode = newMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EditorSystem::setWidgetSpace(WidgetSpace space)
|
void EditorSystem::setWidgetSpace(WidgetSpace space)
|
||||||
{
|
{
|
||||||
m_WidgetSpace = space;
|
m_WidgetSpace = space;
|
||||||
@@ -348,16 +397,23 @@ void EditorSystem::setWidgetSpace(WidgetSpace space)
|
|||||||
|
|
||||||
void EditorSystem::drawUI(World* world, double dt)
|
void EditorSystem::drawUI(World* world, double dt)
|
||||||
{
|
{
|
||||||
|
namespace bfs = boost::filesystem;
|
||||||
|
|
||||||
ImGui::ShowTestWindow();
|
ImGui::ShowTestWindow();
|
||||||
//ImGui::ShowStyleEditor();
|
//ImGui::ShowStyleEditor();
|
||||||
|
|
||||||
if (ImGui::BeginMainMenuBar()) {
|
if (ImGui::BeginMainMenuBar()) {
|
||||||
if (ImGui::BeginMenu("File")) {
|
if (ImGui::BeginMenu("File")) {
|
||||||
|
//if (ImGui::MenuItem("New")) { }
|
||||||
if (ImGui::MenuItem("New")) { }
|
if (ImGui::MenuItem("Import", "Ctrl+O")) {
|
||||||
if (ImGui::MenuItem("Open", "Ctrl+O")) { }
|
fileImport(world);
|
||||||
if (ImGui::MenuItem("Save", "Ctrl+S")) { }
|
}
|
||||||
if (ImGui::MenuItem("Save As...", "Ctrl+Shift+S")) { }
|
if (ImGui::MenuItem("Save", "Ctrl+S")) {
|
||||||
|
fileSave(world);
|
||||||
|
}
|
||||||
|
if (ImGui::MenuItem("Save As...", "Ctrl+Shift+S")) {
|
||||||
|
fileSaveAs(world);
|
||||||
|
}
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
if (ImGui::MenuItem("Close Editor", "F1")) { }
|
if (ImGui::MenuItem("Close Editor", "F1")) { }
|
||||||
|
|
||||||
@@ -392,7 +448,7 @@ void EditorSystem::drawUI(World* world, double dt)
|
|||||||
|
|
||||||
std::string title = std::string("Components #") + std::to_string(m_Selection) + std::string("###Components");
|
std::string title = std::string("Components #") + std::to_string(m_Selection) + std::string("###Components");
|
||||||
if (ImGui::Begin(title.c_str())) {
|
if (ImGui::Begin(title.c_str())) {
|
||||||
if (m_Selection != 0) {
|
if (m_Selection != EntityID_Invalid) {
|
||||||
auto& pools = world->GetComponentPools();
|
auto& pools = world->GetComponentPools();
|
||||||
|
|
||||||
std::vector<const char*> componentTypes;
|
std::vector<const char*> componentTypes;
|
||||||
@@ -432,16 +488,16 @@ void EditorSystem::drawUI(World* world, double dt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto& component = world->GetComponent(m_Selection, componentType);
|
auto& component = world->GetComponent(m_Selection, componentType);
|
||||||
for (auto& pair : ci.FieldTypes) {
|
for (auto& kv : ci.Fields) {
|
||||||
const std::string& field = pair.first;
|
const std::string& fieldName = kv.first;
|
||||||
const std::string& type = pair.second;
|
auto& field = kv.second;
|
||||||
|
|
||||||
ImGui::PushID(field.c_str());
|
ImGui::PushID(fieldName.c_str());
|
||||||
if (type == "Vector") {
|
if (field.Type == "Vector") {
|
||||||
auto& val = component.Property<glm::vec3>(field);
|
auto& val = component.Property<glm::vec3>(fieldName);
|
||||||
if (field == "Scale") {
|
if (fieldName == "Scale") {
|
||||||
ImGui::DragFloat3("", glm::value_ptr(val), 0.1f, 0.f, std::numeric_limits<float>::max());
|
ImGui::DragFloat3("", glm::value_ptr(val), 0.1f, 0.f, std::numeric_limits<float>::max());
|
||||||
} else if (field == "Orientation") {
|
} else if (fieldName == "Orientation") {
|
||||||
glm::vec3 tempVal = glm::fmod(val, glm::vec3(glm::two_pi<float>()));
|
glm::vec3 tempVal = glm::fmod(val, glm::vec3(glm::two_pi<float>()));
|
||||||
if (ImGui::SliderFloat3("", glm::value_ptr(tempVal), 0.f, glm::two_pi<float>())) {
|
if (ImGui::SliderFloat3("", glm::value_ptr(tempVal), 0.f, glm::two_pi<float>())) {
|
||||||
val = tempVal;
|
val = tempVal;
|
||||||
@@ -449,16 +505,16 @@ void EditorSystem::drawUI(World* world, double dt)
|
|||||||
} else {
|
} else {
|
||||||
ImGui::DragFloat3("", glm::value_ptr(val), 0.1f, std::numeric_limits<float>::lowest(), std::numeric_limits<float>::max());
|
ImGui::DragFloat3("", glm::value_ptr(val), 0.1f, std::numeric_limits<float>::lowest(), std::numeric_limits<float>::max());
|
||||||
}
|
}
|
||||||
} else if (type == "Color") {
|
} else if (field.Type == "Color") {
|
||||||
auto& val = component.Property<glm::vec4>(field);
|
auto& val = component.Property<glm::vec4>(fieldName);
|
||||||
ImGui::ColorEdit4("", glm::value_ptr(val), true);
|
ImGui::ColorEdit4("", glm::value_ptr(val), true);
|
||||||
} else if (type == "string") {
|
} else if (field.Type == "string") {
|
||||||
std::string& val = component.Property<std::string>(field);
|
std::string& val = component.Property<std::string>(fieldName);
|
||||||
char tempString[1024];
|
char tempString[1024];
|
||||||
memcpy(tempString, val.c_str(), std::min(val.length() + 1, sizeof(tempString)));
|
memcpy(tempString, val.c_str(), std::min(val.length() + 1, sizeof(tempString)));
|
||||||
if (ImGui::InputText("", tempString, sizeof(tempString))) {
|
if (ImGui::InputText("", tempString, sizeof(tempString))) {
|
||||||
val = std::string(tempString);
|
val = std::string(tempString);
|
||||||
LOG_DEBUG("%s::%s changed!", componentType.c_str(), field.c_str());
|
LOG_DEBUG("%s::%s changed!", componentType.c_str(), fieldName.c_str());
|
||||||
}
|
}
|
||||||
// DROP STUFF
|
// DROP STUFF
|
||||||
if (ImGui::IsItemHovered() && !m_LastDroppedFile.empty()) {
|
if (ImGui::IsItemHovered() && !m_LastDroppedFile.empty()) {
|
||||||
@@ -466,21 +522,21 @@ void EditorSystem::drawUI(World* world, double dt)
|
|||||||
m_LastDroppedFile = "";
|
m_LastDroppedFile = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (type == "double") {
|
} else if (field.Type == "double") {
|
||||||
float tempVal = static_cast<float>(component.Property<double>(field));
|
float tempVal = static_cast<float>(component.Property<double>(fieldName));
|
||||||
if (ImGui::InputFloat("", &tempVal, 0.01f, 1.f)) {
|
if (ImGui::InputFloat("", &tempVal, 0.01f, 1.f)) {
|
||||||
component.SetProperty(field, static_cast<double>(tempVal));
|
component.SetProperty(fieldName, static_cast<double>(tempVal));
|
||||||
}
|
}
|
||||||
} else if (type == "bool") {
|
} else if (field.Type == "bool") {
|
||||||
auto& val = component.Property<bool>(field);
|
auto& val = component.Property<bool>(fieldName);
|
||||||
ImGui::Checkbox("", &val);
|
ImGui::Checkbox("", &val);
|
||||||
} else {
|
} else {
|
||||||
ImGui::TextDisabled(type.c_str());
|
ImGui::TextDisabled(field.Type.c_str());
|
||||||
}
|
}
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::Text(field.c_str());
|
ImGui::Text(fieldName.c_str());
|
||||||
if (ImGui::IsItemHovered()) {
|
if (ImGui::IsItemHovered()) {
|
||||||
ImGui::SetTooltip("field annotation goes here");
|
ImGui::SetTooltip("field annotation goes here");
|
||||||
}
|
}
|
||||||
@@ -492,74 +548,93 @@ void EditorSystem::drawUI(World* world, double dt)
|
|||||||
}
|
}
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
|
|
||||||
if (ImGui::Begin("Entitites")) {
|
if (ImGui::Begin("Entities")) {
|
||||||
static EntityID draggingEntity = 0;
|
|
||||||
auto entityChildren = world->GetEntityChildren();
|
auto entityChildren = world->GetEntityChildren();
|
||||||
std::function<void(EntityID)> recurse = [&](EntityID parent) {
|
std::function<void(EntityID)> recurse = [&](EntityID parent) {
|
||||||
auto range = entityChildren.equal_range(parent);
|
auto range = entityChildren.equal_range(parent);
|
||||||
for (auto it = range.first; it != range.second; it++) {
|
for (auto it = range.first; it != range.second; it++) {
|
||||||
|
if (createEntityNode(world, it->second)) {
|
||||||
ImVec2 pos = ImGui::GetCursorScreenPos();
|
|
||||||
float width = ImGui::GetContentRegionAvailWidth();
|
|
||||||
ImRect bb(pos + ImVec2(20, 0), pos + ImVec2(width, 13));
|
|
||||||
auto window = ImGui::GetCurrentWindow();
|
|
||||||
if (m_Selection == it->second) {
|
|
||||||
const ImU32 col = window->Color(ImGuiCol_HeaderActive);
|
|
||||||
window->DrawList->AddRectFilled(bb.Min, bb.Max, col);
|
|
||||||
}
|
|
||||||
ImGuiID id = window->GetID((std::string("#SelectButton") + std::to_string(it->second)).c_str());
|
|
||||||
bool hovered = false;
|
|
||||||
bool held = false;
|
|
||||||
if (ImGui::ButtonBehavior(bb, id, &hovered, &held)) {
|
|
||||||
m_Selection = it->second;
|
|
||||||
}
|
|
||||||
if (held) {
|
|
||||||
ImVec2 entityDragDelta = ImGui::GetMouseDragDelta(0);
|
|
||||||
if (std::abs(entityDragDelta.x) > 0 && std::abs(entityDragDelta.y) > 0) {
|
|
||||||
if (draggingEntity == 0) {
|
|
||||||
draggingEntity = it->second;
|
|
||||||
LOG_DEBUG("Started drag of entity %i", draggingEntity);
|
|
||||||
}
|
|
||||||
ImGui::SetNextWindowPos(ImGui::GetIO().MousePos + ImVec2(20, 0));
|
|
||||||
ImGui::Begin("Change parent", nullptr, ImVec2(0, 0), 0.3f, ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoSavedSettings);
|
|
||||||
ImGui::Text("#%i", draggingEntity);
|
|
||||||
ImGui::End();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::SetNextTreeNodeOpened(true, ImGuiSetCond_Once);
|
|
||||||
if (ImGui::TreeNode((std::string("#") + std::to_string(it->second)).c_str())) {
|
|
||||||
if (draggingEntity != 0 && ImGui::IsItemHoveredRect() && ImGui::IsMouseReleased(0)) {
|
|
||||||
LOG_DEBUG("Changed parent of %i to %i", draggingEntity, it->second);
|
|
||||||
changeParent(draggingEntity, it->second);
|
|
||||||
draggingEntity = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::BeginPopupContextItem("item context menu")) {
|
|
||||||
if (ImGui::Button("Add")) {
|
|
||||||
EntityID entity = world->CreateEntity(it->second);
|
|
||||||
world->AttachComponent(entity, "Transform");
|
|
||||||
}
|
|
||||||
ImGui::SameLine();
|
|
||||||
if (ImGui::Button("Delete")) {
|
|
||||||
world->DeleteEntity(it->second);
|
|
||||||
ImGui::CloseCurrentPopup();
|
|
||||||
if (m_Selection == it->second) {
|
|
||||||
m_Selection = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ImGui::EndPopup();
|
|
||||||
}
|
|
||||||
recurse(it->second);
|
recurse(it->second);
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
recurse(0);
|
recurse(EntityID_Invalid);
|
||||||
}
|
}
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool EditorSystem::createEntityNode(World* world, EntityID entity)
|
||||||
|
{
|
||||||
|
// HACK: Don't show the widget entities in the entity tree
|
||||||
|
if (entity == m_Widget) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImVec2 pos = ImGui::GetCursorScreenPos();
|
||||||
|
float width = ImGui::GetContentRegionAvailWidth();
|
||||||
|
ImRect bb(pos + ImVec2(20, 0), pos + ImVec2(width, 13));
|
||||||
|
auto window = ImGui::GetCurrentWindow();
|
||||||
|
if (m_Selection == entity) {
|
||||||
|
const ImU32 col = window->Color(ImGuiCol_HeaderActive);
|
||||||
|
window->DrawList->AddRectFilled(bb.Min, bb.Max, col);
|
||||||
|
}
|
||||||
|
ImGuiID id = window->GetID((std::string("#SelectButton") + std::to_string(entity)).c_str());
|
||||||
|
bool hovered = false;
|
||||||
|
bool held = false;
|
||||||
|
if (ImGui::ButtonBehavior(bb, id, &hovered, &held)) {
|
||||||
|
m_Selection = entity;
|
||||||
|
}
|
||||||
|
if (held) {
|
||||||
|
ImVec2 entityDragDelta = ImGui::GetMouseDragDelta(0);
|
||||||
|
if (std::abs(entityDragDelta.x) > 0 && std::abs(entityDragDelta.y) > 0) {
|
||||||
|
if (m_UIDraggingEntity == EntityID_Invalid) {
|
||||||
|
m_UIDraggingEntity = entity;
|
||||||
|
LOG_DEBUG("Started drag of entity %i", m_UIDraggingEntity);
|
||||||
|
}
|
||||||
|
ImGui::SetNextWindowPos(ImGui::GetIO().MousePos + ImVec2(20, 0));
|
||||||
|
ImGui::Begin("Change parent", nullptr, ImVec2(0, 0), 0.3f, ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoSavedSettings);
|
||||||
|
ImGui::Text("#%i", m_UIDraggingEntity);
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SetNextTreeNodeOpened(true, ImGuiSetCond_Once);
|
||||||
|
std::string nodeTitle;
|
||||||
|
const std::string& entityName = world->GetName(entity);
|
||||||
|
if (!entityName.empty()) {
|
||||||
|
nodeTitle = entityName;
|
||||||
|
} else {
|
||||||
|
nodeTitle = std::string("#") + std::to_string(entity);
|
||||||
|
}
|
||||||
|
if (ImGui::TreeNode(nodeTitle.c_str())) {
|
||||||
|
if (m_UIDraggingEntity != EntityID_Invalid && ImGui::IsItemHoveredRect() && ImGui::IsMouseReleased(0)) {
|
||||||
|
LOG_DEBUG("Changed parent of %i to %i", m_UIDraggingEntity, entity);
|
||||||
|
changeParent(m_UIDraggingEntity, entity);
|
||||||
|
m_UIDraggingEntity = EntityID_Invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::BeginPopupContextItem("item context menu")) {
|
||||||
|
if (ImGui::Button("Add")) {
|
||||||
|
EntityID newEntity = world->CreateEntity(entity);
|
||||||
|
world->AttachComponent(newEntity, "Transform");
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("Delete")) {
|
||||||
|
world->DeleteEntity(entity);
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
if (!world->ValidEntity(m_Selection)) {
|
||||||
|
m_Selection = EntityID_Invalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool EditorSystem::createDeleteButton(std::string componentType)
|
bool EditorSystem::createDeleteButton(std::string componentType)
|
||||||
{
|
{
|
||||||
float width = ImGui::GetContentRegionAvailWidth();
|
float width = ImGui::GetContentRegionAvailWidth();
|
||||||
@@ -594,3 +669,48 @@ void EditorSystem::changeParent(EntityID entity, EntityID newParent)
|
|||||||
|
|
||||||
m_World->SetParent(entity, newParent);
|
m_World->SetParent(entity, newParent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EditorSystem::fileImport(World* world)
|
||||||
|
{
|
||||||
|
m_CurrentFile = openDialog(m_DefaultEntityDir);
|
||||||
|
auto file = ResourceManager::Load<EntityFile>(m_CurrentFile.string());
|
||||||
|
EntityFilePreprocessor fpp(file);
|
||||||
|
fpp.RegisterComponents(world);
|
||||||
|
EntityFileParser fp(file);
|
||||||
|
fp.MergeEntities(world);
|
||||||
|
createWidget();
|
||||||
|
updateWidget();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorSystem::fileSave(World* world)
|
||||||
|
{
|
||||||
|
if (boost::filesystem::exists(m_CurrentFile)) {
|
||||||
|
// HACK: Delete the widgets so they don't appear in the saved file
|
||||||
|
world->DeleteEntity(m_Widget);
|
||||||
|
m_Widget = EntityID_Invalid;
|
||||||
|
|
||||||
|
EntityFileWriter writer(m_CurrentFile.string());
|
||||||
|
writer.WriteWorld(world);
|
||||||
|
|
||||||
|
createWidget();
|
||||||
|
} else {
|
||||||
|
fileSaveAs(world);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorSystem::fileSaveAs(World* world)
|
||||||
|
{
|
||||||
|
auto filePath = saveDialog(m_DefaultEntityDir);
|
||||||
|
if (filePath.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// HACK: Delete the widgets so they don't appear in the saved file
|
||||||
|
world->DeleteEntity(m_Widget);
|
||||||
|
m_Widget = EntityID_Invalid;
|
||||||
|
|
||||||
|
EntityFileWriter writer(filePath.string());
|
||||||
|
writer.WriteWorld(world);
|
||||||
|
|
||||||
|
createWidget();
|
||||||
|
}
|
||||||
|
|||||||
+113
-140
@@ -5,30 +5,25 @@ using namespace boost::asio::ip;
|
|||||||
|
|
||||||
Client::Client(ConfigFile* config) : m_Socket(m_IOService)
|
Client::Client(ConfigFile* config) : m_Socket(m_IOService)
|
||||||
{
|
{
|
||||||
|
// Asumes root node is EntityID 0
|
||||||
|
insertIntoServerClientMaps(0, 0);
|
||||||
// Default is local host
|
// Default is local host
|
||||||
std::string address = config->Get<std::string>("Networking.Address", "127.0.0.1");
|
std::string address = config->Get<std::string>("Networking.Address", "127.0.0.1");
|
||||||
int port = config->Get<int>("Networking.Port", 13);
|
int port = config->Get<int>("Networking.Port", 13);
|
||||||
m_ReceiverEndpoint = udp::endpoint(boost::asio::ip::address::from_string(address), port);
|
m_ReceiverEndpoint = udp::endpoint(boost::asio::ip::address::from_string(address), port);
|
||||||
// Set up network stream
|
// Set up network stream
|
||||||
m_PlayerName = config->Get<std::string>("Networking.Name", "Raptorcopter");
|
m_PlayerName = config->Get<std::string>("Networking.Name", "Raptorcopter");
|
||||||
m_NextSnapshot.InputForward = "";
|
|
||||||
m_NextSnapshot.InputRight = "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Client::~Client()
|
Client::~Client()
|
||||||
{
|
{ }
|
||||||
m_EventBroker->Unsubscribe(m_EInputCommand);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Client::Start(World* world, EventBroker* eventBroker)
|
void Client::Start(World* world, EventBroker* eventBroker)
|
||||||
{
|
{
|
||||||
m_WasStarted = true;
|
|
||||||
m_EventBroker = eventBroker;
|
m_EventBroker = eventBroker;
|
||||||
m_World = world;
|
m_World = world;
|
||||||
|
|
||||||
// Subscribe to events
|
// Subscribe to events
|
||||||
//m_EInputCommand = decltype(m_EInputCommand)(std::bind(&Client::OnInputCommand, this, std::placeholders::_1));
|
|
||||||
//m_EventBroker->Subscribe(m_EInputCommand);
|
|
||||||
EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &Client::OnInputCommand);
|
EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &Client::OnInputCommand);
|
||||||
|
|
||||||
m_Socket.connect(m_ReceiverEndpoint);
|
m_Socket.connect(m_ReceiverEndpoint);
|
||||||
@@ -40,77 +35,15 @@ void Client::Update()
|
|||||||
readFromServer();
|
readFromServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::Close()
|
|
||||||
{
|
|
||||||
if (m_WasStarted) {
|
|
||||||
disconnect();
|
|
||||||
m_ThreadIsRunning = false;
|
|
||||||
m_EventBroker->Unsubscribe(m_EInputCommand);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Client::readFromServer()
|
void Client::readFromServer()
|
||||||
{
|
{
|
||||||
if (m_Socket.available()) {
|
while (m_Socket.available()) {
|
||||||
bytesRead = receive(readBuf, INPUTSIZE);
|
bytesRead = receive(readBuf, INPUTSIZE);
|
||||||
if (bytesRead > 0) {
|
if (bytesRead > 0) {
|
||||||
Packet packet(readBuf, bytesRead);
|
Packet packet(readBuf, bytesRead);
|
||||||
parseMessageType(packet);
|
parseMessageType(packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::clock_t currentTime = std::clock();
|
|
||||||
if (snapshotInterval < (1000 * (currentTime - previousSnapshotMessage) / (double)CLOCKS_PER_SEC)) {
|
|
||||||
if (isConnected()) {
|
|
||||||
sendSnapshotToServer();
|
|
||||||
}
|
|
||||||
previousSnapshotMessage = currentTime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Client::sendSnapshotToServer()
|
|
||||||
{
|
|
||||||
// Reset previous key state in snapshot.
|
|
||||||
m_NextSnapshot.InputForward = "";
|
|
||||||
m_NextSnapshot.InputRight = "";
|
|
||||||
|
|
||||||
auto player = m_World->GetComponent(m_PlayerDefinitions[m_PlayerID].EntityID, "Player");
|
|
||||||
|
|
||||||
|
|
||||||
// See if any movement keys are down
|
|
||||||
// We dont care if it's overwritten by later
|
|
||||||
// if statement. Watcha gonna do, right!
|
|
||||||
if (player["Forward"]) {
|
|
||||||
m_NextSnapshot.InputForward = "+Forward";
|
|
||||||
}
|
|
||||||
if (player["Left"]) {
|
|
||||||
m_NextSnapshot.InputRight = "-Right";
|
|
||||||
}
|
|
||||||
if (player["Back"]) {
|
|
||||||
m_NextSnapshot.InputForward = "-Forward";
|
|
||||||
}
|
|
||||||
if (player["Right"]) {
|
|
||||||
m_NextSnapshot.InputRight = "+Right";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_NextSnapshot.InputForward != "") {
|
|
||||||
Packet packet(MessageType::Event, m_SendPacketID);
|
|
||||||
packet.WriteString(m_NextSnapshot.InputForward);
|
|
||||||
send(packet);
|
|
||||||
} else {
|
|
||||||
Packet packet(MessageType::Event, m_SendPacketID);
|
|
||||||
packet.WriteString("0Forward");
|
|
||||||
send(packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_NextSnapshot.InputRight != "") {
|
|
||||||
Packet packet(MessageType::Event, m_SendPacketID);
|
|
||||||
packet.WriteString(m_NextSnapshot.InputRight);
|
|
||||||
send(packet);
|
|
||||||
} else {
|
|
||||||
Packet packet(MessageType::Event, m_SendPacketID);
|
|
||||||
packet.WriteString("0Right");
|
|
||||||
send(packet);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::parseMessageType(Packet& packet)
|
void Client::parseMessageType(Packet& packet)
|
||||||
@@ -121,6 +54,8 @@ void Client::parseMessageType(Packet& packet)
|
|||||||
// Read packet ID
|
// Read packet ID
|
||||||
m_PreviousPacketID = m_PacketID; // Set previous packet id
|
m_PreviousPacketID = m_PacketID; // Set previous packet id
|
||||||
m_PacketID = packet.ReadPrimitive<int>(); //Read new packet id
|
m_PacketID = packet.ReadPrimitive<int>(); //Read new packet id
|
||||||
|
if (m_PacketID <= m_PreviousPacketID)
|
||||||
|
return;
|
||||||
//IdentifyPacketLoss();
|
//IdentifyPacketLoss();
|
||||||
|
|
||||||
switch (static_cast<MessageType>(messageType)) {
|
switch (static_cast<MessageType>(messageType)) {
|
||||||
@@ -140,9 +75,8 @@ void Client::parseMessageType(Packet& packet)
|
|||||||
break;
|
break;
|
||||||
case MessageType::Disconnect:
|
case MessageType::Disconnect:
|
||||||
break;
|
break;
|
||||||
case MessageType::Event:
|
case MessageType::PlayerConnected:
|
||||||
parseEventMessage(packet);
|
parsePlayerConnected(packet);
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -150,10 +84,19 @@ void Client::parseMessageType(Packet& packet)
|
|||||||
|
|
||||||
void Client::parseConnect(Packet& packet)
|
void Client::parseConnect(Packet& packet)
|
||||||
{
|
{
|
||||||
|
// Set your own player id
|
||||||
m_PlayerID = packet.ReadPrimitive<int>();
|
m_PlayerID = packet.ReadPrimitive<int>();
|
||||||
|
m_ServerEntityID = packet.ReadPrimitive<EntityID>();
|
||||||
|
// Map ServerEntityID and your PlayerID
|
||||||
LOG_INFO("%i: I am player: %i", m_PacketID, m_PlayerID);
|
LOG_INFO("%i: I am player: %i", m_PacketID, m_PlayerID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Client::parsePlayerConnected(Packet & packet)
|
||||||
|
{
|
||||||
|
// Map ServerEntityID and other player's PlayerID
|
||||||
|
LOG_INFO("A Player connected");
|
||||||
|
}
|
||||||
|
|
||||||
void Client::parsePing()
|
void Client::parsePing()
|
||||||
{
|
{
|
||||||
m_DurationOfPingTime = 1000 * (std::clock() - m_StartPingTime) / static_cast<double>(CLOCKS_PER_SEC);
|
m_DurationOfPingTime = 1000 * (std::clock() - m_StartPingTime) / static_cast<double>(CLOCKS_PER_SEC);
|
||||||
@@ -167,46 +110,74 @@ void Client::parseServerPing()
|
|||||||
send(packet);
|
send(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::parseEventMessage(Packet& packet)
|
void Client::updateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID, const std::string& componentType)
|
||||||
{
|
{
|
||||||
int Id = -1;
|
for (auto field : componentInfo.FieldsInOrder) {
|
||||||
std::string command = packet.ReadString();
|
ComponentInfo::Field_t fieldInfo = componentInfo.Fields.at(field);
|
||||||
if (command.find("+Player") != std::string::npos) {
|
if (fieldInfo.Type == "string") {
|
||||||
Id = packet.ReadPrimitive<int>();
|
std::string& value = packet.ReadString();
|
||||||
// Sett Player name
|
m_World->GetComponent(entityID, componentType)[fieldInfo.Name] = value;
|
||||||
m_PlayerDefinitions[Id].Name = command.erase(0, 7);
|
} else {
|
||||||
} else {
|
memcpy(m_World->GetComponent(entityID, componentType).Data + fieldInfo.Offset, packet.ReadData(fieldInfo.Stride), fieldInfo.Stride);
|
||||||
LOG_INFO("%i: Event message: %s", m_PacketID, command.c_str());
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Field parse
|
||||||
void Client::parseSnapshot(Packet& packet)
|
void Client::parseSnapshot(Packet& packet)
|
||||||
{
|
{
|
||||||
std::string tempName;
|
std::string componentType = packet.ReadString();
|
||||||
for (size_t i = 0; i < MAXCONNECTIONS; i++) {
|
while (packet.DataReadSize() < packet.Size()) {
|
||||||
// We're checking for empty name for now. This might not be the best way,
|
// Components EntityID
|
||||||
// but it is to avoid sending redundant data.
|
EntityID receivedEntityID = packet.ReadPrimitive<EntityID>();
|
||||||
tempName = packet.ReadString();
|
// Parents EntityID
|
||||||
|
EntityID receivedParentEntityID = packet.ReadPrimitive<EntityID>();
|
||||||
|
ComponentInfo componentInfo = m_World->GetComponents(componentType)->ComponentInfo();
|
||||||
// Apply the position data read to the player entity
|
// Check if the received EntityID is mapped to one of our local EntityIDs
|
||||||
// New player connected on the server side
|
if (serverClientMapsHasEntity(receivedEntityID)) {
|
||||||
if (m_PlayerDefinitions[i].Name == "" && tempName != "") {
|
// Get the local EntityID
|
||||||
m_PlayerDefinitions[i].Name = tempName;
|
EntityID entityID = m_ServerIDToClientID.at(receivedEntityID);
|
||||||
m_PlayerDefinitions[i].EntityID = createPlayer();
|
// Check if the component exists
|
||||||
} else if (m_PlayerDefinitions[i].Name != "" && tempName == "") {
|
if (m_World->HasComponent(entityID, componentType)) {
|
||||||
// Someone disconnected
|
// If the entity and the component exists update it
|
||||||
// TODO: Insert code here
|
updateFields(packet, componentInfo, entityID, componentType);
|
||||||
break;
|
// if entity exists but not the component
|
||||||
} else if (m_PlayerDefinitions[i].Name == "" && tempName == "") {
|
} else {
|
||||||
// Not a connected player
|
// Create component
|
||||||
break;
|
m_World->AttachComponent(entityID, componentType);
|
||||||
|
// Copy data to newly created component
|
||||||
|
updateFields(packet, componentInfo, entityID, componentType);
|
||||||
|
}
|
||||||
|
// If the entity dosent exist nor the component
|
||||||
|
} else {
|
||||||
|
// Create Entity
|
||||||
|
// If entity dosen't exist
|
||||||
|
EntityID newEntityID = m_World->CreateEntity();
|
||||||
|
insertIntoServerClientMaps(receivedEntityID, newEntityID);
|
||||||
|
// Check if EntityIDs are out of sync
|
||||||
|
if (newEntityID != receivedEntityID) {
|
||||||
|
LOG_INFO("Client::parseSnapshot(Packet& packet): Newly created EntityID is not the \
|
||||||
|
same as the one sent by server (EntityIDs are out of sync)");
|
||||||
|
}
|
||||||
|
// Create component
|
||||||
|
m_World->AttachComponent(newEntityID, componentType);
|
||||||
|
// Copy data to newly created component
|
||||||
|
updateFields(packet, componentInfo, newEntityID, componentType);
|
||||||
}
|
}
|
||||||
if (m_PlayerDefinitions[i].EntityID != -1) {
|
|
||||||
|
|
||||||
// Move player to server position
|
// Parent Logic
|
||||||
int dataSize = m_World->GetComponent(m_PlayerDefinitions[i].EntityID, "Transform").Info.Meta.Stride;
|
// Don't need to check if receivedEntityID is mapped. (It should have been set)
|
||||||
memcpy(m_World->GetComponent(m_PlayerDefinitions[i].EntityID, "Transform").Data, packet.ReadData(dataSize), dataSize);
|
if (receivedParentEntityID != std::numeric_limits<EntityID>::max()) {
|
||||||
|
if (serverClientMapsHasEntity(receivedParentEntityID)) {
|
||||||
|
m_World->SetParent(m_ServerIDToClientID.at(receivedEntityID), m_ServerIDToClientID.at(receivedParentEntityID));
|
||||||
|
// If Parent dosen't exist create one and map receivedParentEntityID to it.
|
||||||
|
} else {
|
||||||
|
// Create the new parent and add it to map
|
||||||
|
EntityID newParentEntityID = m_World->CreateEntity();
|
||||||
|
insertIntoServerClientMaps(receivedParentEntityID, newParentEntityID);
|
||||||
|
// Set the newly created Entity as parent.
|
||||||
|
m_World->SetParent(m_ServerIDToClientID.at(receivedEntityID), newParentEntityID);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -223,7 +194,6 @@ int Client::receive(char* data, size_t length)
|
|||||||
if (error) {
|
if (error) {
|
||||||
//LOG_ERROR("receive: %s", error.message().c_str());
|
//LOG_ERROR("receive: %s", error.message().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
return bytesReceived;
|
return bytesReceived;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,47 +228,33 @@ void Client::ping()
|
|||||||
send(packet);
|
send(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::moveMessageHead(char*& data, size_t& length, size_t stepSize)
|
|
||||||
{
|
|
||||||
data += stepSize;
|
|
||||||
length -= stepSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Client::OnInputCommand(const Events::InputCommand & e)
|
bool Client::OnInputCommand(const Events::InputCommand & e)
|
||||||
{
|
{
|
||||||
if (isConnected()) {
|
|
||||||
ComponentWrapper& player = m_World->GetComponent(m_PlayerDefinitions[m_PlayerID].EntityID, "Player");
|
|
||||||
if (e.Command == "Forward") {
|
|
||||||
if (e.Value > 0) {
|
|
||||||
(bool&)player["Forward"] = true;
|
|
||||||
(bool&)player["Back"] = false;
|
|
||||||
} else if (e.Value < 0) {
|
|
||||||
(bool&)player["Back"] = true;
|
|
||||||
(bool&)player["Forward"] = false;
|
|
||||||
} else {
|
|
||||||
(bool&)player["Forward"] = false;
|
|
||||||
(bool&)player["Back"] = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (e.Command == "Right") {
|
|
||||||
if (e.Value > 0) {
|
|
||||||
(bool&)player["Right"] = true;
|
|
||||||
(bool&)player["Left"] = false;
|
|
||||||
} else if (e.Value < 0) {
|
|
||||||
(bool&)player["Left"] = true;
|
|
||||||
(bool&)player["Right"] = false;
|
|
||||||
} else {
|
|
||||||
(bool&)player["Left"] = false;
|
|
||||||
(bool&)player["Right"] = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (e.Command == "ConnectToServer") { // Connect for now
|
if (e.Command == "ConnectToServer") { // Connect for now
|
||||||
connect();
|
connect();
|
||||||
|
LOG_DEBUG("Client::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
Packet packet(MessageType::OnInputCommand, m_SendPacketID);
|
||||||
|
packet.WriteString(e.Command);
|
||||||
|
packet.WritePrimitive(e.PlayerID);
|
||||||
|
packet.WritePrimitive(e.Value);
|
||||||
|
send(packet);
|
||||||
|
LOG_DEBUG("Client::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Client::OnPlayerDamage(const Events::PlayerDamage & e)
|
||||||
|
{
|
||||||
|
Packet packet(MessageType::OnInputCommand, m_SendPacketID);
|
||||||
|
packet.WritePrimitive(e.DamageAmount);
|
||||||
|
packet.WritePrimitive(e.PlayerDamagedID);
|
||||||
|
packet.WriteString(e.TypeOfDamage);
|
||||||
|
send(packet);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void Client::identifyPacketLoss()
|
void Client::identifyPacketLoss()
|
||||||
{
|
{
|
||||||
@@ -328,3 +284,20 @@ EntityID Client::createPlayer()
|
|||||||
ComponentWrapper player = m_World->AttachComponent(entityID, "Player");
|
ComponentWrapper player = m_World->AttachComponent(entityID, "Player");
|
||||||
return entityID;
|
return entityID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Client::clientServerMapsHasEntity(EntityID clientEntityID)
|
||||||
|
{
|
||||||
|
return m_ClientIDToServerID.find(clientEntityID) != m_ClientIDToServerID.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Client::serverClientMapsHasEntity(EntityID serverEntityID)
|
||||||
|
{
|
||||||
|
return m_ServerIDToClientID.find(serverEntityID) != m_ServerIDToClientID.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::insertIntoServerClientMaps(EntityID serverEntityID, EntityID clientEntityID)
|
||||||
|
{
|
||||||
|
m_ServerIDToClientID.insert(std::make_pair(serverEntityID, clientEntityID));
|
||||||
|
m_ClientIDToServerID.insert(std::make_pair(clientEntityID, serverEntityID));
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,13 +3,7 @@
|
|||||||
Packet::Packet(MessageType type, unsigned int& packetID)
|
Packet::Packet(MessageType type, unsigned int& packetID)
|
||||||
{
|
{
|
||||||
m_Data = new char[m_MaxPacketSize];
|
m_Data = new char[m_MaxPacketSize];
|
||||||
// Create message header
|
Init(type, packetID);
|
||||||
// Add message type
|
|
||||||
int messageType = static_cast<int>(type);
|
|
||||||
Packet::WritePrimitive<int>(messageType);
|
|
||||||
packetID = packetID % 1000; // Packet id modulos
|
|
||||||
Packet::WritePrimitive<int>(packetID);
|
|
||||||
packetID++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create message
|
// Create message
|
||||||
@@ -28,12 +22,26 @@ Packet::~Packet()
|
|||||||
delete[] m_Data;
|
delete[] m_Data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Packet::WriteString(std::string str)
|
void Packet::Init(MessageType type, unsigned int & packetID)
|
||||||
|
{
|
||||||
|
m_ReturnDataOffset = 0;
|
||||||
|
m_Offset = 0;
|
||||||
|
// Create message header
|
||||||
|
// Add message type
|
||||||
|
int messageType = static_cast<int>(type);
|
||||||
|
Packet::WritePrimitive<int>(messageType);
|
||||||
|
packetID = packetID % 1000; // Packet id modulos
|
||||||
|
Packet::WritePrimitive<int>(packetID);
|
||||||
|
packetID++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Packet::WriteString(const std::string& str)
|
||||||
{
|
{
|
||||||
// Message, add one extra byte for null terminator
|
// Message, add one extra byte for null terminator
|
||||||
int sizeOfString = str.size() + 1;
|
int sizeOfString = str.size() + 1;
|
||||||
if (m_Offset + sizeOfString > m_MaxPacketSize) {
|
if (m_Offset + sizeOfString > m_MaxPacketSize) {
|
||||||
LOG_WARNING("Package::WriteString(): Data size in packet exceeded maximum package size.\n");
|
LOG_WARNING("Package::WriteString(): Data size in packet exceeded maximum package size. New size is %i bytes\n", m_MaxPacketSize*2);
|
||||||
|
resizeData();
|
||||||
}
|
}
|
||||||
memcpy(m_Data + m_Offset, str.data(), sizeOfString * sizeof(char));
|
memcpy(m_Data + m_Offset, str.data(), sizeOfString * sizeof(char));
|
||||||
m_Offset += sizeOfString * sizeof(char);
|
m_Offset += sizeOfString * sizeof(char);
|
||||||
@@ -42,7 +50,8 @@ void Packet::WriteString(std::string str)
|
|||||||
void Packet::WriteData(char * data, int sizeOfData)
|
void Packet::WriteData(char * data, int sizeOfData)
|
||||||
{
|
{
|
||||||
if (m_Offset + sizeOfData > m_MaxPacketSize) {
|
if (m_Offset + sizeOfData > m_MaxPacketSize) {
|
||||||
LOG_WARNING("Packet::WriteData(): Data size in packet exceeded maximum packet size.\n");
|
LOG_WARNING("Packet::WriteData(): Data size in packet exceeded maximum packet size. New size is %i bytes\n", m_MaxPacketSize*2);
|
||||||
|
resizeData();
|
||||||
}
|
}
|
||||||
memcpy(m_Data + m_Offset, data, sizeOfData);
|
memcpy(m_Data + m_Offset, data, sizeOfData);
|
||||||
m_Offset += sizeOfData;
|
m_Offset += sizeOfData;
|
||||||
@@ -69,4 +78,24 @@ char * Packet::ReadData(int SizeOfData)
|
|||||||
unsigned int oldReturnDataOffset = m_ReturnDataOffset;
|
unsigned int oldReturnDataOffset = m_ReturnDataOffset;
|
||||||
m_ReturnDataOffset += SizeOfData;
|
m_ReturnDataOffset += SizeOfData;
|
||||||
return (m_Data + oldReturnDataOffset);
|
return (m_Data + oldReturnDataOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Packet::resizeData()
|
||||||
|
{
|
||||||
|
|
||||||
|
// Allocate memory to store our data in
|
||||||
|
char* holdData = new char[m_MaxPacketSize];
|
||||||
|
// Copy our data to the newly allocated memory
|
||||||
|
memcpy(holdData, m_Data, m_Offset);
|
||||||
|
// Increase max packet size
|
||||||
|
m_MaxPacketSize = m_MaxPacketSize * 2;
|
||||||
|
// Delete our data
|
||||||
|
delete m_Data;
|
||||||
|
// Allocate twice the memory we had before
|
||||||
|
m_Data = new char[m_MaxPacketSize];
|
||||||
|
// Copy our data to new location
|
||||||
|
memcpy(m_Data, holdData, m_Offset);
|
||||||
|
// Delete the memory allocated to hold our data
|
||||||
|
// while we resized the old data container.
|
||||||
|
delete holdData;
|
||||||
|
}
|
||||||
|
|||||||
+55
-100
@@ -4,7 +4,7 @@ Server::Server() : m_Socket(m_IOService, boost::asio::ip::udp::endpoint(boost::a
|
|||||||
{ }
|
{ }
|
||||||
|
|
||||||
Server::~Server()
|
Server::~Server()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,20 +24,10 @@ void Server::Update()
|
|||||||
readFromClients();
|
readFromClients();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::Close()
|
|
||||||
{
|
|
||||||
m_ThreadIsRunning = false;
|
|
||||||
m_Socket.close();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void Server::readFromClients()
|
void Server::readFromClients()
|
||||||
{
|
{
|
||||||
// m_ThreadIsRunning might be unnecessary but the
|
while (m_Socket.available()) {
|
||||||
// program crashed if it executed m_Socket.available()
|
|
||||||
// when closing the program.
|
|
||||||
|
|
||||||
if (m_Socket.available()) {
|
|
||||||
try {
|
try {
|
||||||
bytesRead = receive(readBuffer, INPUTSIZE);
|
bytesRead = receive(readBuffer, INPUTSIZE);
|
||||||
Packet packet(readBuffer, bytesRead);
|
Packet packet(readBuffer, bytesRead);
|
||||||
@@ -45,7 +35,6 @@ void Server::readFromClients()
|
|||||||
} catch (const std::exception& err) {
|
} catch (const std::exception& err) {
|
||||||
//LOG_ERROR("%i: Read from client crashed %s", m_PacketID, err.what());
|
//LOG_ERROR("%i: Read from client crashed %s", m_PacketID, err.what());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
std::clock_t currentTime = std::clock();
|
std::clock_t currentTime = std::clock();
|
||||||
// Send snapshot
|
// Send snapshot
|
||||||
@@ -88,13 +77,15 @@ void Server::parseMessageType(Packet& packet)
|
|||||||
case MessageType::Message:
|
case MessageType::Message:
|
||||||
break;
|
break;
|
||||||
case MessageType::Snapshot:
|
case MessageType::Snapshot:
|
||||||
parseSnapshot(packet);
|
|
||||||
break;
|
break;
|
||||||
case MessageType::Disconnect:
|
case MessageType::Disconnect:
|
||||||
parseDisconnect();
|
parseDisconnect();
|
||||||
break;
|
break;
|
||||||
case MessageType::Event:
|
case MessageType::OnInputCommand:
|
||||||
parseEvent(packet);
|
parseOnInputCommand(packet);
|
||||||
|
break;
|
||||||
|
case MessageType::OnPlayerDamage:
|
||||||
|
parseOnPlayerDamage(packet);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -112,7 +103,7 @@ int Server::receive(char * data, size_t length)
|
|||||||
|
|
||||||
void Server::send(Packet& packet, int playerID)
|
void Server::send(Packet& packet, int playerID)
|
||||||
{
|
{
|
||||||
m_Socket.send_to(
|
int bytesSent = m_Socket.send_to(
|
||||||
boost::asio::buffer(packet.Data(), packet.Size()),
|
boost::asio::buffer(packet.Data(), packet.Size()),
|
||||||
m_PlayerDefinitions[playerID].Endpoint,
|
m_PlayerDefinitions[playerID].Endpoint,
|
||||||
0);
|
0);
|
||||||
@@ -128,23 +119,6 @@ void Server::send(Packet & packet)
|
|||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::moveMessageHead(char *& data, size_t & length, size_t stepSize)
|
|
||||||
{
|
|
||||||
data += stepSize;
|
|
||||||
length -= stepSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Server::broadcast(std::string message)
|
|
||||||
{
|
|
||||||
Packet packet(MessageType::Event, m_SendPacketID);
|
|
||||||
packet.WriteString(message);
|
|
||||||
for (int i = 0; i < MAXCONNECTIONS; i++) {
|
|
||||||
if (m_PlayerDefinitions[i].Endpoint.address() != boost::asio::ip::address()) {
|
|
||||||
send(packet, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Server::broadcast(Packet& packet)
|
void Server::broadcast(Packet& packet)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < MAXCONNECTIONS; ++i) {
|
for (int i = 0; i < MAXCONNECTIONS; ++i) {
|
||||||
@@ -154,22 +128,34 @@ void Server::broadcast(Packet& packet)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Send snapshot fields
|
||||||
void Server::sendSnapshot()
|
void Server::sendSnapshot()
|
||||||
{
|
{
|
||||||
Packet packet(MessageType::Snapshot, m_SendPacketID);
|
// Should time this
|
||||||
for (size_t i = 0; i < MAXCONNECTIONS; i++) {
|
std::unordered_map<std::string, ComponentPool*> worldComponentPools = m_World->GetComponentPools();
|
||||||
|
for (auto& it : worldComponentPools) {
|
||||||
// Send an empty name if there is no player connected on this position.
|
Packet packet(MessageType::Snapshot, m_SendPacketID);
|
||||||
packet.WriteString(m_PlayerDefinitions[i].Name);
|
ComponentPool* componentPool = it.second;
|
||||||
|
ComponentInfo componentInfo = componentPool->ComponentInfo();
|
||||||
if (m_PlayerDefinitions[i].EntityID == -1) {
|
// Component Type
|
||||||
continue;
|
packet.WriteString(componentInfo.Name);
|
||||||
|
for (auto& componentWrapper : *componentPool) {
|
||||||
|
// Components EntityID
|
||||||
|
packet.WritePrimitive(componentWrapper.EntityID);
|
||||||
|
// Parents EntityID
|
||||||
|
packet.WritePrimitive(m_World->GetParent(componentWrapper.EntityID));
|
||||||
|
for (auto& componentField : componentWrapper.Info.FieldsInOrder) {
|
||||||
|
ComponentInfo::Field_t fieldInfo = componentInfo.Fields.at(componentField);
|
||||||
|
if (fieldInfo.Type == "string") {
|
||||||
|
std::string& value = componentWrapper[componentField];
|
||||||
|
packet.WriteString(value);
|
||||||
|
} else {
|
||||||
|
packet.WriteData(componentWrapper.Data + fieldInfo.Offset, fieldInfo.Stride);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Pack transfrom component into data packet
|
broadcast(packet);
|
||||||
auto transform = m_World->GetComponent(m_PlayerDefinitions[i].EntityID, "Transform");
|
|
||||||
packet.WriteData(transform.Data, transform.Info.Meta.Stride);
|
|
||||||
}
|
}
|
||||||
broadcast(packet);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::sendPing()
|
void Server::sendPing()
|
||||||
@@ -178,10 +164,9 @@ void Server::sendPing()
|
|||||||
for (size_t i = 0; i < MAXCONNECTIONS; i++) {
|
for (size_t i = 0; i < MAXCONNECTIONS; i++) {
|
||||||
if (m_PlayerDefinitions[i].Endpoint.address() != boost::asio::ip::address()) {
|
if (m_PlayerDefinitions[i].Endpoint.address() != boost::asio::ip::address()) {
|
||||||
int ping = 1000 * (m_StopTimes[i] - m_StartPingTime) / static_cast<double>(CLOCKS_PER_SEC);
|
int ping = 1000 * (m_StopTimes[i] - m_StartPingTime) / static_cast<double>(CLOCKS_PER_SEC);
|
||||||
LOG_INFO("%i: Player %i's ping: %i", m_PacketID, i, ping);
|
LOG_INFO("Last packetID received %i: Player %i's ping: %i", m_PacketID, i, ping);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create ping message
|
// Create ping message
|
||||||
Packet packet(MessageType::ServerPing, m_SendPacketID);
|
Packet packet(MessageType::ServerPing, m_SendPacketID);
|
||||||
packet.WriteString("Ping from server");
|
packet.WriteString("Ping from server");
|
||||||
@@ -211,7 +196,7 @@ void Server::checkForTimeOuts()
|
|||||||
|
|
||||||
void Server::disconnect(int i)
|
void Server::disconnect(int i)
|
||||||
{
|
{
|
||||||
broadcast("A player disconnected");
|
//broadcast("A player disconnected");
|
||||||
LOG_INFO("Player %i disconnected/timed out", i);
|
LOG_INFO("Player %i disconnected/timed out", i);
|
||||||
|
|
||||||
// Remove enteties and stuff
|
// Remove enteties and stuff
|
||||||
@@ -220,40 +205,24 @@ void Server::disconnect(int i)
|
|||||||
m_PlayerDefinitions[i].Name = "";
|
m_PlayerDefinitions[i].Name = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::parseEvent(Packet& packet)
|
void Server::parseOnInputCommand(Packet& packet)
|
||||||
{
|
{
|
||||||
size_t i;
|
Events::InputCommand e;
|
||||||
for (i = 0; i < MAXCONNECTIONS; i++) {
|
e.Command = packet.ReadString();
|
||||||
if (m_PlayerDefinitions[i].Endpoint.address() == m_ReceiverEndpoint.address()) {
|
e.PlayerID = packet.ReadPrimitive<int>();
|
||||||
break;
|
e.Value = packet.ReadPrimitive<float>();
|
||||||
}
|
m_EventBroker->Publish(e);
|
||||||
}
|
LOG_DEBUG("Server::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID);
|
||||||
// If no player matches the address return.
|
}
|
||||||
if (i >= 8)
|
|
||||||
return;
|
|
||||||
|
|
||||||
unsigned int entityId = m_PlayerDefinitions[i].EntityID;
|
void Server::parseOnPlayerDamage(Packet & packet)
|
||||||
std::string eventString = packet.ReadString();
|
{
|
||||||
if ("+Forward" == eventString) {
|
Events::PlayerDamage e;
|
||||||
m_World->GetComponent(entityId, "Player")["Forward"] = true;
|
e.DamageAmount = packet.ReadPrimitive<double>();
|
||||||
m_World->GetComponent(entityId, "Player")["Back"] = false;
|
e.PlayerDamagedID = packet.ReadPrimitive<EntityID>();
|
||||||
} else if ("-Forward" == eventString) {
|
e.TypeOfDamage = packet.ReadString();
|
||||||
m_World->GetComponent(entityId, "Player")["Forward"] = false;
|
m_EventBroker->Publish(e);
|
||||||
m_World->GetComponent(entityId, "Player")["Back"] = true;
|
LOG_DEBUG("Server::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.DamageAmount, e.PlayerDamagedID, e.TypeOfDamage.c_str());
|
||||||
} else if ("0Forward" == eventString) {
|
|
||||||
m_World->GetComponent(entityId, "Player")["Forward"] = false;
|
|
||||||
m_World->GetComponent(entityId, "Player")["Back"] = false;
|
|
||||||
}
|
|
||||||
if ("+Right" == eventString) {
|
|
||||||
m_World->GetComponent(entityId, "Player")["Left"] = false;
|
|
||||||
m_World->GetComponent(entityId, "Player")["Right"] = true;
|
|
||||||
} else if ("-Right" == eventString) {
|
|
||||||
m_World->GetComponent(entityId, "Player")["Right"] = false;
|
|
||||||
m_World->GetComponent(entityId, "Player")["Left"] = true;
|
|
||||||
} else if ("0Right" == eventString) {
|
|
||||||
m_World->GetComponent(entityId, "Player")["Right"] = false;
|
|
||||||
m_World->GetComponent(entityId, "Player")["Left"] = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::parseConnect(Packet& packet)
|
void Server::parseConnect(Packet& packet)
|
||||||
@@ -277,15 +246,16 @@ void Server::parseConnect(Packet& packet)
|
|||||||
|
|
||||||
LOG_INFO("Player \"%s\" connected on IP: %s", m_PlayerDefinitions[i].Name.c_str(), m_PlayerDefinitions[i].Endpoint.address().to_string().c_str());
|
LOG_INFO("Player \"%s\" connected on IP: %s", m_PlayerDefinitions[i].Name.c_str(), m_PlayerDefinitions[i].Endpoint.address().to_string().c_str());
|
||||||
|
|
||||||
|
// Send a message to the player that connected
|
||||||
Packet packet(MessageType::Connect, m_SendPacketID);
|
Packet packet(MessageType::Connect, m_SendPacketID);
|
||||||
packet.WritePrimitive<int>(i); // Player ID
|
packet.WritePrimitive<int>(i); // Player ID
|
||||||
|
packet.WritePrimitive<EntityID>(m_PlayerDefinitions[i].EntityID); // Entity ID
|
||||||
send(packet, i);
|
send(packet, i);
|
||||||
|
|
||||||
// Send notification that a player has connected
|
// Send notification that a player has connected
|
||||||
std::string str = m_PacketID + "Player " + m_PlayerDefinitions[i].Name + " connected on: "
|
Packet notificationPacket(MessageType::PlayerConnected, m_PacketID);
|
||||||
+ m_PlayerDefinitions[i].Endpoint.address().to_string();
|
broadcast(notificationPacket);
|
||||||
broadcast(str);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -322,21 +292,6 @@ void Server::parseServerPing()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOT USED
|
|
||||||
void Server::parseSnapshot(Packet& packet)
|
|
||||||
{
|
|
||||||
// Does no logic. Returns snapshot if client request one
|
|
||||||
// The snapshot is not a real snapshot tho...
|
|
||||||
for (int i = 0; i < MAXCONNECTIONS; i++) {
|
|
||||||
if (m_PlayerDefinitions[i].Endpoint.address() != boost::asio::ip::address()) {
|
|
||||||
m_Socket.send_to(
|
|
||||||
boost::asio::buffer("I'm sending a snapshot to you guys!"),
|
|
||||||
m_PlayerDefinitions[i].Endpoint,
|
|
||||||
0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Server::identifyPacketLoss()
|
void Server::identifyPacketLoss()
|
||||||
{
|
{
|
||||||
// if no packets lost, difference should be equal to 1
|
// if no packets lost, difference should be equal to 1
|
||||||
|
|||||||
@@ -50,6 +50,18 @@ void Camera::SetOrientation(glm::quat val)
|
|||||||
UpdateViewMatrix();
|
UpdateViewMatrix();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Camera::SetProjectionMatrix(glm::mat4 val)
|
||||||
|
{
|
||||||
|
m_ProjectionMatrix = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Camera::SetViewMatrix(glm::mat4 val)
|
||||||
|
{
|
||||||
|
m_ViewMatrix = val;
|
||||||
|
}
|
||||||
|
|
||||||
//void Camera::Pitch(float val)
|
//void Camera::Pitch(float val)
|
||||||
//{
|
//{
|
||||||
// m_Pitch = val;
|
// m_Pitch = val;
|
||||||
@@ -64,15 +76,6 @@ void Camera::SetOrientation(glm::quat val)
|
|||||||
|
|
||||||
void Camera::UpdateProjectionMatrix()
|
void Camera::UpdateProjectionMatrix()
|
||||||
{
|
{
|
||||||
// m_ProjectionMatrix = glm::ortho(
|
|
||||||
// -16.f,
|
|
||||||
// 16.f,
|
|
||||||
// -9.f,
|
|
||||||
// 9.f,
|
|
||||||
// m_NearClip,
|
|
||||||
// m_FarClip
|
|
||||||
// );
|
|
||||||
|
|
||||||
m_ProjectionMatrix = glm::perspective(m_FOV, m_AspectRatio, m_NearClip, m_FarClip);
|
m_ProjectionMatrix = glm::perspective(m_FOV, m_AspectRatio, m_NearClip, m_FarClip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,29 +21,25 @@ void DrawScenePass::InitializeShaderPrograms()
|
|||||||
m_BasicForwardProgram->AddShader(std::shared_ptr<Shader>(new FragmentShader("Shaders/BasicForward.frag.glsl")));
|
m_BasicForwardProgram->AddShader(std::shared_ptr<Shader>(new FragmentShader("Shaders/BasicForward.frag.glsl")));
|
||||||
m_BasicForwardProgram->Compile();
|
m_BasicForwardProgram->Compile();
|
||||||
m_BasicForwardProgram->Link();
|
m_BasicForwardProgram->Link();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrawScenePass::Draw(RenderQueueCollection& rq)
|
void DrawScenePass::Draw(RenderScene& scene)
|
||||||
{
|
{
|
||||||
//glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
//glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
GLERROR("Renderer::Draw PickingPass");
|
GLERROR("Renderer::Draw PickingPass");
|
||||||
|
|
||||||
DrawScenePassState state;
|
DrawScenePassState state = DrawScenePassState();
|
||||||
|
|
||||||
|
for (auto &job : scene.ForwardJobs) {
|
||||||
//TODO: Render: Add code for more jobs than modeljobs.
|
|
||||||
for (auto &job : rq.Forward) {
|
|
||||||
auto modelJob = std::dynamic_pointer_cast<ModelJob>(job);
|
auto modelJob = std::dynamic_pointer_cast<ModelJob>(job);
|
||||||
if (modelJob) {
|
if (modelJob) {
|
||||||
GLuint ShaderHandle = m_BasicForwardProgram->GetHandle();
|
GLuint ShaderHandle = m_BasicForwardProgram->GetHandle();
|
||||||
|
|
||||||
m_BasicForwardProgram->Bind();
|
m_BasicForwardProgram->Bind();
|
||||||
//TODO: Kolla upp "header/include/common" shader saken så man slipper skicka in asmycket uniforms
|
//TODO: Kolla upp "header/include/common" shader saken så man slipper skicka in asmycket uniforms
|
||||||
glUniformMatrix4fv(glGetUniformLocation(ShaderHandle, "M"), 1, GL_FALSE, glm::value_ptr(modelJob->ModelMatrix));
|
glUniformMatrix4fv(glGetUniformLocation(ShaderHandle, "M"), 1, GL_FALSE, glm::value_ptr(modelJob->Matrix));
|
||||||
glUniformMatrix4fv(glGetUniformLocation(ShaderHandle, "V"), 1, GL_FALSE, glm::value_ptr(m_Renderer->Camera()->ViewMatrix()));
|
glUniformMatrix4fv(glGetUniformLocation(ShaderHandle, "V"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ViewMatrix()));
|
||||||
glUniformMatrix4fv(glGetUniformLocation(ShaderHandle, "P"), 1, GL_FALSE, glm::value_ptr(m_Renderer->Camera()->ProjectionMatrix()));
|
glUniformMatrix4fv(glGetUniformLocation(ShaderHandle, "P"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ProjectionMatrix()));
|
||||||
glUniform4fv(glGetUniformLocation(ShaderHandle, "Color"), 1, glm::value_ptr(modelJob->Color));
|
glUniform4fv(glGetUniformLocation(ShaderHandle, "Color"), 1, glm::value_ptr(modelJob->Color));
|
||||||
|
|
||||||
//TODO: Renderer: bättre textur felhantering samt fler texturer stöd
|
//TODO: Renderer: bättre textur felhantering samt fler texturer stöd
|
||||||
@@ -59,8 +55,9 @@ void DrawScenePass::Draw(RenderQueueCollection& rq)
|
|||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, modelJob->Model->ElementBuffer);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, modelJob->Model->ElementBuffer);
|
||||||
glDrawElementsBaseVertex(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, 0, modelJob->StartIndex);
|
glDrawElementsBaseVertex(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, 0, modelJob->StartIndex);
|
||||||
|
|
||||||
continue;
|
//continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GLERROR("DrawScene Error");
|
GLERROR("DrawScene Error");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,10 @@ DrawScenePassState::DrawScenePassState()
|
|||||||
GLERROR("---");
|
GLERROR("---");
|
||||||
Enable(GL_DEPTH_TEST);
|
Enable(GL_DEPTH_TEST);
|
||||||
Enable(GL_CULL_FACE);
|
Enable(GL_CULL_FACE);
|
||||||
ClearColor(glm::vec4(255.f / 255, 163.f / 255, 176.f / 255, 0.f));
|
Enable(GL_BLEND);
|
||||||
Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
// ClearColor(glm::vec4(255.f / 255, 163.f / 255, 176.f / 255, 0.f));
|
||||||
|
// Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawScenePassState::~DrawScenePassState()
|
DrawScenePassState::~DrawScenePassState()
|
||||||
|
|||||||
@@ -39,17 +39,10 @@ void DummyRenderer::Initialize()
|
|||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create default camera
|
|
||||||
m_DefaultCamera = new ::Camera((float)m_Resolution.Width / m_Resolution.Height, glm::radians(45.f), 0.01f, 5000.f);
|
|
||||||
m_DefaultCamera->SetPosition(glm::vec3(0, 0, 0));
|
|
||||||
if (m_Camera == nullptr) {
|
|
||||||
m_Camera = m_DefaultCamera;
|
|
||||||
}
|
|
||||||
|
|
||||||
glfwSwapInterval(m_VSYNC);
|
glfwSwapInterval(m_VSYNC);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DummyRenderer::Draw(RenderQueueCollection& rq)
|
void DummyRenderer::Draw(RenderFrame& rq)
|
||||||
{
|
{
|
||||||
glClearColor(255.f / 255, 163.f / 255, 176.f / 255, 0.f);
|
glClearColor(255.f / 255, 163.f / 255, 176.f / 255, 0.f);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|||||||
@@ -43,70 +43,109 @@ void PickingPass::InitializeShaderPrograms()
|
|||||||
m_PickingProgram->Link();
|
m_PickingProgram->Link();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PickingPass::Draw(RenderQueueCollection& rq)
|
void PickingPass::Draw(RenderScene& scene)
|
||||||
{
|
{
|
||||||
m_PickingColorsToEntity.clear();
|
|
||||||
PickingPassState* state = new PickingPassState(m_PickingBuffer.GetHandle());
|
PickingPassState* state = new PickingPassState(m_PickingBuffer.GetHandle());
|
||||||
|
|
||||||
int r = 0;
|
|
||||||
int g = 0;
|
|
||||||
//TODO: Render: Add code for more jobs than modeljobs.
|
//TODO: Render: Add code for more jobs than modeljobs.
|
||||||
|
|
||||||
GLuint ShaderHandle = m_PickingProgram->GetHandle();
|
GLuint ShaderHandle = m_PickingProgram->GetHandle();
|
||||||
m_PickingProgram->Bind();
|
m_PickingProgram->Bind();
|
||||||
|
|
||||||
std::map<EntityID, glm::vec2> entityColors;
|
|
||||||
|
|
||||||
for (auto &job : rq.Forward) {
|
m_Camera = scene.Camera;
|
||||||
auto modelJob = std::dynamic_pointer_cast<ModelJob>(job);
|
|
||||||
|
|
||||||
if (modelJob) {
|
for (auto &job : scene.ForwardJobs) {
|
||||||
int pickColor[2] = { r, g };
|
auto modelJob = std::dynamic_pointer_cast<ModelJob>(job);
|
||||||
auto color = entityColors.find(modelJob->Entity);
|
|
||||||
if (color != entityColors.end()) {
|
if (modelJob) {
|
||||||
pickColor[0] = color->second[0];
|
int pickColor[2] = { m_ColorCounter[0], m_ColorCounter[1] };
|
||||||
pickColor[1] = color->second[1];
|
|
||||||
} else {
|
PickingInfo pickInfo;
|
||||||
entityColors[modelJob->Entity] = glm::vec2(pickColor[0], pickColor[1]);
|
pickInfo.Entity = modelJob->Entity;
|
||||||
if (r + 10 > 255) {
|
pickInfo.World = modelJob->World;
|
||||||
r = 0;
|
pickInfo.Camera = scene.Camera;
|
||||||
g += 1;
|
|
||||||
|
auto color = m_EntityColors.find(std::make_tuple(pickInfo.Entity, pickInfo.World, pickInfo.Camera));
|
||||||
|
if (color != m_EntityColors.end()) {
|
||||||
|
pickColor[0] = color->second[0];
|
||||||
|
pickColor[1] = color->second[1];
|
||||||
} else {
|
} else {
|
||||||
r += 1;
|
m_EntityColors[std::make_tuple(pickInfo.Entity, pickInfo.World, pickInfo.Camera)] = glm::ivec2(pickColor[0], pickColor[1]);
|
||||||
|
if (m_ColorCounter[0] > 255) {
|
||||||
|
m_ColorCounter[0] = 0;
|
||||||
|
m_ColorCounter[1]++;;
|
||||||
|
} else {
|
||||||
|
m_ColorCounter[0]++;;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
m_PickingColorsToEntity[glm::vec2(pickColor[0], pickColor[1])] = modelJob->Entity;
|
|
||||||
|
|
||||||
//Render picking stuff
|
|
||||||
//TODO: Kolla upp "header/include/common" shader saken så man slipper skicka in asmycket uniforms
|
|
||||||
glUniformMatrix4fv(glGetUniformLocation(ShaderHandle, "M"), 1, GL_FALSE, glm::value_ptr(modelJob->ModelMatrix));
|
|
||||||
glUniformMatrix4fv(glGetUniformLocation(ShaderHandle, "V"), 1, GL_FALSE, glm::value_ptr(m_Renderer->Camera()->ViewMatrix()));
|
|
||||||
glUniformMatrix4fv(glGetUniformLocation(ShaderHandle, "P"), 1, GL_FALSE, glm::value_ptr(m_Renderer->Camera()->ProjectionMatrix()));
|
|
||||||
glUniform2fv(glGetUniformLocation(ShaderHandle, "PickingColor"), 1, glm::value_ptr(glm::vec2(pickColor[0], pickColor[1])));
|
|
||||||
|
|
||||||
glBindVertexArray(modelJob->Model->VAO);
|
m_PickingColorsToEntity[glm::ivec2(pickColor[0], pickColor[1])] = pickInfo;
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, modelJob->Model->ElementBuffer);
|
|
||||||
glDrawElementsBaseVertex(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, nullptr, modelJob->StartIndex);
|
glUniformMatrix4fv(glGetUniformLocation(ShaderHandle, "M"), 1, GL_FALSE, glm::value_ptr(modelJob->Matrix));
|
||||||
|
glUniformMatrix4fv(glGetUniformLocation(ShaderHandle, "V"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ViewMatrix()));
|
||||||
|
glUniformMatrix4fv(glGetUniformLocation(ShaderHandle, "P"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ProjectionMatrix()));
|
||||||
|
glUniform2fv(glGetUniformLocation(ShaderHandle, "PickingColor"), 1, glm::value_ptr(glm::vec2(pickColor[0], pickColor[1])));
|
||||||
|
|
||||||
|
glBindVertexArray(modelJob->Model->VAO);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, modelJob->Model->ElementBuffer);
|
||||||
|
glDrawElementsBaseVertex(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, nullptr, modelJob->StartIndex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
m_PickingBuffer.Unbind();
|
m_PickingBuffer.Unbind();
|
||||||
GLERROR("PickingPass Error");
|
GLERROR("PickingPass Error");
|
||||||
|
|
||||||
//Publish pick event every frame with the pick data that can be picked by the event
|
|
||||||
|
delete state;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void PickingPass::ClearPicking()
|
||||||
|
{
|
||||||
|
m_PickingColorsToEntity.clear();
|
||||||
|
m_EntityColors.clear();
|
||||||
|
m_ColorCounter[0] = 1;
|
||||||
|
m_ColorCounter[1] = 0;
|
||||||
|
|
||||||
|
m_PickingBuffer.Bind();
|
||||||
|
glClearColor(0.f, 0.f, 0.f, 0.f);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
m_PickingBuffer.Unbind();
|
||||||
|
}
|
||||||
|
|
||||||
|
PickData PickingPass::Pick(glm::vec2 screenCoord)
|
||||||
|
{
|
||||||
int fbWidth;
|
int fbWidth;
|
||||||
int fbHeight;
|
int fbHeight;
|
||||||
glfwGetFramebufferSize(m_Renderer->Window(), &fbWidth, &fbHeight);
|
glfwGetFramebufferSize(m_Renderer->Window(), &fbWidth, &fbHeight);
|
||||||
Events::Picking pickEvent = Events::Picking(
|
|
||||||
&m_PickingBuffer,
|
|
||||||
&m_DepthBuffer,
|
|
||||||
m_Renderer->Camera()->ProjectionMatrix(),
|
|
||||||
m_Renderer->Camera()->ViewMatrix(),
|
|
||||||
Rectangle(fbWidth, fbHeight),
|
|
||||||
&m_PickingColorsToEntity);
|
|
||||||
|
|
||||||
m_EventBroker->Publish(pickEvent);
|
Rectangle resolution = Rectangle(fbWidth, fbHeight);
|
||||||
|
PickData pickData;
|
||||||
|
// Invert screen y coordinate
|
||||||
|
screenCoord.y = resolution.Height - screenCoord.y;
|
||||||
|
ScreenCoords::PixelData data = ScreenCoords::ToPixelData(screenCoord, &m_PickingBuffer, m_DepthBuffer);
|
||||||
|
pickData.Depth = data.Depth;
|
||||||
|
|
||||||
delete state;
|
PickingInfo pickInfo;
|
||||||
|
|
||||||
|
auto it = m_PickingColorsToEntity.find(glm::ivec2(data.Color[0], data.Color[1]));
|
||||||
|
if (it != m_PickingColorsToEntity.end()) {
|
||||||
|
pickInfo = it->second;
|
||||||
|
} else {
|
||||||
|
pickData.Entity = EntityID_Invalid;
|
||||||
|
return pickData;
|
||||||
|
}
|
||||||
|
|
||||||
|
pickData.Position = ScreenCoords::ToWorldPos(screenCoord.x, screenCoord.y, data.Depth, resolution, pickInfo.Camera->ProjectionMatrix(), pickInfo.Camera->ViewMatrix());
|
||||||
|
pickData.Entity = pickInfo.Entity;
|
||||||
|
pickData.Camera = pickInfo.Camera;
|
||||||
|
pickData.World = pickInfo.World;
|
||||||
|
return pickData;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PickingPass::GenerateTexture(GLuint* texture, GLenum wrapping, GLenum filtering, glm::vec2 dimensions, GLint internalFormat, GLint format, GLenum type) const
|
void PickingPass::GenerateTexture(GLuint* texture, GLenum wrapping, GLenum filtering, glm::vec2 dimensions, GLint internalFormat, GLint format, GLenum type) const
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ PickingPassState::PickingPassState(GLuint frameBuffer)
|
|||||||
Enable(GL_CULL_FACE);
|
Enable(GL_CULL_FACE);
|
||||||
|
|
||||||
glm::vec4 clearColor = glm::vec4(0.f);
|
glm::vec4 clearColor = glm::vec4(0.f);
|
||||||
ClearColor(clearColor);
|
//ClearColor(clearColor);
|
||||||
Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
//Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
PickingPassState::~PickingPassState()
|
PickingPassState::~PickingPassState()
|
||||||
|
|||||||
@@ -81,6 +81,9 @@ RawModel::RawModel(std::string fileName)
|
|||||||
float opacity;
|
float opacity;
|
||||||
material->Get(AI_MATKEY_OPACITY, opacity);
|
material->Get(AI_MATKEY_OPACITY, opacity);
|
||||||
desc.DiffuseVertexColor = glm::vec4(diffuse.r, diffuse.g, diffuse.b, opacity);
|
desc.DiffuseVertexColor = glm::vec4(diffuse.r, diffuse.g, diffuse.b, opacity);
|
||||||
|
|
||||||
|
desc.DiffuseVertexColor = glm::vec4(diffuse.r, diffuse.g, diffuse.b, opacity);
|
||||||
|
|
||||||
// Material specular color
|
// Material specular color
|
||||||
aiColor3D specular;
|
aiColor3D specular;
|
||||||
material->Get(AI_MATKEY_COLOR_SPECULAR, specular);
|
material->Get(AI_MATKEY_COLOR_SPECULAR, specular);
|
||||||
@@ -134,6 +137,7 @@ RawModel::RawModel(std::string fileName)
|
|||||||
matGroup.EndIndex = m_Indices.size() - 1;
|
matGroup.EndIndex = m_Indices.size() - 1;
|
||||||
// Material shininess
|
// Material shininess
|
||||||
material->Get(AI_MATKEY_SHININESS, matGroup.Shininess);
|
material->Get(AI_MATKEY_SHININESS, matGroup.Shininess);
|
||||||
|
material->Get(AI_MATKEY_OPACITY, matGroup.Transparency);
|
||||||
//LOG_DEBUG("Shininess: %f", matGroup.Shininess);
|
//LOG_DEBUG("Shininess: %f", matGroup.Shininess);
|
||||||
// Diffuse texture
|
// Diffuse texture
|
||||||
//LOG_DEBUG("%i diffuse textures found", material->GetTextureCount(aiTextureType_DIFFUSE));
|
//LOG_DEBUG("%i diffuse textures found", material->GetTextureCount(aiTextureType_DIFFUSE));
|
||||||
|
|||||||
@@ -1,116 +0,0 @@
|
|||||||
#include "Rendering/RenderQueueFactory.h"
|
|
||||||
|
|
||||||
|
|
||||||
RenderQueueFactory::RenderQueueFactory()
|
|
||||||
{
|
|
||||||
m_RenderQueues = RenderQueueCollection();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RenderQueueFactory::Update(World* world)
|
|
||||||
{
|
|
||||||
m_RenderQueues.Clear();
|
|
||||||
FillModels(world, &m_RenderQueues.Forward);
|
|
||||||
FillLights(world, &m_RenderQueues.Lights);
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::mat4 RenderQueueFactory::ModelMatrix(World* world, EntityID entity)
|
|
||||||
{
|
|
||||||
glm::vec3 position = AbsolutePosition(world, entity);
|
|
||||||
glm::quat orientation = AbsoluteOrientation(world, entity);
|
|
||||||
glm::vec3 scale = AbsoluteScale(world, entity);
|
|
||||||
|
|
||||||
glm::mat4 modelMatrix = glm::translate(glm::mat4(), position) * glm::toMat4(orientation) * glm::scale(scale);
|
|
||||||
return modelMatrix;
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::vec3 RenderQueueFactory::AbsolutePosition(World* world, EntityID entity)
|
|
||||||
{
|
|
||||||
glm::vec3 position;
|
|
||||||
|
|
||||||
do {
|
|
||||||
ComponentWrapper transform = world->GetComponent(entity, "Transform");
|
|
||||||
EntityID parent = world->GetParent(entity);
|
|
||||||
if (parent != 0) {
|
|
||||||
position += AbsoluteOrientation(world, parent) * (glm::vec3)transform["Position"];
|
|
||||||
} else {
|
|
||||||
position += (glm::vec3)transform["Position"];
|
|
||||||
}
|
|
||||||
entity = parent;
|
|
||||||
} while (entity != 0);
|
|
||||||
|
|
||||||
return position;
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::quat RenderQueueFactory::AbsoluteOrientation(World* world, EntityID entity)
|
|
||||||
{
|
|
||||||
glm::quat orientation;
|
|
||||||
|
|
||||||
do {
|
|
||||||
ComponentWrapper transform = world->GetComponent(entity, "Transform");
|
|
||||||
orientation = glm::quat((glm::vec3)transform["Orientation"]) * orientation;
|
|
||||||
entity = world->GetParent(entity);
|
|
||||||
} while (entity != 0);
|
|
||||||
|
|
||||||
return orientation;
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::vec3 RenderQueueFactory::AbsoluteScale(World* world, EntityID entity)
|
|
||||||
{
|
|
||||||
glm::vec3 scale(1.f);
|
|
||||||
|
|
||||||
do {
|
|
||||||
ComponentWrapper transform = world->GetComponent(entity, "Transform");
|
|
||||||
scale *= (glm::vec3)transform["Scale"];
|
|
||||||
entity = world->GetParent(entity);
|
|
||||||
} while (entity != 0);
|
|
||||||
|
|
||||||
return scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RenderQueueFactory::FillModels(World* world, RenderQueue* renderQueue)
|
|
||||||
{
|
|
||||||
auto models = world->GetComponents("Model");
|
|
||||||
if (models == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& modelC : *models) {
|
|
||||||
bool visible = modelC["Visible"];
|
|
||||||
if (!visible) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
std::string resource = modelC["Resource"];
|
|
||||||
if (resource.empty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
glm::vec4 color = modelC["Color"];
|
|
||||||
Model* model = ResourceManager::Load<Model>(resource);
|
|
||||||
if (model == nullptr) {
|
|
||||||
model = ResourceManager::Load<Model>("Models/Core/Error.obj");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto texGroup : model->TextureGroups) {
|
|
||||||
ModelJob job;
|
|
||||||
job.TextureID = (texGroup.Texture) ? texGroup.Texture->ResourceID : 0;
|
|
||||||
job.DiffuseTexture = texGroup.Texture.get();
|
|
||||||
job.NormalTexture = texGroup.NormalMap.get();
|
|
||||||
job.SpecularTexture = texGroup.SpecularMap.get();
|
|
||||||
job.Model = model;
|
|
||||||
job.StartIndex = texGroup.StartIndex;
|
|
||||||
job.EndIndex = texGroup.EndIndex;
|
|
||||||
job.ModelMatrix = model->m_Matrix * ModelMatrix(world, modelC.EntityID);
|
|
||||||
job.Color = color;
|
|
||||||
|
|
||||||
//TODO: RENDERER: Not sure if the best solution for pickingColor to entity link is this
|
|
||||||
job.Entity = modelC.EntityID;
|
|
||||||
|
|
||||||
renderQueue->Add(job);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RenderQueueFactory::FillLights(World* world, RenderQueue* renderQueue)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -0,0 +1,188 @@
|
|||||||
|
#include "Rendering/RenderSystem.h"
|
||||||
|
|
||||||
|
RenderSystem::RenderSystem(EventBroker* eventBrokerer, const IRenderer* renderer, RenderFrame* renderFrame) :ImpureSystem(eventBrokerer)
|
||||||
|
{
|
||||||
|
m_Renderer = renderer;
|
||||||
|
m_RenderFrame = renderFrame;
|
||||||
|
EVENT_SUBSCRIBE_MEMBER(m_ESetCamera, &RenderSystem::OnSetCamera);
|
||||||
|
EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &RenderSystem::OnInputCommand);
|
||||||
|
|
||||||
|
m_Camera = new Camera((float)m_Renderer->Resolution().Width / m_Renderer->Resolution().Height, glm::radians(45.f), 0.01f, 5000.f);
|
||||||
|
m_DebugCameraInputController = new DebugCameraInputController<RenderSystem>(eventBrokerer, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderSystem::~RenderSystem()
|
||||||
|
{
|
||||||
|
delete m_Camera;
|
||||||
|
delete m_DebugCameraInputController;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RenderSystem::OnSetCamera(const Events::SetCamera &event)
|
||||||
|
{
|
||||||
|
auto cameras = m_World->GetComponents("Camera");
|
||||||
|
|
||||||
|
if (cameras != nullptr) {
|
||||||
|
for (auto it = cameras->begin(); it != cameras->end(); it++) {
|
||||||
|
if ((std::string)(*it)["Name"] == event.Name) {
|
||||||
|
switchCamera((*it).EntityID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderSystem::switchCamera(EntityID entity)
|
||||||
|
{
|
||||||
|
if(m_World->HasComponent(entity, "Camera")) {
|
||||||
|
|
||||||
|
if (m_CurrentCamera != EntityID_Invalid) {
|
||||||
|
if (m_World->HasComponent(m_CurrentCamera, "Model")) {
|
||||||
|
m_World->GetComponent(m_CurrentCamera, "Model")["Visible"] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_World->HasComponent(entity, "Model")) {
|
||||||
|
m_World->GetComponent(entity, "Model")["Visible"] = false;
|
||||||
|
}
|
||||||
|
m_CurrentCamera = entity;
|
||||||
|
m_SwitchCamera = false;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
LOG_ERROR("Entity %i does not have a CameraComponent", entity);
|
||||||
|
m_SwitchCamera = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderSystem::updateProjectionMatrix(ComponentWrapper& cameraComponent)
|
||||||
|
{
|
||||||
|
double fov = cameraComponent["FOV"];
|
||||||
|
double aspectRatio = (float)m_Renderer->Resolution().Width / m_Renderer->Resolution().Height;
|
||||||
|
double nearClip = cameraComponent["NearClip"];
|
||||||
|
double farClip = cameraComponent["FarClip"];
|
||||||
|
|
||||||
|
m_Camera->SetFOV(glm::radians(fov));
|
||||||
|
m_Camera->SetAspectRatio(aspectRatio);
|
||||||
|
m_Camera->SetNearClip(nearClip);
|
||||||
|
m_Camera->SetFarClip(farClip);
|
||||||
|
m_Camera->UpdateProjectionMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderSystem::fillModels(std::list<std::shared_ptr<RenderJob>>& jobs, World* world)
|
||||||
|
{
|
||||||
|
auto models = world->GetComponents("Model");
|
||||||
|
if (models == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& modelComponent : *models) {
|
||||||
|
bool visible = modelComponent["Visible"];
|
||||||
|
if (!visible) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
std::string resource = modelComponent["Resource"];
|
||||||
|
if (resource.empty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Model* model = ResourceManager::Load<::Model>(resource);
|
||||||
|
if (model == nullptr) {
|
||||||
|
model = ResourceManager::Load<::Model>("Models/Core/Error.obj");
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::mat4 modelMatrix = Transform::ModelMatrix(modelComponent.EntityID, world);
|
||||||
|
|
||||||
|
for (auto texGroup : model->TextureGroups) {
|
||||||
|
std::shared_ptr<ModelJob> modelJob = std::shared_ptr<ModelJob>(new ModelJob(model, m_Camera, modelMatrix, texGroup, modelComponent, world));
|
||||||
|
jobs.push_back(modelJob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RenderSystem::OnInputCommand(const Events::InputCommand& e)
|
||||||
|
{
|
||||||
|
if (e.Command == "SwitchCamera" && e.Value > 0) {
|
||||||
|
m_SwitchCamera = true;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderSystem::Update(World* world, double dt)
|
||||||
|
{
|
||||||
|
m_World = world;
|
||||||
|
m_EventBroker->Process<RenderSystem>();
|
||||||
|
|
||||||
|
updateCamera(world, dt);
|
||||||
|
|
||||||
|
//Only supports opaque geometry atm
|
||||||
|
m_RenderFrame->Clear();
|
||||||
|
|
||||||
|
RenderScene rs;
|
||||||
|
rs.Camera = m_Camera;
|
||||||
|
rs.Viewport = Rectangle(1280, 720);
|
||||||
|
fillModels(rs.ForwardJobs, world);
|
||||||
|
m_RenderFrame->Add(rs);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderSystem::updateCamera(World* world, double dt)
|
||||||
|
{
|
||||||
|
if (m_SwitchCamera) {
|
||||||
|
auto cameras = world->GetComponents("Camera");
|
||||||
|
for (auto it = cameras->begin(); it != cameras->end(); it++) {
|
||||||
|
if ((*it).EntityID == m_CurrentCamera) {
|
||||||
|
it++;
|
||||||
|
if (it != cameras->end()) {
|
||||||
|
switchCamera((*it).EntityID);
|
||||||
|
} else {
|
||||||
|
switchCamera((*cameras->begin()).EntityID);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ComponentWrapper& cameraComponent = world->GetComponent(m_CurrentCamera, "Camera");
|
||||||
|
ComponentWrapper& cameraTransform = world->GetComponent(m_CurrentCamera, "Transform");
|
||||||
|
|
||||||
|
m_DebugCameraInputController->SetOrientation(glm::quat((glm::vec3)cameraTransform["Orientation"]));
|
||||||
|
m_DebugCameraInputController->SetPosition(cameraTransform["Position"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_World->ValidEntity(m_CurrentCamera)) {
|
||||||
|
if (world->HasComponent(m_CurrentCamera, "Camera") && world->HasComponent(m_CurrentCamera, "Transform")) {
|
||||||
|
ComponentWrapper& cameraComponent = world->GetComponent(m_CurrentCamera, "Camera");
|
||||||
|
ComponentWrapper& cameraTransform = world->GetComponent(m_CurrentCamera, "Transform");
|
||||||
|
|
||||||
|
m_DebugCameraInputController->Update(dt);
|
||||||
|
(glm::vec3&)cameraTransform["Orientation"] = glm::eulerAngles(m_DebugCameraInputController->Orientation());
|
||||||
|
(glm::vec3&)cameraTransform["Position"] = m_DebugCameraInputController->Position();
|
||||||
|
|
||||||
|
glm::vec3 position = Transform::AbsolutePosition(world, m_CurrentCamera);
|
||||||
|
glm::quat orientation = Transform::AbsoluteOrientation(world, m_CurrentCamera);
|
||||||
|
|
||||||
|
m_Camera->SetPosition(position);
|
||||||
|
m_Camera->SetOrientation(orientation);
|
||||||
|
|
||||||
|
updateProjectionMatrix(cameraComponent);
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m_Camera = m_Camera;
|
||||||
|
|
||||||
|
auto cameras = world->GetComponents("Camera");
|
||||||
|
if (cameras != nullptr) {
|
||||||
|
if (cameras->begin() != cameras->end()) {
|
||||||
|
ComponentWrapper& cameraC = *cameras->begin();
|
||||||
|
switchCamera(cameraC.EntityID);
|
||||||
|
|
||||||
|
ComponentWrapper& cameraComponent = world->GetComponent(m_CurrentCamera, "Camera");
|
||||||
|
ComponentWrapper& cameraTransform = world->GetComponent(m_CurrentCamera, "Transform");
|
||||||
|
|
||||||
|
m_DebugCameraInputController->SetOrientation(glm::quat((glm::vec3)cameraTransform["Orientation"]));
|
||||||
|
m_DebugCameraInputController->SetPosition(cameraTransform["Position"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Camera->UpdateViewMatrix();
|
||||||
|
}
|
||||||
@@ -1,29 +1,29 @@
|
|||||||
#include "Rendering/Renderer.h"
|
#include "Rendering/Renderer.h"
|
||||||
#include "Rendering/DebugCameraInputController.h"
|
|
||||||
|
|
||||||
void Renderer::Initialize()
|
void Renderer::Initialize()
|
||||||
{
|
{
|
||||||
InitializeWindow();
|
InitializeWindow();
|
||||||
// Create default camera
|
|
||||||
m_DefaultCamera = new ::Camera((float)m_Resolution.Width / m_Resolution.Height, glm::radians(45.f), 0.01f, 5000.f);
|
|
||||||
m_DefaultCamera->SetPosition(glm::vec3(0, 0, 10));
|
|
||||||
if (m_Camera == nullptr) {
|
|
||||||
m_Camera = m_DefaultCamera;
|
|
||||||
}
|
|
||||||
TEMPCreateLights();
|
|
||||||
InitializeRenderPasses();
|
InitializeRenderPasses();
|
||||||
|
|
||||||
glfwSwapInterval(m_VSYNC);
|
glfwSwapInterval(m_VSYNC);
|
||||||
InitializeShaders();
|
InitializeShaders();
|
||||||
InitializeTextures();
|
InitializeTextures();
|
||||||
InitializeSSBOs();
|
|
||||||
//CalculateFrustum();
|
|
||||||
|
|
||||||
m_ScreenQuad = ResourceManager::Load<Model>("Models/Core/ScreenQuad.obj");
|
m_ScreenQuad = ResourceManager::Load<Model>("Models/Core/ScreenQuad.obj");
|
||||||
m_UnitQuad = ResourceManager::Load<Model>("Models/Core/UnitQuad.obj");
|
m_UnitQuad = ResourceManager::Load<Model>("Models/Core/UnitQuad.obj");
|
||||||
m_UnitSphere = ResourceManager::Load<Model>("Models/Core/UnitSphere.obj");
|
m_UnitSphere = ResourceManager::Load<Model>("Models/Core/UnitSphere.obj");
|
||||||
|
|
||||||
m_ImGuiRenderPass = new ImGuiRenderPass(this, m_EventBroker);
|
m_ImGuiRenderPass = new ImGuiRenderPass(this, m_EventBroker);
|
||||||
|
|
||||||
|
|
||||||
|
// Create default camera
|
||||||
|
m_DefaultCamera = new ::Camera((float)m_Resolution.Width / m_Resolution.Height, glm::radians(45.f), 0.01f, 5000.f);
|
||||||
|
m_DefaultCamera->SetPosition(glm::vec3(0, 0, 10));
|
||||||
|
if (m_Camera == nullptr) {
|
||||||
|
m_Camera = m_DefaultCamera;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::InitializeWindow()
|
void Renderer::InitializeWindow()
|
||||||
@@ -75,54 +75,11 @@ void Renderer::InitializeShaders()
|
|||||||
m_DrawScreenQuadProgram->AddShader(std::shared_ptr<Shader>(new FragmentShader("Shaders/DrawScreenQuad.frag.glsl")));
|
m_DrawScreenQuadProgram->AddShader(std::shared_ptr<Shader>(new FragmentShader("Shaders/DrawScreenQuad.frag.glsl")));
|
||||||
m_DrawScreenQuadProgram->Compile();
|
m_DrawScreenQuadProgram->Compile();
|
||||||
m_DrawScreenQuadProgram->Link();
|
m_DrawScreenQuadProgram->Link();
|
||||||
|
|
||||||
//m_CalculateFrustumProgram = ResourceManager::Load<ShaderProgram>("#CalculateFrustumProgram");
|
|
||||||
//m_CalculateFrustumProgram.AddShader(std::shared_ptr<Shader>(new ComputeShader("Shaders/GridFrustum.comp.glsl")));
|
|
||||||
//m_CalculateFrustumProgram.Compile();
|
|
||||||
//m_CalculateFrustumProgram.Link();
|
|
||||||
|
|
||||||
//m_LightCullProgram = ResourceManager::Load<ShaderProgram>("#LightCullProgram");
|
|
||||||
//m_LightCullProgram.AddShader(std::shared_ptr<Shader>(new ComputeShader("Shaders/cullLights.comp.glsl")));
|
|
||||||
//m_LightCullProgram.Compile();
|
|
||||||
//m_LightCullProgram.Link();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::InputUpdate(double dt)
|
void Renderer::InputUpdate(double dt)
|
||||||
{
|
{
|
||||||
static DebugCameraInputController<Renderer> firstPersonInputController(m_EventBroker, -1);
|
|
||||||
|
|
||||||
glm::vec3 m_Position = m_Camera->Position();
|
|
||||||
if (glfwGetKey(m_Window, GLFW_KEY_O) == GLFW_PRESS)
|
|
||||||
{
|
|
||||||
m_Position = glm::vec3(0.f, 0.f, 5.f);
|
|
||||||
}
|
|
||||||
if (glfwGetKey(m_Window, GLFW_KEY_W) == GLFW_PRESS)
|
|
||||||
{
|
|
||||||
m_Position += m_Camera->Forward() * m_CameraMoveSpeed * (float)dt;
|
|
||||||
}
|
|
||||||
if (glfwGetKey(m_Window, GLFW_KEY_S) == GLFW_PRESS)
|
|
||||||
{
|
|
||||||
m_Position -= m_Camera->Forward() * m_CameraMoveSpeed * (float)dt;
|
|
||||||
}
|
|
||||||
if (glfwGetKey(m_Window, GLFW_KEY_D) == GLFW_PRESS)
|
|
||||||
{
|
|
||||||
m_Position += m_Camera->Right() * m_CameraMoveSpeed * (float)dt;
|
|
||||||
}
|
|
||||||
if (glfwGetKey(m_Window, GLFW_KEY_A) == GLFW_PRESS)
|
|
||||||
{
|
|
||||||
m_Position -= m_Camera->Right() * m_CameraMoveSpeed * (float)dt;
|
|
||||||
}
|
|
||||||
if (glfwGetKey(m_Window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS)
|
|
||||||
{
|
|
||||||
m_CameraMoveSpeed = 5.f;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
m_CameraMoveSpeed = 0.5f;
|
|
||||||
}
|
|
||||||
|
|
||||||
firstPersonInputController.Update(dt);
|
|
||||||
m_Camera->SetOrientation(firstPersonInputController.Orientation());
|
|
||||||
m_Camera->SetPosition(firstPersonInputController.Position());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::Update(double dt)
|
void Renderer::Update(double dt)
|
||||||
@@ -132,20 +89,31 @@ void Renderer::Update(double dt)
|
|||||||
m_ImGuiRenderPass->Update(dt);
|
m_ImGuiRenderPass->Update(dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::Draw(RenderQueueCollection& rq)
|
void Renderer::Draw(RenderFrame& frame)
|
||||||
{
|
{
|
||||||
m_PickingPass->Draw(rq);
|
glClearColor(255.f / 255, 163.f / 255, 176.f / 255, 0.f);
|
||||||
//DrawScreenQuad(m_PickingPass->PickingTexture());
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
//CullLights();
|
|
||||||
|
m_PickingPass->ClearPicking();
|
||||||
glClearColor(255.f / 255, 163.f / 255, 176.f / 255, 1.f);
|
for (auto scene : frame.RenderScenes){
|
||||||
|
m_Camera = scene->Camera; // remove renderer camera when Editor uses the render scene cameras.
|
||||||
|
m_PickingPass->Draw(*scene);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
m_DrawScenePass->Draw(*scene);
|
||||||
|
GLERROR("Renderer::Draw m_DrawScenePass->Draw");
|
||||||
|
}
|
||||||
|
|
||||||
m_DrawScenePass->Draw(rq);
|
|
||||||
GLERROR("Renderer::Draw m_DrawScenePass->Draw");
|
|
||||||
m_ImGuiRenderPass->Draw();
|
m_ImGuiRenderPass->Draw();
|
||||||
glfwSwapBuffers(m_Window);
|
glfwSwapBuffers(m_Window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PickData Renderer::Pick(glm::vec2 screenCoord)
|
||||||
|
{
|
||||||
|
return m_PickingPass->Pick(screenCoord);
|
||||||
|
}
|
||||||
|
|
||||||
void Renderer::DrawScreenQuad(GLuint textureToDraw)
|
void Renderer::DrawScreenQuad(GLuint textureToDraw)
|
||||||
{
|
{
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
@@ -185,95 +153,8 @@ void Renderer::GenerateTexture(GLuint* texture, GLenum wrapping, GLenum filterin
|
|||||||
GLERROR("Texture initialization failed");
|
GLERROR("Texture initialization failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::InitializeSSBOs()
|
|
||||||
{
|
|
||||||
printf("Size: %i\n", sizeof(m_Frustums));
|
|
||||||
glGenBuffers(1, &m_FrustumSSBO);
|
|
||||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_FrustumSSBO);
|
|
||||||
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(m_Frustums), &m_Frustums, GL_DYNAMIC_COPY);
|
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_FrustumSSBO);
|
|
||||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
|
|
||||||
|
|
||||||
GLERROR("m_FrustumSSBO");
|
|
||||||
|
|
||||||
glGenBuffers(1, &m_LightSSBO);
|
|
||||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_LightSSBO);
|
|
||||||
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(m_PointLights), &m_PointLights, GL_DYNAMIC_COPY);
|
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_LightSSBO);
|
|
||||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
|
|
||||||
|
|
||||||
GLERROR("m_LightSSBO");
|
|
||||||
|
|
||||||
|
|
||||||
glGenBuffers(1, &m_LightGridSSBO);
|
|
||||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_LightGridSSBO);
|
|
||||||
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(m_LightGrid), &m_LightGrid, GL_DYNAMIC_COPY);
|
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, m_LightGridSSBO);
|
|
||||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
|
|
||||||
|
|
||||||
GLERROR("m_LightGridSSBO");
|
|
||||||
|
|
||||||
|
|
||||||
glGenBuffers(1, &m_LightOffsetSSBO);
|
|
||||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_LightOffsetSSBO);
|
|
||||||
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(m_LightOffset), &m_LightOffset, GL_DYNAMIC_COPY);
|
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, m_LightOffsetSSBO);
|
|
||||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
|
|
||||||
|
|
||||||
GLERROR("m_LightOffsetSSBO");
|
|
||||||
|
|
||||||
|
|
||||||
glGenBuffers(1, &m_LightIndexSSBO);
|
|
||||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_LightIndexSSBO);
|
|
||||||
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(m_LightIndex), &m_LightIndex, GL_DYNAMIC_COPY);
|
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, m_LightIndexSSBO);
|
|
||||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
|
|
||||||
|
|
||||||
GLERROR("m_LightIndexSSBO");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::InitializeRenderPasses()
|
void Renderer::InitializeRenderPasses()
|
||||||
{
|
{
|
||||||
m_DrawScenePass = new DrawScenePass(this);
|
m_DrawScenePass = new DrawScenePass(this);
|
||||||
m_PickingPass = new PickingPass(this, m_EventBroker);
|
m_PickingPass = new PickingPass(this, m_EventBroker);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::CalculateFrustum()
|
|
||||||
{
|
|
||||||
GLERROR("CalculateFrustum Error-1");
|
|
||||||
m_CalculateFrustumProgram->Bind();
|
|
||||||
|
|
||||||
GLERROR("CalculateFrustum Error1");
|
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_FrustumSSBO);
|
|
||||||
GLERROR("CalculateFrustum Error2");
|
|
||||||
glUniformMatrix4fv(glGetUniformLocation(m_CalculateFrustumProgram->GetHandle(), "P"), 1, false, glm::value_ptr(m_Camera->ProjectionMatrix()));
|
|
||||||
GLERROR("CalculateFrustum Error3");
|
|
||||||
glUniform2f(glGetUniformLocation(m_CalculateFrustumProgram->GetHandle(), "ScreenDimensions"), m_Resolution.Width, m_Resolution.Height);
|
|
||||||
GLERROR("CalculateFrustum Error4");
|
|
||||||
glDispatchCompute(5, 3, 1);
|
|
||||||
GLERROR("CalculateFrustum Error5");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::TEMPCreateLights()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < NUM_LIGHTS; i++) {
|
|
||||||
m_PointLights[i].Position = glm::vec4(i, 0.f, 0.f, 0.f);
|
|
||||||
m_PointLights[i].Color = glm::vec4(1.f, 0.5f, 0.f + i*0.1f, 1.f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Renderer::CullLights()
|
|
||||||
{
|
|
||||||
m_LightCullProgram->Bind();
|
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_FrustumSSBO);
|
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_LightSSBO);
|
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, m_LightGridSSBO);
|
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, m_LightOffsetSSBO);
|
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, m_LightIndexSSBO);
|
|
||||||
glDispatchCompute(m_Resolution.Width / TILE_SIZE, m_Resolution.Height / TILE_SIZE, 1);
|
|
||||||
GLERROR("CullLights Error");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ file(GLOB SOURCE_FILES
|
|||||||
set(SOURCE_FILES
|
set(SOURCE_FILES
|
||||||
${SOURCE_FILES}
|
${SOURCE_FILES}
|
||||||
"Game.cpp"
|
"Game.cpp"
|
||||||
|
"HealthSystem.cpp"
|
||||||
"PlayerSystem.cpp"
|
"PlayerSystem.cpp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+33
-55
@@ -1,14 +1,16 @@
|
|||||||
#include "Game.h"
|
#include "Game.h"
|
||||||
#include "Collision/TriggerSystem.h"
|
#include "Collision/TriggerSystem.h"
|
||||||
#include "Collision/CollisionSystem.h"
|
#include "Collision/CollisionSystem.h"
|
||||||
|
#include "Game/HealthSystem.h"
|
||||||
|
#include "Core/EntityFileWriter.h"
|
||||||
|
|
||||||
Game::Game(int argc, char* argv[])
|
Game::Game(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
ResourceManager::RegisterType<ConfigFile>("ConfigFile");
|
ResourceManager::RegisterType<ConfigFile>("ConfigFile");
|
||||||
ResourceManager::RegisterType<Model>("Model");
|
ResourceManager::RegisterType<Model>("Model");
|
||||||
ResourceManager::RegisterType<Texture>("Texture");
|
ResourceManager::RegisterType<Texture>("Texture");
|
||||||
ResourceManager::RegisterType<EntityXMLFile>("EntityXMLFile");
|
|
||||||
ResourceManager::RegisterType<ShaderProgram>("ShaderProgram");
|
ResourceManager::RegisterType<ShaderProgram>("ShaderProgram");
|
||||||
|
ResourceManager::RegisterType<EntityFile>("EntityFile");
|
||||||
|
|
||||||
m_Config = ResourceManager::Load<ConfigFile>("Config.ini");
|
m_Config = ResourceManager::Load<ConfigFile>("Config.ini");
|
||||||
LOG_LEVEL = static_cast<_LOG_LEVEL>(m_Config->Get<int>("Debug.LogLevel", 1));
|
LOG_LEVEL = static_cast<_LOG_LEVEL>(m_Config->Get<int>("Debug.LogLevel", 1));
|
||||||
@@ -16,10 +18,9 @@ Game::Game(int argc, char* argv[])
|
|||||||
// Create the core event broker
|
// Create the core event broker
|
||||||
m_EventBroker = new EventBroker();
|
m_EventBroker = new EventBroker();
|
||||||
|
|
||||||
m_RenderQueueFactory = new RenderQueueFactory();
|
|
||||||
|
|
||||||
// Create the renderer
|
// Create the renderer
|
||||||
m_Renderer = new Renderer(m_EventBroker);
|
m_Renderer = new Renderer(m_EventBroker, m_World);
|
||||||
m_Renderer->SetFullscreen(m_Config->Get<bool>("Video.Fullscreen", false));
|
m_Renderer->SetFullscreen(m_Config->Get<bool>("Video.Fullscreen", false));
|
||||||
m_Renderer->SetVSYNC(m_Config->Get<bool>("Video.VSYNC", false));
|
m_Renderer->SetVSYNC(m_Config->Get<bool>("Video.VSYNC", false));
|
||||||
m_Renderer->SetResolution(Rectangle::Rectangle(
|
m_Renderer->SetResolution(Rectangle::Rectangle(
|
||||||
@@ -29,7 +30,8 @@ Game::Game(int argc, char* argv[])
|
|||||||
m_Config->Get<int>("Video.Height", 720)
|
m_Config->Get<int>("Video.Height", 720)
|
||||||
));
|
));
|
||||||
m_Renderer->Initialize();
|
m_Renderer->Initialize();
|
||||||
m_Renderer->Camera()->SetFOV(glm::radians(m_Config->Get<float>("Video.FOV", 90.f)));
|
//m_Renderer->Camera()->SetFOV(glm::radians(m_Config->Get<float>("Video.FOV", 90.f)));
|
||||||
|
m_RenderFrame = new RenderFrame();
|
||||||
|
|
||||||
// Create input manager
|
// Create input manager
|
||||||
m_InputManager = new InputManager(m_Renderer->Window(), m_EventBroker);
|
m_InputManager = new InputManager(m_Renderer->Window(), m_EventBroker);
|
||||||
@@ -47,16 +49,30 @@ Game::Game(int argc, char* argv[])
|
|||||||
m_World = new World();
|
m_World = new World();
|
||||||
std::string mapToLoad = m_Config->Get<std::string>("Debug.LoadMap", "");
|
std::string mapToLoad = m_Config->Get<std::string>("Debug.LoadMap", "");
|
||||||
if (!mapToLoad.empty()) {
|
if (!mapToLoad.empty()) {
|
||||||
ResourceManager::Load<EntityXMLFile>(mapToLoad)->PopulateWorld(m_World);
|
auto file = ResourceManager::Load<EntityFile>(mapToLoad);
|
||||||
|
EntityFilePreprocessor fpp(file);
|
||||||
|
fpp.RegisterComponents(m_World);
|
||||||
|
EntityFileParser fp(file);
|
||||||
|
fp.MergeEntities(m_World);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create system pipeline
|
// Create system pipeline
|
||||||
m_SystemPipeline = new SystemPipeline(m_EventBroker);
|
m_SystemPipeline = new SystemPipeline(m_EventBroker);
|
||||||
m_SystemPipeline->AddSystem<RaptorCopterSystem>();
|
|
||||||
m_SystemPipeline->AddSystem<PlayerSystem>();
|
|
||||||
m_SystemPipeline->AddSystem<EditorSystem>(m_Renderer);
|
//All systems with orderlevel 0 will be updated first.
|
||||||
m_SystemPipeline->AddSystem<CollisionSystem>();
|
unsigned int updateOrderLevel = 0;
|
||||||
m_SystemPipeline->AddSystem<TriggerSystem>();
|
m_SystemPipeline->AddSystem<RaptorCopterSystem>(updateOrderLevel);
|
||||||
|
m_SystemPipeline->AddSystem<PlayerSystem>(updateOrderLevel);
|
||||||
|
m_SystemPipeline->AddSystem<EditorSystem>(updateOrderLevel, m_Renderer);
|
||||||
|
m_SystemPipeline->AddSystem<HealthSystem>(updateOrderLevel);
|
||||||
|
|
||||||
|
//Collision and TriggerSystem should update after player.
|
||||||
|
++updateOrderLevel;
|
||||||
|
m_SystemPipeline->AddSystem<CollisionSystem>(updateOrderLevel);
|
||||||
|
m_SystemPipeline->AddSystem<TriggerSystem>(updateOrderLevel);
|
||||||
|
++updateOrderLevel;
|
||||||
|
m_SystemPipeline->AddSystem<RenderSystem>(updateOrderLevel, m_Renderer, m_RenderFrame);
|
||||||
|
|
||||||
// Invoke network
|
// Invoke network
|
||||||
if (m_Config->Get<bool>("Networking.StartNetwork", false)) {
|
if (m_Config->Get<bool>("Networking.StartNetwork", false)) {
|
||||||
@@ -64,17 +80,17 @@ Game::Game(int argc, char* argv[])
|
|||||||
networkFunction();
|
networkFunction();
|
||||||
}
|
}
|
||||||
m_LastTime = glfwGetTime();
|
m_LastTime = glfwGetTime();
|
||||||
|
|
||||||
debugInitialize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Game::~Game()
|
Game::~Game()
|
||||||
{
|
{
|
||||||
// Call before to ensure that thread closes correctly.
|
delete m_SystemPipeline;
|
||||||
//if (m_IsClientOrServer)
|
delete m_World;
|
||||||
// m_ClientOrServer.Close();
|
|
||||||
|
|
||||||
delete m_FrameStack;
|
delete m_FrameStack;
|
||||||
|
delete m_InputProxy;
|
||||||
|
delete m_InputManager;
|
||||||
|
delete m_RenderFrame;
|
||||||
|
delete m_Renderer;
|
||||||
delete m_EventBroker;
|
delete m_EventBroker;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,56 +116,18 @@ void Game::Tick()
|
|||||||
if (m_IsClientOrServer) {
|
if (m_IsClientOrServer) {
|
||||||
m_ClientOrServer->Update();
|
m_ClientOrServer->Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterate through systems and update world!
|
// Iterate through systems and update world!
|
||||||
m_SystemPipeline->Update(m_World, dt);
|
m_SystemPipeline->Update(m_World, dt);
|
||||||
debugTick(dt);
|
|
||||||
m_Renderer->Update(dt);
|
m_Renderer->Update(dt);
|
||||||
m_EventBroker->Process<Client>();
|
m_EventBroker->Process<Client>();
|
||||||
|
|
||||||
m_RenderQueueFactory->Update(m_World);
|
|
||||||
GLERROR("Game::Tick m_RenderQueueFactory->Update");
|
GLERROR("Game::Tick m_RenderQueueFactory->Update");
|
||||||
m_Renderer->Draw(m_RenderQueueFactory->RenderQueues());
|
m_Renderer->Draw(*m_RenderFrame);
|
||||||
GLERROR("Game::Tick m_Renderer->Draw");
|
GLERROR("Game::Tick m_Renderer->Draw");
|
||||||
m_EventBroker->Swap();
|
m_EventBroker->Swap();
|
||||||
m_EventBroker->Clear();
|
m_EventBroker->Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Game::debugOnInputCommand(const Events::InputCommand& e)
|
|
||||||
{
|
|
||||||
if (e.Command == "DebugReload" && e.Value == 1) {
|
|
||||||
std::string mapToLoad = m_Config->Get<std::string>("Debug.LoadMap", "");
|
|
||||||
if (!mapToLoad.empty()) {
|
|
||||||
delete m_World;
|
|
||||||
m_World = new World();
|
|
||||||
ResourceManager::Release("EntityXMLFile", mapToLoad);
|
|
||||||
ResourceManager::Load<EntityXMLFile>(mapToLoad)->PopulateWorld(m_World);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (e.Command == "SwitchToServer" && e.Value > 0) {
|
|
||||||
m_ClientOrServer->Close(); // memory leak for now, use delete when it works
|
|
||||||
//delete m_ClientOrServer;
|
|
||||||
m_ClientOrServer = new Server();
|
|
||||||
LOG_INFO("Switching to server");
|
|
||||||
m_ClientOrServer->Start(m_World, m_EventBroker);
|
|
||||||
}
|
|
||||||
else if (e.Command == "SwitchToClient" && e.Value > 0) {
|
|
||||||
m_ClientOrServer->Close(); // memory leak for now, use delete when it works
|
|
||||||
//delete m_ClientOrServer;
|
|
||||||
m_ClientOrServer = new Client(m_Config);
|
|
||||||
m_ClientOrServer->Start(m_World, m_EventBroker);
|
|
||||||
LOG_INFO("Switching to client");
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Game::debugInitialize()
|
|
||||||
{
|
|
||||||
EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &Game::debugOnInputCommand);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Game::debugTick(double dt)
|
void Game::debugTick(double dt)
|
||||||
{
|
{
|
||||||
m_EventBroker->Process<Game>();
|
m_EventBroker->Process<Game>();
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
#include "HealthSystem.h"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
HealthSystem::HealthSystem(EventBroker* eventBroker)
|
||||||
|
: PureSystem(eventBroker, "Health")
|
||||||
|
{
|
||||||
|
//subscribe/listenTo playerdamage,healthpickup events (using the eventBroker)
|
||||||
|
EVENT_SUBSCRIBE_MEMBER(m_EPlayerDamage, &HealthSystem::OnPlayerDamaged);
|
||||||
|
EVENT_SUBSCRIBE_MEMBER(m_EPlayerHealthPickup, &HealthSystem::OnPlayerHealthPickup);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HealthSystem::UpdateComponent(World *world, ComponentWrapper &health, double dt)
|
||||||
|
{
|
||||||
|
//if entityID of health is 9 then the players ID is also 9 (player,health are connected to the same entity)
|
||||||
|
ComponentWrapper player = world->GetComponent(health.EntityID, "Player");
|
||||||
|
double maxHealth = (double)health["MaxHealth"];
|
||||||
|
|
||||||
|
//process the DeltaHealthVector and change the entitys health accordingly
|
||||||
|
for (size_t i = m_DeltaHealthVector.size(); i > 0; i--)
|
||||||
|
{
|
||||||
|
auto deltaHP = m_DeltaHealthVector[i - 1];
|
||||||
|
//if we have a healthchange for the current player and health is greater than 0, then apply it
|
||||||
|
if (std::get<0>(deltaHP) == player.EntityID && (double)health["Health"] > 0.0f) {
|
||||||
|
//get the deltaHP value from the tuple and make sure you dont get more than maxHealth
|
||||||
|
double newHealth = std::min((double)health["Health"] + (double)std::get<1>(deltaHP), maxHealth);
|
||||||
|
health["Health"] = newHealth;
|
||||||
|
m_DeltaHealthVector.erase(m_DeltaHealthVector.begin() + i - 1);
|
||||||
|
//check if health is <= 0
|
||||||
|
if ((double)health["Health"] <= 0.0f) {
|
||||||
|
//publish death event
|
||||||
|
Events::PlayerDeath e;
|
||||||
|
e.PlayerID = player.EntityID;
|
||||||
|
m_EventBroker->Publish(e);
|
||||||
|
//clear the remaining hpDeltas for the dead player
|
||||||
|
for (size_t j = m_DeltaHealthVector.size(); j > 0; j--)
|
||||||
|
{
|
||||||
|
if (std::get<0>(m_DeltaHealthVector[j - 1]) == player.EntityID)
|
||||||
|
m_DeltaHealthVector.erase(m_DeltaHealthVector.begin() + j - 1);
|
||||||
|
}
|
||||||
|
//break the loop if the player is dead
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HealthSystem::OnPlayerDamaged(const Events::PlayerDamage& e)
|
||||||
|
{
|
||||||
|
//save the changed HP to a vector. it will be taken care of in UpdateComponent
|
||||||
|
m_DeltaHealthVector.push_back(std::make_tuple(e.PlayerDamagedID, -e.DamageAmount));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HealthSystem::OnPlayerHealthPickup(const Events::PlayerHealthPickup& e)
|
||||||
|
{
|
||||||
|
//save the changed HP to a vector. it will be taken care of in UpdateComponent
|
||||||
|
m_DeltaHealthVector.push_back(std::make_tuple(e.PlayerHealedID, e.HealthAmount));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
#include <boost/test/execution_monitor.hpp>
|
||||||
|
using boost::unit_test_framework::test_suite;
|
||||||
|
using boost::unit_test_framework::test_case;
|
||||||
|
#include <stdlib.h>//srand
|
||||||
|
|
||||||
|
//#define private public
|
||||||
|
#include "Engine\Core\ConfigFile.h"
|
||||||
|
|
||||||
|
#define _CRTDBG_MAP_ALLOC
|
||||||
|
#include <crtdbg.h>
|
||||||
|
#define DEBUG_CLIENTBLOCK new( _CLIENT_BLOCK, __FILE__, __LINE__)
|
||||||
|
#define new DEBUG_CLIENTBLOCK
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE(confTest)
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(configFileTest)
|
||||||
|
{
|
||||||
|
//note: this ConfigFileclass currently has memleaks!
|
||||||
|
|
||||||
|
ResourceManager::RegisterType<ConfigFile>("ConfigFile");
|
||||||
|
auto m_Config = ResourceManager::Load<ConfigFile>("ConfigTest.ini");
|
||||||
|
|
||||||
|
//bägge måste vara av samma typ, T typen är string
|
||||||
|
//http://www.boost.org/doc/libs/1_42_0/doc/html/boost_propertytree/tutorial.html
|
||||||
|
//"Note that we construct the path to the value by separating the individual keys with dots"
|
||||||
|
|
||||||
|
//get from tree tests
|
||||||
|
auto getSomething = m_Config->Get("Test.Test1", 0);
|
||||||
|
BOOST_CHECK(getSomething == 423);
|
||||||
|
|
||||||
|
auto getSomething2 = m_Config->Get("fsdfdsfd.T", std::string(""));
|
||||||
|
BOOST_CHECK(getSomething2 == "\"gfdjakflsdl!\"");
|
||||||
|
|
||||||
|
//set/get tests
|
||||||
|
m_Config->Set("Test.4321", 123);
|
||||||
|
auto getSomething3 = m_Config->Get("Test.4321", 0);
|
||||||
|
BOOST_CHECK(getSomething3 == 123);
|
||||||
|
|
||||||
|
m_Config->Set("3_2_1_0_5", "t454j54hj5k32");
|
||||||
|
auto getSomething4 = m_Config->Get("3_2_1_0_5", std::string(""));
|
||||||
|
BOOST_CHECK(getSomething4 == "t454j54hj5k32");
|
||||||
|
|
||||||
|
//***check so outputwindow says: EE: Failed to find "DefaultConfigTestNotExists.ini"! Relying on hardcoded default values!
|
||||||
|
auto m_Config2 = ResourceManager::Load<ConfigFile>("ConfigTestNotExists.ini");
|
||||||
|
|
||||||
|
//set value/savetodisk/load/checkvalue...
|
||||||
|
m_Config->SaveToDisk();
|
||||||
|
m_Config->Set("Test.4321", 145);
|
||||||
|
m_Config->SaveToDisk();
|
||||||
|
auto m_Config3 = ResourceManager::Load<ConfigFile>("ConfigTest.ini");
|
||||||
|
auto getSomething5 = m_Config->Get("Test.4321", 0);
|
||||||
|
BOOST_CHECK(getSomething5 == 145);
|
||||||
|
|
||||||
|
//***check so outputwindow says: EE: Failed to parse "DefaultConfigTestFailed.ini"
|
||||||
|
//***check so outputwindow says: EE: Failed to parse "ConfigTestFailed.ini":
|
||||||
|
auto m_Config4 = ResourceManager::Load<ConfigFile>("ConfigTestFailed.ini");
|
||||||
|
|
||||||
|
//reload,onchildreload unimplemented
|
||||||
|
|
||||||
|
//NOTE:still massive amount of memoryleaks from this method
|
||||||
|
_CrtDumpMemoryLeaks();
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
#ifndef EVENTFIXTURE_H
|
||||||
|
#define EVENTFIXTURE_H
|
||||||
|
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
#include "Core\EventBroker.h"
|
||||||
|
|
||||||
|
template <typename EventType>
|
||||||
|
struct EventFixture
|
||||||
|
{
|
||||||
|
EventFixture()
|
||||||
|
{
|
||||||
|
this->ventBroker = new EventBroker();
|
||||||
|
m_EEventType = decltype(m_EEventType)(std::bind(&EventFixture::OnEvent, this, std::placeholders::_1));
|
||||||
|
this->ventBroker->Subscribe(m_EEventType);
|
||||||
|
Run();
|
||||||
|
Check();
|
||||||
|
}
|
||||||
|
~EventFixture()
|
||||||
|
{
|
||||||
|
this->ventBroker->Unsubscribe(m_EEventType);
|
||||||
|
delete this->ventBroker;
|
||||||
|
}
|
||||||
|
|
||||||
|
EventBroker* ventBroker = nullptr;
|
||||||
|
EventRelay<EventFixture, EventType> m_EEventType;
|
||||||
|
bool m_EventRecieved = false;
|
||||||
|
EventType Before;
|
||||||
|
EventType After;
|
||||||
|
|
||||||
|
bool OnEvent(const EventType& event)
|
||||||
|
{
|
||||||
|
m_EventRecieved = true;
|
||||||
|
After = event;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Run()
|
||||||
|
{
|
||||||
|
// Publish the event
|
||||||
|
this->ventBroker->Publish(Before);
|
||||||
|
// Clear to swap buffers
|
||||||
|
this->ventBroker->Swap();
|
||||||
|
// Process the event
|
||||||
|
this->ventBroker->template Process<EventFixture>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Check()
|
||||||
|
{
|
||||||
|
BOOST_CHECK(m_EventRecieved);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
#include "EventFixture.h"
|
||||||
|
|
||||||
|
struct ETestEvent : public Event
|
||||||
|
{
|
||||||
|
int Int = 5;
|
||||||
|
float Float = 1.33333f;
|
||||||
|
double Double = 1.33333;
|
||||||
|
std::string String = "Hello World";
|
||||||
|
};
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(EventBrokerTest)
|
||||||
|
{
|
||||||
|
EventFixture<ETestEvent> f;
|
||||||
|
BOOST_CHECK(f.Before.Int == f.After.Int);
|
||||||
|
BOOST_CHECK_CLOSE(f.Before.Float, f.After.Float, 0.00001f);
|
||||||
|
BOOST_CHECK_CLOSE(f.Before.Double, f.After.Double, 0.00001f);
|
||||||
|
BOOST_CHECK(f.Before.String == f.After.String);
|
||||||
|
}
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
using boost::unit_test_framework::test_suite;
|
||||||
|
using boost::unit_test_framework::test_case;
|
||||||
|
|
||||||
|
#include "HealthSystemTest.h"
|
||||||
|
#include "Game/HealthSystem.h"
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE(HealthSystemSuite)
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(HealthSystemTest)
|
||||||
|
{
|
||||||
|
//this tests 2 healthevents and the healthsystem
|
||||||
|
GameHealthSystemTest game;
|
||||||
|
//100 loops will be more than enough to do the test
|
||||||
|
int loops = 100;
|
||||||
|
bool success = false;
|
||||||
|
while (loops > 0) {
|
||||||
|
game.Tick();
|
||||||
|
if (game.TestSucceeded) {
|
||||||
|
success = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
loops--;
|
||||||
|
}
|
||||||
|
//The system will process the events, hence it will take a while before we can read anything
|
||||||
|
BOOST_TEST(success);
|
||||||
|
}
|
||||||
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
||||||
|
GameHealthSystemTest::GameHealthSystemTest()
|
||||||
|
{
|
||||||
|
ResourceManager::RegisterType<ConfigFile>("ConfigFile");
|
||||||
|
ResourceManager::RegisterType<EntityXMLFile>("EntityXMLFile");
|
||||||
|
|
||||||
|
m_Config = ResourceManager::Load<ConfigFile>("Config.ini");
|
||||||
|
LOG_LEVEL = static_cast<_LOG_LEVEL>(m_Config->Get<int>("Debug.LogLevel", 1));
|
||||||
|
|
||||||
|
// Create the core event broker
|
||||||
|
m_EventBroker = new EventBroker();
|
||||||
|
|
||||||
|
// Create a world
|
||||||
|
m_World = new World();
|
||||||
|
std::string mapToLoad = m_Config->Get<std::string>("Debug.LoadMap", "");
|
||||||
|
if (!mapToLoad.empty()) {
|
||||||
|
ResourceManager::Load<EntityXMLFile>(mapToLoad)->PopulateWorld(m_World);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create system pipeline
|
||||||
|
m_SystemPipeline = new SystemPipeline(m_EventBroker);
|
||||||
|
m_SystemPipeline->AddSystem<PlayerSystem>(0);
|
||||||
|
m_SystemPipeline->AddSystem<HealthSystem>(0);
|
||||||
|
|
||||||
|
//The Test
|
||||||
|
//create entity which has transorm,player,model,health in it. i.e. is a player
|
||||||
|
EntityID playerID = m_World->CreateEntity();
|
||||||
|
ComponentWrapper transform = m_World->AttachComponent(playerID, "Transform");
|
||||||
|
ComponentWrapper model = m_World->AttachComponent(playerID, "Model");
|
||||||
|
model["Resource"] = "Models/Core/UnitSphere.obj";
|
||||||
|
ComponentWrapper player = m_World->AttachComponent(playerID, "Player");
|
||||||
|
ComponentWrapper health = m_World->AttachComponent(playerID, "Health");
|
||||||
|
healthsID = playerID;
|
||||||
|
double currentHealth = (double)m_World->GetComponent(healthsID, "Health")["Health"];
|
||||||
|
|
||||||
|
//heal player with 40
|
||||||
|
Events::PlayerHealthPickup e3;
|
||||||
|
e3.HealthAmount = 40.0f;
|
||||||
|
e3.PlayerHealedID = healthsID;
|
||||||
|
m_EventBroker->Publish(e3);
|
||||||
|
//damage player with 50
|
||||||
|
Events::PlayerDamage e;
|
||||||
|
e.DamageAmount = 50.0f;
|
||||||
|
e.PlayerDamagedID = healthsID;
|
||||||
|
m_EventBroker->Publish(e);
|
||||||
|
//heal some other player with 40
|
||||||
|
Events::PlayerHealthPickup e2;
|
||||||
|
e2.HealthAmount = 40.0f;
|
||||||
|
e2.PlayerHealedID = healthsID+1;
|
||||||
|
m_EventBroker->Publish(e2);
|
||||||
|
|
||||||
|
EntityID playerID2 = m_World->CreateEntity();
|
||||||
|
ComponentWrapper transform2 = m_World->AttachComponent(playerID2, "Transform");
|
||||||
|
ComponentWrapper model2 = m_World->AttachComponent(playerID2, "Model");
|
||||||
|
model2["Resource"] = "Models/Core/UnitSphere.obj";
|
||||||
|
ComponentWrapper player2 = m_World->AttachComponent(playerID2, "Player");
|
||||||
|
ComponentWrapper health2 = m_World->AttachComponent(playerID2, "Health");
|
||||||
|
//END TEST
|
||||||
|
}
|
||||||
|
|
||||||
|
GameHealthSystemTest::~GameHealthSystemTest()
|
||||||
|
{
|
||||||
|
delete m_SystemPipeline;
|
||||||
|
delete m_World;
|
||||||
|
delete m_EventBroker;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameHealthSystemTest::Tick()
|
||||||
|
{
|
||||||
|
glfwPollEvents();
|
||||||
|
|
||||||
|
double currentTime = glfwGetTime();
|
||||||
|
double dt = currentTime - m_LastTime;
|
||||||
|
m_LastTime = currentTime;
|
||||||
|
|
||||||
|
// Iterate through systems and update world!
|
||||||
|
m_SystemPipeline->Update(m_World, dt);
|
||||||
|
|
||||||
|
m_EventBroker->Swap();
|
||||||
|
m_EventBroker->Clear();
|
||||||
|
|
||||||
|
//if health reaches 90 then we know the test has succeeded (start with 100hp, remove 50hp, add 40hp)
|
||||||
|
double currentHealth = (double)m_World->GetComponent(healthsID, "Health")["Health"];
|
||||||
|
if (currentHealth==90)
|
||||||
|
TestSucceeded = true;
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
#ifndef HealthTest_h__
|
||||||
|
#define HealthTest_h__
|
||||||
|
|
||||||
|
#include "Core/ResourceManager.h"
|
||||||
|
#include "Core/ConfigFile.h"
|
||||||
|
#include "Core/EventBroker.h"
|
||||||
|
#include "Rendering/Renderer.h"
|
||||||
|
#include "Core/InputManager.h"
|
||||||
|
#include "GUI/Frame.h"
|
||||||
|
#include "Core/World.h"
|
||||||
|
#include "Rendering/RenderQueueFactory.h"
|
||||||
|
#include "Input/InputProxy.h"
|
||||||
|
#include "Input/KeyboardInputHandler.h"
|
||||||
|
#include "Input/MouseInputHandler.h"
|
||||||
|
#include "Core/EKeyDown.h"
|
||||||
|
#include "Core/EntityXMLFile.h"
|
||||||
|
#include "Core/SystemPipeline.h"
|
||||||
|
#include "RaptorCopterSystem.h"
|
||||||
|
#include "PlayerSystem.h"
|
||||||
|
#include "Editor/EditorSystem.h"
|
||||||
|
|
||||||
|
class GameHealthSystemTest
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GameHealthSystemTest();
|
||||||
|
~GameHealthSystemTest();
|
||||||
|
|
||||||
|
void Tick();
|
||||||
|
bool TestSucceeded = false;
|
||||||
|
|
||||||
|
private:
|
||||||
|
double m_LastTime;
|
||||||
|
ConfigFile* m_Config = nullptr;
|
||||||
|
EventBroker* m_EventBroker;
|
||||||
|
World* m_World;
|
||||||
|
SystemPipeline* m_SystemPipeline;
|
||||||
|
int healthsID;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
|
#include "Engine\Core\InputManager.h"
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE(inputManagerTests)
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(inputManagerTest)
|
||||||
|
{
|
||||||
|
//already tested eventbroker so inputManager is indirectly already tested
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
@@ -34,16 +34,12 @@ BOOST_AUTO_TEST_CASE(octTreeTest)
|
|||||||
BOOST_CHECK(someAABB.MaxCorner() == maxCorner);
|
BOOST_CHECK(someAABB.MaxCorner() == maxCorner);
|
||||||
BOOST_CHECK(someAABB.Center() == 0.5f * (minCorner + maxCorner));
|
BOOST_CHECK(someAABB.Center() == 0.5f * (minCorner + maxCorner));
|
||||||
|
|
||||||
//simple OctTree constructor check
|
|
||||||
//OctTree someOctTree(someAABB, 5);
|
|
||||||
//BOOST_CHECK(someOctTree.m_Children[0] != nullptr);
|
|
||||||
|
|
||||||
//simple destructor check in the end, just look for memleaks, then it didnt clear the AABB structure
|
//simple destructor check in the end, just look for memleaks, then it didnt clear the AABB structure
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(octTreeTest2)
|
BOOST_AUTO_TEST_CASE(octTreeTest2)
|
||||||
{
|
{
|
||||||
//octtree ritningen osv
|
//octtree draw etc
|
||||||
Game game(0, nullptr);
|
Game game(0, nullptr);
|
||||||
while (game.Running()) {
|
while (game.Running()) {
|
||||||
game.Tick();
|
game.Tick();
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ Game::Game(int argc, char* argv[]) : someOctTree(AABB(-0.5f*worldSize, 0.5f*worl
|
|||||||
ResourceManager::RegisterType<ConfigFile>("ConfigFile");
|
ResourceManager::RegisterType<ConfigFile>("ConfigFile");
|
||||||
ResourceManager::RegisterType<Model>("Model");
|
ResourceManager::RegisterType<Model>("Model");
|
||||||
ResourceManager::RegisterType<Texture>("Texture");
|
ResourceManager::RegisterType<Texture>("Texture");
|
||||||
|
ResourceManager::RegisterType<EntityXMLFile>("EntityXMLFile");
|
||||||
|
ResourceManager::RegisterType<ShaderProgram>("ShaderProgram");
|
||||||
|
|
||||||
m_Config = ResourceManager::Load<ConfigFile>("Config.ini");
|
m_Config = ResourceManager::Load<ConfigFile>("Config.ini");
|
||||||
LOG_LEVEL = static_cast<_LOG_LEVEL>(m_Config->Get<int>("Debug.LogLevel", 1));
|
LOG_LEVEL = static_cast<_LOG_LEVEL>(m_Config->Get<int>("Debug.LogLevel", 1));
|
||||||
@@ -25,9 +27,14 @@ Game::Game(int argc, char* argv[]) : someOctTree(AABB(-0.5f*worldSize, 0.5f*worl
|
|||||||
m_Config->Get<int>("Video.Height", 720)
|
m_Config->Get<int>("Video.Height", 720)
|
||||||
));
|
));
|
||||||
m_Renderer->Initialize();
|
m_Renderer->Initialize();
|
||||||
|
m_Renderer->Camera()->SetFOV(glm::radians(m_Config->Get<float>("Video.FOV", 90.f)));
|
||||||
|
|
||||||
// Create input manager
|
// Create input manager
|
||||||
m_InputManager = new InputManager(m_Renderer->Window(), m_EventBroker);
|
m_InputManager = new InputManager(m_Renderer->Window(), m_EventBroker);
|
||||||
|
m_InputProxy = new InputProxy(m_EventBroker);
|
||||||
|
m_InputProxy->AddHandler<KeyboardInputHandler>();
|
||||||
|
m_InputProxy->AddHandler<MouseInputHandler>();
|
||||||
|
m_InputProxy->LoadBindings("Input.ini");
|
||||||
|
|
||||||
// Create the root level GUI frame
|
// Create the root level GUI frame
|
||||||
m_FrameStack = new GUI::Frame(m_EventBroker);
|
m_FrameStack = new GUI::Frame(m_EventBroker);
|
||||||
@@ -37,6 +44,9 @@ Game::Game(int argc, char* argv[]) : someOctTree(AABB(-0.5f*worldSize, 0.5f*worl
|
|||||||
// Create a TEST WORLD
|
// Create a TEST WORLD
|
||||||
m_World = new HardcodedTestWorld();
|
m_World = new HardcodedTestWorld();
|
||||||
|
|
||||||
|
m_SystemPipeline = new SystemPipeline(m_EventBroker);
|
||||||
|
m_SystemPipeline->AddSystem<PlayerSystem>(0);
|
||||||
|
|
||||||
m_LastTime = glfwGetTime();
|
m_LastTime = glfwGetTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,9 +62,14 @@ void Game::Tick()
|
|||||||
double dt = currentTime - m_LastTime;
|
double dt = currentTime - m_LastTime;
|
||||||
m_LastTime = currentTime;
|
m_LastTime = currentTime;
|
||||||
|
|
||||||
|
// Handle input in a weird looking but responsive way
|
||||||
|
m_EventBroker->Process<InputManager>();
|
||||||
m_EventBroker->Swap();
|
m_EventBroker->Swap();
|
||||||
m_InputManager->Update(dt);
|
m_InputManager->Update(dt);
|
||||||
m_Renderer->Update(dt);
|
m_EventBroker->Swap();
|
||||||
|
m_InputProxy->Update(dt);
|
||||||
|
m_EventBroker->Swap();
|
||||||
|
m_InputProxy->Process();
|
||||||
m_EventBroker->Swap();
|
m_EventBroker->Swap();
|
||||||
|
|
||||||
#define TEST1
|
#define TEST1
|
||||||
@@ -70,7 +85,7 @@ void Game::Tick()
|
|||||||
AABB boxi;
|
AABB boxi;
|
||||||
boxi.CreateFromCenter(pos, maxPos - minPos);
|
boxi.CreateFromCenter(pos, maxPos - minPos);
|
||||||
frameCounter++;
|
frameCounter++;
|
||||||
if (frameCounter > 50) {
|
if (frameCounter > 1) {
|
||||||
m_World->someOctTree.ClearDynamicObjects();
|
m_World->someOctTree.ClearDynamicObjects();
|
||||||
m_World->someOctTree.AddDynamicObject(boxi);
|
m_World->someOctTree.AddDynamicObject(boxi);
|
||||||
frameCounter = 0;
|
frameCounter = 0;
|
||||||
@@ -149,8 +164,8 @@ void Game::Tick()
|
|||||||
if (someOctTree.BoxCollides(redBox, AABB())) {
|
if (someOctTree.BoxCollides(redBox, AABB())) {
|
||||||
//this checks AABB vs AABB
|
//this checks AABB vs AABB
|
||||||
//if (Collision::AABBVsAABB(redBox, aabb)) {
|
//if (Collision::AABBVsAABB(redBox, aabb)) {
|
||||||
m_Renderer->Camera()->SetPosition(m_PrevPos);
|
//m_Renderer->Camera()->SetPosition(m_PrevPos);
|
||||||
m_Renderer->Camera()->SetOrientation(m_PrevOri);
|
//m_Renderer->Camera()->SetOrientation(m_PrevOri);
|
||||||
model["Color"] = greenCol;
|
model["Color"] = greenCol;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -163,8 +178,14 @@ void Game::Tick()
|
|||||||
m_RenderQueueFactory->Update(m_World);
|
m_RenderQueueFactory->Update(m_World);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_Renderer->Draw(m_RenderQueueFactory->RenderQueues());
|
// Iterate through systems and update world!
|
||||||
|
m_SystemPipeline->Update(m_World, dt);
|
||||||
|
m_Renderer->Update(dt);
|
||||||
|
|
||||||
|
m_RenderQueueFactory->Update(m_World);
|
||||||
|
GLERROR("Game::Tick m_RenderQueueFactory->Update");
|
||||||
|
m_Renderer->Draw(m_RenderQueueFactory->RenderQueues());
|
||||||
|
GLERROR("Game::Tick m_Renderer->Draw");
|
||||||
m_EventBroker->Swap();
|
m_EventBroker->Swap();
|
||||||
m_EventBroker->Clear();
|
m_EventBroker->Clear();
|
||||||
|
|
||||||
|
|||||||
@@ -9,11 +9,19 @@
|
|||||||
#include "GUI/Frame.h"
|
#include "GUI/Frame.h"
|
||||||
#include "Core/World.h"
|
#include "Core/World.h"
|
||||||
#include "Rendering/RenderQueueFactory.h"
|
#include "Rendering/RenderQueueFactory.h"
|
||||||
|
#include "Input/InputProxy.h"
|
||||||
|
#include "Input/KeyboardInputHandler.h"
|
||||||
|
#include "Input/MouseInputHandler.h"
|
||||||
|
#include "Core/EKeyDown.h"
|
||||||
|
#include "Core/EntityXMLFile.h"
|
||||||
|
#include "Core/SystemPipeline.h"
|
||||||
|
#include "RaptorCopterSystem.h"
|
||||||
|
#include "PlayerSystem.h"
|
||||||
|
#include "Editor/EditorSystem.h"
|
||||||
|
|
||||||
#include "OctTreeTestHardCodedTestWorld.h"
|
#include "OctTreeTestHardCodedTestWorld.h"
|
||||||
#include "Collision/Collision.h"
|
#include "Collision/Collision.h"
|
||||||
|
|
||||||
|
|
||||||
class Game
|
class Game
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -32,6 +40,8 @@ private:
|
|||||||
GUI::Frame* m_FrameStack;
|
GUI::Frame* m_FrameStack;
|
||||||
HardcodedTestWorld* m_World;
|
HardcodedTestWorld* m_World;
|
||||||
RenderQueueFactory* m_RenderQueueFactory;
|
RenderQueueFactory* m_RenderQueueFactory;
|
||||||
|
InputProxy* m_InputProxy;
|
||||||
|
SystemPipeline* m_SystemPipeline;
|
||||||
|
|
||||||
//Test1
|
//Test1
|
||||||
int frameCounter = 0;
|
int frameCounter = 0;
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
#include "Core/World.h"
|
||||||
|
|
||||||
|
//private->public hack doesnt work, tons of link errors
|
||||||
|
//so there is currently no good way to test this class
|
||||||
|
//#define private public
|
||||||
|
#include "Core/ResourceManager.h"
|
||||||
|
#include "Core/ConfigFile.h"
|
||||||
|
#include "Rendering/Renderer.h"
|
||||||
|
#include "Engine\Rendering\Texture.h"
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE(resourceManagerTests)
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(resourceManagerTest)
|
||||||
|
{
|
||||||
|
World m_World;
|
||||||
|
|
||||||
|
//private static metoder/variabler
|
||||||
|
|
||||||
|
ResourceManager::RegisterType<ConfigFile>("ConfigFile");
|
||||||
|
BOOST_CHECK(!ResourceManager::IsResourceLoaded("ConfigFile", "Config.ini"));
|
||||||
|
auto m_Config = ResourceManager::Load<ConfigFile>("Config.ini");
|
||||||
|
BOOST_CHECK(ResourceManager::IsResourceLoaded("ConfigFile", "Config.ini"));
|
||||||
|
ResourceManager::Release("ConfigFile", "Config.ini");
|
||||||
|
BOOST_CHECK(!ResourceManager::IsResourceLoaded("ConfigFile", "Config.ini"));
|
||||||
|
|
||||||
|
//configfile without register
|
||||||
|
//check so output says "EE failed to load: type not registered..."
|
||||||
|
auto m_ScreenQuadNoRegister = ResourceManager::Load<Model>("Models/Core/ScreenQuad.obj");
|
||||||
|
BOOST_CHECK(!ResourceManager::IsResourceLoaded("Model", "Models/Core/ScreenQuad.obj"));
|
||||||
|
|
||||||
|
//there is no error feedback to check if you try to release the wrong resources - hence that cant be tested either
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
Reference in New Issue
Block a user