Merge pull request #36 from teamfisk/PlayerMovement

Player movement
This commit is contained in:
William Moberg
2016-01-18 13:32:42 +01:00
101 changed files with 1589 additions and 646 deletions
@@ -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
}
}
+56 -38
View File
@@ -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);
}
}
+43 -16
View File
@@ -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)
+27 -11
View File
@@ -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;
}
+5 -8
View File
@@ -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()
{}
{ }
+182 -3
View File
@@ -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);
}
+17 -4
View File
@@ -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);
+106 -55
View File
@@ -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();
}
+1 -1
View File
@@ -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") {
+30
View File
@@ -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;
}
+11 -6
View File
@@ -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;
+32 -10
View File
@@ -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());
+10 -9
View File
@@ -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);
}
+5 -4
View File
@@ -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()
+12 -6
View File
@@ -10,17 +10,23 @@ include_directories(
${Boost_INCLUDE_DIRS}
)
file(GLOB SOURCE_FILES
"${INCLUDE_PATH}/*.h"
#"*.cpp"
file(GLOB SOURCE_FILES_Systems
"${INCLUDE_PATH}/Systems/*.h"
"Systems/*.cpp"
)
#source_group(Core FILES ${SOURCE_FILES})
source_group(Systems FILES ${SOURCE_FILES_Systems})
file(GLOB SOURCE_FILES_Events
"${INCLUDE_PATH}/Events/*.h"
"Events/*.cpp"
)
source_group(Events FILES ${SOURCE_FILES_Events})
set(SOURCE_FILES
${SOURCE_FILES}
"Game.cpp"
"HealthSystem.cpp"
"PlayerSystem.cpp"
${SOURCE_FILES_Systems}
${SOURCE_FILES_Events}
)
set(LIBRARIES
+21 -8
View File
@@ -1,7 +1,12 @@
#include "Game.h"
#include "Collision/CollidableOctreeSystem.h"
#include "Collision/TriggerSystem.h"
#include "Collision/CollisionSystem.h"
#include "Game/HealthSystem.h"
#include "Systems/RaptorCopterSystem.h"
#include "Systems/HealthSystem.h"
#include "Systems/PlayerMovementSystem.h"
#include "Systems/SpawnerSystem.h"
#include "Systems/PlayerSpawnSystem.h"
#include "Core/EntityFileWriter.h"
Game::Game(int argc, char* argv[])
@@ -62,21 +67,27 @@ Game::Game(int argc, char* argv[])
//SO MUCH TEMP PLEASE REMOVE ME OMFG VIKTOR HELP
m_Renderer->m_World = m_World;
// Create Octrees
m_OctreeCollision = new Octree(AABB(glm::vec3(-100), glm::vec3(100)), 4);
m_OctreeFrustrumCulling = new Octree(AABB(glm::vec3(-100), glm::vec3(100)), 4);
// Create system pipeline
m_SystemPipeline = new SystemPipeline(m_EventBroker);
//All systems with orderlevel 0 will be updated first.
// All systems with orderlevel 0 will be updated first.
unsigned int updateOrderLevel = 0;
m_SystemPipeline->AddSystem<RaptorCopterSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<PlayerSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<EditorSystem>(updateOrderLevel, m_Renderer);
m_SystemPipeline->AddSystem<HealthSystem>(updateOrderLevel);
//Collision and TriggerSystem should update after player.
m_SystemPipeline->AddSystem<PlayerMovementSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<SpawnerSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<PlayerSpawnSystem>(updateOrderLevel);
// Populate Octree with collidables
++updateOrderLevel;
m_SystemPipeline->AddSystem<CollisionSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<TriggerSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<CollidableOctreeSystem>(updateOrderLevel, m_OctreeCollision);
// Collision and TriggerSystem should update after player.
++updateOrderLevel;
m_SystemPipeline->AddSystem<CollisionSystem>(updateOrderLevel, m_OctreeCollision);
m_SystemPipeline->AddSystem<TriggerSystem>(updateOrderLevel, m_OctreeCollision);
++updateOrderLevel;
m_SystemPipeline->AddSystem<RenderSystem>(updateOrderLevel, m_Renderer, m_RenderFrame);
@@ -96,6 +107,8 @@ Game::~Game()
{
delete m_SystemPipeline;
delete m_SoundSystem;
delete m_OctreeFrustrumCulling;
delete m_OctreeCollision;
delete m_World;
delete m_FrameStack;
delete m_InputProxy;
-42
View File
@@ -1,42 +0,0 @@
#include "PlayerSystem.h"
void PlayerSystem::UpdateComponent(World * world, ComponentWrapper & player, double dt)
{
player["Velocity"] = glm::vec3(0.f, 0.f, 0.f);
if ((bool&)player["Forward"] == true) {
((glm::vec3&)player["Velocity"]).z = m_Speed * float(dt) * -1;
}
if ((bool&)player["Left"] == true) {
((glm::vec3&)player["Velocity"]).x = m_Speed * float(dt) * -1;
}
if ((bool&)player["Back"] == true) {
((glm::vec3&)player["Velocity"]).z = m_Speed * float(dt);
}
if ((bool&)player["Right"] == true) {
((glm::vec3&)player["Velocity"]).x = m_Speed * float(dt);
}
if ((glm::vec3)player["Velocity"] != glm::vec3(0.f)) {
ComponentWrapper& transform = world->GetComponent(player.EntityID, "Transform");
(glm::vec3&)transform["Position"] += (glm::vec3)player["Velocity"];
}
}
bool PlayerSystem::OnTouch(const Events::TriggerTouch &event)
{
LOG_INFO("Player entity %i touched widget (entity %i).", event.Entity, event.Trigger);
return false;
}
bool PlayerSystem::OnEnter(const Events::TriggerEnter &event)
{
LOG_INFO("Player entity %i entered widget (entity %i).", event.Entity, event.Trigger);
return false;
}
bool PlayerSystem::OnLeave(const Events::TriggerLeave &event)
{
LOG_INFO("Player entity %i left widget (entity %i).", event.Entity, event.Trigger);
return false;
}
@@ -1,32 +1,32 @@
#include "HealthSystem.h"
#include <algorithm>
#include "Systems/HealthSystem.h"
HealthSystem::HealthSystem(EventBroker* eventBroker)
: PureSystem(eventBroker, "Health")
: System(eventBroker)
, PureSystem("Health")
{
//subscribe/listenTo playerdamage,healthpickup events (using the eventBroker)
EVENT_SUBSCRIBE_MEMBER(m_EPlayerDamage, &HealthSystem::OnPlayerDamaged);
EVENT_SUBSCRIBE_MEMBER(m_EPlayerHealthPickup, &HealthSystem::OnPlayerHealthPickup);
}
void HealthSystem::UpdateComponent(World *world, ComponentWrapper &health, double dt)
void HealthSystem::UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt)
{
//if entityID of health is 9 then the players ID is also 9 (player,health are connected to the same entity)
ComponentWrapper player = world->GetComponent(health.EntityID, "Player");
double maxHealth = (double)health["MaxHealth"];
ComponentWrapper player = world->GetComponent(component.EntityID, "Player");
double maxHealth = (double)component["MaxHealth"];
//process the DeltaHealthVector and change the entitys health accordingly
for (size_t i = m_DeltaHealthVector.size(); i > 0; i--)
{
auto deltaHP = m_DeltaHealthVector[i - 1];
//if we have a healthchange for the current player and health is greater than 0, then apply it
if (std::get<0>(deltaHP) == player.EntityID && (double)health["Health"] > 0.0f) {
if (std::get<0>(deltaHP) == player.EntityID && (double)component["Health"] > 0.0f) {
//get the deltaHP value from the tuple and make sure you dont get more than maxHealth
double newHealth = std::min((double)health["Health"] + (double)std::get<1>(deltaHP), maxHealth);
health["Health"] = newHealth;
double newHealth = std::min((double)component["Health"] + (double)std::get<1>(deltaHP), maxHealth);
component["Health"] = newHealth;
m_DeltaHealthVector.erase(m_DeltaHealthVector.begin() + i - 1);
//check if health is <= 0
if ((double)health["Health"] <= 0.0f) {
if ((double)component["Health"] <= 0.0f) {
//publish death event
Events::PlayerDeath e;
e.PlayerID = player.EntityID;
+16
View File
@@ -0,0 +1,16 @@
#include "Systems/PlayerMovementSystem.h"
void PlayerMovementSystem::UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt)
{
ComponentWrapper& cTransform = entity["Transform"];
if (!entity.HasComponent("Physics")) {
return;
}
ComponentWrapper& cPhysics = entity["Physics"];
glm::vec3& velocity = cPhysics["Velocity"];
velocity.y -= 9.82 * dt;
glm::vec3& position = cTransform["Position"];
position += velocity * (float)dt;
}
+51
View File
@@ -0,0 +1,51 @@
#include "Systems/PlayerSpawnSystem.h"
PlayerSpawnSystem::PlayerSpawnSystem(EventBroker* eventBroker)
: System(eventBroker)
{
EVENT_SUBSCRIBE_MEMBER(m_OnInputCommand, &PlayerSpawnSystem::OnInputCommand);
}
void PlayerSpawnSystem::Update(World* world, double dt)
{
auto playerSpawns = world->GetComponents("PlayerSpawn");
if (playerSpawns == nullptr) {
return;
}
for (auto& team : m_SpawnRequests) {
for (auto& cPlayerSpawn : *playerSpawns) {
EntityWrapper spawner(world, cPlayerSpawn.EntityID);
if (!spawner.HasComponent("Spawner")) {
continue;
}
// If the spawner has a team affiliation, check it
if (spawner.HasComponent("Team")) {
if ((int)spawner["Team"]["Team"] != team) {
continue;
}
}
// Spawn the player!
EntityWrapper player = SpawnerSystem::Spawn(spawner);
// Set the player team affiliation
player["Team"]["Team"] = team;
}
}
m_SpawnRequests.clear();
}
bool PlayerSpawnSystem::OnInputCommand(const Events::InputCommand& e)
{
if (e.Command != "PickTeam") {
return false;
}
if (e.Value != 0) {
m_SpawnRequests.push_back((int)e.Value);
}
return true;
}
+61
View File
@@ -0,0 +1,61 @@
#include "Systems/SpawnerSystem.h"
SpawnerSystem::SpawnerSystem(EventBroker* eventBroker) : System(eventBroker)
{
EVENT_SUBSCRIBE_MEMBER(m_OnSpawnerSpawn, &SpawnerSystem::OnSpawnerSpawn);
}
EntityWrapper SpawnerSystem::Spawn(EntityWrapper spawner, EntityWrapper parent /*= EntityWrapper::Invalid*/)
{
// Spawn the entity in the parent's world if it exists, otherwise in the spawner's world
World* world = parent.World;
if (world == nullptr) {
world = spawner.World;
}
// Find any SpawnPoints existing as children of spawner
auto children = spawner.World->GetChildren(spawner.ID);
std::vector<EntityWrapper> spawnPoints;
for (auto kv = children.first; kv != children.second; ++kv) {
const EntityID& child = kv->second;
if (spawner.World->HasComponent(child, "SpawnPoint")) {
spawnPoints.push_back(EntityWrapper(spawner.World, child));
}
}
// Choose a random SpawnPoint
EntityWrapper spawnPoint = spawner;
if (!spawnPoints.empty()) {
if (spawnPoints.size() > 1) {
static std::random_device randomDevice;
static std::mt19937 randomGenerator(randomDevice());
std::uniform_int_distribution<> distribution(0, std::distance(spawnPoints.begin(), spawnPoints.end()) - 1);
auto randomSpawnPointIt = spawnPoints.begin();
std::advance(randomSpawnPointIt, distribution(randomGenerator));
spawnPoint = *randomSpawnPointIt;
} else {
spawnPoint = spawnPoints.front();
}
}
// Load the entity file and parse it
const std::string& entityFilePath = spawner["Spawner"]["EntityFile"];
auto entityFile = ResourceManager::Load<EntityFile>(entityFilePath);
if (entityFile == nullptr) {
return EntityWrapper::Invalid;
}
EntityFileParser parser(entityFile);
EntityWrapper spawnedEntity(world, parser.MergeEntities(world, parent.ID));
// Set its position and orientation to that of the SpawnPoint
spawnedEntity["Transform"]["Position"] = Transform::AbsolutePosition(spawnPoint.World, spawnPoint.ID);
spawnedEntity["Transform"]["Orientation"] = glm::eulerAngles(Transform::AbsoluteOrientation(spawnPoint.World, spawnPoint.ID));
return spawnedEntity;
}
bool SpawnerSystem::OnSpawnerSpawn(Events::SpawnerSpawn& e)
{
EntityWrapper spawnedEntity = Spawn(e.Spawner, e.Parent);
return true;
}
+3 -3
View File
@@ -7,7 +7,7 @@ using boost::unit_test_framework::test_case;
#include "Engine/Core/AABB.h"
#include "Engine/Core/Ray.h"
#include <stdlib.h>//srand
#include "Engine/Core/OctTree.h"
#include "Engine/Core/Octree.h"
//vs model
#include <sstream>
#include <string>
@@ -205,9 +205,9 @@ BOOST_AUTO_TEST_CASE(octTest)
{
glm::vec3 mini = glm::vec3(-1, -1, -1);
glm::vec3 maxi = glm::vec3(1, 1, 1);
OctTree tree(AABB(mini, maxi), 2);
Octree tree(AABB(mini, maxi), 2);
tree.AddDynamicObject(AABB(mini, -0.9f*maxi));
OctTree::Output data;
Octree::Output data;
glm::vec3 origin = 3.0f * mini;
bool rayIntersected = tree.RayCollides(Ray(origin , mini - origin), data);
BOOST_CHECK(rayIntersected);
+2 -2
View File
@@ -10,8 +10,8 @@ BOOST_AUTO_TEST_CASE(ComponentPoolTest)
//ci.Name = "Test";
//ci.FieldTypes["Field"] = "int";
//ci.FieldOffsets["Field"] = 0;
//ci.Meta.Allocation = 3;
//ci.Meta.Stride = sizeof(EntityID) + sizeof(int);
//ci.Meta->Allocation = 3;
//ci.Stride = sizeof(EntityID) + sizeof(int);
//std::vector<ComponentWrapper> wrappers;
//ComponentPool pool(ci);
+9 -9
View File
@@ -3,7 +3,7 @@ using boost::unit_test_framework::test_suite;
using boost::unit_test_framework::test_case;
#include <stdlib.h>//srand
#include "Engine/Core/OctTree.h"
#include "Engine/Core/Octree.h"
#include "Engine/Core/Ray.h"
#include "OldOctTree.h"
@@ -13,7 +13,7 @@ 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);
Octree tree(AABB(mini, maxi), 2);
AABB firstQuadrant(mini, 0.8f*mini);
tree.AddStaticObject(firstQuadrant);
AABB testBox(0.9f*mini, 0.8f*mini);
@@ -21,9 +21,9 @@ BOOST_AUTO_TEST_CASE(octSameRegionTest)
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.Origin().x, firstQuadrant.Origin().x, 0.00001f);
BOOST_CHECK_CLOSE_FRACTION(box.Origin().y, firstQuadrant.Origin().y, 0.00001f);
BOOST_CHECK_CLOSE_FRACTION(box.Origin().z, firstQuadrant.Origin().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);
@@ -117,7 +117,7 @@ BOOST_AUTO_TEST_CASE(octRegionPerfTestWithDuplicates)
BOOST_AUTO_TEST_CASE(octRegionPerfTestNoDuplicates)
{
TestLoop<OctTree>(RegionTest<OctTree>);
TestLoop<Octree>(RegionTest<Octree>);
BOOST_CHECK(true);
}
@@ -129,7 +129,7 @@ BOOST_AUTO_TEST_CASE(octBoxPerfTestWithDuplicates)
BOOST_AUTO_TEST_CASE(octBoxPerfTestNoDuplicates)
{
TestLoop<OctTree>(BoxTest<OctTree>);
TestLoop<Octree>(BoxTest<Octree>);
BOOST_CHECK(true);
}
@@ -141,7 +141,7 @@ BOOST_AUTO_TEST_CASE(octRayPerfTestWithDuplicates)
BOOST_AUTO_TEST_CASE(octRayPerfTestNoDuplicates)
{
TestLoop<OctTree>(RayTest<OctTree>);
TestLoop<Octree>(RayTest<Octree>);
BOOST_CHECK(true);
}
@@ -153,7 +153,7 @@ BOOST_AUTO_TEST_CASE(octNopPerfTestWithDuplicates)
BOOST_AUTO_TEST_CASE(octNopPerfTestNoDuplicates)
{
TestLoop<OctTree>(NopTest<OctTree>);
TestLoop<Octree>(NopTest<Octree>);
BOOST_CHECK(true);
}
+2 -2
View File
@@ -91,7 +91,7 @@ void Game::Tick()
frameCounter = 0;
}
ComponentWrapper transform = m_World->GetComponent(m_World->anotherBoxTransformId, "Transform");
transform["Position"] = boxi.Center();
transform["Position"] = boxi.Origin();
//check all children again in the tree if they have a box in them or not, and colormark them if they do
//contentboxarna får man ut - inte childboxarna!
@@ -110,7 +110,7 @@ void Game::Tick()
//REQUIRED: childIndicesContainingBox must be public to test this!
for each (auto someBoxIndex in boxIndex)
{
glm::vec3 pos = m_World->someOctTree.m_Root->m_Children[someBoxIndex]->m_Box.Center();
glm::vec3 pos = m_World->someOctTree.m_Root->m_Children[someBoxIndex]->m_Box.Origin();
if (abs(pos.x - oneLinkedObject.posxyz.x) < 0.005f &&
abs(pos.y - oneLinkedObject.posxyz.y) < 0.005f &&
abs(pos.z - oneLinkedObject.posxyz.z) < 0.005f) {
+1 -1
View File
@@ -55,7 +55,7 @@ private:
glm::quat m_PrevOri;
glm::vec3 worldSize = glm::vec3(50, 50, 50);
OctTree someOctTree;
Octree someOctTree;
};
+1 -1
View File
@@ -7,7 +7,7 @@ using boost::unit_test_framework::test_case;
#include "Engine/Core/AABB.h"
#include "Engine/Core/Ray.h"
#include <stdlib.h>//srand
#include "Engine/Core/OctTree.h"
#include "Engine/Core/Octree.h"
//vs memleaks
//#define _CRTDBG_MAP_ALLOC
+8 -8
View File
@@ -16,9 +16,9 @@ class HardcodedTestWorld : public World
public:
struct LinkOctTreeAndModel {
EntityID entId;
OctTree::OctChild* child;
Octree::Child* child;
glm::vec3 posxyz;
LinkOctTreeAndModel(EntityID eId, OctTree::OctChild* ch, glm::vec3 pos)
LinkOctTreeAndModel(EntityID eId, Octree::Child* ch, glm::vec3 pos)
{
entId = eId;
child = ch;
@@ -27,7 +27,7 @@ public:
};
EntityID anotherBoxTransformId;
std::vector<LinkOctTreeAndModel> linkOM;
OctTree someOctTree;
Octree someOctTree;
//constructor
HardcodedTestWorld()
@@ -77,7 +77,7 @@ private:
auto someAABB = AABB(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(1.0f, 1.0f, 1.0f));
//draw main box first
AddBoxModel(someAABB.Center(), someAABB.HalfSize().x, someOctTree.m_Root, tempId);
AddBoxModel(someAABB.Origin(), someAABB.HalfSize().x, someOctTree.m_Root, tempId);
//add anotherbox in octTree
auto anotherBox = AABB(glm::vec3(0.1f, 0.1f, 0.1f), glm::vec3(0.2f, 0.2f, 0.2f));
@@ -85,19 +85,19 @@ private:
someOctTree.AddDynamicObject(anotherBox);
//draw anotherbox and save it in anotherBoxTransformId
AddBoxModel(anotherBox.Center(), anotherBox.HalfSize().x, someOctTree.m_Root, anotherBoxTransformId);
AddBoxModel(anotherBox.Origin(), anotherBox.HalfSize().x, someOctTree.m_Root, anotherBoxTransformId);
//draw the octTree
for (size_t j = 0; j < 8; j++)
{
AddBoxModel(someOctTree.m_Root->m_Children[j]->m_Box.Center(),
AddBoxModel(someOctTree.m_Root->m_Children[j]->m_Box.Origin(),
someOctTree.m_Root->m_Children[j]->m_Box.HalfSize().x, someOctTree.m_Root->m_Children[j], tempId);
auto someChild = someOctTree.m_Root->m_Children[j];
for (size_t i = 0; i < 8; i++)
{
AddBoxModel(someChild->m_Children[i]->m_Box.Center(),
AddBoxModel(someChild->m_Children[i]->m_Box.Origin(),
someChild->m_Children[i]->m_Box.HalfSize().x, someChild->m_Children[i], tempId);
}
}
@@ -115,7 +115,7 @@ private:
model["Resource"] = "Models/Core/UnitBox.obj";
}
void AddBoxModel(const glm::vec3 &center, const float &halfSize, OctTree::OctChild* child, EntityID &outEntityId) {
void AddBoxModel(const glm::vec3 &center, const float &halfSize, Octree::Child* child, EntityID &outEntityId) {
World& world = *this;
EntityID entityDummyScene = world.CreateEntity();
+3 -3
View File
@@ -54,7 +54,7 @@ OctTree::OctTree(const AABB& octTreeBounds, int subDivisions)
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)) {
@@ -172,7 +172,7 @@ bool OctTree::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.
@@ -279,7 +279,7 @@ void OctTree::ClearDynamicObjects()
// z : - + - + - + - +
int OctTree::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);
}
+1 -1
View File
@@ -20,7 +20,7 @@ BOOST_AUTO_TEST_CASE(WorldTestSingleAllocation, * boost::unit_test::tolerance(0.
ComponentWrapper c = w.AttachComponent(e, "Test");
// Check default values
BOOST_TEST((int)c["TestInteger"] == c.Property<int>("TestInteger"));
BOOST_TEST((int)c["TestInteger"] == c.Field<int>("TestInteger"));
BOOST_TEST((int)c["TestInteger"] == 1337);
BOOST_TEST((double)c["TestDouble"] == 13.37);
BOOST_TEST((std::string)c["TestString"] == "Carlito");