@@ -0,0 +1,18 @@
|
||||
#include "Collision/CollidableOctreeSystem.h"
|
||||
|
||||
void CollidableOctreeSystem::Update(World* world, double dt)
|
||||
{
|
||||
m_Octree->ClearDynamicObjects();
|
||||
}
|
||||
|
||||
void CollidableOctreeSystem::UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt)
|
||||
{
|
||||
if (entity.HasComponent("AABB")) {
|
||||
boost::optional<AABB> absoluteAABB = Collision::EntityAbsoluteAABB(entity);
|
||||
if (absoluteAABB) {
|
||||
m_Octree->AddDynamicObject(*absoluteAABB);
|
||||
}
|
||||
} else if (entity.HasComponent("Model")) {
|
||||
// TODO: Derive AABB from model
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ bool RayAABBIntr(const Ray& ray, const AABB& box)
|
||||
{
|
||||
glm::vec3 w = 75.0f * ray.Direction();
|
||||
glm::vec3 v = glm::abs(w);
|
||||
glm::vec3 c = ray.Origin() - box.Center() + w;
|
||||
glm::vec3 c = ray.Origin() - box.Origin() + w;
|
||||
glm::vec3 half = box.HalfSize();
|
||||
|
||||
if (abs(c.x) > v.x + half.x) {
|
||||
@@ -68,8 +68,8 @@ bool RayVsAABB(const Ray& ray, const AABB& box, float& outDistance)
|
||||
|
||||
bool AABBVsAABB(const AABB& a, const AABB& b)
|
||||
{
|
||||
const glm::vec3& aCenter = a.Center();
|
||||
const glm::vec3& bCenter = b.Center();
|
||||
const glm::vec3& aCenter = a.Origin();
|
||||
const glm::vec3& bCenter = b.Origin();
|
||||
const glm::vec3& aHSize = a.HalfSize();
|
||||
const glm::vec3& bHSize = b.HalfSize();
|
||||
//Test will probably exit because of the X and Z axes more often, so test them first.
|
||||
@@ -199,11 +199,51 @@ bool RayVsModel(const Ray& ray,
|
||||
return hit;
|
||||
}
|
||||
|
||||
bool AABBvsTriangles(const AABB& box, const std::vector<RawModel::Vertex>& modelVertices, const std::vector<unsigned int>& modelIndices, const glm::mat4& modelMatrix, glm::vec3& outResolutionVector)
|
||||
{
|
||||
bool hit = false;
|
||||
|
||||
const glm::vec3& origin = box.Origin();
|
||||
const glm::vec3& min = box.MinCorner();
|
||||
const glm::vec3& max = box.MaxCorner();
|
||||
|
||||
outResolutionVector.x = INFINITY;
|
||||
|
||||
for (int i = 0; i < modelIndices.size(); ++i) {
|
||||
glm::vec3 p = modelVertices[i].Position;
|
||||
p = glm::vec3(modelMatrix * glm::vec4(p.x, p.y, p.z, 1));
|
||||
|
||||
float distFromOrigin = glm::abs(origin.x - p.x);
|
||||
float penetration = box.HalfSize().x - distFromOrigin;
|
||||
if (penetration > 0 && penetration < glm::abs(outResolutionVector.x)) {
|
||||
if (p.x > origin.x) {
|
||||
outResolutionVector.x = -penetration;
|
||||
} else {
|
||||
outResolutionVector.x = penetration;
|
||||
}
|
||||
hit = true;
|
||||
}
|
||||
//glm::vec3 pLocal = origin - p;
|
||||
//for (int axis = 0; axis < 3; ++axis) {
|
||||
// if (p[axis] < min[axis] || p[axis] > max[axis]) {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// if (glm::abs(pLocal[axis]) < box.HalfSize()[axis]) {
|
||||
// outResolutionVector[axis] = (glm::sign(pLocal[axis]) * box.HalfSize()[axis]) - pLocal[axis];
|
||||
// hit = true;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
return hit;
|
||||
}
|
||||
|
||||
bool IsSameBoxProbably(const AABB& first, const AABB& second, const float epsilon)
|
||||
{
|
||||
const glm::vec3& ma1 = first.MaxCorner();
|
||||
const glm::vec3& ma2 = first.MaxCorner();
|
||||
const glm::vec3& mi1 = second.MinCorner();
|
||||
const glm::vec3& ma2 = second.MaxCorner();
|
||||
const glm::vec3& mi1 = first.MinCorner();
|
||||
const glm::vec3& mi2 = second.MinCorner();
|
||||
return (std::abs(ma1.x - ma2.x) < epsilon) &&
|
||||
(std::abs(mi1.x - mi2.x) < epsilon) &&
|
||||
@@ -238,45 +278,23 @@ bool attachAABBComponentFromModel(World* world, EntityID id)
|
||||
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;
|
||||
collision["Origin"] = 0.5f * (maxi + mini);
|
||||
collision["Size"] = maxi - mini;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetEntityBox(World* world, ComponentWrapper& AABBComponent, AABB& outBox)
|
||||
boost::optional<AABB> EntityAbsoluteAABB(EntityWrapper& entity)
|
||||
{
|
||||
ComponentWrapper& cTrans = world->GetComponent(AABBComponent.EntityID, "Transform");
|
||||
ComponentWrapper model = world->GetComponent(AABBComponent.EntityID, "Model");
|
||||
Model* modelRes = ResourceManager::Load<Model>(model["Resource"]);
|
||||
outBox.CreateFromCenter(AABBComponent["BoxCenter"], AABBComponent["BoxSize"]);
|
||||
glm::vec3 mini = outBox.MinCorner();
|
||||
glm::vec3 maxi = outBox.MaxCorner();
|
||||
|
||||
if (modelRes == nullptr) {
|
||||
return false;
|
||||
}
|
||||
glm::mat4 modelMatrix = modelRes->Matrix() *
|
||||
glm::translate(glm::mat4(), (glm::vec3)cTrans["Position"]) *
|
||||
glm::scale((glm::vec3)cTrans["Scale"]);
|
||||
|
||||
outBox = AABB(modelMatrix * glm::vec4(mini.x, mini.y, mini.z, 1),
|
||||
modelMatrix * glm::vec4(maxi.x, maxi.y, maxi.z, 1));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetEntityBox(World* world, EntityID entity, AABB& outBox, bool forceBoxFromModel)
|
||||
{
|
||||
if (!world->HasComponent(entity, "AABB")) {
|
||||
if (forceBoxFromModel) {
|
||||
if (!attachAABBComponentFromModel(world, entity))
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (!entity.HasComponent("AABB")) {
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
ComponentWrapper& cBox = world->GetComponent(entity, "AABB");
|
||||
return GetEntityBox(world, cBox, outBox);
|
||||
ComponentWrapper& cAABB = entity["AABB"];
|
||||
glm::vec3 absPosition = Transform::AbsolutePosition(entity.World, entity.ID);
|
||||
glm::vec3 absScale = Transform::AbsoluteScale(entity.World, entity.ID);
|
||||
glm::vec3 origin = absPosition + (glm::vec3)cAABB["Origin"];
|
||||
glm::vec3 size = (glm::vec3)cAABB["Size"] * absScale;
|
||||
return AABB::FromOriginSize(origin, size);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,33 +2,60 @@
|
||||
#include "Collision/CollisionSystem.h"
|
||||
#include "Core/AABB.h"
|
||||
|
||||
void CollisionSystem::UpdateComponent(World * world, ComponentWrapper & cAABB, double dt)
|
||||
void CollisionSystem::UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt)
|
||||
{
|
||||
//Right now, cAABB is a component attached to any entity that should be collideable.
|
||||
AABB thisBox;
|
||||
if (!Collision::GetEntityBox(world, cAABB, thisBox)) {
|
||||
if (!entity.HasComponent("Physics")) {
|
||||
return;
|
||||
}
|
||||
ComponentWrapper& cPhysics = entity["Physics"];
|
||||
|
||||
boost::optional<AABB> boundingBox = Collision::EntityAbsoluteAABB(entity);
|
||||
if (!boundingBox) {
|
||||
return;
|
||||
}
|
||||
ComponentWrapper& cTransform = entity["Transform"];
|
||||
AABB& boxA = *boundingBox;
|
||||
|
||||
//Press 'Z' to enable/disable collision.
|
||||
if (zPress) {
|
||||
return;
|
||||
}
|
||||
//Here, mover should be an object that moves, currently only players.
|
||||
for (auto& mover : *world->GetComponents("Player")) {
|
||||
if (cAABB.EntityID == mover.EntityID) {
|
||||
|
||||
// Collide against octree
|
||||
std::vector<AABB> octreeResult;
|
||||
m_Octree->BoxesInSameRegion(*boundingBox, octreeResult);
|
||||
for (auto& boxB : octreeResult) {
|
||||
glm::vec3 resolutionVector;
|
||||
if (Collision::IsSameBoxProbably(boxA, boxB)) {
|
||||
continue;
|
||||
}
|
||||
AABB otherBox;
|
||||
if (!Collision::GetEntityBox(world, mover.EntityID, otherBox)) {
|
||||
continue;
|
||||
}
|
||||
glm::vec3 resolveTranslation;
|
||||
if (Collision::AABBVsAABB(otherBox, thisBox, resolveTranslation)) {
|
||||
ComponentWrapper& trans = world->GetComponent(mover.EntityID, "Transform");
|
||||
//TODO: Special treatment if both are movers.
|
||||
trans["Position"] = (glm::vec3)trans["Position"] + resolveTranslation;
|
||||
if (Collision::AABBVsAABB(boxA, boxB, resolutionVector)) {
|
||||
(glm::vec3&)cTransform["Position"] += resolutionVector;
|
||||
cPhysics["Velocity"] = glm::vec3(0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// HACK: Temporarily collide against all collidable models since they're not in the octree yet
|
||||
//auto otherCollidables = world->GetComponents("Model");
|
||||
//for (auto& cModel : *otherCollidables) {
|
||||
// if (cModel.EntityID == entity) {
|
||||
// continue;
|
||||
// }
|
||||
// if (!world->HasComponent(cModel.EntityID, "Collidable")) {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// auto absPosition = RenderQueueFactory::AbsolutePosition(world, cModel.EntityID);
|
||||
// auto absOrientation = RenderQueueFactory::AbsoluteOrientation(world, cModel.EntityID);
|
||||
// auto absScale = RenderQueueFactory::AbsoluteScale(world, cModel.EntityID);
|
||||
// glm::mat4 modelMatrix = glm::translate(absPosition); // *glm::toMat4(absOrientation) * glm::scale(absScale);
|
||||
|
||||
// auto model = ResourceManager::Load<Model>(cModel["Resource"]);
|
||||
// glm::vec3 resolutionVector;
|
||||
// if (Collision::AABBvsTriangles(boxA, model->m_Vertices, model->m_Indices, modelMatrix, resolutionVector)) {
|
||||
// (glm::vec3&)cTransform["Position"] += resolutionVector;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
bool CollisionSystem::OnKeyUp(const Events::KeyUp & event)
|
||||
|
||||
@@ -3,27 +3,27 @@
|
||||
#include "Core/AABB.h"
|
||||
#include "Rendering/Model.h"
|
||||
|
||||
void TriggerSystem::UpdateComponent(World* world, ComponentWrapper& trigger, double dt)
|
||||
void TriggerSystem::UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt)
|
||||
{
|
||||
//Currently only players can trigger things.
|
||||
auto players = world->GetComponents("Player");
|
||||
if (players == nullptr) {
|
||||
return;
|
||||
}
|
||||
EntityID tId = trigger.EntityID;
|
||||
AABB triggerBox;
|
||||
EntityID tId = component.EntityID;
|
||||
boost::optional<AABB> triggerBox = Collision::EntityAbsoluteAABB(entity);
|
||||
//The trigger *should* have a bounding box, or something, to test against so it can be triggered.
|
||||
if (!Collision::GetEntityBox(world, tId, triggerBox, true)) {
|
||||
if (!triggerBox) {
|
||||
return;
|
||||
}
|
||||
for (auto& pc : *players) {
|
||||
EntityID pId = pc.EntityID;
|
||||
AABB playerBox;
|
||||
boost::optional<AABB> playerBox = Collision::EntityAbsoluteAABB(EntityWrapper(world, pId));
|
||||
//The player can't trigger anything without an AABB.
|
||||
if (!Collision::GetEntityBox(world, pId, playerBox, true)) {
|
||||
if (!playerBox) {
|
||||
continue;
|
||||
}
|
||||
if (!Collision::AABBVsAABB(triggerBox, playerBox)) {
|
||||
if (!Collision::AABBVsAABB(*triggerBox, *playerBox)) {
|
||||
//Entity is not touching the trigger,
|
||||
//Throw event if it was previously.
|
||||
if (throwLeaveIfWasInTrigger(m_EntitiesTouchingTrigger[tId], pId, tId)) {
|
||||
@@ -34,10 +34,9 @@ void TriggerSystem::UpdateComponent(World* world, ComponentWrapper& trigger, dou
|
||||
throwLeaveIfWasInTrigger(m_EntitiesCompletelyInTrigger[tId], pId, tId);
|
||||
} else {
|
||||
//Entity is at least touching the trigger.
|
||||
AABB completelyInsideBox;
|
||||
completelyInsideBox.CreateFromCenter(triggerBox.Center(), triggerBox.Size() - 2.0f * playerBox.Size());
|
||||
if (Collision::AABBVsAABB(completelyInsideBox, playerBox) &&
|
||||
glm::all(glm::greaterThan(triggerBox.Size(), playerBox.Size()))) {
|
||||
AABB completelyInsideBox = AABB::FromOriginSize((*triggerBox).Origin(), (*triggerBox).Size() - 2.0f * (*playerBox).Size());
|
||||
if (Collision::AABBVsAABB(completelyInsideBox, *playerBox) &&
|
||||
glm::all(glm::greaterThan((*triggerBox).Size(), (*playerBox).Size()))) {
|
||||
//Entity is completely inside the trigger.
|
||||
//If it was only touching before, it is erased.
|
||||
m_EntitiesTouchingTrigger[tId].erase(pId);
|
||||
@@ -79,3 +78,20 @@ bool TriggerSystem::throwLeaveIfWasInTrigger(std::unordered_set<EntityID>& trigg
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TriggerSystem::OnTouch(const Events::TriggerTouch &event)
|
||||
{
|
||||
LOG_INFO("Player entity %i touched trigger entity %i.", event.Entity, event.Trigger);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TriggerSystem::OnEnter(const Events::TriggerEnter &event)
|
||||
{
|
||||
LOG_INFO("Player entity %i entered trigger entity %i.", event.Entity, event.Trigger);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TriggerSystem::OnLeave(const Events::TriggerLeave &event)
|
||||
{
|
||||
LOG_INFO("Player entity %i left trigger entity %i.", event.Entity, event.Trigger);
|
||||
return true;
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
AABB::AABB(const glm::vec3& minPos, const glm::vec3& maxPos)
|
||||
: m_MinCorner(minPos)
|
||||
, m_MaxCorner(maxPos)
|
||||
, m_Center(0.5f * (maxPos + minPos))
|
||||
, m_Origin(0.5f * (maxPos + minPos))
|
||||
, m_HalfSize(0.5f * (maxPos - minPos))
|
||||
{
|
||||
DEBUG_IF(glm::any(glm::lessThan(m_MaxCorner, m_MinCorner))) {
|
||||
@@ -20,15 +20,12 @@ AABB::AABB(const glm::vec3& minPos, const glm::vec3& maxPos)
|
||||
|
||||
AABB::AABB(const glm::vec4& minPos, const glm::vec4& maxPos)
|
||||
: AABB(glm::vec3(minPos), glm::vec3(maxPos))
|
||||
{}
|
||||
{ }
|
||||
|
||||
void AABB::CreateFromCenter(const glm::vec3& center, const glm::vec3& size)
|
||||
AABB AABB::FromOriginSize(const glm::vec3& origin, const glm::vec3& size)
|
||||
{
|
||||
m_Center = center;
|
||||
m_HalfSize = 0.5f * size;
|
||||
m_MinCorner = m_Center - m_HalfSize;
|
||||
m_MaxCorner = m_Center + m_HalfSize;
|
||||
return AABB(origin - (size/2.f), origin + (size/2.f));
|
||||
}
|
||||
|
||||
AABB::~AABB()
|
||||
{}
|
||||
{ }
|
||||
|
||||
@@ -21,14 +21,24 @@ void EntityFile::Parse(const EntityFileHandler* handler) const
|
||||
using namespace xercesc;
|
||||
|
||||
EntityFileSAXHandler saxHandler(handler, nullptr);
|
||||
m_SAX2XMLReader->setFeature(XMLUni::fgXercesCacheGrammarFromParse, true);
|
||||
m_SAX2XMLReader->setFeature(XMLUni::fgXercesUseCachedGrammarInParse, true);
|
||||
setReaderFeatures(m_SAX2XMLReader);
|
||||
m_SAX2XMLReader->setContentHandler(&saxHandler);
|
||||
m_SAX2XMLReader->setErrorHandler(&saxHandler);
|
||||
m_SAX2XMLReader->setDeclarationHandler(&saxHandler);
|
||||
m_SAX2XMLReader->parse(m_FilePath.string().c_str());
|
||||
}
|
||||
|
||||
void EntityFile::setReaderFeatures(xercesc::SAX2XMLReader* reader)
|
||||
{
|
||||
using namespace xercesc;
|
||||
reader->setFeature(XMLUni::fgXercesCacheGrammarFromParse, true);
|
||||
reader->setFeature(XMLUni::fgXercesUseCachedGrammarInParse, true);
|
||||
reader->setFeature(XMLUni::fgSAX2CoreValidation, true);
|
||||
reader->setFeature(XMLUni::fgSAX2CoreNameSpaces, true);
|
||||
reader->setFeature(XMLUni::fgXercesSchema, true);
|
||||
reader->setFeature(XMLUni::fgXercesSchemaFullChecking, true);
|
||||
}
|
||||
|
||||
std::size_t EntityFile::GetTypeStride(std::string typeName)
|
||||
{
|
||||
std::map<std::string, size_t> typeStrides{
|
||||
@@ -37,6 +47,7 @@ std::size_t EntityFile::GetTypeStride(std::string typeName)
|
||||
{ "float", sizeof(float) },
|
||||
{ "double", sizeof(double) },
|
||||
{ "string", sizeof(std::string) },
|
||||
{ "enum", sizeof(int) },
|
||||
{ "Vector", sizeof(glm::vec3) },
|
||||
{ "Quaternion", sizeof(glm::quat) },
|
||||
{ "Color", sizeof(glm::vec4) }
|
||||
@@ -75,7 +86,7 @@ void EntityFile::WriteAttributeData(char* outData, const ComponentInfo::Field_t&
|
||||
|
||||
void EntityFile::WriteValueData(char* outData, const ComponentInfo::Field_t& field, const char* valueData)
|
||||
{
|
||||
if (field.Type == "int") {
|
||||
if (field.Type == "int" || field.Type == "enum") {
|
||||
int value = boost::lexical_cast<int>(valueData);
|
||||
memcpy(outData, reinterpret_cast<char*>(&value), field.Stride);
|
||||
} else if (field.Type == "float") {
|
||||
@@ -93,3 +104,171 @@ void EntityFile::WriteValueData(char* outData, const ComponentInfo::Field_t& fie
|
||||
LOG_WARNING("Unknown value data type: %s", field.Type.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
EntityFileSAXHandler::EntityFileSAXHandler(const EntityFileHandler* handler, xercesc::SAX2XMLReader* reader) : m_Handler(handler)
|
||||
, m_Reader(reader)
|
||||
{
|
||||
// 0 is imaginary base parent
|
||||
m_EntityStack.push(0);
|
||||
m_StateStack.push(State::Unknown);
|
||||
}
|
||||
|
||||
void EntityFileSAXHandler::startElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname, const xercesc::Attributes& attrs)
|
||||
{
|
||||
std::string name = XS::ToString(_localName);
|
||||
|
||||
if (m_StateStack.top() == State::Unknown || m_StateStack.top() == State::Entity) {
|
||||
if (name == "Entity") {
|
||||
m_StateStack.push(State::Entity);
|
||||
onStartEntity(attrs);
|
||||
return;
|
||||
}
|
||||
if (name == "EntityRef") {
|
||||
onStartEntityRef(attrs);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::string uri = XS::ToString(_uri);
|
||||
if (m_StateStack.top() == State::Entity) {
|
||||
if (uri == "components") {
|
||||
m_StateStack.push(State::Component);
|
||||
onStartComponent(name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_StateStack.top() == State::Component) {
|
||||
m_StateStack.push(State::ComponentField);
|
||||
onStartComponentField(name, attrs);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void EntityFileSAXHandler::endElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname)
|
||||
{
|
||||
std::string name = XS::ToString(_localName);
|
||||
if (m_StateStack.top() == State::Entity) {
|
||||
if (name == "Entity") {
|
||||
m_StateStack.pop();
|
||||
onEndEntity();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::string uri = XS::ToString(_uri);
|
||||
if (m_StateStack.top() == State::Component) {
|
||||
//if (uri == "components") {
|
||||
m_StateStack.pop();
|
||||
onEndComponent(name);
|
||||
return;
|
||||
//}
|
||||
}
|
||||
|
||||
if (m_StateStack.top() == State::ComponentField) {
|
||||
m_StateStack.pop();
|
||||
onEndComponentField(name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void EntityFileSAXHandler::characters(const XMLCh* const chars, const XMLSize_t length)
|
||||
{
|
||||
if (m_StateStack.top() == State::ComponentField) {
|
||||
char* transcoded = xercesc::XMLString::transcode(chars);
|
||||
onFieldData(transcoded);
|
||||
}
|
||||
}
|
||||
|
||||
void EntityFileSAXHandler::fatalError(const xercesc::SAXParseException& e)
|
||||
{
|
||||
XS::ToString s(e.getMessage());
|
||||
LOG_ERROR("SAXParseException: %s", ((std::string)s).c_str());
|
||||
//throw e;
|
||||
}
|
||||
|
||||
void EntityFileSAXHandler::error(const xercesc::SAXParseException& e)
|
||||
{
|
||||
XS::ToString s(e.getMessage());
|
||||
LOG_ERROR("SAXParseException: %s", ((std::string)s).c_str());
|
||||
}
|
||||
|
||||
void EntityFileSAXHandler::warning(const xercesc::SAXParseException& e)
|
||||
{
|
||||
XS::ToString s(e.getMessage());
|
||||
LOG_ERROR("SAXParseException: %s", ((std::string)s).c_str());
|
||||
}
|
||||
|
||||
void EntityFileSAXHandler::onStartEntity(const xercesc::Attributes& attrs)
|
||||
{
|
||||
EntityID parent = m_EntityStack.top();
|
||||
|
||||
if (m_Handler->m_OnStartEntityCallback) {
|
||||
std::string name;
|
||||
auto xName = attrs.getValue(XS::ToXMLCh("name"));
|
||||
if (xName != nullptr) {
|
||||
name = XS::ToString(xName);
|
||||
}
|
||||
m_Handler->m_OnStartEntityCallback(m_NextEntityID, parent, name);
|
||||
}
|
||||
|
||||
m_EntityStack.push(m_NextEntityID);
|
||||
m_NextEntityID++;
|
||||
}
|
||||
|
||||
void EntityFileSAXHandler::onEndEntity()
|
||||
{
|
||||
m_EntityStack.pop();
|
||||
}
|
||||
|
||||
void EntityFileSAXHandler::onStartEntityRef(const xercesc::Attributes& attrs)
|
||||
{
|
||||
std::string path = XS::ToString(attrs.getValue(XS::ToXMLCh("file")));
|
||||
|
||||
xercesc::SAX2XMLReader* reader = xercesc::XMLReaderFactory::createXMLReader();
|
||||
EntityFile::setReaderFeatures(reader);
|
||||
reader->setContentHandler(this);
|
||||
reader->setErrorHandler(this);
|
||||
reader->parse(path.c_str());
|
||||
delete reader;
|
||||
}
|
||||
|
||||
void EntityFileSAXHandler::onStartComponentField(const std::string& field, const xercesc::Attributes& attrs)
|
||||
{
|
||||
//LOG_DEBUG(" Field: %s", field.c_str());
|
||||
m_CurrentField = field;
|
||||
m_CurrentAttributes.clear();
|
||||
for (int i = 0; i < attrs.getLength(); i++) {
|
||||
auto name = attrs.getQName(i);
|
||||
auto value = attrs.getValue(name);
|
||||
//LOG_DEBUG(" %s = %s", (char*)XS::ToString(name), (char*)XS::ToString(value));
|
||||
m_CurrentAttributes[XS::ToString(name).operator std::string()] = XS::ToString(value).operator std::string();
|
||||
}
|
||||
|
||||
if (m_Handler->m_OnStartFieldCallback) {
|
||||
m_Handler->m_OnStartFieldCallback(m_EntityStack.top(), m_CurrentComponent, field, m_CurrentAttributes);
|
||||
}
|
||||
}
|
||||
|
||||
void EntityFileSAXHandler::onEndComponent(const std::string& name) { }
|
||||
|
||||
void EntityFileSAXHandler::onStartComponent(const std::string& name)
|
||||
{
|
||||
//LOG_DEBUG(" Component: %s", name.c_str());
|
||||
m_CurrentComponent = name;
|
||||
if (m_Handler->m_OnStartComponentCallback) {
|
||||
m_Handler->m_OnStartComponentCallback(m_EntityStack.top(), name);
|
||||
}
|
||||
}
|
||||
|
||||
void EntityFileSAXHandler::onEndComponentField(const std::string& field) { }
|
||||
|
||||
void EntityFileSAXHandler::onFieldData(char* data)
|
||||
{
|
||||
//LOG_DEBUG(" Data: %s", data);
|
||||
if (m_Handler->m_OnStartFieldDataCallback) {
|
||||
m_Handler->m_OnStartFieldDataCallback(m_EntityStack.top(), m_CurrentComponent, m_CurrentField, data);
|
||||
}
|
||||
|
||||
xercesc::XMLString::release(&data);
|
||||
}
|
||||
|
||||
@@ -9,17 +9,21 @@ EntityFileParser::EntityFileParser(const EntityFile* entityFile)
|
||||
m_Handler.SetStartFieldDataCallback(std::bind(&EntityFileParser::onFieldData, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
|
||||
}
|
||||
|
||||
void EntityFileParser::MergeEntities(World* world)
|
||||
EntityID EntityFileParser::MergeEntities(World* world, EntityID baseParent /*= EntityID_Invalid */)
|
||||
{
|
||||
m_World = world;
|
||||
m_EntityIDMapper[0] = 0;
|
||||
m_EntityIDMapper[0] = baseParent;
|
||||
m_EntityFile->Parse(&m_Handler);
|
||||
return m_FirstEntity;
|
||||
}
|
||||
|
||||
void EntityFileParser::onStartEntity(EntityID entity, EntityID parent, const std::string& name)
|
||||
{
|
||||
EntityID realParent = m_EntityIDMapper.at(parent);
|
||||
EntityID realEntity = m_World->CreateEntity(realParent);
|
||||
if (m_FirstEntity == EntityID_Invalid) {
|
||||
m_FirstEntity = realEntity;
|
||||
}
|
||||
if (!name.empty()) {
|
||||
m_World->SetName(realEntity, name);
|
||||
}
|
||||
@@ -38,7 +42,12 @@ void EntityFileParser::onStartComponentField(EntityID entity, const std::string&
|
||||
{
|
||||
EntityID realEntity = m_EntityIDMapper.at(entity);
|
||||
ComponentWrapper component = m_World->GetComponent(realEntity, componentType);
|
||||
auto& field = component.Info.Fields.at(fieldName);
|
||||
auto fieldIt = component.Info.Fields.find(fieldName);
|
||||
if (fieldIt == component.Info.Fields.end()) {
|
||||
LOG_ERROR("Tried to set unknown field \"%s\" of component type \"%s\"! Ignoring.", fieldName.c_str(), componentType.c_str());
|
||||
return;
|
||||
}
|
||||
auto& field = fieldIt->second;
|
||||
|
||||
LOG_DEBUG("Field \"%s\" type \"%s\"", fieldName.c_str(), field.Type.c_str());
|
||||
LOG_DEBUG("Attributes:");
|
||||
@@ -54,7 +63,11 @@ void EntityFileParser::onFieldData(EntityID entity, const std::string& component
|
||||
{
|
||||
EntityID realEntity = m_EntityIDMapper.at(entity);
|
||||
ComponentWrapper component = m_World->GetComponent(realEntity, componentType);
|
||||
auto& field = component.Info.Fields.at(fieldName);
|
||||
auto fieldIt = component.Info.Fields.find(fieldName);
|
||||
if (fieldIt == component.Info.Fields.end()) {
|
||||
return;
|
||||
}
|
||||
auto& field = fieldIt->second;
|
||||
|
||||
char* data = component.Data + field.Offset;
|
||||
EntityFile::WriteValueData(data, field, fieldData);
|
||||
|
||||
@@ -16,12 +16,12 @@ EntityFilePreprocessor::EntityFilePreprocessor(const EntityFile* entityFile)
|
||||
|
||||
for (auto& kv : m_ComponentInfo) {
|
||||
auto& info = kv.second;
|
||||
LOG_DEBUG("Component: %s (%s)", info.Name.c_str(), info.Meta.Annotation.c_str());
|
||||
LOG_DEBUG("Stride: %i", info.Meta.Stride);
|
||||
LOG_DEBUG("Allocation: %i", info.Meta.Allocation);
|
||||
LOG_DEBUG("Component: %s (%s)", info.Name.c_str(), info.Meta->Annotation.c_str());
|
||||
LOG_DEBUG("Stride: %i", info.Stride);
|
||||
LOG_DEBUG("Allocation: %i", info.Meta->Allocation);
|
||||
for (auto& kv : info.Fields) {
|
||||
auto& field = kv.second;
|
||||
LOG_DEBUG("\t%i\t%s %s", field.Offset, field.Type, kv.first.c_str());
|
||||
LOG_DEBUG("\t%i\t%s %s", field.Offset, field.Type.c_str(), kv.first.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,62 +62,36 @@ void EntityFilePreprocessor::parseComponentInfo()
|
||||
}
|
||||
|
||||
ComponentInfo compInfo;
|
||||
compInfo.Meta = std::make_shared<ComponentInfo::Meta_t>();
|
||||
|
||||
// Name
|
||||
compInfo.Name = XS::ToString(element->getName());
|
||||
// Known allocation
|
||||
compInfo.Meta.Allocation = m_ComponentCounts[compInfo.Name];
|
||||
compInfo.Meta->Allocation = m_ComponentCounts[compInfo.Name];
|
||||
// Annotation
|
||||
auto componentAnnotation = element->getAnnotation();
|
||||
if (componentAnnotation != nullptr) {
|
||||
// Parse annotation XML
|
||||
char* annotationString = XMLString::transcode(componentAnnotation->getAnnotationString());
|
||||
MemBufInputSource annotationInput(reinterpret_cast<const XMLByte*>(annotationString), strlen(annotationString), "MemBuf: Annotation String");
|
||||
XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager, grammarPool);
|
||||
parser.setErrorHandler(&errorHandler);
|
||||
parser.parse(annotationInput);
|
||||
XMLString::release(&annotationString);
|
||||
auto doc = parser.getDocument();
|
||||
|
||||
// TODO: Add allocation estimations from external file on map-to-map basis
|
||||
// Add allocation estimation(s)
|
||||
//auto allocationTags = doc->getElementsByTagName(XSTR("meta:allocation"));
|
||||
//for (int i = 0; i < allocationTags->getLength(); ++i) {
|
||||
// auto allocation = dynamic_cast<DOMElement*>(allocationTags->item(i));
|
||||
// auto child = allocation->getFirstChild();
|
||||
// if (child == nullptr) {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// XSValue::Status status;
|
||||
// XSValue* val = XSValue::getActualValue(child->getNodeValue(), XSValue::dt_integer, status);
|
||||
// compInfo.Meta.Allocation += val->fData.fValue.f_int;
|
||||
//}
|
||||
|
||||
// Save documentation string
|
||||
auto documentationTags = doc->getElementsByTagName(XS::ToXMLCh("xs:documentation"));
|
||||
if (documentationTags->getLength() != 0) {
|
||||
auto child = documentationTags->item(0)->getFirstChild();
|
||||
if (child != nullptr) {
|
||||
compInfo.Meta.Annotation = XS::ToString(child->getNodeValue());
|
||||
}
|
||||
}
|
||||
compInfo.Meta->Annotation = parseAnnotationXML(componentAnnotation->getAnnotationString());
|
||||
} else {
|
||||
LOG_WARNING("Component is missing an annotation!");
|
||||
LOG_WARNING("Component \"%s\" is missing an annotation!", compInfo.Name.c_str());
|
||||
}
|
||||
|
||||
// <xs:complexType>
|
||||
auto typeDefinition = element->getTypeDefinition();
|
||||
// Allow empty components
|
||||
if (typeDefinition == nullptr) {
|
||||
continue;
|
||||
}
|
||||
if (typeDefinition->getTypeCategory() != XSTypeDefinition::COMPLEX_TYPE) {
|
||||
LOG_ERROR("Type definition wasn't COMPLEX_TYPE! Skipping.");
|
||||
LOG_ERROR("Failed to parse component definition for \"%s\": Type definition wasn't COMPLEX_TYPE!", compInfo.Name.c_str());
|
||||
continue;
|
||||
}
|
||||
auto complexTypeDefinition = dynamic_cast<XSComplexTypeDefinition*>(typeDefinition);
|
||||
|
||||
// <xs:all>
|
||||
auto modelGroupParticle = complexTypeDefinition->getParticle();
|
||||
if (modelGroupParticle->getTermType() != XSParticle::TERM_MODELGROUP) {
|
||||
LOG_ERROR("Model group particle wasn't TERM_MODELGROUP! Skipping.");
|
||||
if (modelGroupParticle == nullptr || modelGroupParticle->getTermType() != XSParticle::TERM_MODELGROUP) {
|
||||
LOG_ERROR("Failed to parse component definition for \"%s\": Model group particle was null or wasn't TERM_MODELGROUP!", compInfo.Name.c_str());
|
||||
continue;
|
||||
}
|
||||
auto modelGroup = modelGroupParticle->getModelGroupTerm();
|
||||
@@ -129,31 +103,65 @@ void EntityFilePreprocessor::parseComponentInfo()
|
||||
for (unsigned int i = 0; i < particles->size(); ++i) {
|
||||
auto particle = particles->elementAt(i);
|
||||
if (particle->getTermType() != XSParticle::TERM_ELEMENT) {
|
||||
LOG_ERROR("Particle wasn't TERM_ELEMENT! Skipping.");
|
||||
LOG_ERROR("Failed to parse a field definition in component \"%s\": Particle wasn't TERM_ELEMENT! Skipping.", compInfo.Name.c_str());
|
||||
continue;
|
||||
}
|
||||
auto elementDeclaration = particle->getElementTerm();
|
||||
|
||||
std::string name = XS::ToString(elementDeclaration->getName());
|
||||
std::string type = XS::ToString(elementDeclaration->getTypeDefinition()->getName());
|
||||
std::string typeNamespace = XS::ToString(elementDeclaration->getTypeDefinition()->getNamespace());
|
||||
std::string baseType = XS::ToString(elementDeclaration->getTypeDefinition()->getBaseType()->getName());
|
||||
|
||||
std::string effectiveType = type;
|
||||
size_t stride = EntityFile::GetTypeStride(type);
|
||||
if (stride == 0) {
|
||||
std::cout << "Warning: Field \"" << name << "\" in component \"" << compInfo.Name << "\" uses unexpected field type \"" << type << "\". Skipping." << std::endl;
|
||||
continue;
|
||||
stride = EntityFile::GetTypeStride(baseType);
|
||||
if (stride == 0) {
|
||||
LOG_WARNING("Field \"%s\" in component \"%s\" uses unexpected field type \"%s\" with base type \"%s\". Skipping.", name.c_str(), compInfo.Name.c_str(), type.c_str(), baseType.c_str());
|
||||
continue;
|
||||
}
|
||||
effectiveType = baseType;
|
||||
}
|
||||
|
||||
// Annotation
|
||||
auto fieldAnnotation = elementDeclaration->getAnnotation();
|
||||
if (fieldAnnotation != nullptr) {
|
||||
compInfo.Meta->FieldAnnotations[name] = parseAnnotationXML(fieldAnnotation->getAnnotationString());
|
||||
} else {
|
||||
LOG_WARNING("Component field \"%s.%s\" is missing an annotation!", compInfo.Name.c_str(), name.c_str());
|
||||
}
|
||||
|
||||
if (effectiveType == "enum") {
|
||||
// Parse potential enum type definition for field type
|
||||
if (compInfo.Meta->FieldEnumDefinitions.count(name) == 0) {
|
||||
auto enumTypeDefinition = xsModel->getTypeDefinition(XS::ToXMLCh(type), XS::ToXMLCh("components"));
|
||||
auto xsComplexType = dynamic_cast<XSComplexTypeDefinition*>(enumTypeDefinition);
|
||||
auto xsComplexContent = xsComplexType->getParticle();
|
||||
auto xsExtension = xsComplexContent->getModelGroupTerm();
|
||||
auto xsExtensionParticles = xsExtension->getParticles();
|
||||
auto xsChoice = xsExtensionParticles->elementAt(0)->getModelGroupTerm();
|
||||
auto xsChoiceParticles = xsChoice->getParticles();
|
||||
for (int i = 0; i < xsChoiceParticles->size(); ++i) {
|
||||
auto enumElement = xsChoiceParticles->elementAt(i)->getElementTerm();
|
||||
std::string enumName = XS::ToString(enumElement->getName());
|
||||
std::string enumValue = XS::ToString(enumElement->getConstraintValue());
|
||||
compInfo.Meta->FieldEnumDefinitions[name][enumName] = boost::lexical_cast<int>(enumValue);
|
||||
LOG_DEBUG("ENUM %s = %s", enumName.c_str(), enumValue.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto& field = compInfo.Fields[name];
|
||||
field.Name = name;
|
||||
field.Type = type;
|
||||
field.Type = effectiveType;
|
||||
field.Offset = fieldOffset;
|
||||
field.Stride = stride;
|
||||
compInfo.FieldsInOrder.push_back(name);
|
||||
|
||||
fieldOffset += stride;
|
||||
}
|
||||
|
||||
compInfo.Meta.Stride = fieldOffset;
|
||||
compInfo.Stride = fieldOffset;
|
||||
m_ComponentInfo[compInfo.Name] = compInfo;
|
||||
}
|
||||
}
|
||||
@@ -166,13 +174,22 @@ void EntityFilePreprocessor::parseDefaults()
|
||||
|
||||
for (auto& ci : m_ComponentInfo) {
|
||||
// Allocate memory for default values
|
||||
ci.second.Defaults = std::shared_ptr<char>(new char[ci.second.Meta.Stride]);
|
||||
memset(ci.second.Defaults.get(), 0, ci.second.Meta.Stride);
|
||||
|
||||
XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager);
|
||||
parser.setErrorHandler(&errorHandler);
|
||||
ci.second.Defaults = std::shared_ptr<char>(new char[ci.second.Stride]);
|
||||
memset(ci.second.Defaults.get(), 0, ci.second.Stride);
|
||||
|
||||
std::string componentName = ci.first;
|
||||
|
||||
XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager);
|
||||
parser.setDoSchema(true);
|
||||
parser.setDoNamespaces(true);
|
||||
parser.setErrorHandler(&errorHandler);
|
||||
parser.setValidationScheme(XercesDOMParser::Val_Always);
|
||||
parser.setValidationSchemaFullChecking(true);
|
||||
//parser.setDoNamespaces(true);
|
||||
//boost::filesystem::path schemaLocation = "Schema/Components/" + componentName + ".xsd";
|
||||
//std::string namespaceSchema = schemaLocation.string();
|
||||
//parser.setExternalNoNamespaceSchemaLocation("Teamasdasdasdasd.xsd");
|
||||
|
||||
LOG_DEBUG("Parsing defaults for component %s", componentName.c_str());
|
||||
boost::filesystem::path defaultsFile = "Schema/Components/" + componentName + ".xml";
|
||||
|
||||
@@ -184,7 +201,7 @@ void EntityFilePreprocessor::parseDefaults()
|
||||
}
|
||||
|
||||
// Find the node in the components namespace matching the component name
|
||||
std::string tagName = "c:" + componentName;
|
||||
std::string tagName = componentName;
|
||||
auto rootNodes = doc->getElementsByTagName(XS::ToXMLCh(tagName));
|
||||
if (rootNodes->getLength() == 0) {
|
||||
LOG_ERROR("Couldn't find defaults for component \"%s\"! Skipping.", componentName.c_str());
|
||||
@@ -217,9 +234,19 @@ void EntityFilePreprocessor::parseDefaults()
|
||||
EntityFile::WriteAttributeData(data, field, attributes);
|
||||
}
|
||||
|
||||
// Handle potential field values
|
||||
auto childNode = fieldElement->getFirstChild();
|
||||
if (childNode != nullptr && childNode->getNodeType() == DOMNode::TEXT_NODE) {
|
||||
if (childNode == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// An enum will either have an element node with a text node inside,
|
||||
// or contain a text node directly.
|
||||
if (childNode->getNodeType() == DOMNode::ELEMENT_NODE) {
|
||||
childNode = childNode->getFirstChild();
|
||||
}
|
||||
|
||||
// Handle potential field values
|
||||
if (childNode->getNodeType() == DOMNode::TEXT_NODE) {
|
||||
char* cstrValue = XMLString::transcode(childNode->getNodeValue());
|
||||
EntityFile::WriteValueData(data, field, cstrValue);
|
||||
XMLString::release(&cstrValue);
|
||||
@@ -228,3 +255,27 @@ void EntityFilePreprocessor::parseDefaults()
|
||||
}
|
||||
}
|
||||
|
||||
std::string EntityFilePreprocessor::parseAnnotationXML(const XMLCh* xml)
|
||||
{
|
||||
using namespace xercesc;
|
||||
|
||||
// Parse annotation XML
|
||||
char* annotationString = XMLString::transcode(xml);
|
||||
MemBufInputSource annotationInput(reinterpret_cast<const XMLByte*>(annotationString), strlen(annotationString), "MemBuf: Annotation String");
|
||||
XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager);
|
||||
//parser.setErrorHandler(&errorHandler);
|
||||
parser.parse(annotationInput);
|
||||
XMLString::release(&annotationString);
|
||||
auto doc = parser.getDocument();
|
||||
|
||||
// Save documentation string
|
||||
auto documentationTags = doc->getElementsByTagName(XS::ToXMLCh("xs:documentation"));
|
||||
if (documentationTags->getLength() != 0) {
|
||||
auto child = documentationTags->item(0)->getFirstChild();
|
||||
if (child != nullptr) {
|
||||
return XS::ToString(child->getNodeValue());
|
||||
}
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ void EntityFileWriter::appentEntityComponents(xercesc::DOMElement* parentElement
|
||||
fieldElement->setAttribute(X("Y"), X(boost::lexical_cast<std::string>(q.y)));
|
||||
fieldElement->setAttribute(X("Z"), X(boost::lexical_cast<std::string>(q.z)));
|
||||
fieldElement->setAttribute(X("W"), X(boost::lexical_cast<std::string>(q.w)));
|
||||
} else if (field.Type == "int") {
|
||||
} else if (field.Type == "int" || field.Type == "enum") {
|
||||
const int& value = c[fieldName];
|
||||
fieldElement->appendChild(doc->createTextNode(X(boost::lexical_cast<std::string>(value))));
|
||||
} else if (field.Type == "float") {
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
#include "Core/EntityWrapper.h"
|
||||
#include "Core/World.h"
|
||||
|
||||
const EntityWrapper EntityWrapper::Invalid = EntityWrapper(nullptr, EntityID_Invalid);
|
||||
|
||||
bool EntityWrapper::operator==(const EntityWrapper& e)
|
||||
{
|
||||
return (this->World == e.World) && (this->ID == e.ID);
|
||||
}
|
||||
|
||||
bool EntityWrapper::HasComponent(const std::string& componentName)
|
||||
{
|
||||
return World->HasComponent(ID, componentName);
|
||||
}
|
||||
|
||||
ComponentWrapper EntityWrapper::operator[](const std::string& componentName)
|
||||
{
|
||||
if (World->HasComponent(ID, componentName)) {
|
||||
return World->GetComponent(ID, componentName);
|
||||
} else {
|
||||
LOG_WARNING("EntityWrapper implicitly attached \"%s\" component to #%i as a result of a fetch request!", componentName.c_str(), ID);
|
||||
return World->AttachComponent(ID, componentName);
|
||||
}
|
||||
}
|
||||
|
||||
EntityWrapper::operator EntityID()
|
||||
{
|
||||
return this->ID;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include <algorithm>
|
||||
#include <bitset>
|
||||
|
||||
#include "Core/OctTree.h"
|
||||
#include "Core/Octree.h"
|
||||
#include "Collision/Collision.h"
|
||||
|
||||
namespace
|
||||
@@ -21,65 +21,61 @@ bool isFirstLower(const ChildInfo& first, const ChildInfo& second)
|
||||
|
||||
}
|
||||
|
||||
OctTree::OctTree()
|
||||
: OctTree(AABB(), 0)
|
||||
{}
|
||||
|
||||
OctTree::OctTree(const AABB& octTreeBounds, int subDivisions)
|
||||
: m_Root(new OctChild(octTreeBounds, subDivisions, m_StaticObjects, m_DynamicObjects))
|
||||
Octree::Octree(const AABB& octTreeBounds, int subDivisions)
|
||||
: m_Root(new Child(octTreeBounds, subDivisions, m_StaticObjects, m_DynamicObjects))
|
||||
, m_UpdatedOnce(false)
|
||||
{}
|
||||
{ }
|
||||
|
||||
OctTree::~OctTree()
|
||||
Octree::~Octree()
|
||||
{
|
||||
delete m_Root;
|
||||
}
|
||||
|
||||
void OctTree::AddDynamicObject(const AABB& box)
|
||||
void Octree::AddDynamicObject(const AABB& box)
|
||||
{
|
||||
m_Root->AddDynamicObject(box);
|
||||
m_DynamicObjects.push_back(box);
|
||||
}
|
||||
|
||||
void OctTree::AddStaticObject(const AABB& box)
|
||||
void Octree::AddStaticObject(const AABB& box)
|
||||
{
|
||||
m_Root->AddStaticObject(box);
|
||||
m_StaticObjects.push_back(box);
|
||||
}
|
||||
|
||||
void OctTree::BoxesInSameRegion(const AABB& box, std::vector<AABB>& outBoxes)
|
||||
void Octree::BoxesInSameRegion(const AABB& box, std::vector<AABB>& outBoxes)
|
||||
{
|
||||
falsifyObjectChecks();
|
||||
m_Root->BoxesInSameRegion(box, outBoxes);
|
||||
}
|
||||
|
||||
void OctTree::ClearObjects()
|
||||
void Octree::ClearObjects()
|
||||
{
|
||||
m_StaticObjects.clear();
|
||||
m_DynamicObjects.clear();
|
||||
m_Root->ClearObjects();
|
||||
}
|
||||
|
||||
void OctTree::ClearDynamicObjects()
|
||||
void Octree::ClearDynamicObjects()
|
||||
{
|
||||
m_DynamicObjects.clear();
|
||||
m_Root->ClearDynamicObjects();
|
||||
}
|
||||
|
||||
bool OctTree::RayCollides(const Ray& ray, Output& data)
|
||||
bool Octree::RayCollides(const Ray& ray, Output& data)
|
||||
{
|
||||
falsifyObjectChecks();
|
||||
data.CollideDistance = -1;
|
||||
return m_Root->RayCollides(ray, data);
|
||||
}
|
||||
|
||||
bool OctTree::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected)
|
||||
bool Octree::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected)
|
||||
{
|
||||
falsifyObjectChecks();
|
||||
return m_Root->BoxCollides(boxToTest, outBoxIntersected);
|
||||
}
|
||||
|
||||
void OctTree::falsifyObjectChecks()
|
||||
void Octree::falsifyObjectChecks()
|
||||
{
|
||||
for (auto& obj : m_StaticObjects) {
|
||||
obj.Checked = false;
|
||||
@@ -89,7 +85,7 @@ void OctTree::falsifyObjectChecks()
|
||||
}
|
||||
}
|
||||
|
||||
OctTree::OctChild::OctChild(const AABB& octTreeBounds,
|
||||
Octree::Child::Child(const AABB& octTreeBounds,
|
||||
int subDivisions,
|
||||
std::vector<ContainedObject>& staticObjects,
|
||||
std::vector<ContainedObject>& dynamicObjects)
|
||||
@@ -98,7 +94,7 @@ OctTree::OctChild::OctChild(const AABB& octTreeBounds,
|
||||
, m_DynamicObjectsRef(dynamicObjects)
|
||||
{
|
||||
if (subDivisions == 0) {
|
||||
for (OctChild*& c : m_Children) {
|
||||
for (Child*& c : m_Children) {
|
||||
c = nullptr;
|
||||
}
|
||||
} else {
|
||||
@@ -107,7 +103,7 @@ OctTree::OctChild::OctChild(const AABB& octTreeBounds,
|
||||
glm::vec3 minPos, maxPos;
|
||||
const glm::vec3& parentMin = m_Box.MinCorner();
|
||||
const glm::vec3& parentMax = m_Box.MaxCorner();
|
||||
const glm::vec3& parentCenter = m_Box.Center();
|
||||
const glm::vec3& parentCenter = m_Box.Origin();
|
||||
std::bitset<3> bits(i);
|
||||
//If child is 4,5,6,7.
|
||||
if (bits.test(2)) {
|
||||
@@ -134,14 +130,14 @@ OctTree::OctChild::OctChild(const AABB& octTreeBounds,
|
||||
minPos.z = parentMin.z;
|
||||
maxPos.z = parentCenter.z;
|
||||
}
|
||||
m_Children[i] = new OctChild(AABB(minPos, maxPos), subDivisions, m_StaticObjectsRef, m_DynamicObjectsRef);
|
||||
m_Children[i] = new Child(AABB(minPos, maxPos), subDivisions, m_StaticObjectsRef, m_DynamicObjectsRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OctTree::OctChild::~OctChild()
|
||||
Octree::Child::~Child()
|
||||
{
|
||||
for (OctChild*& c : m_Children) {
|
||||
for (Child*& c : m_Children) {
|
||||
if (c != nullptr) {
|
||||
delete c;
|
||||
c = nullptr;
|
||||
@@ -149,7 +145,7 @@ OctTree::OctChild::~OctChild()
|
||||
}
|
||||
}
|
||||
|
||||
bool OctTree::OctChild::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const
|
||||
bool Octree::Child::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const
|
||||
{
|
||||
if (hasChildren()) {
|
||||
for (int i : childIndicesContainingBox(boxToTest)) {
|
||||
@@ -182,7 +178,7 @@ bool OctTree::OctChild::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersect
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OctTree::OctChild::RayCollides(const Ray& ray, Output& data) const
|
||||
bool Octree::Child::RayCollides(const Ray& ray, Output& data) const
|
||||
{
|
||||
//If the node AABB is missed, everything it contains is missed.
|
||||
if (Collision::RayAABBIntr(ray, m_Box)) {
|
||||
@@ -192,7 +188,7 @@ bool OctTree::OctChild::RayCollides(const Ray& ray, Output& data) const
|
||||
std::vector<ChildInfo> childInfos;
|
||||
childInfos.reserve(8);
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
childInfos.push_back({ i, glm::distance(ray.Origin(), m_Children[i]->m_Box.Center()) });
|
||||
childInfos.push_back({ i, glm::distance(ray.Origin(), m_Children[i]->m_Box.Origin()) });
|
||||
}
|
||||
std::sort(childInfos.begin(), childInfos.end(), isFirstLower);
|
||||
//Loop through the children, starting with the one closest to the ray origin. I.e the first to be hit.
|
||||
@@ -234,7 +230,7 @@ bool OctTree::OctChild::RayCollides(const Ray& ray, Output& data) const
|
||||
}
|
||||
|
||||
|
||||
void OctTree::OctChild::AddDynamicObject(const AABB& box)
|
||||
void Octree::Child::AddDynamicObject(const AABB& box)
|
||||
{
|
||||
if (hasChildren()) {
|
||||
for (auto i : childIndicesContainingBox(box)) {
|
||||
@@ -246,7 +242,7 @@ void OctTree::OctChild::AddDynamicObject(const AABB& box)
|
||||
}
|
||||
}
|
||||
|
||||
void OctTree::OctChild::AddStaticObject(const AABB& box)
|
||||
void Octree::Child::AddStaticObject(const AABB& box)
|
||||
{
|
||||
if (hasChildren()) {
|
||||
for (auto i : childIndicesContainingBox(box)) {
|
||||
@@ -258,7 +254,7 @@ void OctTree::OctChild::AddStaticObject(const AABB& box)
|
||||
}
|
||||
}
|
||||
|
||||
void OctTree::OctChild::BoxesInSameRegion(const AABB& box, std::vector<AABB>& outBoxes) const
|
||||
void Octree::Child::BoxesInSameRegion(const AABB& box, std::vector<AABB>& outBoxes) const
|
||||
{
|
||||
if (hasChildren()) {
|
||||
for (auto i : childIndicesContainingBox(box)) {
|
||||
@@ -292,10 +288,10 @@ void OctTree::OctChild::BoxesInSameRegion(const AABB& box, std::vector<AABB>& ou
|
||||
}
|
||||
}
|
||||
|
||||
void OctTree::OctChild::ClearObjects()
|
||||
void Octree::Child::ClearObjects()
|
||||
{
|
||||
if (hasChildren()) {
|
||||
for (OctChild*& c : m_Children) {
|
||||
for (Child*& c : m_Children) {
|
||||
c->ClearObjects();
|
||||
}
|
||||
} else {
|
||||
@@ -304,10 +300,10 @@ void OctTree::OctChild::ClearObjects()
|
||||
}
|
||||
}
|
||||
|
||||
void OctTree::OctChild::ClearDynamicObjects()
|
||||
void Octree::Child::ClearDynamicObjects()
|
||||
{
|
||||
if (hasChildren()) {
|
||||
for (OctChild*& c : m_Children) {
|
||||
for (Child*& c : m_Children) {
|
||||
c->ClearObjects();
|
||||
}
|
||||
} else {
|
||||
@@ -327,13 +323,13 @@ void OctTree::OctChild::ClearDynamicObjects()
|
||||
// x : - - - - + + + +
|
||||
// y : - - + + - - + +
|
||||
// z : - + - + - + - +
|
||||
int OctTree::OctChild::childIndexContainingPoint(const glm::vec3& point) const
|
||||
int Octree::Child::childIndexContainingPoint(const glm::vec3& point) const
|
||||
{
|
||||
const glm::vec3& c = m_Box.Center();
|
||||
const glm::vec3& c = m_Box.Origin();
|
||||
return (1 << 2) * (point.x >= c.x) | (1 << 1) * (point.y >= c.y) | (point.z >= c.z);
|
||||
}
|
||||
|
||||
std::vector<int> OctTree::OctChild::childIndicesContainingBox(const AABB& box) const
|
||||
std::vector<int> Octree::Child::childIndicesContainingBox(const AABB& box) const
|
||||
{
|
||||
int minInd = childIndexContainingPoint(box.MinCorner());
|
||||
int maxInd = childIndexContainingPoint(box.MaxCorner());
|
||||
@@ -371,7 +367,7 @@ std::vector<int> OctTree::OctChild::childIndicesContainingBox(const AABB& box) c
|
||||
}
|
||||
}
|
||||
|
||||
inline bool OctTree::OctChild::hasChildren() const
|
||||
inline bool Octree::Child::hasChildren() const
|
||||
{
|
||||
return m_Children[0] != nullptr;
|
||||
}
|
||||
@@ -66,7 +66,7 @@ void World::RegisterComponent(ComponentInfo& ci)
|
||||
}
|
||||
}
|
||||
|
||||
ComponentWrapper World::AttachComponent(EntityID entity, std::string componentType)
|
||||
ComponentWrapper World::AttachComponent(EntityID entity, const std::string& componentType)
|
||||
{
|
||||
// TODO: Allocate dynamic pool if component isn't registered
|
||||
ComponentPool* pool = m_ComponentPools.at(componentType);
|
||||
@@ -75,31 +75,31 @@ ComponentWrapper World::AttachComponent(EntityID entity, std::string componentTy
|
||||
// Allocate space for the component
|
||||
ComponentWrapper c = pool->Allocate(entity);
|
||||
// Write default values
|
||||
memcpy(c.Data, ci.Defaults.get(), ci.Meta.Stride);
|
||||
memcpy(c.Data, ci.Defaults.get(), ci.Stride);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
bool World::HasComponent(EntityID entity, std::string componentType) const
|
||||
bool World::HasComponent(EntityID entity, const std::string& componentType) const
|
||||
{
|
||||
ComponentPool* pool = m_ComponentPools.at(componentType);
|
||||
return pool->KnowsEntity(entity);
|
||||
}
|
||||
|
||||
ComponentWrapper World::GetComponent(EntityID entity, std::string componentType)
|
||||
ComponentWrapper World::GetComponent(EntityID entity, const std::string& componentType)
|
||||
{
|
||||
ComponentPool* pool = m_ComponentPools.at(componentType);
|
||||
return pool->GetByEntity(entity);
|
||||
}
|
||||
|
||||
void World::DeleteComponent(EntityID entity, std::string componentType)
|
||||
void World::DeleteComponent(EntityID entity, const std::string& componentType)
|
||||
{
|
||||
ComponentPool* pool = m_ComponentPools.at(componentType);
|
||||
ComponentWrapper c = pool->GetByEntity(entity);
|
||||
return pool->Delete(c);
|
||||
}
|
||||
|
||||
const ComponentPool* World::GetComponents(std::string componentType)
|
||||
const ComponentPool* World::GetComponents(const std::string& componentType)
|
||||
{
|
||||
auto it = m_ComponentPools.find(componentType);
|
||||
return (it != m_ComponentPools.end()) ? it->second : nullptr;
|
||||
@@ -125,6 +125,11 @@ void World::SetParent(EntityID entity, EntityID parent)
|
||||
m_EntityChildren.insert(std::make_pair(parent, entity));
|
||||
}
|
||||
|
||||
const std::pair<std::unordered_multimap<EntityID, EntityID>::const_iterator, std::unordered_multimap<EntityID, EntityID>::const_iterator> World::GetChildren(EntityID entity)
|
||||
{
|
||||
return m_EntityChildren.equal_range(entity);
|
||||
}
|
||||
|
||||
void World::SetName(EntityID entity, const std::string& name)
|
||||
{
|
||||
m_EntityNames[entity] = name;
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
#include <imgui/imgui_internal.h>
|
||||
|
||||
EditorSystem::EditorSystem(EventBroker* eventBroker, IRenderer* renderer)
|
||||
: ImpureSystem(eventBroker)
|
||||
: System(eventBroker)
|
||||
, ImpureSystem()
|
||||
, m_Renderer(renderer)
|
||||
{
|
||||
auto config = ResourceManager::Load<ConfigFile>("Config.ini");
|
||||
@@ -483,8 +484,8 @@ void EditorSystem::drawUI(World* world, double dt)
|
||||
}
|
||||
|
||||
if (ImGui::CollapsingHeader(componentType.c_str())) {
|
||||
if (!ci.Meta.Annotation.empty()) {
|
||||
ImGui::Text(ci.Meta.Annotation.c_str());
|
||||
if (!ci.Meta->Annotation.empty()) {
|
||||
ImGui::Text(ci.Meta->Annotation.c_str());
|
||||
}
|
||||
|
||||
auto& component = world->GetComponent(m_Selection, componentType);
|
||||
@@ -492,9 +493,10 @@ void EditorSystem::drawUI(World* world, double dt)
|
||||
const std::string& fieldName = kv.first;
|
||||
auto& field = kv.second;
|
||||
|
||||
ImGui::PushID(fieldName.c_str());
|
||||
std::string uniqueID = componentType + fieldName;
|
||||
ImGui::PushID(uniqueID.c_str());
|
||||
if (field.Type == "Vector") {
|
||||
auto& val = component.Property<glm::vec3>(fieldName);
|
||||
auto& val = component.Field<glm::vec3>(fieldName);
|
||||
if (fieldName == "Scale") {
|
||||
ImGui::DragFloat3("", glm::value_ptr(val), 0.1f, 0.f, std::numeric_limits<float>::max());
|
||||
} else if (fieldName == "Orientation") {
|
||||
@@ -506,10 +508,10 @@ void EditorSystem::drawUI(World* world, double dt)
|
||||
ImGui::DragFloat3("", glm::value_ptr(val), 0.1f, std::numeric_limits<float>::lowest(), std::numeric_limits<float>::max());
|
||||
}
|
||||
} else if (field.Type == "Color") {
|
||||
auto& val = component.Property<glm::vec4>(fieldName);
|
||||
auto& val = component.Field<glm::vec4>(fieldName);
|
||||
ImGui::ColorEdit4("", glm::value_ptr(val), true);
|
||||
} else if (field.Type == "string") {
|
||||
std::string& val = component.Property<std::string>(fieldName);
|
||||
std::string& val = component.Field<std::string>(fieldName);
|
||||
char tempString[1024];
|
||||
memcpy(tempString, val.c_str(), std::min(val.length() + 1, sizeof(tempString)));
|
||||
if (ImGui::InputText("", tempString, sizeof(tempString))) {
|
||||
@@ -523,12 +525,32 @@ void EditorSystem::drawUI(World* world, double dt)
|
||||
}
|
||||
|
||||
} else if (field.Type == "double") {
|
||||
float tempVal = static_cast<float>(component.Property<double>(fieldName));
|
||||
float tempVal = static_cast<float>(component.Field<double>(fieldName));
|
||||
if (ImGui::InputFloat("", &tempVal, 0.01f, 1.f)) {
|
||||
component.SetProperty(fieldName, static_cast<double>(tempVal));
|
||||
component.SetField(fieldName, static_cast<double>(tempVal));
|
||||
}
|
||||
} else if (field.Type == "int") {
|
||||
int val = component.Field<int>(fieldName);
|
||||
ImGui::InputInt("", &val);
|
||||
} else if (field.Type == "enum") {
|
||||
int currentValue = component.Field<int>(fieldName);
|
||||
int item = -1;
|
||||
std::stringstream enumKeys;
|
||||
std::vector<int> enumValues;
|
||||
int i = 0;
|
||||
for (auto& kv : ci.Meta->FieldEnumDefinitions.at(fieldName)) {
|
||||
enumKeys << kv.first << " (" << kv.second << ")" << '\0';
|
||||
enumValues.push_back(kv.second);
|
||||
if (currentValue == kv.second) {
|
||||
item = i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (ImGui::Combo("", &item, enumKeys.str().c_str())) {
|
||||
component.SetField(fieldName, enumValues.at(item));
|
||||
}
|
||||
} else if (field.Type == "bool") {
|
||||
auto& val = component.Property<bool>(fieldName);
|
||||
auto& val = component.Field<bool>(fieldName);
|
||||
ImGui::Checkbox("", &val);
|
||||
} else {
|
||||
ImGui::TextDisabled(field.Type.c_str());
|
||||
|
||||
@@ -20,15 +20,16 @@ void InputProxy::LoadBindings(std::string file)
|
||||
for (auto& origin : config->GetAll<std::string>("Bindings")) {
|
||||
Events::BindOrigin e;
|
||||
e.Origin = origin.first;
|
||||
e.Command = origin.second;
|
||||
e.Value = 1.f;
|
||||
if (!e.Command.empty()) {
|
||||
char prefix = e.Command.at(0);
|
||||
if (prefix == '+' || prefix == '-') {
|
||||
e.Command = e.Command.substr(1);
|
||||
if (prefix == '-') {
|
||||
e.Value *= -1.f;
|
||||
}
|
||||
const std::string& command = origin.second;
|
||||
if (!command.empty()) {
|
||||
boost::char_separator<char> separator(", ");
|
||||
boost::tokenizer<decltype(separator)> tokenizer(command, separator);
|
||||
auto token = tokenizer.begin();
|
||||
e.Command = *token;
|
||||
if (++token != tokenizer.end()) {
|
||||
e.Value = boost::lexical_cast<float>(*token);
|
||||
} else {
|
||||
e.Value = 1.f;
|
||||
}
|
||||
OnBindOrigin(e);
|
||||
}
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
#include "Rendering/RenderSystem.h"
|
||||
|
||||
RenderSystem::RenderSystem(EventBroker* eventBrokerer, const IRenderer* renderer, RenderFrame* renderFrame) :ImpureSystem(eventBrokerer)
|
||||
RenderSystem::RenderSystem(EventBroker* eventBroker, const IRenderer* renderer, RenderFrame* renderFrame)
|
||||
: System(eventBroker)
|
||||
, m_Renderer(renderer)
|
||||
, m_RenderFrame(renderFrame)
|
||||
{
|
||||
m_Renderer = renderer;
|
||||
m_RenderFrame = renderFrame;
|
||||
EVENT_SUBSCRIBE_MEMBER(m_ESetCamera, &RenderSystem::OnSetCamera);
|
||||
EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &RenderSystem::OnInputCommand);
|
||||
|
||||
m_Camera = new Camera((float)m_Renderer->Resolution().Width / m_Renderer->Resolution().Height, glm::radians(45.f), 0.01f, 5000.f);
|
||||
m_DebugCameraInputController = new DebugCameraInputController<RenderSystem>(eventBrokerer, -1);
|
||||
m_DebugCameraInputController = new DebugCameraInputController<RenderSystem>(eventBroker, -1);
|
||||
}
|
||||
|
||||
RenderSystem::~RenderSystem()
|
||||
|
||||
Reference in New Issue
Block a user