Merge branch 'OctTree' of github.com:teamfisk/TacticalZ into OctTree
# Conflicts: # include/Engine/Core/OctTree.h # src/Engine/Core/OctTree.cpp
This commit is contained in:
+1
-1
Submodule assets updated: 4bd902b697...b37468222e
@@ -1,13 +1,13 @@
|
|||||||
# XERCES_FOUND
|
# Xerces_FOUND
|
||||||
# XERCES_INCLUDE_DIRS
|
# Xerces_INCLUDE_DIRS
|
||||||
# XERCES_LIBRARIES
|
# Xerces_LIBRARIES
|
||||||
|
|
||||||
find_path(XERCES_INCLUDE_DIR xercesc/dom/dom.hpp
|
find_path(Xerces_INCLUDE_DIR xercesc/dom/dom.hpp
|
||||||
/usr/local/include
|
/usr/local/include
|
||||||
/usr/include
|
/usr/include
|
||||||
)
|
)
|
||||||
|
|
||||||
find_library(XERCES_LIBRARY
|
find_library(Xerces_LIBRARY
|
||||||
NAMES
|
NAMES
|
||||||
xerces-c_3
|
xerces-c_3
|
||||||
xerces-c_3D
|
xerces-c_3D
|
||||||
@@ -16,8 +16,8 @@ find_library(XERCES_LIBRARY
|
|||||||
/usr/lib
|
/usr/lib
|
||||||
)
|
)
|
||||||
|
|
||||||
set(XERCES_INCLUDE_DIRS ${XERCES_INCLUDE_DIR})
|
set(Xerces_INCLUDE_DIRS ${Xerces_INCLUDE_DIR})
|
||||||
set(XERCES_LIBRARIES ${XERCES_LIBRARY})
|
set(Xerces_LIBRARIES ${Xerces_LIBRARY})
|
||||||
|
|
||||||
find_package_handle_standard_args(Xerces DEFAULT_MSG XERCES_LIBRARY XERCES_INCLUDE_DIR)
|
find_package_handle_standard_args(Xerces DEFAULT_MSG Xerces_LIBRARY Xerces_INCLUDE_DIR)
|
||||||
mark_as_advanced(Xerces_FOUND XERCES_INCLUDE_DIR XERCES_LIBRARY)
|
mark_as_advanced(Xerces_FOUND Xerces_INCLUDE_DIR Xerces_LIBRARY)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
#define ComponentWrapper_h__
|
#define ComponentWrapper_h__
|
||||||
|
|
||||||
#include "../Common.h"
|
#include "../Common.h"
|
||||||
#include "EntityWrapper.h"
|
#include "Entity.h"
|
||||||
#include "ComponentInfo.h"
|
#include "ComponentInfo.h"
|
||||||
#include "Util/Any.h"
|
#include "Util/Any.h"
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ struct ComponentWrapper
|
|||||||
ComponentWrapper(const ComponentInfo& componentInfo, char* data)
|
ComponentWrapper(const ComponentInfo& componentInfo, char* data)
|
||||||
: Info(componentInfo)
|
: Info(componentInfo)
|
||||||
, EntityID(*reinterpret_cast<::EntityID*>(data))
|
, EntityID(*reinterpret_cast<::EntityID*>(data))
|
||||||
, Data(data + sizeof(EntityID))
|
, Data(data + sizeof(::EntityID))
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
const ComponentInfo& Info;
|
const ComponentInfo& Info;
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#ifndef Entity_h__
|
||||||
|
#define Entity_h__
|
||||||
|
|
||||||
|
typedef unsigned int EntityID;
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
#include "ResourceManager.h"
|
|
||||||
|
|
||||||
class EntityFile : public Resource
|
|
||||||
{
|
|
||||||
friend class ResourceManager;
|
|
||||||
|
|
||||||
private:
|
|
||||||
EntityFile(std::string path);
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
};
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
#ifndef Entity_h__
|
|
||||||
#define Entity_h__
|
|
||||||
|
|
||||||
typedef unsigned int EntityID;
|
|
||||||
|
|
||||||
struct EntityWrapper
|
|
||||||
{
|
|
||||||
EntityWrapper(EntityID entityID)
|
|
||||||
: ID(entityID)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
EntityID ID;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
#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,7 +13,8 @@ public:
|
|||||||
struct Output
|
struct Output
|
||||||
{
|
{
|
||||||
float CollideDistance;
|
float CollideDistance;
|
||||||
};
|
};
|
||||||
|
|
||||||
OctTree();
|
OctTree();
|
||||||
~OctTree();
|
~OctTree();
|
||||||
//For the root OctTree, [octTreeBounds] should be a box containing the entire level.
|
//For the root OctTree, [octTreeBounds] should be a box containing the entire level.
|
||||||
@@ -24,43 +25,84 @@ public:
|
|||||||
OctTree(const OctTree& other) = delete;
|
OctTree(const OctTree& other) = delete;
|
||||||
OctTree(const OctTree&& other) = delete;
|
OctTree(const OctTree&& other) = delete;
|
||||||
OctTree& operator= (const OctTree& other) = delete;
|
OctTree& operator= (const OctTree& other) = delete;
|
||||||
|
//Add a dynamic object (one that moves around) into the tree.
|
||||||
|
void AddDynamicObject(const AABB& box);
|
||||||
|
//Add a static object (that does not move) into the tree.
|
||||||
|
void AddStaticObject(const AABB& box);
|
||||||
|
//Get the boxes that are in the same area as the input [box], the boxes are put in [outBoxes].
|
||||||
|
void BoxesInSameRegion(const AABB& box, std::vector<AABB>& outBoxes);
|
||||||
|
//Empty the tree of all objects, static and dynamic.
|
||||||
|
void ClearObjects();
|
||||||
|
//Empty the tree of all dynamic objects. Static objects remain in the tree.
|
||||||
|
void ClearDynamicObjects();
|
||||||
|
|
||||||
//Collision test function. WTODO: Probably remove or relocate elsewhere, Collision system?
|
//Collision test function. WTODO: Probably remove or relocate elsewhere, Collision system?
|
||||||
void Update(float dt, World* world, Camera* cam);
|
void Update(float dt, World* world, Camera* cam);
|
||||||
|
|
||||||
void AddDynamicObject(const AABB& box);
|
|
||||||
void AddStaticObject(const AABB& box);
|
|
||||||
|
|
||||||
void BoxesInSameRegion(const AABB& box, std::vector<AABB>& outBoxes) const;
|
|
||||||
|
|
||||||
void ClearObjects();
|
|
||||||
void ClearDynamicObjects();
|
|
||||||
|
|
||||||
//Returns true if the ray collides with something in the tree. Result is written to [data].
|
//Returns true if the ray collides with something in the tree. Result is written to [data].
|
||||||
bool RayCollides(const Ray& ray, Output& data) const;
|
bool RayCollides(const Ray& ray, Output& data);
|
||||||
//Returns true if the box collides with something in the tree.
|
//Returns true if the box collides with something in the tree.
|
||||||
//On collision with a box, that box is written to [outBoxIntersected].
|
//On collision with a box, that box is written to [outBoxIntersected].
|
||||||
bool BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const;
|
//Note: More efficient than calling BoxesInSameRegion from outside and testing there.
|
||||||
|
bool BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
OctTree* m_Children[8];
|
struct OctChild; //Fwd declaration;
|
||||||
//WTODO: Do -derived class from AABB- struct containing AABB, with a bool Tested, falsify at
|
struct ContainedObject
|
||||||
//start of Collision test, set on check, don't check if set already. Solves duplicate boxes in tree.
|
{
|
||||||
//Store indices in the struct, pointing to grand ancestor list of boxes, need the same AABB not copies to save Tested.
|
ContainedObject()
|
||||||
//WTODO: Boxes collide with themselves? Fix somehow, maybe float epsilon stuff.
|
: Box(AABB())
|
||||||
std::vector<AABB> m_StaticObjects;
|
, Checked(false)
|
||||||
std::vector<AABB> m_DynamicObjects;
|
{}
|
||||||
AABB m_Box;
|
ContainedObject(AABB box)
|
||||||
|
: Box(box)
|
||||||
|
, Checked(false)
|
||||||
|
{}
|
||||||
|
AABB Box;
|
||||||
|
bool Checked;
|
||||||
|
};
|
||||||
|
OctChild* m_Root;
|
||||||
|
std::vector<ContainedObject> m_StaticObjects;
|
||||||
|
std::vector<ContainedObject> m_DynamicObjects;
|
||||||
|
|
||||||
bool m_UpdatedOnce;
|
bool m_UpdatedOnce;
|
||||||
unsigned int m_BoxID;
|
unsigned int m_BoxID;
|
||||||
glm::vec3 m_PrevPos;
|
glm::vec3 m_PrevPos;
|
||||||
glm::quat m_PrevOri;
|
glm::quat m_PrevOri;
|
||||||
|
|
||||||
inline bool hasChildren() const;
|
void falsifyObjectChecks();
|
||||||
public:
|
|
||||||
int childIndexContainingPoint(const glm::vec3& point) const;
|
struct OctChild
|
||||||
std::vector<int> childIndicesContainingBox(const AABB& box) const;
|
{
|
||||||
|
~OctChild();
|
||||||
|
OctChild(const AABB& octTreeBounds,
|
||||||
|
int subDivisions,
|
||||||
|
std::vector<OctTree::ContainedObject>& staticObjects,
|
||||||
|
std::vector<OctTree::ContainedObject>& dynamicObjects);
|
||||||
|
OctChild(const OctChild& other) = delete;
|
||||||
|
OctChild(const OctChild&& other) = delete;
|
||||||
|
OctChild& operator= (const OctChild& other) = delete;
|
||||||
|
void AddDynamicObject(const AABB& box);
|
||||||
|
void AddStaticObject(const AABB& box);
|
||||||
|
void BoxesInSameRegion(const AABB& box, std::vector<AABB>& outBoxes) const;
|
||||||
|
void ClearObjects();
|
||||||
|
void ClearDynamicObjects();
|
||||||
|
bool RayCollides(const Ray& ray, Output& data) const;
|
||||||
|
bool BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const;
|
||||||
|
|
||||||
|
OctChild* m_Children[8];
|
||||||
|
//Indices into the lists in OctTree.
|
||||||
|
std::vector<int> m_StaticObjIndices;
|
||||||
|
std::vector<int> m_DynamicObjIndices;
|
||||||
|
AABB m_Box;
|
||||||
|
//Reference to the lists in OctTree.
|
||||||
|
std::vector<OctTree::ContainedObject>& m_StaticObjectsRef;
|
||||||
|
std::vector<OctTree::ContainedObject>& m_DynamicObjectsRef;
|
||||||
|
|
||||||
|
inline bool hasChildren() const;
|
||||||
|
int childIndexContainingPoint(const glm::vec3& point) const;
|
||||||
|
std::vector<int> childIndicesContainingBox(const AABB& box) const;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -81,6 +81,8 @@ public:
|
|||||||
@param resourceName Fully qualified name of the resource to reload.
|
@param resourceName Fully qualified name of the resource to reload.
|
||||||
*/
|
*/
|
||||||
static void Reload(std::string resourceName);
|
static void Reload(std::string resourceName);
|
||||||
|
|
||||||
|
static void Release(std::string resourceType, std::string resourceName);
|
||||||
|
|
||||||
static void Update();
|
static void Update();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#ifndef System_h__
|
||||||
|
#define System_h__
|
||||||
|
|
||||||
|
#include "EventBroker.h"
|
||||||
|
#include "World.h"
|
||||||
|
#include "ComponentWrapper.h"
|
||||||
|
|
||||||
|
class System
|
||||||
|
{
|
||||||
|
friend class SystemPipeline;
|
||||||
|
|
||||||
|
public:
|
||||||
|
System(const EventBroker* eventBroker, std::string componentType)
|
||||||
|
: m_EventBroker(eventBroker)
|
||||||
|
, m_ComponentType(componentType)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
virtual void Update(World* world, ComponentWrapper& component, double dt) = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const EventBroker* m_EventBroker;
|
||||||
|
std::string m_ComponentType;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
#ifndef SystemPipeline_h__
|
||||||
|
#define SystemPipeline_h__
|
||||||
|
|
||||||
|
#include "../Common.h"
|
||||||
|
#include "EventBroker.h"
|
||||||
|
#include "System.h"
|
||||||
|
#include "World.h"
|
||||||
|
|
||||||
|
class SystemPipeline
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SystemPipeline(const EventBroker* eventBroker)
|
||||||
|
: m_EventBroker(eventBroker)
|
||||||
|
{ }
|
||||||
|
~SystemPipeline()
|
||||||
|
{
|
||||||
|
for (auto& pair : m_Systems) {
|
||||||
|
for (auto& system : pair.second) {
|
||||||
|
delete system;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename... Arguments>
|
||||||
|
void AddSystem(Arguments... args)
|
||||||
|
{
|
||||||
|
System* system = new T(m_EventBroker, args...);
|
||||||
|
if (!system->m_ComponentType.empty()) {
|
||||||
|
m_Systems[system->m_ComponentType].push_back(system);
|
||||||
|
} else {
|
||||||
|
LOG_ERROR("Failed to add system \"%s\": Missing component type!", typeid(T).name());
|
||||||
|
delete system;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Update(World* world, double dt)
|
||||||
|
{
|
||||||
|
for (auto& pair : m_Systems) {
|
||||||
|
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->Update(world, component, dt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const EventBroker* m_EventBroker;
|
||||||
|
std::unordered_map<std::string, std::vector<System*>> m_Systems;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
#define World_h__
|
#define World_h__
|
||||||
|
|
||||||
#include "../Common.h"
|
#include "../Common.h"
|
||||||
#include "EntityWrapper.h"
|
#include "Entity.h"
|
||||||
#include "ObjectPool.h"
|
#include "ObjectPool.h"
|
||||||
#include "ComponentPool.h"
|
#include "ComponentPool.h"
|
||||||
|
|
||||||
@@ -12,6 +12,7 @@ public:
|
|||||||
World() = default;
|
World() = default;
|
||||||
~World();
|
~World();
|
||||||
|
|
||||||
|
// Create empty entity
|
||||||
EntityID CreateEntity(EntityID parent = 0);
|
EntityID CreateEntity(EntityID parent = 0);
|
||||||
|
|
||||||
// Register a component type and allocate space for it
|
// Register a component type and allocate space for it
|
||||||
@@ -21,10 +22,12 @@ public:
|
|||||||
// 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);
|
||||||
// Get all components of the specified type
|
// Get all components of the specified type
|
||||||
const ComponentPool& GetComponents(std::string componentType);
|
const ComponentPool* GetComponents(std::string componentType);
|
||||||
|
// Get entity parent
|
||||||
|
EntityID GetParent(EntityID entity);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EntityID m_CurrentEntityID = 0;
|
EntityID m_CurrentEntityID = 1;
|
||||||
|
|
||||||
std::unordered_map<EntityID, EntityID> m_EntityParents;
|
std::unordered_map<EntityID, EntityID> m_EntityParents;
|
||||||
std::unordered_multimap<EntityID, EntityID> m_EntityChildren;
|
std::unordered_multimap<EntityID, EntityID> m_EntityChildren;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
#include "../Common.h"
|
#include "../Common.h"
|
||||||
#include "../GLM.h"
|
#include "../GLM.h"
|
||||||
#include "../Core/Util/Rectangle.h"
|
#include "../Core/Util/Rectangle.h"
|
||||||
#include "../Core/EntityWrapper.h"
|
#include "../Core/Entity.h"
|
||||||
|
|
||||||
class Model;
|
class Model;
|
||||||
class Skeleton;
|
class Skeleton;
|
||||||
|
|||||||
@@ -22,7 +22,10 @@ private:
|
|||||||
void FillLights(World* world, RenderQueue* renderQueue);
|
void FillLights(World* world, RenderQueue* renderQueue);
|
||||||
|
|
||||||
glm::mat4 ModelMatrix(World* world, EntityID entity);
|
glm::mat4 ModelMatrix(World* world, EntityID entity);
|
||||||
glm::vec3 GetAbsolutePosition(World* world, ComponentWrapper transformComponent);
|
|
||||||
|
glm::vec3 AbsolutePosition(World* world, EntityID entity);
|
||||||
|
glm::quat AbsoluteOrientation(World* world, EntityID entity);
|
||||||
|
glm::vec3 AbsoluteScale(World* world, EntityID entity);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
+11
-3
@@ -9,8 +9,10 @@
|
|||||||
#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 "Core/EKeyDown.h"
|
||||||
class OctTree;
|
#include "Core/EntityXMLFile.h"
|
||||||
|
#include "Core/SystemPipeline.h"
|
||||||
|
#include "RaptorCopterSystem.h"
|
||||||
|
|
||||||
class Game
|
class Game
|
||||||
{
|
{
|
||||||
@@ -29,8 +31,14 @@ private:
|
|||||||
InputManager* m_InputManager;
|
InputManager* m_InputManager;
|
||||||
GUI::Frame* m_FrameStack;
|
GUI::Frame* m_FrameStack;
|
||||||
World* m_World;
|
World* m_World;
|
||||||
|
SystemPipeline* m_SystemPipeline;
|
||||||
RenderQueueFactory* m_RenderQueueFactory;
|
RenderQueueFactory* m_RenderQueueFactory;
|
||||||
OctTree* m_OctTree;
|
|
||||||
|
EventRelay<Game, Events::KeyUp> m_EKeyUp;
|
||||||
|
bool testOnKeyUp(const Events::KeyUp& e);
|
||||||
|
|
||||||
|
void testIntialize();
|
||||||
|
void testTick(double dt);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,146 +0,0 @@
|
|||||||
#include <list>
|
|
||||||
#include <tuple>
|
|
||||||
#include <boost/any.hpp>
|
|
||||||
#include "GLM.h"
|
|
||||||
#include "Core/World.h"
|
|
||||||
#include "Core/Util/Any.h"
|
|
||||||
|
|
||||||
class HardcodedTestWorld : public World
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HardcodedTestWorld()
|
|
||||||
: World()
|
|
||||||
{
|
|
||||||
registerTestComponents();
|
|
||||||
createTestEntities();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void registerTestComponents()
|
|
||||||
{
|
|
||||||
ComponentWrapperFactory f;
|
|
||||||
|
|
||||||
|
|
||||||
f = ComponentWrapperFactory("Test");
|
|
||||||
f.AddProperty("TestInteger", 1337);
|
|
||||||
f.AddProperty("TestFloat", 13.37f);
|
|
||||||
f.AddProperty("TestString", std::string("Carlito"));
|
|
||||||
RegisterComponent(f);
|
|
||||||
|
|
||||||
f = ComponentWrapperFactory("Debug");
|
|
||||||
f.AddProperty("Name", std::string("Unnamed"));
|
|
||||||
RegisterComponent(f);
|
|
||||||
|
|
||||||
f = ComponentWrapperFactory("Transform");
|
|
||||||
f.AddProperty("Position", glm::vec3(0.f, 0.f, 0.f));
|
|
||||||
f.AddProperty("Orientation", glm::quat());
|
|
||||||
f.AddProperty("Scale", glm::vec3(1.f, 1.f, 1.f));
|
|
||||||
RegisterComponent(f);
|
|
||||||
|
|
||||||
f = ComponentWrapperFactory("Model");
|
|
||||||
f.AddProperty("Resource", std::string());
|
|
||||||
f.AddProperty("Color", glm::vec4(1.f, 1.f, 1.f, 1.f));
|
|
||||||
f.AddProperty("Visible", true);
|
|
||||||
RegisterComponent(f);
|
|
||||||
|
|
||||||
f = ComponentWrapperFactory("Collision");
|
|
||||||
f.AddProperty("BoxCenter", glm::vec3(0.f, 0.f, 0.f));
|
|
||||||
f.AddProperty("BoxSize", glm::vec3(1.f, 1.f, 1.f));
|
|
||||||
RegisterComponent(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void createTestEntities()
|
|
||||||
{
|
|
||||||
World& world = *this;
|
|
||||||
|
|
||||||
// Create an entity
|
|
||||||
EntityID e = world.CreateEntity();
|
|
||||||
|
|
||||||
// Attach a Debug component
|
|
||||||
ComponentWrapper debug = world.AttachComponent(e, "Debug");
|
|
||||||
// Set the Name field of the Debug component using subscript operator
|
|
||||||
debug["Name"] = "Carlito";
|
|
||||||
|
|
||||||
// Attach a Transform component
|
|
||||||
world.AttachComponent(e, "Transform");
|
|
||||||
// Fetch the component based on EntityID and component type
|
|
||||||
ComponentWrapper transform = world.GetComponent(e, "Transform");
|
|
||||||
// Set the fields of the Transform component
|
|
||||||
transform["Position"] = glm::vec3(0.f, 0.f, 0.f);
|
|
||||||
transform["Scale"] = glm::vec3(1.f, 1.f, 1.f);
|
|
||||||
|
|
||||||
// Move on the X axis by fetching field as reference
|
|
||||||
((glm::vec3&)transform["Position"]).x += 10.f;
|
|
||||||
// Shrink by a factor of 100
|
|
||||||
((glm::vec3&)transform["Scale"]) /= 100.f;
|
|
||||||
|
|
||||||
// Loop through all Transform components and print them
|
|
||||||
for (auto& transform : world.GetComponents("Transform")) {
|
|
||||||
glm::vec3 pos = transform["Position"];
|
|
||||||
std::cout << "Position: " << pos.x << " " << pos.y << " " << pos.z << std::endl;
|
|
||||||
glm::vec3 scale = transform["Scale"];
|
|
||||||
std::cout << "Scale: " << scale.x << " " << scale.y << " " << scale.z << std::endl;
|
|
||||||
|
|
||||||
// Fetch the Debug component also present in this entity
|
|
||||||
ComponentWrapper debug = world.GetComponent(transform.EntityID, "Debug");
|
|
||||||
std::cout << "Name: " << (std::string)debug["Name"] << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Create some test widgets
|
|
||||||
{
|
|
||||||
EntityID entityScaleWidget = world.CreateEntity();
|
|
||||||
ComponentWrapper transform = world.AttachComponent(entityScaleWidget, "Transform");
|
|
||||||
transform["Position"] = glm::vec3(-1.5f, 0.f, 0.f);
|
|
||||||
ComponentWrapper model = world.AttachComponent(entityScaleWidget, "Model");
|
|
||||||
model["Resource"] = "Models/ScaleWidget.obj";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
EntityID entityRotationWidget = world.CreateEntity();
|
|
||||||
ComponentWrapper transform = world.AttachComponent(entityRotationWidget, "Transform");
|
|
||||||
transform["Position"] = glm::vec3(1.5f, 0.f, 0.f);
|
|
||||||
ComponentWrapper model = world.AttachComponent(entityRotationWidget, "Model");
|
|
||||||
model["Resource"] = "Models/RotationWidget.obj";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
EntityID entityDummyScene = world.CreateEntity();
|
|
||||||
ComponentWrapper transform = world.AttachComponent(entityDummyScene, "Transform");
|
|
||||||
transform["Position"] = glm::vec3(0, 0.f, 0.f);
|
|
||||||
ComponentWrapper model = world.AttachComponent(entityDummyScene, "Model");
|
|
||||||
model["Resource"] = "Models/DummyScene.obj";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
EntityID entityCollisionBox = world.CreateEntity();
|
|
||||||
ComponentWrapper transform = world.AttachComponent(entityCollisionBox, "Transform");
|
|
||||||
transform["Position"] = glm::vec3(0.f, 2.f, 0.f);
|
|
||||||
ComponentWrapper model = world.AttachComponent(entityCollisionBox, "Model");
|
|
||||||
model["Resource"] = "Models/Core/UnitBox.obj";
|
|
||||||
|
|
||||||
ComponentWrapper collision = world.AttachComponent(entityCollisionBox, "Collision");
|
|
||||||
glm::vec3 pos = transform["Position"];
|
|
||||||
glm::vec3 scale = transform["Scale"];
|
|
||||||
glm::quat ori = transform["Orientation"];
|
|
||||||
Model* modelRes = ResourceManager::Load<Model>(model["Resource"]);
|
|
||||||
|
|
||||||
//WTODO: This only works for objects that never moves/scales/rotates since modelMatrix don't change.
|
|
||||||
//For dynamic objects, should save a collision box in modelspace and transform box with modelMatrix per collision check.
|
|
||||||
glm::mat4 modelMatrix = modelRes->m_Matrix * glm::translate(glm::mat4(), pos) * glm::toMat4(ori) * glm::scale(scale);
|
|
||||||
|
|
||||||
glm::vec3 mini = glm::vec3(INFINITY, INFINITY, INFINITY);
|
|
||||||
glm::vec3 maxi = glm::vec3(-INFINITY, -INFINITY, -INFINITY);
|
|
||||||
for (const auto& v : modelRes->m_Vertices) {
|
|
||||||
const auto& wPos = modelMatrix * glm::vec4(v.Position.x, v.Position.y, v.Position.z, 1);
|
|
||||||
maxi.x = std::max(wPos.x, maxi.x);
|
|
||||||
maxi.y = std::max(wPos.y, maxi.y);
|
|
||||||
maxi.z = std::max(wPos.z, maxi.z);
|
|
||||||
mini.x = std::min(wPos.x, mini.x);
|
|
||||||
mini.y = std::min(wPos.y, mini.y);
|
|
||||||
mini.z = std::min(wPos.z, mini.z);
|
|
||||||
}
|
|
||||||
collision["BoxCenter"] = 0.5f * (maxi + mini);
|
|
||||||
collision["BoxSize"] = maxi - mini;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#include "Common.h"
|
||||||
|
#include "Core/System.h"
|
||||||
|
|
||||||
|
class RaptorCopterSystem : public System
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RaptorCopterSystem(const EventBroker* eventBroker)
|
||||||
|
: System(eventBroker, "RaptorCopter")
|
||||||
|
{ }
|
||||||
|
|
||||||
|
virtual void Update(World* world, ComponentWrapper& raptorCopter, double dt) override
|
||||||
|
{
|
||||||
|
ComponentWrapper& transform = world->GetComponent(raptorCopter.EntityID, "Transform");
|
||||||
|
(glm::vec3&)transform["Orientation"] += (float)(double)raptorCopter["Speed"] * (float)dt * (glm::vec3)raptorCopter["Axis"];
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
[Debug]
|
[Debug]
|
||||||
LogLevel=1
|
LogLevel=1
|
||||||
|
LoadMap=
|
||||||
|
|
||||||
[Video]
|
[Video]
|
||||||
Fullscreen=false
|
Fullscreen=false
|
||||||
|
|||||||
@@ -2,5 +2,7 @@
|
|||||||
|
|
||||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="components" elementFormDefault="qualified">
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="components" elementFormDefault="qualified">
|
||||||
<xs:include schemaLocation="Components/Transform.xsd"/>
|
<xs:include schemaLocation="Components/Transform.xsd"/>
|
||||||
|
<xs:include schemaLocation="Components/Model.xsd"/>
|
||||||
<xs:include schemaLocation="Components/Test.xsd"/>
|
<xs:include schemaLocation="Components/Test.xsd"/>
|
||||||
|
<xs:include schemaLocation="Components/RaptorCopter.xsd"/>
|
||||||
</xs:schema>
|
</xs:schema>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<c:Model>
|
||||||
|
<Resource></Resource>
|
||||||
|
<Color R="1" G="1" B="1" A="1"/>
|
||||||
|
<Visible>true</Visible>
|
||||||
|
</c:Model>
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<?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="Model">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>A visible model loaded from disk</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:all>
|
||||||
|
<xs:element name="Resource" type="t:string" minOccurs="0">
|
||||||
|
<xs:annotation><xs:documentation>Model file</xs:documentation></xs:annotation>
|
||||||
|
</xs:element>
|
||||||
|
<xs:element name="Color" type="t:Color" minOccurs="0">
|
||||||
|
<xs:annotation><xs:documentation>Color tint</xs:documentation></xs:annotation>
|
||||||
|
</xs:element>
|
||||||
|
<xs:element name="Visible" type="t:bool" minOccurs="0">
|
||||||
|
<xs:annotation><xs:documentation>Wether the model is visible or not</xs:documentation></xs:annotation>
|
||||||
|
</xs:element>
|
||||||
|
</xs:all>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
</xs:schema>
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
<c:RaptorCopter>
|
||||||
|
<Speed>0</Speed>
|
||||||
|
<Axis X="0" Y="0" Z="0"/>
|
||||||
|
</c:RaptorCopter>
|
||||||
@@ -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="RaptorCopter">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:all>
|
||||||
|
<xs:element name="Speed" type="t:double" minOccurs="0"/>
|
||||||
|
<xs:element name="Axis" type="t:Vector" minOccurs="0"/>
|
||||||
|
</xs:all>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
</xs:schema>
|
||||||
@@ -2,5 +2,5 @@
|
|||||||
<Integer>1</Integer>
|
<Integer>1</Integer>
|
||||||
<Float>1.333</Float>
|
<Float>1.333</Float>
|
||||||
<Vector X="1.33333" Y="2.33333" Z="3.33333"/>
|
<Vector X="1.33333" Y="2.33333" Z="3.33333"/>
|
||||||
<Quaternion I="1.33333" J="2.33333" K="3.33333"/>
|
<Quaternion X="1.33333" Y="2.33333" Z="3.33333" W="4.44444"/>
|
||||||
</c:Test>
|
</c:Test>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<TransformComponent>
|
<c:Transform>
|
||||||
<Position X="0" Y="0" Z="0"/>
|
<Position X="0" Y="0" Z="0"/>
|
||||||
<Orientation I="0" J="0" K="0"/>
|
<Orientation X="0" Y="0" Z="0" W="0"/>
|
||||||
<Scale X="1" Y="1" Z="1"/>
|
<Scale X="1" Y="1" Z="1"/>
|
||||||
</TransformComponent>
|
</c:Transform>
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
<xs:element name="Position" type="t:Vector" minOccurs="0">
|
<xs:element name="Position" type="t:Vector" minOccurs="0">
|
||||||
<xs:annotation><xs:documentation>The position vector</xs:documentation></xs:annotation>
|
<xs:annotation><xs:documentation>The position vector</xs:documentation></xs:annotation>
|
||||||
</xs:element>
|
</xs:element>
|
||||||
<xs:element name="Orientation" type="t:Quaternion" minOccurs="0"/>
|
<xs:element name="Orientation" type="t:Vector" minOccurs="0"/>
|
||||||
<xs:element name="Scale" type="t:Vector" minOccurs="0"/>
|
<xs:element name="Scale" type="t:Vector" minOccurs="0"/>
|
||||||
</xs:all>
|
</xs:all>
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
|
|||||||
@@ -3,18 +3,114 @@
|
|||||||
<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">
|
<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">
|
||||||
<Components>
|
<Components>
|
||||||
<c:Transform>
|
<c:Transform>
|
||||||
<Position X="1.02" Y="3.123123" Z="41.123"/>
|
<Orientation X="0" Y="0" Z="0"/>
|
||||||
<Orientation I="1.234" J="1.234" K="1.234"/>
|
|
||||||
<Scale X="1.02" Y="3.123123" Z="41.123"/>
|
|
||||||
</c:Transform>
|
</c:Transform>
|
||||||
<c:Test>
|
<c:Model>
|
||||||
<Integer>12</Integer>
|
<Resource>Models/DummyScene.obj</Resource>
|
||||||
<Double>11.11</Double>
|
</c:Model>
|
||||||
<String>Hello World</String>
|
|
||||||
</c:Test>
|
|
||||||
</Components>
|
</Components>
|
||||||
<Children>
|
<Children>
|
||||||
<xi:include href="OtherEntity.xml"/>
|
<Entity>
|
||||||
<xi:include href="OtherEntity.xml"/>
|
<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"/>
|
||||||
|
</c:Transform>
|
||||||
|
<c:Model>
|
||||||
|
<Resource>Models/RotationWidget.obj</Resource>
|
||||||
|
</c:Model>
|
||||||
|
</Components>
|
||||||
|
</Entity>
|
||||||
|
<Entity>
|
||||||
|
<Components>
|
||||||
|
<c:Transform>
|
||||||
|
<Position X="0" Y="-0"/>
|
||||||
|
<Scale X="1" Y="1" Z="1"/>
|
||||||
|
</c:Transform>
|
||||||
|
<!--<c:Move>
|
||||||
|
<Speed>1</Speed>
|
||||||
|
<Direction X="-1"/>
|
||||||
|
<Rotation Y="3.14"/>
|
||||||
|
</c:Move>-->
|
||||||
|
</Components>
|
||||||
|
<Children>
|
||||||
|
<Entity>
|
||||||
|
<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>
|
||||||
|
</Children>
|
||||||
|
</Entity>
|
||||||
</Children>
|
</Children>
|
||||||
</Entity>
|
</Entity>
|
||||||
@@ -3,6 +3,10 @@
|
|||||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="types" elementFormDefault="qualified">
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="types" elementFormDefault="qualified">
|
||||||
<xs:include schemaLocation="Types/Quaternion.xsd"/>
|
<xs:include schemaLocation="Types/Quaternion.xsd"/>
|
||||||
<xs:include schemaLocation="Types/Vector.xsd"/>
|
<xs:include schemaLocation="Types/Vector.xsd"/>
|
||||||
|
<xs:include schemaLocation="Types/Color.xsd"/>
|
||||||
|
<xs:simpleType name="bool">
|
||||||
|
<xs:restriction base="xs:boolean"></xs:restriction>
|
||||||
|
</xs:simpleType>
|
||||||
<xs:simpleType name="int">
|
<xs:simpleType name="int">
|
||||||
<xs:restriction base="xs:integer"></xs:restriction>
|
<xs:restriction base="xs:integer"></xs:restriction>
|
||||||
</xs:simpleType>
|
</xs:simpleType>
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
|
||||||
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="types" elementFormDefault="qualified">
|
||||||
|
<xs:complexType name="Color">
|
||||||
|
<xs:attribute name="R" type="xs:decimal" default="0.0"/>
|
||||||
|
<xs:attribute name="G" type="xs:decimal" default="0.0"/>
|
||||||
|
<xs:attribute name="B" type="xs:decimal" default="0.0"/>
|
||||||
|
<xs:attribute name="A" type="xs:decimal" default="1.0"/>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:schema>
|
||||||
@@ -7,11 +7,13 @@
|
|||||||
<xs:element name="Entity">
|
<xs:element name="Entity">
|
||||||
<xs:complexType>
|
<xs:complexType>
|
||||||
<xs:all>
|
<xs:all>
|
||||||
<xs:element name="Components">
|
<xs:element name="Components" minOccurs="0">
|
||||||
<xs:complexType>
|
<xs:complexType>
|
||||||
<xs:all>
|
<xs:all>
|
||||||
<xs:element ref="c:Transform" minOccurs="0"/>
|
<xs:element ref="c:Transform" minOccurs="0"/>
|
||||||
|
<xs:element ref="c:Model" minOccurs="0"/>
|
||||||
<xs:element ref="c:Test" minOccurs="0"/>
|
<xs:element ref="c:Test" minOccurs="0"/>
|
||||||
|
<xs:element ref="c:RaptorCopter" minOccurs="0"/>
|
||||||
</xs:all>
|
</xs:all>
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
</xs:element>
|
</xs:element>
|
||||||
|
|||||||
@@ -0,0 +1,481 @@
|
|||||||
|
#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) },
|
||||||
|
{ "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_float, status);
|
||||||
|
if (val == nullptr) {
|
||||||
|
LOG_ERROR("Element \"%s\" doesn't have an \"%s\" attribute!", XSTR(element->getTagName()), attribute);
|
||||||
|
return 0.f;
|
||||||
|
} else {
|
||||||
|
return val->fData.fValue.f_float;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityXMLFile::writeData(const xercesc::DOMElement* element, std::string typeName, char* outData)
|
||||||
|
{
|
||||||
|
using namespace xercesc;
|
||||||
|
|
||||||
|
XSValue::DataType dataType = XSValue::getDataType(XSTR(typeName.c_str()));
|
||||||
|
if (dataType == XSValue::DataType::dt_MAXCOUNT) {
|
||||||
|
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 (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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+174
-50
@@ -21,6 +21,16 @@ bool isFirstLower(const ChildInfo& first, const ChildInfo& second)
|
|||||||
return first.Distance < second.Distance;
|
return first.Distance < second.Distance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isSameBoxProbably(const AABB& first, const AABB& second)
|
||||||
|
{
|
||||||
|
const float EPS = 0.0001f;
|
||||||
|
const auto& ma = first.MaxCorner();
|
||||||
|
const auto& mi = first.MinCorner();
|
||||||
|
return (std::abs(ma.x - mi.x) < EPS) &&
|
||||||
|
(std::abs(ma.z - mi.z) < EPS) &&
|
||||||
|
(std::abs(ma.y - mi.y) < EPS);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OctTree::OctTree()
|
OctTree::OctTree()
|
||||||
@@ -28,11 +38,79 @@ OctTree::OctTree()
|
|||||||
{}
|
{}
|
||||||
|
|
||||||
OctTree::OctTree(const AABB& octTreeBounds, int subDivisions)
|
OctTree::OctTree(const AABB& octTreeBounds, int subDivisions)
|
||||||
: m_Box(octTreeBounds)
|
: m_Root(new OctChild(octTreeBounds, subDivisions, m_StaticObjects, m_DynamicObjects))
|
||||||
, m_UpdatedOnce(false)
|
, m_UpdatedOnce(false)
|
||||||
|
{}
|
||||||
|
|
||||||
|
OctTree::~OctTree()
|
||||||
|
{
|
||||||
|
delete m_Root;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OctTree::AddDynamicObject(const AABB& box)
|
||||||
|
{
|
||||||
|
m_Root->AddDynamicObject(box);
|
||||||
|
m_DynamicObjects.push_back(box);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OctTree::AddStaticObject(const AABB& box)
|
||||||
|
{
|
||||||
|
m_Root->AddStaticObject(box);
|
||||||
|
m_StaticObjects.push_back(box);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OctTree::BoxesInSameRegion(const AABB& box, std::vector<AABB>& outBoxes)
|
||||||
|
{
|
||||||
|
falsifyObjectChecks();
|
||||||
|
m_Root->BoxesInSameRegion(box, outBoxes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OctTree::ClearObjects()
|
||||||
|
{
|
||||||
|
m_StaticObjects.clear();
|
||||||
|
m_DynamicObjects.clear();
|
||||||
|
m_Root->ClearObjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OctTree::ClearDynamicObjects()
|
||||||
|
{
|
||||||
|
m_DynamicObjects.clear();
|
||||||
|
m_Root->ClearDynamicObjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OctTree::RayCollides(const Ray& ray, Output& data)
|
||||||
|
{
|
||||||
|
falsifyObjectChecks();
|
||||||
|
data.CollideDistance = -1;
|
||||||
|
return m_Root->RayCollides(ray, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OctTree::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected)
|
||||||
|
{
|
||||||
|
falsifyObjectChecks();
|
||||||
|
return m_Root->BoxCollides(boxToTest, outBoxIntersected);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OctTree::falsifyObjectChecks()
|
||||||
|
{
|
||||||
|
for (auto& obj : m_StaticObjects) {
|
||||||
|
obj.Checked = false;
|
||||||
|
}
|
||||||
|
for (auto& obj : m_DynamicObjects) {
|
||||||
|
obj.Checked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OctTree::OctChild::OctChild(const AABB& octTreeBounds,
|
||||||
|
int subDivisions,
|
||||||
|
std::vector<ContainedObject>& staticObjects,
|
||||||
|
std::vector<ContainedObject>& dynamicObjects)
|
||||||
|
: m_Box(octTreeBounds)
|
||||||
|
, m_StaticObjectsRef(staticObjects)
|
||||||
|
, m_DynamicObjectsRef(dynamicObjects)
|
||||||
{
|
{
|
||||||
if (subDivisions == 0) {
|
if (subDivisions == 0) {
|
||||||
for (OctTree*& c : m_Children) {
|
for (OctChild*& c : m_Children) {
|
||||||
c = nullptr;
|
c = nullptr;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -68,14 +146,14 @@ OctTree::OctTree(const AABB& octTreeBounds, int subDivisions)
|
|||||||
minPos.z = parentMin.z;
|
minPos.z = parentMin.z;
|
||||||
maxPos.z = parentCenter.z;
|
maxPos.z = parentCenter.z;
|
||||||
}
|
}
|
||||||
m_Children[i] = new OctTree(AABB(minPos, maxPos), subDivisions);
|
m_Children[i] = new OctChild(AABB(minPos, maxPos), subDivisions, m_StaticObjectsRef, m_DynamicObjectsRef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OctTree::~OctTree()
|
OctTree::OctChild::~OctChild()
|
||||||
{
|
{
|
||||||
for (OctTree*& c : m_Children) {
|
for (OctChild*& c : m_Children) {
|
||||||
if (c != nullptr) {
|
if (c != nullptr) {
|
||||||
delete c;
|
delete c;
|
||||||
c = nullptr;
|
c = nullptr;
|
||||||
@@ -85,19 +163,22 @@ OctTree::~OctTree()
|
|||||||
|
|
||||||
void OctTree::Update(float dt, World* world, Camera* cam)
|
void OctTree::Update(float dt, World* world, Camera* cam)
|
||||||
{
|
{
|
||||||
AABB aabb;
|
|
||||||
for (ComponentWrapper& c : world->GetComponents("Collision")) {
|
for (ComponentWrapper& c : world->GetComponents("Collision")) {
|
||||||
|
AABB aabb;
|
||||||
aabb.CreateFromCenter(c["BoxCenter"], c["BoxSize"]);
|
aabb.CreateFromCenter(c["BoxCenter"], c["BoxSize"]);
|
||||||
AddStaticObject(aabb);
|
AddDynamicObject(aabb);
|
||||||
}
|
}
|
||||||
const glm::vec4 redCol = glm::vec4(1, 0.2f, 0, 1);
|
const glm::vec4 redCol = glm::vec4(1, 0.2f, 0, 1);
|
||||||
const glm::vec4 greenCol = glm::vec4(0.1f, 1.0f, 0.25f, 1);
|
const glm::vec4 greenCol = glm::vec4(0.1f, 1.0f, 0.25f, 1);
|
||||||
const glm::vec3 boxSize = 0.1f*glm::vec3(1.0f, 1.0f, 1.0f);
|
const glm::vec4 blueCol = glm::vec4(0.1f, 0.05f, 0.95f, 1);
|
||||||
|
const glm::vec4 cyanCol = glm::vec4(0.1f, 0.9f, 0.85f, 1);
|
||||||
|
const glm::vec3 boxSize = 0.05f*glm::vec3(1.0f, 1.0f, 1.0f);
|
||||||
|
|
||||||
if (!m_UpdatedOnce) {
|
if (!m_UpdatedOnce) {
|
||||||
m_BoxID = world->CreateEntity();
|
m_BoxID = world->CreateEntity();
|
||||||
ComponentWrapper transform = world->AttachComponent(m_BoxID, "Transform");
|
ComponentWrapper transform = world->AttachComponent(m_BoxID, "Transform");
|
||||||
transform["Scale"] = boxSize;
|
transform["Scale"] = boxSize;
|
||||||
|
|
||||||
ComponentWrapper model = world->AttachComponent(m_BoxID, "Model");
|
ComponentWrapper model = world->AttachComponent(m_BoxID, "Model");
|
||||||
model["Resource"] = "Models/Core/UnitBox.obj";
|
model["Resource"] = "Models/Core/UnitBox.obj";
|
||||||
m_UpdatedOnce = true;
|
m_UpdatedOnce = true;
|
||||||
@@ -109,21 +190,24 @@ void OctTree::Update(float dt, World* world, Camera* cam)
|
|||||||
ComponentWrapper transform = world->GetComponent(m_BoxID, "Transform");
|
ComponentWrapper transform = world->GetComponent(m_BoxID, "Transform");
|
||||||
transform["Position"] = boxPos;
|
transform["Position"] = boxPos;
|
||||||
ComponentWrapper model = world->GetComponent(m_BoxID, "Model");
|
ComponentWrapper model = world->GetComponent(m_BoxID, "Model");
|
||||||
if (BoxCollides(box, AABB())) {
|
bool collBox = BoxCollides(box, AABB());
|
||||||
//if (Collision::AABBVsAABB(box, aabb)) {
|
if (collBox) {
|
||||||
cam->SetPosition(m_PrevPos);
|
cam->SetPosition(m_PrevPos);
|
||||||
cam->SetOrientation(m_PrevOri);
|
cam->SetOrientation(m_PrevOri);
|
||||||
model["Color"] = greenCol;
|
bool collRay = RayCollides({ cam->Position(), cam->Forward() }, Output());
|
||||||
|
model["Color"] = collRay ? cyanCol : greenCol;
|
||||||
|
} else if (RayCollides({ cam->Position(), cam->Forward() }, Output())) {
|
||||||
|
model["Color"] = blueCol;
|
||||||
} else {
|
} else {
|
||||||
model["Color"] = redCol;
|
model["Color"] = redCol;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_PrevPos = cam->Position();
|
m_PrevPos = cam->Position();
|
||||||
m_PrevOri = cam->Orientation();
|
m_PrevOri = cam->Orientation();
|
||||||
ClearObjects();
|
ClearDynamicObjects();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OctTree::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const
|
bool OctTree::OctChild::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const
|
||||||
{
|
{
|
||||||
if (hasChildren()) {
|
if (hasChildren()) {
|
||||||
for (int i : childIndicesContainingBox(boxToTest)) {
|
for (int i : childIndicesContainingBox(boxToTest)) {
|
||||||
@@ -131,23 +215,32 @@ bool OctTree::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
std::vector<std::vector<AABB>> objVectors = {
|
for (int i : m_StaticObjIndices) {
|
||||||
m_StaticObjects,
|
if (!m_StaticObjectsRef[i].Checked) {
|
||||||
m_DynamicObjects
|
const AABB& objBox = m_StaticObjectsRef[i].Box;
|
||||||
};
|
if (Collision::AABBVsAABB(boxToTest, objBox)) {
|
||||||
for (const auto& objVector : objVectors) {
|
outBoxIntersected = objBox;
|
||||||
for (const auto& obj : objVector) {
|
|
||||||
if (Collision::AABBVsAABB(boxToTest, obj)) {
|
|
||||||
outBoxIntersected = obj;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
m_StaticObjectsRef[i].Checked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i : m_DynamicObjIndices) {
|
||||||
|
if (!m_DynamicObjectsRef[i].Checked) {
|
||||||
|
const AABB& objBox = m_DynamicObjectsRef[i].Box;
|
||||||
|
if (!isSameBoxProbably(boxToTest, objBox) &&
|
||||||
|
Collision::AABBVsAABB(boxToTest, objBox)) {
|
||||||
|
outBoxIntersected = objBox;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
m_DynamicObjectsRef[i].Checked = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OctTree::RayCollides(const Ray& ray, Output& data) const
|
bool OctTree::OctChild::RayCollides(const Ray& ray, Output& data) const
|
||||||
{
|
{
|
||||||
//If the node AABB is missed, everything it contains is missed.
|
//If the node AABB is missed, everything it contains is missed.
|
||||||
if (Collision::RayAABBIntr(ray, m_Box)) {
|
if (Collision::RayAABBIntr(ray, m_Box)) {
|
||||||
@@ -170,18 +263,25 @@ bool OctTree::RayCollides(const Ray& ray, Output& data) const
|
|||||||
//Check against boxes in the node.
|
//Check against boxes in the node.
|
||||||
float minDist = INFINITY;
|
float minDist = INFINITY;
|
||||||
bool intersected = false;
|
bool intersected = false;
|
||||||
std::vector<std::vector<AABB>> objVectors = {
|
for (int i : m_StaticObjIndices) {
|
||||||
m_StaticObjects,
|
float dist;
|
||||||
m_DynamicObjects
|
//If we haven't tested against this object before, and the ray hits.
|
||||||
};
|
if (!m_StaticObjectsRef[i].Checked &&
|
||||||
for (const auto& objVector : objVectors) {
|
Collision::RayVsAABB(ray, m_StaticObjectsRef[i].Box, dist)) {
|
||||||
for (const auto& obj : objVector) {
|
minDist = std::min(dist, minDist);
|
||||||
float dist;
|
intersected = true;
|
||||||
if (Collision::RayVsAABB(ray, obj, dist)) {
|
|
||||||
minDist = std::min(dist, minDist);
|
|
||||||
intersected = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
m_StaticObjectsRef[i].Checked = true;
|
||||||
|
}
|
||||||
|
for (int i : m_DynamicObjIndices) {
|
||||||
|
float dist;
|
||||||
|
//If we haven't tested against this object before, and the ray hits.
|
||||||
|
if (!m_DynamicObjectsRef[i].Checked &&
|
||||||
|
Collision::RayVsAABB(ray, m_DynamicObjectsRef[i].Box, dist)) {
|
||||||
|
minDist = std::min(dist, minDist);
|
||||||
|
intersected = true;
|
||||||
|
}
|
||||||
|
m_DynamicObjectsRef[i].Checked = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
data.CollideDistance = minDist;
|
data.CollideDistance = minDist;
|
||||||
@@ -192,60 +292,84 @@ bool OctTree::RayCollides(const Ray& ray, Output& data) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void OctTree::AddDynamicObject(const AABB& box)
|
void OctTree::OctChild::AddDynamicObject(const AABB& box)
|
||||||
{
|
{
|
||||||
if (hasChildren()) {
|
if (hasChildren()) {
|
||||||
for (auto i : childIndicesContainingBox(box)) {
|
for (auto i : childIndicesContainingBox(box)) {
|
||||||
m_Children[i]->AddDynamicObject(box);
|
m_Children[i]->AddDynamicObject(box);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
m_DynamicObjects.push_back(box);
|
//Since it hasn't been added yet to the real object list, the index is after the last =size.
|
||||||
|
m_DynamicObjIndices.push_back(m_DynamicObjectsRef.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OctTree::AddStaticObject(const AABB& box)
|
void OctTree::OctChild::AddStaticObject(const AABB& box)
|
||||||
{
|
{
|
||||||
if (hasChildren()) {
|
if (hasChildren()) {
|
||||||
for (auto i : childIndicesContainingBox(box)) {
|
for (auto i : childIndicesContainingBox(box)) {
|
||||||
m_Children[i]->AddStaticObject(box);
|
m_Children[i]->AddStaticObject(box);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
m_StaticObjects.push_back(box);
|
//Since it hasn't been added yet to the real object list, the index is after the last =size.
|
||||||
|
m_StaticObjIndices.push_back(m_StaticObjectsRef.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OctTree::BoxesInSameRegion(const AABB& box, std::vector<AABB>& outBoxes) const
|
void OctTree::OctChild::BoxesInSameRegion(const AABB& box, std::vector<AABB>& outBoxes) const
|
||||||
{
|
{
|
||||||
if (hasChildren()) {
|
if (hasChildren()) {
|
||||||
for (auto i : childIndicesContainingBox(box)) {
|
for (auto i : childIndicesContainingBox(box)) {
|
||||||
m_Children[i]->BoxesInSameRegion(box, outBoxes);
|
m_Children[i]->BoxesInSameRegion(box, outBoxes);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
outBoxes.insert(outBoxes.end(), m_StaticObjects.begin(), m_StaticObjects.end());
|
int startIndex = outBoxes.size();
|
||||||
outBoxes.insert(outBoxes.end(), m_DynamicObjects.begin(), m_DynamicObjects.end());
|
int numDuplicates = 0;
|
||||||
|
outBoxes.resize(outBoxes.size() + m_StaticObjIndices.size() + m_DynamicObjIndices.size());
|
||||||
|
for (size_t i = 0; i < m_StaticObjIndices.size(); ++i){
|
||||||
|
ContainedObject& obj = m_StaticObjectsRef[m_StaticObjIndices[i]];
|
||||||
|
if (obj.Checked) {
|
||||||
|
++numDuplicates;
|
||||||
|
} else {
|
||||||
|
obj.Checked = true;
|
||||||
|
outBoxes[startIndex + i - numDuplicates] = obj.Box;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < m_DynamicObjIndices.size(); ++i) {
|
||||||
|
ContainedObject& obj = m_DynamicObjectsRef[m_DynamicObjIndices[i]];
|
||||||
|
if (obj.Checked) {
|
||||||
|
++numDuplicates;
|
||||||
|
} else {
|
||||||
|
obj.Checked = true;
|
||||||
|
outBoxes[startIndex + i - numDuplicates] = obj.Box;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < numDuplicates; ++i) {
|
||||||
|
outBoxes.pop_back();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OctTree::ClearObjects()
|
void OctTree::OctChild::ClearObjects()
|
||||||
{
|
{
|
||||||
if (hasChildren()) {
|
if (hasChildren()) {
|
||||||
for (OctTree*& c : m_Children) {
|
for (OctChild*& c : m_Children) {
|
||||||
c->ClearObjects();
|
c->ClearObjects();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
m_DynamicObjects.clear();
|
m_DynamicObjIndices.clear();
|
||||||
m_StaticObjects.clear();
|
m_StaticObjIndices.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OctTree::ClearDynamicObjects()
|
void OctTree::OctChild::ClearDynamicObjects()
|
||||||
{
|
{
|
||||||
if (hasChildren()) {
|
if (hasChildren()) {
|
||||||
for (OctTree*& c : m_Children) {
|
for (OctChild*& c : m_Children) {
|
||||||
c->ClearObjects();
|
c->ClearObjects();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
m_DynamicObjects.clear();
|
m_DynamicObjIndices.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,13 +385,13 @@ void OctTree::ClearDynamicObjects()
|
|||||||
// x : - - - - + + + +
|
// x : - - - - + + + +
|
||||||
// y : - - + + - - + +
|
// y : - - + + - - + +
|
||||||
// z : - + - + - + - +
|
// z : - + - + - + - +
|
||||||
int OctTree::childIndexContainingPoint(const glm::vec3& point) const
|
int OctTree::OctChild::childIndexContainingPoint(const glm::vec3& point) const
|
||||||
{
|
{
|
||||||
const glm::vec3& c = m_Box.Center();
|
const glm::vec3& c = m_Box.Center();
|
||||||
return (1 << 2) * (point.x >= c.x) | (1 << 1) * (point.y >= c.y) | (point.z >= c.z);
|
return (1 << 2) * (point.x >= c.x) | (1 << 1) * (point.y >= c.y) | (point.z >= c.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<int> OctTree::childIndicesContainingBox(const AABB& box) const
|
std::vector<int> OctTree::OctChild::childIndicesContainingBox(const AABB& box) const
|
||||||
{
|
{
|
||||||
int minInd = childIndexContainingPoint(box.MinCorner());
|
int minInd = childIndexContainingPoint(box.MinCorner());
|
||||||
int maxInd = childIndexContainingPoint(box.MaxCorner());
|
int maxInd = childIndexContainingPoint(box.MaxCorner());
|
||||||
@@ -305,7 +429,7 @@ std::vector<int> OctTree::childIndicesContainingBox(const AABB& box) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool OctTree::hasChildren() const
|
inline bool OctTree::OctChild::hasChildren() const
|
||||||
{
|
{
|
||||||
return m_Children[0] != nullptr;
|
return m_Children[0] != nullptr;
|
||||||
}
|
}
|
||||||
@@ -35,6 +35,20 @@ void ResourceManager::Reload(std::string resourceName)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ResourceManager::Release(std::string resourceType, std::string resourceName)
|
||||||
|
{
|
||||||
|
auto key = std::make_pair(resourceType, resourceName);
|
||||||
|
if (m_ResourceCache.find(key) == m_ResourceCache.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto resource = m_ResourceCache.at(key);
|
||||||
|
m_ResourceCache.erase(key);
|
||||||
|
m_ResourceFromName.erase(resourceName);
|
||||||
|
m_ResourceParents.erase(resource);
|
||||||
|
delete resource;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int ResourceManager::GetNewResourceID(unsigned int typeID)
|
unsigned int ResourceManager::GetNewResourceID(unsigned int typeID)
|
||||||
{
|
{
|
||||||
return m_ResourceCount[typeID]++;
|
return m_ResourceCount[typeID]++;
|
||||||
|
|||||||
@@ -41,9 +41,16 @@ ComponentWrapper World::GetComponent(EntityID entity, std::string componentType)
|
|||||||
return pool->GetByEntity(entity);
|
return pool->GetByEntity(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
const ComponentPool& World::GetComponents(std::string componentType)
|
const ComponentPool* World::GetComponents(std::string componentType)
|
||||||
{
|
{
|
||||||
return *m_ComponentPools.at(componentType);
|
auto it = m_ComponentPools.find(componentType);
|
||||||
|
return (it != m_ComponentPools.end()) ? it->second : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
EntityID World::GetParent(EntityID entity)
|
||||||
|
{
|
||||||
|
return m_EntityParents.at(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityID World::generateEntityID()
|
EntityID World::generateEntityID()
|
||||||
|
|||||||
@@ -34,10 +34,10 @@ RawModel::RawModel(std::string fileName)
|
|||||||
numIndices += face.mNumIndices;
|
numIndices += face.mNumIndices;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LOG_DEBUG("Vertex count %i", numVertices);
|
//LOG_DEBUG("Vertex count %i", numVertices);
|
||||||
LOG_DEBUG("Index count %i", numIndices);
|
//LOG_DEBUG("Index count %i", numIndices);
|
||||||
|
|
||||||
LOG_DEBUG("Model has %i embedded textures", scene->mNumTextures);
|
//LOG_DEBUG("Model has %i embedded textures", scene->mNumTextures);
|
||||||
|
|
||||||
std::vector<std::tuple<std::string, glm::mat4>> boneInfo;
|
std::vector<std::tuple<std::string, glm::mat4>> boneInfo;
|
||||||
std::map<std::string, int> boneNameMapping;
|
std::map<std::string, int> boneNameMapping;
|
||||||
@@ -132,35 +132,35 @@ 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);
|
||||||
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));
|
||||||
if (material->GetTextureCount(aiTextureType_DIFFUSE)) {
|
if (material->GetTextureCount(aiTextureType_DIFFUSE)) {
|
||||||
aiString path;
|
aiString path;
|
||||||
aiTextureMapping mapping;
|
aiTextureMapping mapping;
|
||||||
material->GetTexture(aiTextureType_DIFFUSE, 0, &path, &mapping);
|
material->GetTexture(aiTextureType_DIFFUSE, 0, &path, &mapping);
|
||||||
std::string absolutePath = (boost::filesystem::path(fileName).branch_path() / path.C_Str()).string();
|
std::string absolutePath = (boost::filesystem::path(fileName).branch_path() / path.C_Str()).string();
|
||||||
LOG_DEBUG("Diffuse texture: %s", absolutePath.c_str());
|
//LOG_DEBUG("Diffuse texture: %s", absolutePath.c_str());
|
||||||
matGroup.Texture = std::shared_ptr<Texture>(ResourceManager::Load<Texture>(absolutePath));
|
matGroup.Texture = std::shared_ptr<Texture>(ResourceManager::Load<Texture>(absolutePath));
|
||||||
}
|
}
|
||||||
// Normal map
|
// Normal map
|
||||||
LOG_DEBUG("%i normal maps found", material->GetTextureCount(aiTextureType_HEIGHT));
|
//LOG_DEBUG("%i normal maps found", material->GetTextureCount(aiTextureType_HEIGHT));
|
||||||
if (material->GetTextureCount(aiTextureType_HEIGHT)) {
|
if (material->GetTextureCount(aiTextureType_HEIGHT)) {
|
||||||
aiString path;
|
aiString path;
|
||||||
aiTextureMapping mapping;
|
aiTextureMapping mapping;
|
||||||
material->GetTexture(aiTextureType_HEIGHT, 0, &path, &mapping);
|
material->GetTexture(aiTextureType_HEIGHT, 0, &path, &mapping);
|
||||||
std::string absolutePath = (boost::filesystem::path(fileName).branch_path() / path.C_Str()).string();
|
std::string absolutePath = (boost::filesystem::path(fileName).branch_path() / path.C_Str()).string();
|
||||||
LOG_DEBUG("Normal map: %s", absolutePath.c_str());
|
//LOG_DEBUG("Normal map: %s", absolutePath.c_str());
|
||||||
matGroup.NormalMap = std::shared_ptr<Texture>(ResourceManager::Load<Texture>(absolutePath));
|
matGroup.NormalMap = std::shared_ptr<Texture>(ResourceManager::Load<Texture>(absolutePath));
|
||||||
}
|
}
|
||||||
// Specular map
|
// Specular map
|
||||||
LOG_DEBUG("%i specular maps found", material->GetTextureCount(aiTextureType_SPECULAR));
|
//LOG_DEBUG("%i specular maps found", material->GetTextureCount(aiTextureType_SPECULAR));
|
||||||
if (material->GetTextureCount(aiTextureType_SPECULAR)) {
|
if (material->GetTextureCount(aiTextureType_SPECULAR)) {
|
||||||
aiString path;
|
aiString path;
|
||||||
aiTextureMapping mapping;
|
aiTextureMapping mapping;
|
||||||
material->GetTexture(aiTextureType_SPECULAR, 0, &path, &mapping);
|
material->GetTexture(aiTextureType_SPECULAR, 0, &path, &mapping);
|
||||||
std::string absolutePath = (boost::filesystem::path(fileName).branch_path() / path.C_Str()).string();
|
std::string absolutePath = (boost::filesystem::path(fileName).branch_path() / path.C_Str()).string();
|
||||||
LOG_DEBUG("Specular map: %s", absolutePath.c_str());
|
//LOG_DEBUG("Specular map: %s", absolutePath.c_str());
|
||||||
matGroup.SpecularMap = std::shared_ptr<Texture>(ResourceManager::Load<Texture>(absolutePath));
|
matGroup.SpecularMap = std::shared_ptr<Texture>(ResourceManager::Load<Texture>(absolutePath));
|
||||||
}
|
}
|
||||||
TextureGroups.push_back(matGroup);
|
TextureGroups.push_back(matGroup);
|
||||||
@@ -216,20 +216,20 @@ RawModel::RawModel(std::string fileName)
|
|||||||
m_Skeleton = new Skeleton();
|
m_Skeleton = new Skeleton();
|
||||||
CreateSkeleton(boneInfo, boneNameMapping, scene->mRootNode, -1);
|
CreateSkeleton(boneInfo, boneNameMapping, scene->mRootNode, -1);
|
||||||
int numBones = m_Skeleton->Bones.size();
|
int numBones = m_Skeleton->Bones.size();
|
||||||
LOG_DEBUG("Bone count: %i", numBones);
|
//LOG_DEBUG("Bone count: %i", numBones);
|
||||||
if (numBones > 0) {
|
if (numBones > 0) {
|
||||||
m_Skeleton->PrintSkeleton();
|
m_Skeleton->PrintSkeleton();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Animations
|
// Animations
|
||||||
LOG_DEBUG("Animation count: %i", scene->mNumAnimations);
|
//LOG_DEBUG("Animation count: %i", scene->mNumAnimations);
|
||||||
for (int i = 0; i < scene->mNumAnimations; ++i) {
|
for (int i = 0; i < scene->mNumAnimations; ++i) {
|
||||||
auto animation = scene->mAnimations[i];
|
auto animation = scene->mAnimations[i];
|
||||||
std::string animationName = animation->mName.C_Str();
|
std::string animationName = animation->mName.C_Str();
|
||||||
LOG_DEBUG("Animation: %s", animationName.c_str());
|
//LOG_DEBUG("Animation: %s", animationName.c_str());
|
||||||
LOG_DEBUG("Duration: %f", animation->mDuration);
|
//LOG_DEBUG("Duration: %f", animation->mDuration);
|
||||||
LOG_DEBUG("Ticks per second: %f", animation->mTicksPerSecond);
|
//LOG_DEBUG("Ticks per second: %f", animation->mTicksPerSecond);
|
||||||
|
|
||||||
Skeleton::Animation skelAnim;
|
Skeleton::Animation skelAnim;
|
||||||
skelAnim.Name = animationName;
|
skelAnim.Name = animationName;
|
||||||
@@ -303,7 +303,7 @@ void RawModel::CreateSkeleton(std::vector<std::tuple<std::string, glm::mat4>> &b
|
|||||||
|
|
||||||
// Find the bone by name in the bone info list
|
// Find the bone by name in the bone info list
|
||||||
if (boneNameMapping.find(nodeName) == boneNameMapping.end()) {
|
if (boneNameMapping.find(nodeName) == boneNameMapping.end()) {
|
||||||
LOG_DEBUG("Node \"%s\" was not a bone", nodeName.c_str());
|
//LOG_DEBUG("Node \"%s\" was not a bone", nodeName.c_str());
|
||||||
} else {
|
} else {
|
||||||
glm::mat4 offsetMatrix;
|
glm::mat4 offsetMatrix;
|
||||||
int ID = boneNameMapping[nodeName];
|
int ID = boneNameMapping[nodeName];
|
||||||
|
|||||||
@@ -15,49 +15,87 @@ void RenderQueueFactory::Update(World* world)
|
|||||||
|
|
||||||
glm::mat4 RenderQueueFactory::ModelMatrix(World* world, EntityID entity)
|
glm::mat4 RenderQueueFactory::ModelMatrix(World* world, EntityID entity)
|
||||||
{
|
{
|
||||||
//should really return absolute model matrix based on parents position, scale and orientation
|
glm::vec3 position = AbsolutePosition(world, entity);
|
||||||
//GetAbsolutePosition(World* world, ComponentWrapper transformComponent)
|
glm::quat orientation = AbsoluteOrientation(world, entity);
|
||||||
|
glm::vec3 scale = AbsoluteScale(world, entity);
|
||||||
|
|
||||||
ComponentWrapper transformComponent = world->GetComponent(entity, "Transform");
|
glm::mat4 modelMatrix = glm::translate(glm::mat4(), position) * glm::toMat4(orientation) * glm::scale(scale);
|
||||||
glm::vec3 position = transformComponent["Position"];
|
|
||||||
glm::vec3 scale = transformComponent["Scale"];
|
|
||||||
glm::quat oritentation = transformComponent["Orientation"];
|
|
||||||
|
|
||||||
glm::mat4 modelMatrix = glm::translate(glm::mat4(), position) * glm::toMat4(oritentation) * glm::scale(scale);
|
|
||||||
return modelMatrix;
|
return modelMatrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 GetAbsolutePosition(World* world, ComponentWrapper transformComponent)
|
|
||||||
|
glm::vec3 RenderQueueFactory::AbsolutePosition(World* world, EntityID entity)
|
||||||
{
|
{
|
||||||
// positionComponent.EntityID
|
glm::vec3 position;
|
||||||
return glm::vec3();
|
|
||||||
|
do {
|
||||||
|
ComponentWrapper transform = world->GetComponent(entity, "Transform");
|
||||||
|
position += AbsoluteOrientation(world, entity) * (glm::vec3)transform["Position"];
|
||||||
|
entity = world->GetParent(entity);
|
||||||
|
} 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)
|
||||||
|
{
|
||||||
|
ComponentWrapper transform = world->GetComponent(entity, "Transform");
|
||||||
|
glm::vec3 scale = (glm::vec3)transform["Scale"];
|
||||||
|
|
||||||
|
EntityID parent = world->GetParent(entity);
|
||||||
|
if (parent != 0) {
|
||||||
|
return AbsoluteScale(world, parent) * scale;
|
||||||
|
} else {
|
||||||
|
return scale;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderQueueFactory::FillModels(World* world, RenderQueue* renderQueue)
|
void RenderQueueFactory::FillModels(World* world, RenderQueue* renderQueue)
|
||||||
{
|
{
|
||||||
for(auto& modelC : world->GetComponents("Model")) {
|
auto models = world->GetComponents("Model");
|
||||||
ModelJob job;
|
if (models == nullptr) {
|
||||||
std::string resource = modelC["Resource"];
|
return;
|
||||||
glm::vec4 color = modelC["Color"];
|
}
|
||||||
Model* model = ResourceManager::Load<Model>(resource);
|
|
||||||
|
|
||||||
for (auto texGroup : model->TextureGroups) {
|
for (auto& modelC : *models) {
|
||||||
job.TextureID = (texGroup.Texture) ? texGroup.Texture->ResourceID : 0;
|
std::string resource = modelC["Resource"];
|
||||||
job.DiffuseTexture = texGroup.Texture.get();
|
if (resource.empty()) {
|
||||||
job.NormalTexture = texGroup.NormalMap.get();
|
continue;
|
||||||
job.SpecularTexture = texGroup.SpecularMap.get();
|
}
|
||||||
job.Model = model;
|
glm::vec4 color = modelC["Color"];
|
||||||
job.StartIndex = texGroup.StartIndex;
|
Model* model = ResourceManager::Load<Model>(resource);
|
||||||
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
|
for (auto texGroup : model->TextureGroups) {
|
||||||
job.Entity = modelC.EntityID;
|
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;
|
||||||
|
|
||||||
renderQueue->Add(job);
|
//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)
|
void RenderQueueFactory::FillLights(World* world, RenderQueue* renderQueue)
|
||||||
|
|||||||
+43
-13
@@ -1,12 +1,11 @@
|
|||||||
#include "Game.h"
|
#include "Game.h"
|
||||||
#include "HardcodedTestWorld.h"
|
|
||||||
#include "Core/OctTree.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");
|
||||||
|
|
||||||
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));
|
||||||
@@ -36,21 +35,26 @@ Game::Game(int argc, char* argv[])
|
|||||||
m_FrameStack->Width = m_Renderer->Resolution().Width;
|
m_FrameStack->Width = m_Renderer->Resolution().Width;
|
||||||
m_FrameStack->Height = m_Renderer->Resolution().Height;
|
m_FrameStack->Height = m_Renderer->Resolution().Height;
|
||||||
|
|
||||||
// Create a TEST WORLD
|
// Create a world
|
||||||
m_World = new HardcodedTestWorld();
|
m_World = new World();
|
||||||
|
std::string mapToLoad = m_Config->Get<std::string>("Debug.LoadMap", "");
|
||||||
//WTODO: Current worldsize is temp.
|
if (!mapToLoad.empty()) {
|
||||||
glm::vec3 worldSize = glm::vec3(50, 50, 50);
|
ResourceManager::Load<EntityXMLFile>(mapToLoad)->PopulateWorld(m_World);
|
||||||
m_OctTree = new OctTree(AABB(-0.5f*worldSize, 0.5f*worldSize), 2);
|
}
|
||||||
|
|
||||||
|
// Create system pipeline
|
||||||
|
m_SystemPipeline = new SystemPipeline(m_EventBroker);
|
||||||
|
m_SystemPipeline->AddSystem<RaptorCopterSystem>();
|
||||||
|
|
||||||
m_LastTime = glfwGetTime();
|
m_LastTime = glfwGetTime();
|
||||||
|
|
||||||
|
testIntialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
Game::~Game()
|
Game::~Game()
|
||||||
{
|
{
|
||||||
delete m_FrameStack;
|
delete m_FrameStack;
|
||||||
delete m_EventBroker;
|
delete m_EventBroker;
|
||||||
delete m_OctTree;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::Tick()
|
void Game::Tick()
|
||||||
@@ -62,13 +66,13 @@ void Game::Tick()
|
|||||||
m_EventBroker->Swap();
|
m_EventBroker->Swap();
|
||||||
m_InputManager->Update(dt);
|
m_InputManager->Update(dt);
|
||||||
m_Renderer->Update(dt);
|
m_Renderer->Update(dt);
|
||||||
|
|
||||||
m_OctTree->Update(dt, m_World, m_Renderer->Camera());
|
|
||||||
|
|
||||||
m_EventBroker->Swap();
|
m_EventBroker->Swap();
|
||||||
|
|
||||||
m_RenderQueueFactory->Update(m_World);
|
// Iterate through systems and update world!
|
||||||
|
m_SystemPipeline->Update(m_World, dt);
|
||||||
|
testTick(dt);
|
||||||
|
|
||||||
|
m_RenderQueueFactory->Update(m_World);
|
||||||
m_Renderer->Draw(m_RenderQueueFactory->RenderQueues());
|
m_Renderer->Draw(m_RenderQueueFactory->RenderQueues());
|
||||||
|
|
||||||
m_EventBroker->Swap();
|
m_EventBroker->Swap();
|
||||||
@@ -76,3 +80,29 @@ void Game::Tick()
|
|||||||
|
|
||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Game::testOnKeyUp(const Events::KeyUp& e)
|
||||||
|
{
|
||||||
|
if (e.KeyCode == GLFW_KEY_R) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::testIntialize()
|
||||||
|
{
|
||||||
|
EVENT_SUBSCRIBE_MEMBER(m_EKeyUp, &Game::testOnKeyUp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::testTick(double dt)
|
||||||
|
{
|
||||||
|
m_EventBroker->Process<Game>();
|
||||||
|
}
|
||||||
|
|||||||
@@ -45,4 +45,24 @@ BOOST_AUTO_TEST_CASE(octTreeTest2)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(octSameRegionTest)
|
||||||
|
{
|
||||||
|
glm::vec3 mini = glm::vec3(-1, -1, -1);
|
||||||
|
glm::vec3 maxi = glm::vec3(1, 1, 1);
|
||||||
|
OctTree tree(AABB(mini, maxi), 2);
|
||||||
|
AABB firstQuadrant(mini, 0.8f*mini);
|
||||||
|
tree.AddStaticObject(firstQuadrant);
|
||||||
|
AABB testBox(0.9f*mini, 0.8f*mini);
|
||||||
|
std::vector<AABB> region;
|
||||||
|
tree.BoxesInSameRegion(testBox, region);
|
||||||
|
BOOST_REQUIRE(region.size() == 1);
|
||||||
|
AABB& box = region[0];
|
||||||
|
BOOST_CHECK_CLOSE_FRACTION(box.Center().x, firstQuadrant.Center().x, 0.00001f);
|
||||||
|
BOOST_CHECK_CLOSE_FRACTION(box.Center().y, firstQuadrant.Center().y, 0.00001f);
|
||||||
|
BOOST_CHECK_CLOSE_FRACTION(box.Center().z, firstQuadrant.Center().z, 0.00001f);
|
||||||
|
BOOST_CHECK_CLOSE_FRACTION(box.HalfSize().x, firstQuadrant.HalfSize().x, 0.00001f);
|
||||||
|
BOOST_CHECK_CLOSE_FRACTION(box.HalfSize().y, firstQuadrant.HalfSize().y, 0.00001f);
|
||||||
|
BOOST_CHECK_CLOSE_FRACTION(box.HalfSize().z, firstQuadrant.HalfSize().z, 0.00001f);
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ BOOST_AUTO_TEST_CASE(WorldTestMultipleAllocations, * utf::tolerance(0.00001))
|
|||||||
|
|
||||||
// Loop through them and check data
|
// Loop through them and check data
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (auto& c : w.GetComponents("Test")) {
|
for (auto& c : *w.GetComponents("Test")) {
|
||||||
BOOST_TEST((int)c["TestInteger"] == i);
|
BOOST_TEST((int)c["TestInteger"] == i);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user