Merge remote-tracking branch 'origin/master' into TextRendering

# Conflicts:
#	include/Engine/Rendering/RenderQueue.h
#	include/Engine/Rendering/RenderSystem.h
#	include/Game/Game.h
#	resources/Schema/Types/Entity.xsd
#	src/Engine/Rendering/RenderSystem.cpp
This commit is contained in:
viktorljung
2016-01-18 17:44:26 +01:00
159 changed files with 4202 additions and 990 deletions
+9 -2
View File
@@ -10,8 +10,8 @@ find_package(PNG REQUIRED)
find_package(Xerces REQUIRED)
find_package(Freetype REQUIRED)
# Because FindOpenAL is retarded
#set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "${CMAKE_SOURCE_DIR}/deps/include/AL")
#find_package(OpenAL REQUIRED)
set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "${CMAKE_SOURCE_DIR}/deps/include/OpenAL")
find_package(OpenAL REQUIRED)
if(UNIX)
find_package(X11 REQUIRED)
endif()
@@ -54,6 +54,12 @@ file(GLOB SOURCE_FILES_Network
)
source_group(Network FILES ${SOURCE_FILES_Network})
file(GLOB SOURCE_FILES_Sound
"${INCLUDE_PATH}/Sound/*.h"
"Sound/*.cpp"
)
source_group(Sound FILES ${SOURCE_FILES_Sound})
file(GLOB SOURCE_FILES_Rendering
"${INCLUDE_PATH}/Rendering/*.h"
"Rendering/*.cpp"
@@ -88,6 +94,7 @@ set(SOURCE_FILES
${SOURCE_FILES_Core_Util}
${SOURCE_FILES_Input}
${SOURCE_FILES_Network}
${SOURCE_FILES_Sound}
${SOURCE_FILES_GUI}
${SOURCE_FILES_Rendering}
${SOURCE_FILES_Rendering_Util}
@@ -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
}
}
+58 -40
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) &&
@@ -225,11 +265,11 @@ bool attachAABBComponentFromModel(World* world, EntityID id)
return false;
}
glm::mat4 modelMatrix = modelRes->m_Matrix;
glm::mat4 modelMatrix = modelRes->Matrix();
glm::vec3 mini = glm::vec3(INFINITY, INFINITY, INFINITY);
glm::vec3 maxi = glm::vec3(-INFINITY, -INFINITY, -INFINITY);
for (const auto& v : modelRes->m_Vertices) {
for (const auto& v : modelRes->Vertices()) {
const auto& wPos = modelMatrix * glm::vec4(v.Position.x, v.Position.y, v.Position.z, 1);
maxi.x = std::max(wPos.x, maxi.x);
maxi.y = std::max(wPos.y, maxi.y);
@@ -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->m_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;
}
+5
View File
@@ -0,0 +1,5 @@
#include "Core/MemoryPool.h"
namespace DisableMemoryPool
{
bool Value = false;
}
@@ -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;
}
+56 -48
View File
@@ -1,4 +1,7 @@
#include "Core/ResourceManager.h"
#include "boost/thread/thread.hpp"
#include "boost/thread/mutex.hpp"
#include "boost/thread/lock_guard.hpp"
std::unordered_map<std::string, std::string> ResourceManager::m_CompilerTypenameToResourceType;
std::unordered_map<std::string, std::function<Resource*(std::string)>> ResourceManager::m_FactoryFunctions;
@@ -6,10 +9,13 @@ std::unordered_map<std::pair<std::string, std::string>, Resource*> ResourceManag
std::unordered_map<std::string, Resource*> ResourceManager::m_ResourceFromName;
std::unordered_map<Resource*, Resource*> ResourceManager::m_ResourceParents;
unsigned int ResourceManager::m_CurrentResourceTypeID = 0;
bool ResourceManager::UseThreading = false;
std::unordered_map<std::string, unsigned int> ResourceManager::m_ResourceTypeIDs;
std::unordered_map<unsigned int, unsigned int> ResourceManager::m_ResourceCount;
bool ResourceManager::m_Preloading = false;
FileWatcher ResourceManager::m_FileWatcher;
std::unordered_map<std::pair<std::string, std::string>, boost::thread> ResourceManager::m_LoadingThreads;
std::unordered_map<std::pair<std::string, std::string>, std::exception_ptr> ResourceManager::m_LoadingThreadExceptions;
boost::recursive_mutex ResourceManager::m_Mutex;
unsigned int ResourceManager::GetTypeID(std::string resourceType)
{
@@ -74,63 +80,65 @@ void ResourceManager::Update()
m_FileWatcher.Check();
}
void ResourceManager::Preload(std::string resourceType, std::string resourceName)
{
if (IsResourceLoaded(resourceType, resourceName)) {
//LOG_WARNING("Attempted to preload resource \"%s\" multiple times!", resourceName.c_str());
return;
}
m_Preloading = true;
LOG_INFO("Preloading resource \"%s\"", resourceName.c_str());
CreateResource(resourceType, resourceName, nullptr);
m_Preloading = false;
}
Resource* ResourceManager::Load(std::string resourceType, std::string resourceName, Resource* parent /*= nullptr*/)
{
auto it = m_ResourceCache.find(std::make_pair(resourceType, resourceName));
if (it != m_ResourceCache.end()) {
return it->second;
}
if (m_Preloading) {
LOG_INFO("Preloading resource \"%s\"", resourceName.c_str());
} else {
LOG_WARNING("Hot-loading resource \"%s\"", resourceName.c_str());
}
return CreateResource(resourceType, resourceName, parent);
}
Resource* ResourceManager::CreateResource(std::string resourceType, std::string resourceName, Resource* parent)
Resource* ResourceManager::createResource(const std::string& resourceType, const std::string& resourceName, Resource* parent, std::exception_ptr& exception)
{
auto facIt = m_FactoryFunctions.find(resourceType);
if (facIt == m_FactoryFunctions.end()) {
LOG_ERROR("Failed to load resource \"%s\" of type \"%s\": type not registered", resourceName.c_str(), resourceType.c_str());
return nullptr;
cacheResource(nullptr, resourceType, resourceName, parent);
//This basically throws an exception.
exception = std::make_exception_ptr(Resource::FailedLoadingException()); return nullptr;
}
// Call the factory function
Resource* resource;
try {
resource = facIt->second(resourceName);
return cacheResource(facIt->second(resourceName), resourceType, resourceName, parent);
} catch (const Resource::StillLoadingException&) {
exception = std::current_exception(); return nullptr;
} catch (const std::exception& e) {
LOG_ERROR("Failed to load resource \"%s\" of type \"%s\": %s", resourceName.c_str(), resourceType.c_str(), e.what());
cacheResource(nullptr, resourceType, resourceName, parent);
exception = std::current_exception(); return nullptr;
}
}
Resource* ResourceManager::createResourceThrowing(const std::string& resourceType, const std::string& resourceName, Resource* parent)
{
std::exception_ptr exception;
Resource* res = createResource(resourceType, resourceName, parent, exception);
if (exception) {
std::rethrow_exception(exception);
}
return res;
}
Resource* ResourceManager::cacheResource(Resource* resource, const std::string& resourceType, const std::string& resourceName, Resource* parent)
{
//Lock the mutex immediately, and unlock it when leaving the code block.
boost::lock_guard<decltype(m_Mutex)> guard(m_Mutex);
if (resource != nullptr) {
// Store IDs
resource->TypeID = GetTypeID(resourceType);
resource->ResourceID = GetNewResourceID(resource->TypeID);
} catch (const std::exception& e) {
resource = nullptr;
LOG_ERROR("Failed to load resource \"%s\" of type \"%s\": %s", resourceName.c_str(), resourceType.c_str(), e.what());
}
// Cache
m_ResourceCache[std::make_pair(resourceType, resourceName)] = resource;
m_ResourceFromName[resourceName] = resource;
if (parent != nullptr) {
m_ResourceParents[resource] = parent;
}
if (!boost::filesystem::is_directory(resourceName)) {
LOG_DEBUG("Adding watch for %s", resourceName.c_str());
m_FileWatcher.AddWatch(resourceName, fileWatcherCallback);
}
return resource;
// Cache
m_ResourceCache[std::make_pair(resourceType, resourceName)] = resource;
m_ResourceFromName[resourceName] = resource;
if (parent != nullptr) {
m_ResourceParents[resource] = parent;
}
//if (!boost::filesystem::is_directory(resourceName)) {
// LOG_DEBUG("Adding watch for %s", resourceName.c_str());
// m_FileWatcher.AddWatch(resourceName, fileWatcherCallback);
//}
return resource;
}
bool ResourceManager::IsMainThread()
{
static boost::thread::id MainThreadId = boost::this_thread::get_id();
return boost::this_thread::get_id() == MainThreadId;
}
+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);
}
+66
View File
@@ -0,0 +1,66 @@
#include "Rendering/DrawFinalPass.h"
DrawFinalPass::DrawFinalPass(IRenderer* renderer, LightCullingPass* lightCullingPass)
{
m_Renderer = renderer;
m_LightCullingPass = lightCullingPass;
InitializeTextures();
InitializeShaderPrograms();
}
void DrawFinalPass::InitializeTextures()
{
m_WhiteTexture = ResourceManager::Load<Texture>("Textures/Core/Blank.png");
}
void DrawFinalPass::InitializeShaderPrograms()
{
m_ForwardPlusProgram = ResourceManager::Load<ShaderProgram>("#ForwardPlusProgram");
m_ForwardPlusProgram->AddShader(std::shared_ptr<Shader>(new VertexShader("Shaders/ForwardPlus.vert.glsl")));
m_ForwardPlusProgram->AddShader(std::shared_ptr<Shader>(new FragmentShader("Shaders/ForwardPlus.frag.glsl")));
m_ForwardPlusProgram->Compile();
m_ForwardPlusProgram->Link();
}
void DrawFinalPass::Draw(RenderScene& scene)
{
GLERROR("DrawFinalPass::Draw: Pre");
DrawFinalPassState state;
m_ForwardPlusProgram->Bind();
GLuint shaderHandle = m_ForwardPlusProgram->GetHandle();
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_LightCullingPass->LightSSBO());
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, m_LightCullingPass->LightGridSSBO());
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, m_LightCullingPass->LightIndexSSBO());
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "V"), 1, GL_FALSE, glm::value_ptr(m_Renderer->Camera()->ViewMatrix()));
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "P"), 1, GL_FALSE, glm::value_ptr(m_Renderer->Camera()->ProjectionMatrix()));
glUniform2f(glGetUniformLocation(shaderHandle, "ScreenDimensions"), m_Renderer->Resolution().Width, m_Renderer->Resolution().Height);
//TODO: Render: Add code for more jobs than modeljobs.
for (auto &job : scene.ForwardJobs) {
auto modelJob = std::dynamic_pointer_cast<ModelJob>(job);
if(modelJob) {
//TODO: Kolla upp "header/include/common" shader saken så man slipper skicka in asmycket uniforms
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "M"), 1, GL_FALSE, glm::value_ptr(modelJob->Matrix));
glUniform4fv(glGetUniformLocation(shaderHandle, "Color"), 1, glm::value_ptr(modelJob->Color));
if(modelJob->DiffuseTexture != nullptr) {
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, modelJob->DiffuseTexture->m_Texture);
} else {
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_WhiteTexture->m_Texture);
}
glBindVertexArray(modelJob->Model->VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, modelJob->Model->ElementBuffer);
glDrawElementsBaseVertex(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, 0, modelJob->StartIndex);
continue;
}
}
GLERROR("DrawFinalPass::Draw: END");
}
@@ -0,0 +1,18 @@
#include "Rendering/DrawFinalPassState.h"
DrawFinalPassState::DrawFinalPassState()
{
BindFramebuffer(0);
Enable(GL_BLEND);
BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Enable(GL_DEPTH_TEST);
Enable(GL_CULL_FACE);
ClearColor(glm::vec4(200.f / 255, 0.f / 255, 200.f / 255, 0.f));
Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
DrawFinalPassState::~DrawFinalPassState()
{
}
+4 -5
View File
@@ -14,7 +14,6 @@ void DrawScenePass::InitializeTextures()
void DrawScenePass::InitializeShaderPrograms()
{
//Gör så att shaders är en resource, tex som texture classen. Konstruktorn måste vara privat.
m_BasicForwardProgram = ResourceManager::Load<ShaderProgram>("#BasicForwardProgram");
m_BasicForwardProgram->AddShader(std::shared_ptr<Shader>(new VertexShader("Shaders/BasicForward.vert.glsl")));
@@ -26,16 +25,16 @@ void DrawScenePass::InitializeShaderPrograms()
void DrawScenePass::Draw(RenderScene& scene)
{
//glBindFramebuffer(GL_FRAMEBUFFER, 0);
GLERROR("Renderer::Draw PickingPass");
GLERROR("DrawScenePass::Draw: Pre");
DrawScenePassState state = DrawScenePassState();
m_BasicForwardProgram->Bind();
for (auto &job : scene.ForwardJobs) {
auto modelJob = std::dynamic_pointer_cast<ModelJob>(job);
if (modelJob) {
GLuint ShaderHandle = m_BasicForwardProgram->GetHandle();
m_BasicForwardProgram->Bind();
//TODO: Kolla upp "header/include/common" shader saken så man slipper skicka in asmycket uniforms
glUniformMatrix4fv(glGetUniformLocation(ShaderHandle, "M"), 1, GL_FALSE, glm::value_ptr(modelJob->Matrix));
glUniformMatrix4fv(glGetUniformLocation(ShaderHandle, "V"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ViewMatrix()));
@@ -57,7 +56,7 @@ void DrawScenePass::Draw(RenderScene& scene)
//continue;
}
}
GLERROR("DrawScene Error");
}
GLERROR("DrawScenePass::Draw: End");
}
+1 -3
View File
@@ -17,10 +17,9 @@ Font::Font(std::string path)
it++;
if (it != tok.end()) {
try {
LOG_INFO("DFhdoölshöldsihjgf");
fontSize = boost::lexical_cast<int>((*it).c_str());
} catch (boost::bad_lexical_cast const&) {
std::cout << "Error: input string was not valid" << std::endl;
LOG_ERROR("input string did not have a valid font resolution");
}
}
} else {
@@ -28,7 +27,6 @@ Font::Font(std::string path)
}
FT_Library library;
if (FT_Init_FreeType(&library)) {
+151
View File
@@ -0,0 +1,151 @@
#include "Rendering/LightCullingPass.h"
LightCullingPass::LightCullingPass(IRenderer* renderer)
{
m_Renderer = renderer;
SetSSBOSizes();
InitializeSSBOs();
InitializeShaderPrograms();
//GenerateNewFrustum(TODO);
}
LightCullingPass::~LightCullingPass()
{
}
void LightCullingPass::GenerateNewFrustum(RenderScene& scene)
{
if (scene.PointLightJobs.size() == 0)
return;
GLERROR("CalculateFrustum Error: Pre");
m_CalculateFrustumProgram->Bind();
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_FrustumSSBO);
glUniformMatrix4fv(glGetUniformLocation(m_CalculateFrustumProgram->GetHandle(), "P"), 1, false, glm::value_ptr(scene.Camera->ProjectionMatrix()));
glUniform2f(glGetUniformLocation(m_CalculateFrustumProgram->GetHandle(), "ScreenDimensions"), m_Renderer->Resolution().Width, m_Renderer->Resolution().Height);
glDispatchCompute((int)(m_Renderer->Resolution().Width/(TILE_SIZE*TILE_SIZE) + 1), (int)(m_Renderer->Resolution().Height/(TILE_SIZE*TILE_SIZE) + 1), 1);
GLERROR("CalculateFrustum Error: End");
}
void LightCullingPass::OnResolutionChange()
{
SetSSBOSizes();
}
void LightCullingPass::SetSSBOSizes()
{
m_NumberOfTiles = (int)(m_Renderer->Resolution().Width*m_Renderer->Resolution().Height)/TILE_SIZE;
//m_Frustums = new Frustum[s];
//m_LightGrid = new LightGrid[s];
//m_LightIndex = new float[s*200];
m_Frustums = new Frustum[m_NumberOfTiles];
m_LightGrid = new LightGrid[m_NumberOfTiles];
m_LightIndex = new float[m_NumberOfTiles*MAX_LIGHTS_PER_TILE];
}
void LightCullingPass::CullLights(RenderScene& scene)
{
GLERROR("CullLights Error: Pre");
m_LightOffset = 0;
glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_LightOffsetSSBO);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(m_LightOffset), &m_LightOffset, GL_DYNAMIC_COPY);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_LightSSBO);
if (m_PointLights.size() > 0) {
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(PointLight) * m_PointLights.size(), &(m_PointLights[0]), GL_DYNAMIC_COPY);
} else {
GLfloat zero = 0.f;
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLfloat), &zero , GL_DYNAMIC_COPY);
}
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
m_LightCullProgram->Bind();
glUniform2f(glGetUniformLocation(m_LightCullProgram->GetHandle(), "ScreenDimensions"), m_Renderer->Resolution().Width, m_Renderer->Resolution().Height);
glUniformMatrix4fv(glGetUniformLocation(m_LightCullProgram->GetHandle(), "V"), 1, false, glm::value_ptr(scene.Camera->ViewMatrix()));
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_FrustumSSBO);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_LightSSBO);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, m_LightGridSSBO);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, m_LightOffsetSSBO);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, m_LightIndexSSBO);
glDispatchCompute(m_Renderer->Resolution().Width / TILE_SIZE, m_Renderer->Resolution().Height / TILE_SIZE, 1);
GLERROR("CullLights Error: End");
}
void LightCullingPass::FillLightList(RenderScene& scene)
{
m_PointLights.clear();
for(auto &job : scene.PointLightJobs) {
auto pointLightjob = std::dynamic_pointer_cast<PointLightJob>(job);
if (pointLightjob) {
PointLight p;
p.Color = pointLightjob->Color;
p.Falloff = pointLightjob->Falloff;
p.Intensity = pointLightjob->Intensity;
p.Position = glm::vec4(glm::vec3(pointLightjob->Position), 1.f);
p.Radius = pointLightjob->Radius;
p.Padding = 123.f;
m_PointLights.push_back(p);
continue;
}
}
}
void LightCullingPass::InitializeSSBOs()
{
glGenBuffers(1, &m_FrustumSSBO);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_FrustumSSBO);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(Frustum)*m_NumberOfTiles, m_Frustums, GL_DYNAMIC_COPY);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
GLERROR("m_FrustumSSBO");
glGenBuffers(1, &m_LightSSBO);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_LightSSBO);
if(m_PointLights.size() > 0) {
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(PointLight) * m_PointLights.size(), &(m_PointLights[0]), GL_DYNAMIC_COPY);
}
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
GLERROR("m_LightSSBO");
glGenBuffers(1, &m_LightGridSSBO);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_LightGridSSBO);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(LightGrid)*m_NumberOfTiles, m_LightGrid, GL_DYNAMIC_COPY);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
GLERROR("m_LightGridSSBO");
glGenBuffers(1, &m_LightOffsetSSBO);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_LightOffsetSSBO);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(m_LightOffset), &m_LightOffset, GL_DYNAMIC_COPY);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
GLERROR("m_LightOffsetSSBO");
glGenBuffers(1, &m_LightIndexSSBO);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_LightIndexSSBO);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(float)*m_NumberOfTiles*MAX_LIGHTS_PER_TILE, m_LightIndex, GL_DYNAMIC_COPY);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
GLERROR("m_LightIndexSSBO");
}
void LightCullingPass::InitializeShaderPrograms()
{
m_CalculateFrustumProgram = ResourceManager::Load<ShaderProgram>("#CalculateFrustumProgram");
m_CalculateFrustumProgram->AddShader(std::shared_ptr<Shader>(new ComputeShader("Shaders/GridFrustum.comp.glsl")));
m_CalculateFrustumProgram->Compile();
m_CalculateFrustumProgram->Link();
m_LightCullProgram = ResourceManager::Load<ShaderProgram>("#LightCullProgram");
m_LightCullProgram->AddShader(std::shared_ptr<Shader>(new ComputeShader("Shaders/CullLights.comp.glsl")));
m_LightCullProgram->Compile();
m_LightCullProgram->Link();
}
+62 -48
View File
@@ -1,60 +1,74 @@
#include "Rendering/Model.h"
Model::Model(std::string fileName)
: RawModel(fileName)
{
// Generate GL buffers
GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, m_Vertices.size() * sizeof(Vertex), &m_Vertices[0], GL_STATIC_DRAW);
//Try loading the model asyncronously, if it throws any exceptions then let it propagate back to caller.
m_RawModel = ResourceManager::Load<RawModel, true>(fileName);
glGenBuffers(1, &ElementBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ElementBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_Indices.size() * sizeof(unsigned int), &m_Indices[0], GL_STATIC_DRAW);
for (auto& group : m_RawModel->MaterialGroups) {
if (!group.TexturePath.empty()) {
group.Texture = std::shared_ptr<Texture>(ResourceManager::Load<Texture>(group.TexturePath));
}
if (!group.NormalMapPath.empty()) {
group.NormalMap = std::shared_ptr<Texture>(ResourceManager::Load<Texture>(group.NormalMapPath));
}
if (!group.SpecularMapPath.empty()) {
group.SpecularMap = std::shared_ptr<Texture>(ResourceManager::Load<Texture>(group.SpecularMapPath));
}
}
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
GLERROR("GLEW: BufferFail4");
// Generate GL buffers
GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, m_RawModel->m_Vertices.size() * sizeof(RawModel::Vertex), &m_RawModel->m_Vertices[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
std::vector<int> structSizes = { 3, 3, 3, 3, 2, 4, 4, 4, 4, 4, 4 };
int stride = 0;
for (int size : structSizes) {
stride += size;
}
stride *= sizeof(GLfloat);
int offset = 0;
{
int element = 0;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * offset)); element++;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
}
GLERROR("GLEW: BufferFail5");
glGenBuffers(1, &ElementBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ElementBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_RawModel->m_Indices.size() * sizeof(unsigned int), &m_RawModel->m_Indices[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glEnableVertexAttribArray(3);
glEnableVertexAttribArray(4);
glEnableVertexAttribArray(5);
glEnableVertexAttribArray(6);
glEnableVertexAttribArray(7);
glEnableVertexAttribArray(8);
glEnableVertexAttribArray(9);
glEnableVertexAttribArray(10);
GLERROR("GLEW: BufferFail5");
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
GLERROR("GLEW: BufferFail4");
//CreateBuffers();
glBindBuffer(GL_ARRAY_BUFFER, buffer);
std::vector<int> structSizes = { 3, 3, 3, 3, 2, 4, 4, 4, 4, 4, 4 };
int stride = 0;
for (int size : structSizes) {
stride += size;
}
stride *= sizeof(GLfloat);
int offset = 0;
{
int element = 0;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * offset)); element++;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++;
}
GLERROR("GLEW: BufferFail5");
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glEnableVertexAttribArray(3);
glEnableVertexAttribArray(4);
glEnableVertexAttribArray(5);
glEnableVertexAttribArray(6);
glEnableVertexAttribArray(7);
glEnableVertexAttribArray(8);
glEnableVertexAttribArray(9);
glEnableVertexAttribArray(10);
GLERROR("GLEW: BufferFail5");
//CreateBuffers();
}
Model::~Model()
+4 -10
View File
@@ -145,9 +145,7 @@ RawModel::RawModel(std::string fileName)
aiString path;
aiTextureMapping mapping;
material->GetTexture(aiTextureType_DIFFUSE, 0, &path, &mapping);
std::string absolutePath = (boost::filesystem::path(fileName).branch_path() / path.C_Str()).string();
//LOG_DEBUG("Diffuse texture: %s", absolutePath.c_str());
matGroup.Texture = std::shared_ptr<Texture>(ResourceManager::Load<Texture>(absolutePath));
matGroup.TexturePath = (boost::filesystem::path(fileName).branch_path() / path.C_Str()).string();
}
// Normal map
//LOG_DEBUG("%i normal maps found", material->GetTextureCount(aiTextureType_HEIGHT));
@@ -155,9 +153,7 @@ RawModel::RawModel(std::string fileName)
aiString path;
aiTextureMapping mapping;
material->GetTexture(aiTextureType_HEIGHT, 0, &path, &mapping);
std::string absolutePath = (boost::filesystem::path(fileName).branch_path() / path.C_Str()).string();
//LOG_DEBUG("Normal map: %s", absolutePath.c_str());
matGroup.NormalMap = std::shared_ptr<Texture>(ResourceManager::Load<Texture>(absolutePath));
matGroup.NormalMapPath = (boost::filesystem::path(fileName).branch_path() / path.C_Str()).string();
}
// Specular map
//LOG_DEBUG("%i specular maps found", material->GetTextureCount(aiTextureType_SPECULAR));
@@ -165,11 +161,9 @@ RawModel::RawModel(std::string fileName)
aiString path;
aiTextureMapping mapping;
material->GetTexture(aiTextureType_SPECULAR, 0, &path, &mapping);
std::string absolutePath = (boost::filesystem::path(fileName).branch_path() / path.C_Str()).string();
//LOG_DEBUG("Specular map: %s", absolutePath.c_str());
matGroup.SpecularMap = std::shared_ptr<Texture>(ResourceManager::Load<Texture>(absolutePath));
matGroup.SpecularMapPath = (boost::filesystem::path(fileName).branch_path() / path.C_Str()).string();
}
TextureGroups.push_back(matGroup);
MaterialGroups.push_back(matGroup);
// Bones
std::map<int, std::vector<std::tuple<int, float>>> vertexWeights;
+1
View File
@@ -3,6 +3,7 @@
bool RenderState::Enable(GLenum cap)
{
if (glIsEnabled(cap)) {
//LOG_WARNING("Trying to enable somthing that is already enabled.");
return false;
}
m_ResetFunctions.push_back(std::bind(glDisable, cap));
+65 -21
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()
@@ -39,11 +40,17 @@ void RenderSystem::switchCamera(EntityID entity)
if (m_World->HasComponent(m_CurrentCamera, "Model")) {
m_World->GetComponent(m_CurrentCamera, "Model")["Visible"] = true;
}
if (m_World->HasComponent(m_CurrentCamera, "Listener")) {
m_World->DeleteComponent(m_CurrentCamera, "Listener");
}
}
if (m_World->HasComponent(entity, "Model")) {
m_World->GetComponent(entity, "Model")["Visible"] = false;
}
if (!m_World->HasComponent(entity, "Listener")) {
m_World->AttachComponent(entity, "Listener");
}
m_CurrentCamera = entity;
m_SwitchCamera = false;
@@ -84,21 +91,52 @@ void RenderSystem::fillModels(std::list<std::shared_ptr<RenderJob>>& jobs, World
continue;
}
Model* model = ResourceManager::Load<::Model>(resource);
if (model == nullptr) {
model = ResourceManager::Load<::Model>("Models/Core/Error.obj");
Model* model;
try {
model = ResourceManager::Load<::Model, true>(resource);
} catch (const Resource::StillLoadingException&) {
//continue;
model = ResourceManager::Load<::Model>("Models/Core/UnitRaptor.obj");
} catch (const std::exception&) {
try {
model = ResourceManager::Load<::Model>("Models/Core/Error.obj");
} catch (const std::exception&) {
continue;
}
}
glm::mat4 modelMatrix = Transform::ModelMatrix(modelComponent.EntityID, world);
for (auto texGroup : model->TextureGroups) {
std::shared_ptr<ModelJob> modelJob = std::shared_ptr<ModelJob>(new ModelJob(model, m_Camera, modelMatrix, texGroup, modelComponent, world));
for (auto matGroup : model->MaterialGroups()) {
std::shared_ptr<ModelJob> modelJob = std::shared_ptr<ModelJob>(new ModelJob(model, m_Camera, modelMatrix, matGroup, modelComponent, world));
jobs.push_back(modelJob);
}
}
}
void RenderSystem::fillLight(std::list<std::shared_ptr<RenderJob>>& jobs, World* world)
{
auto pointLights = world->GetComponents("PointLight");
if (pointLights == nullptr) {
return;
}
for (auto& pointlightC : *pointLights) {
bool visible = pointlightC["Visible"];
if (!visible) {
continue;
}
auto transformC = world->GetComponent(pointlightC.EntityID, "Transform");
if (&transformC == nullptr) {
return;
}
std::shared_ptr<PointLightJob> pointLightJob = std::shared_ptr<PointLightJob>(new PointLightJob(transformC, pointlightC, m_World));
jobs.push_back(pointLightJob);
}
}
void RenderSystem::fillText(std::list<std::shared_ptr<RenderJob>>& jobs, World* world)
{
auto texts = world->GetComponents("Text");
@@ -125,7 +163,7 @@ void RenderSystem::fillText(std::list<std::shared_ptr<RenderJob>>& jobs, World*
glm::mat4 modelMatrix = Transform::ModelMatrix(textComponent.EntityID, world);
std::shared_ptr<TextJob> modelJob = std::shared_ptr<TextJob>(new TextJob(modelMatrix, font, textComponent));
jobs.push_back(modelJob);
}
}
@@ -149,12 +187,13 @@ void RenderSystem::Update(World* world, double dt)
//Only supports opaque geometry atm
m_RenderFrame->Clear();
RenderScene rs;
rs.Camera = m_Camera;
rs.Viewport = Rectangle(1280, 720);
fillModels(rs.ForwardJobs, world);
fillText(rs.TextJobs, world);
m_RenderFrame->Add(rs);
RenderScene scene;
scene.Camera = m_Camera;
scene.Viewport = Rectangle(1280, 720);
fillModels(scene.ForwardJobs, world);
fillLight(scene.PointLightJobs, world);
fillText(scene.TextJobs, world);
m_RenderFrame->Add(scene);
}
@@ -162,6 +201,9 @@ void RenderSystem::updateCamera(World* world, double dt)
{
if (m_SwitchCamera) {
auto cameras = world->GetComponents("Camera");
if (cameras == nullptr) {
return;
}
for (auto it = cameras->begin(); it != cameras->end(); it++) {
if ((*it).EntityID == m_CurrentCamera) {
it++;
@@ -173,11 +215,13 @@ void RenderSystem::updateCamera(World* world, double dt)
break;
}
}
ComponentWrapper& cameraComponent = world->GetComponent(m_CurrentCamera, "Camera");
ComponentWrapper& cameraTransform = world->GetComponent(m_CurrentCamera, "Transform");
if (m_World->HasComponent(m_CurrentCamera, "Camera")) {
ComponentWrapper& cameraComponent = world->GetComponent(m_CurrentCamera, "Camera");
ComponentWrapper& cameraTransform = world->GetComponent(m_CurrentCamera, "Transform");
m_DebugCameraInputController->SetOrientation(glm::quat((glm::vec3)cameraTransform["Orientation"]));
m_DebugCameraInputController->SetPosition(cameraTransform["Position"]);
m_DebugCameraInputController->SetOrientation(glm::quat((glm::vec3)cameraTransform["Orientation"]));
m_DebugCameraInputController->SetPosition(cameraTransform["Position"]);
}
}
if (m_World->ValidEntity(m_CurrentCamera)) {
+33 -8
View File
@@ -96,16 +96,22 @@ void Renderer::Update(double dt)
void Renderer::Draw(RenderFrame& frame)
{
glClearColor(255.f / 255, 163.f / 255, 176.f / 255, 0.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
m_PickingPass->ClearPicking();
for (auto scene : frame.RenderScenes){
m_Camera = scene->Camera; // remove renderer camera when Editor uses the render scene cameras.
FillDepth(*scene);
m_PickingPass->Draw(*scene);
m_LightCullingPass->GenerateNewFrustum(*scene);
m_LightCullingPass->FillLightList(*scene);
m_LightCullingPass->CullLights(*scene);
m_DrawFinalPass->Draw(*scene);
//m_DrawScenePass->Draw(rq);
m_DrawScenePass->Draw(*scene);
GLERROR("Renderer::Draw m_DrawScenePass->Draw");
m_TextRenderer->Draw(*scene);
@@ -138,14 +144,14 @@ void Renderer::DrawScreenQuad(GLuint textureToDraw)
glBindVertexArray(m_ScreenQuad->VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ScreenQuad->ElementBuffer);
glDrawElementsBaseVertex(GL_TRIANGLES, m_ScreenQuad->TextureGroups[0].EndIndex - m_ScreenQuad->TextureGroups[0].StartIndex +1
, GL_UNSIGNED_INT, 0, m_ScreenQuad->TextureGroups[0].StartIndex);
glDrawElementsBaseVertex(GL_TRIANGLES, m_ScreenQuad->MaterialGroups()[0].EndIndex - m_ScreenQuad->MaterialGroups()[0].StartIndex +1
, GL_UNSIGNED_INT, 0, m_ScreenQuad->MaterialGroups()[0].StartIndex);
}
void Renderer::InitializeTextures()
{
m_ErrorTexture=ResourceManager::Load<Texture>("Textures/Core/ErrorTexture.png");
m_WhiteTexture=ResourceManager::Load<Texture>("Textures/Core/Blank.png");
m_ErrorTexture = ResourceManager::Load<Texture>("Textures/Core/ErrorTexture.png");
m_WhiteTexture = ResourceManager::Load<Texture>("Textures/Core/Blank.png");
}
void Renderer::GenerateTexture(GLuint* texture, GLenum wrapping, GLenum filtering, glm::vec2 dimensions, GLint internalFormat, GLint format, GLenum type)
@@ -156,7 +162,7 @@ void Renderer::GenerateTexture(GLuint* texture, GLenum wrapping, GLenum filterin
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapping);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, dimensions.x, dimensions.y, 0, format, type, NULL);//TODO: Renderer: Fix the precision and Resolution
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, dimensions.x, dimensions.y, 0, format, type, nullptr);//TODO: Renderer: Fix the precision and Resolution
GLERROR("Texture initialization failed");
}
@@ -164,4 +170,23 @@ void Renderer::InitializeRenderPasses()
{
m_DrawScenePass = new DrawScenePass(this);
m_PickingPass = new PickingPass(this, m_EventBroker);
m_LightCullingPass = new LightCullingPass(this);
m_DrawFinalPass = new DrawFinalPass(this, m_LightCullingPass);
}
//Temp func
void Renderer::FillDepth(RenderScene& scene)
{
for (auto job : scene.ForwardJobs) {
auto modelJob = std::dynamic_pointer_cast<ModelJob>(job);
if(! modelJob) {
return;
}
glm::vec3 abspos = Transform::AbsolutePosition(modelJob->World, modelJob->Entity);
glm::vec3 worldpos = glm::vec3(scene.Camera->ViewMatrix() * glm::vec4(abspos, 1));
modelJob->Depth = worldpos.z;
}
scene.ForwardJobs.sort(Renderer::DepthSort);
}
+32 -32
View File
@@ -2,48 +2,48 @@
Texture::Texture(std::string path)
{
PNG image(path);
PNG image(path);
if (image.Width == 0 && image.Height == 0 || image.Format == Image::ImageFormat::Unknown) {
image = PNG("Textures/Core/ErrorTexture.png");
if (image.Width == 0 && image.Height == 0 || image.Format == Image::ImageFormat::Unknown) {
LOG_ERROR("Couldn't even load the error texture. This is a dark day indeed.");
return;
}
}
if (image.Width == 0 && image.Height == 0 || image.Format == Image::ImageFormat::Unknown) {
image = PNG("Textures/Core/ErrorTexture.png");
if (image.Width == 0 && image.Height == 0 || image.Format == Image::ImageFormat::Unknown) {
LOG_ERROR("Couldn't even load the error texture. This is a dark day indeed.");
return;
}
}
this->Width = image.Width;
this->Height = image.Height;
this->Width = image.Width;
this->Height = image.Height;
GLint format;
switch (image.Format) {
case Image::ImageFormat::RGB:
format = GL_RGB;
break;
case Image::ImageFormat::RGBA:
format = GL_RGBA;
break;
}
GLint format;
switch (image.Format) {
case Image::ImageFormat::RGB:
format = GL_RGB;
break;
case Image::ImageFormat::RGBA:
format = GL_RGBA;
break;
}
// Construct the OpenGL texture
glGenTextures(1, &m_Texture);
glBindTexture(GL_TEXTURE_2D, m_Texture);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, format, image.Width, image.Height, 0, format, GL_UNSIGNED_BYTE, image.Data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
GLERROR("Texture load");
// Construct the OpenGL texture
glGenTextures(1, &m_Texture);
glBindTexture(GL_TEXTURE_2D, m_Texture);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, format, image.Width, image.Height, 0, format, GL_UNSIGNED_BYTE, image.Data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
GLERROR("Texture load");
}
Texture::~Texture()
{
glDeleteTextures(1, &m_Texture);
glDeleteTextures(1, &m_Texture);
}
void Texture::Bind(GLenum textureUnit /* = GL_TEXTURE0 */)
{
glActiveTexture(textureUnit);
glBindTexture(GL_TEXTURE_2D, m_Texture);
glActiveTexture(textureUnit);
glBindTexture(GL_TEXTURE_2D, m_Texture);
}
+304
View File
@@ -0,0 +1,304 @@
#include "Sound/SoundSystem.h"
SoundSystem::SoundSystem(World* world, EventBroker* eventBroker, bool editorMode)
{
m_EventBroker = eventBroker;
m_World = world;
m_EditorEnabled = editorMode;
initOpenAL();
alSpeedOfSound(340.29f);
alDistanceModel(AL_LINEAR_DISTANCE);
alDopplerFactor(1);
EVENT_SUBSCRIBE_MEMBER(m_EPlaySoundOnEntity, &SoundSystem::OnPlaySoundOnEntity);
EVENT_SUBSCRIBE_MEMBER(m_EPlaySoundOnPosition, &SoundSystem::OnPlaySoundOnPosition);
EVENT_SUBSCRIBE_MEMBER(m_EPlayBackgroundMusic, &SoundSystem::OnPlayBackgroundMusic);
EVENT_SUBSCRIBE_MEMBER(m_EStopSound, &SoundSystem::OnStopSound);
EVENT_SUBSCRIBE_MEMBER(m_EPauseSound, &SoundSystem::OnPauseSound);
EVENT_SUBSCRIBE_MEMBER(m_EContinueSound, &SoundSystem::OnContinueSound);
EVENT_SUBSCRIBE_MEMBER(m_ESetBGMGain, &SoundSystem::OnSetBGMGain);
EVENT_SUBSCRIBE_MEMBER(m_ESetSFXGain, &SoundSystem::OnSetSFXGain);
}
SoundSystem::~SoundSystem()
{
stopEmitters(); // Stopps emitters
deleteInactiveEmitters(); // Deletes stopped emitters
// Delete entities
std::unordered_map<EntityID, Source*>::iterator it;
for (it = m_Sources.begin(); it != m_Sources.end(); it++) {
m_World->DeleteEntity((*it).first);
}
m_Sources.clear();
alcDestroyContext(m_ALCcontext);
alcCloseDevice(m_ALCdevice);
}
void SoundSystem::stopEmitters()
{
std::unordered_map<EntityID, Source*>::iterator it;
for (it = m_Sources.begin(); it != m_Sources.end(); it++) {
if (getSourceState(it->second->ALsource) == AL_PLAYING) {
stopSound(it->second);
}
}
}
void SoundSystem::Update(double dt)
{
m_EventBroker->Process<SoundSystem>();
addNewEmitters(dt); // can be optimized with "EEntityCreated"
deleteInactiveEmitters(); // can be optimized with "EEntityDeleted"
updateEmitters( dt);
updateListener( dt);
}
void SoundSystem::deleteInactiveEmitters()
{
std::unordered_map<EntityID, Source*>::iterator it;
for (it = m_Sources.begin(); it != m_Sources.end();) {
if (m_World->ValidEntity(it->first)
&& m_World->HasComponent(it->first, "SoundEmitter")) {
if (getSourceState(it->second->ALsource) != AL_STOPPED) {
// Nothing to see here, move along
it++;
continue;
} else {
// Sound has been stopped / finished playing.
alDeleteBuffers(1, &it->second->ALsource);
alDeleteSources(1, &it->second->ALsource);
m_World->DeleteEntity(it->first);
delete it->second;
it = m_Sources.erase(it);
}
} else {
// Entity / Component has been removed
stopSound((*it).second);
alDeleteBuffers(1, &it->second->ALsource);
alDeleteSources(1, &it->second->ALsource);
delete it->second;
it = m_Sources.erase(it);
}
}
}
void SoundSystem::addNewEmitters(double dt)
{
auto emitterComponents = m_World->GetComponents("SoundEmitter");
if (emitterComponents == nullptr) {
return;
}
for (auto it = emitterComponents->begin(); it != emitterComponents->end(); it++) {
EntityID emitter = (*it).EntityID;
std::unordered_map<EntityID, Source*>::iterator source;
source = m_Sources.find(emitter);
if (source == m_Sources.end()) { // Did not exist, add it
Source* source = createSource((std::string)(*it)["FilePath"]);
m_Sources[emitter] = source;
}
}
}
void SoundSystem::updateEmitters(double dt)
{
std::unordered_map<EntityID, Source*>::iterator it;
for (it = m_Sources.begin(); it != m_Sources.end(); it++) {
// Get previous pos
glm::vec3 previousPos;
alGetSource3f(it->second->ALsource, AL_POSITION, &previousPos.x, &previousPos.y, &previousPos.z);
// Get next pos
glm::vec3 nextPos = Transform::AbsolutePosition(m_World, it->first);
// Calculate velocity
glm::vec3 velocity = glm::vec3(nextPos - previousPos) / (float)dt;
setSourcePos(it->second->ALsource, nextPos);
setSourceVel(it->second->ALsource, velocity);
float gain;
(bool)(it->second->Type) ? gain = m_SFXVolumeChannel : gain = m_BGMVolumeChannel;
auto emitter = m_World->GetComponent(it->first, "SoundEmitter");
setSoundProperties(it->second->ALsource, &emitter);
// To make an emitter play when spawned in editor mode
if (m_EditorEnabled) {
// Path changed
if (it->second->SoundResource->Path() != (std::string)emitter["FilePath"]) {
it->second->SoundResource = ResourceManager::Load<Sound>((std::string)emitter["FilePath"]);
if (it->second->SoundResource->Buffer() != 0) {
playSound(it->second);
}
}
}
}
}
void SoundSystem::updateListener(double dt)
{
// Should only be one listener.
auto listenerComponents = m_World->GetComponents("Listener");
if (listenerComponents == nullptr) {
return;
}
for (auto it = listenerComponents->begin(); it != listenerComponents->end(); it++) {
EntityID listener = (*it).EntityID;
glm::vec3 previousPos;
alGetListener3f(AL_POSITION, &previousPos.x, &previousPos.y, &previousPos.z); // Get previous pos
glm::vec3 nextPos = Transform::AbsolutePosition(m_World, listener); // Get next (current) pos
glm::vec3 velocity = glm::vec3(nextPos - previousPos) / (float)dt; // Calculate velocity
setListenerPos(nextPos);
setListenerVel(velocity);
setListenerOri(glm::eulerAngles(Transform::AbsoluteOrientation(m_World, listener)));
}
}
Source* SoundSystem::createSource(std::string filePath)
{
ALuint alSource;
alGenSources((ALuint)1, &alSource);
alSourcef(alSource, AL_REFERENCE_DISTANCE, 1.0);
alSourcef(alSource, AL_MAX_DISTANCE, FLT_MAX);
Source* source = new Source();
source->ALsource = alSource;
source->SoundResource = ResourceManager::Load<Sound>(filePath);
return source;
}
void SoundSystem::playSound(Source* source)
{
alSourcei(source->ALsource, AL_BUFFER, source->SoundResource->Buffer());
alSourcePlay(source->ALsource);
}
void SoundSystem::stopSound(Source* source)
{
alSourceStop(source->ALsource);
}
bool SoundSystem::OnPlaySoundOnEntity(const Events::PlaySoundOnEntity & e)
{
Source* source = createSource(e.FilePath);
source->Type = SoundType::SFX;
m_Sources[e.EmitterID] = source;
playSound(source);
return false;
}
bool SoundSystem::OnPlaySoundOnPosition(const Events::PlaySoundOnPosition & e)
{
Source* source = createSource(e.FilePath);
auto emitterID = m_World->CreateEntity();
auto transform = m_World->AttachComponent(emitterID, "Transform");
(glm::vec3&)transform["Position"] = e.Position;
auto emitter = m_World->AttachComponent(emitterID, "SoundEmitter");
(float&)(double)emitter["Gain"] = e.Gain;
(float&)(double)emitter["Pitch"] = e.Pitch;
(bool&)emitter["Loop"] = e.Loop;
(float&)(double)emitter["MaxDistance"] = e.MaxDistance;
(float&)(double)emitter["RollOffFactor"] = e.RollOffFactor;
(float&)(double)emitter["ReferenceDistance"] = e.ReferenceDistance;
auto model = m_World->AttachComponent(emitterID, "Model");
(std::string&)model["Resource"] = "Models/Core/UnitCube.obj";
source->Type = SoundType::SFX;
m_Sources[emitterID] = source;
playSound(source);
return true;
}
bool SoundSystem::OnPauseSound(const Events::PauseSound & e)
{
alSourcePause(m_Sources[e.EmitterID]->ALsource);
return true;
}
bool SoundSystem::OnStopSound(const Events::StopSound & e)
{
alSourceStop(m_Sources[e.EmitterID]->ALsource);
return true;
}
bool SoundSystem::OnContinueSound(const Events::ContinueSound & e)
{
alSourcePlay(m_Sources[e.EmitterID]->ALsource);
return true;
}
bool SoundSystem::OnPlayBackgroundMusic(const Events::PlayBackgroundMusic & e)
{
auto listenerComponents = m_World->GetComponents("Listener");
for (auto it = listenerComponents->begin(); it != listenerComponents->end(); it++) {
auto emitterChild = m_World->CreateEntity((*it).EntityID);
auto emitter = m_World->AttachComponent(emitterChild, "SoundEmitter");
(bool&)emitter["Loop"] = true;
(std::string&)emitter["FilePath"] = e.FilePath;
m_World->AttachComponent(emitterChild, "Transform");
Source* source = createSource(e.FilePath);
source->Type = SoundType::BGM;
m_Sources[emitterChild] = source;
playSound(source);
}
return true;
}
bool SoundSystem::OnSetBGMGain(const Events::SetBGMGain & e)
{
m_BGMVolumeChannel = e.Gain;
return true;
}
bool SoundSystem::OnSetSFXGain(const Events::SetSFXGain & e)
{
m_SFXVolumeChannel = e.Gain;
return true;
}
void SoundSystem::setListenerOri(glm::vec3 ori)
{
// Calculate forward and up vector.
glm::vec3 forward = glm::vec3(0.0, 0.0, -1.0);
forward = glm::rotateX(forward, ori.x);
forward = glm::rotateY(forward, ori.y);
forward = glm::rotateZ(forward, ori.z);
glm::normalize(forward);
glm::vec3 up = glm::vec3(0.0, 1.0, 0.0);
up = glm::rotateX(up, ori.x);
up = glm::rotateY(up, ori.y);
up = glm::rotateZ(up, ori.z);
glm::normalize(up);
ALfloat lOri[6] = { forward.x, forward.y, forward.z, up.x, up.y, up.z };
alListenerfv(AL_ORIENTATION, lOri);
}
ALenum SoundSystem::getSourceState(ALuint source)
{
ALenum state;
alGetSourcei(source, AL_SOURCE_STATE, &state);
return state;
}
void SoundSystem::setGain(Source * source, float gain)
{
alSourcef(source->ALsource, AL_GAIN, gain);
}
void SoundSystem::setSoundProperties(ALuint source, ComponentWrapper* soundComponent)
{
alSourcef(source, AL_GAIN, (float)(double)(*soundComponent)["Gain"]);
alSourcef(source, AL_PITCH, (float)(double)(*soundComponent)["Pitch"]);
alSourcei(source, AL_LOOPING, (int)(bool)(*soundComponent)["Loop"]); // YOLO
alSourcef(source, AL_MAX_DISTANCE, (float)(double)(*soundComponent)["MaxDistance"]);
alSourcef(source, AL_ROLLOFF_FACTOR, (float)(double)(*soundComponent)["RollOffFactor"]);
alSourcef(source, AL_REFERENCE_DISTANCE, (float)(double)(*soundComponent)["ReferenceDistance"]);
}
void SoundSystem::initOpenAL()
{
// Initialize OpenAL
m_ALCdevice = alcOpenDevice(nullptr);
if (m_ALCdevice != nullptr) {
m_ALCcontext = alcCreateContext(m_ALCdevice, nullptr);
alcMakeContextCurrent(m_ALCcontext);
} else {
LOG_ERROR("OpenAL failed to initialize.");
}
}