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

# Conflicts:
#	resources/Schema/Entities/RenderingWorld.xml
#	resources/Shaders/ForwardPlus.frag.glsl
#	src/Engine/Editor/EditorSystem.cpp
#	src/Engine/Network/Server.cpp
#	src/Engine/Rendering/DrawFinalPass.cpp
#	src/Tests/OctTreeTestGameClass.cpp
#	src/Tests/OctTreeTestHardCodedTestWorld.h
#	src/Tests/ResourceManagerTest.cpp
This commit is contained in:
antc13
2016-01-24 14:40:52 +01:00
172 changed files with 6609 additions and 2458 deletions
+3
View File
@@ -8,6 +8,7 @@ find_package(assimp REQUIRED)
find_package(ZLIB REQUIRED)
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/OpenAL")
find_package(OpenAL REQUIRED)
@@ -25,6 +26,7 @@ include_directories(
${assimp_INCLUDE_DIRS}
${PNG_INCLUDE_DIRS}
${Xerces_INCLUDE_DIRS}
${FREETYPE_INCLUDE_DIRS}
${OPENAL_INCLUDE_DIR}
${X11_INCLUDE_DIRS}
)
@@ -126,6 +128,7 @@ set(LIBRARIES
${assimp_LIBRARIES}
${PNG_LIBRARIES}
${Xerces_LIBRARIES}
${FREETYPE_LIBRARIES}
${OPENAL_LIBRARY}
${X11_LIBRARIES}
)
@@ -1,11 +1,11 @@
#include "Collision/CollidableOctreeSystem.h"
void CollidableOctreeSystem::Update(World* world, double dt)
void CollidableOctreeSystem::Update(double dt)
{
m_Octree->ClearDynamicObjects();
}
void CollidableOctreeSystem::UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt)
void CollidableOctreeSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt)
{
if (entity.HasComponent("AABB")) {
boost::optional<AABB> absoluteAABB = Collision::EntityAbsoluteAABB(entity);
+2 -2
View File
@@ -2,7 +2,7 @@
#include "Collision/CollisionSystem.h"
#include "Core/AABB.h"
void CollisionSystem::UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt)
void CollisionSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt)
{
if (!entity.HasComponent("Physics")) {
return;
@@ -23,7 +23,7 @@ void CollisionSystem::UpdateComponent(World* world, EntityWrapper& entity, Compo
// Collide against octree
std::vector<AABB> octreeResult;
m_Octree->BoxesInSameRegion(*boundingBox, octreeResult);
m_Octree->ObjectsInSameRegion(*boundingBox, octreeResult);
for (auto& boxB : octreeResult) {
glm::vec3 resolutionVector;
if (Collision::IsSameBoxProbably(boxA, boxB)) {
+9 -6
View File
@@ -3,10 +3,10 @@
#include "Core/AABB.h"
#include "Rendering/Model.h"
void TriggerSystem::UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt)
void TriggerSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt)
{
//Currently only players can trigger things.
auto players = world->GetComponents("Player");
auto players = m_World->GetComponents("Player");
if (players == nullptr) {
return;
}
@@ -18,7 +18,7 @@ void TriggerSystem::UpdateComponent(World* world, EntityWrapper& entity, Compone
}
for (auto& pc : *players) {
EntityID pId = pc.EntityID;
boost::optional<AABB> playerBox = Collision::EntityAbsoluteAABB(EntityWrapper(world, pId));
boost::optional<AABB> playerBox = Collision::EntityAbsoluteAABB(EntityWrapper(m_World, pId));
//The player can't trigger anything without an AABB.
if (!playerBox) {
continue;
@@ -34,9 +34,12 @@ void TriggerSystem::UpdateComponent(World* world, EntityWrapper& entity, Compone
throwLeaveIfWasInTrigger(m_EntitiesCompletelyInTrigger[tId], pId, tId);
} else {
//Entity is at least touching the trigger.
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()))) {
AABB completelyInsideBox;
bool playerFitsInTrigger = glm::all(glm::greaterThan((*triggerBox).Size(), (*playerBox).Size()));
if (playerFitsInTrigger) {
completelyInsideBox = AABB::FromOriginSize((*triggerBox).Origin(), (*triggerBox).Size() - 2.0f * (*playerBox).Size());
}
if (playerFitsInTrigger && Collision::AABBVsAABB(completelyInsideBox, *playerBox)) {
//Entity is completely inside the trigger.
//If it was only touching before, it is erased.
m_EntitiesTouchingTrigger[tId].erase(pId);
+2
View File
@@ -15,6 +15,8 @@ AABB::AABB(const glm::vec3& minPos, const glm::vec3& maxPos)
m_MinCorner.y = glm::min(m_MaxCorner.y, m_MinCorner.y);
m_MaxCorner.z = glm::max(m_MaxCorner.z, m_MinCorner.z);
m_MinCorner.z = glm::min(m_MaxCorner.z, m_MinCorner.z);
m_Origin = 0.5f * (m_MaxCorner + m_MinCorner);
m_HalfSize = 0.5f * (m_MaxCorner - m_MinCorner);
}
}
+5 -1
View File
@@ -50,7 +50,6 @@ ComponentWrapper ComponentPool::GetByEntity(EntityID ent)
return ComponentWrapper(m_ComponentInfo, m_EntityToComponent.at(ent));
}
bool ComponentPool::KnowsEntity(EntityID ent)
{
return m_EntityToComponent.find(ent) != m_EntityToComponent.end();
@@ -72,6 +71,11 @@ ComponentPool::iterator ComponentPool::end() const
return iterator(m_ComponentInfo, m_Pool.end(), m_Pool.end());
}
size_t ComponentPool::size() const
{
return m_Pool.size();
}
template <typename InterpretType /*= char*/>
void ComponentPool::Dump() const
{
+25 -19
View File
@@ -47,7 +47,7 @@ std::size_t EntityFile::GetTypeStride(std::string typeName)
{ "float", sizeof(float) },
{ "double", sizeof(double) },
{ "string", sizeof(std::string) },
{ "enum", sizeof(int) },
{ "enum", sizeof(ComponentInfo::EnumType) },
{ "Vector", sizeof(glm::vec3) },
{ "Quaternion", sizeof(glm::quat) },
{ "Color", sizeof(glm::vec4) }
@@ -86,23 +86,29 @@ 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" || field.Type == "enum") {
int value = boost::lexical_cast<int>(valueData);
memcpy(outData, reinterpret_cast<char*>(&value), field.Stride);
} else if (field.Type == "float") {
float value = boost::lexical_cast<float>(valueData);
memcpy(outData, reinterpret_cast<char*>(&value), field.Stride);
} else if (field.Type == "double") {
double value = boost::lexical_cast<double>(valueData);
memcpy(outData, reinterpret_cast<char*>(&value), field.Stride);
} else if (field.Type == "bool") {
bool value = (valueData[0] == 't'); // Lazy bool evaluation
memcpy(outData, reinterpret_cast<char*>(&value), field.Stride);
} else if (field.Type == "string") {
new (outData) std::string(valueData);
} else {
LOG_WARNING("Unknown value data type: %s", field.Type.c_str());
}
// Catch and ignore casting errors so whitespace around string enums won't mess anything up
try {
if (field.Type == "int") {
int value = boost::lexical_cast<int>(valueData);
memcpy(outData, reinterpret_cast<char*>(&value), field.Stride);
} else if (field.Type == "enum") {
ComponentInfo::EnumType value = boost::lexical_cast<ComponentInfo::EnumType>(valueData);
memcpy(outData, reinterpret_cast<char*>(&value), field.Stride);
} else if (field.Type == "float") {
float value = boost::lexical_cast<float>(valueData);
memcpy(outData, reinterpret_cast<char*>(&value), field.Stride);
} else if (field.Type == "double") {
double value = boost::lexical_cast<double>(valueData);
memcpy(outData, reinterpret_cast<char*>(&value), field.Stride);
} else if (field.Type == "bool") {
bool value = (valueData[0] == 't'); // Lazy bool evaluation
memcpy(outData, reinterpret_cast<char*>(&value), field.Stride);
} else if (field.Type == "string") {
new (outData) std::string(valueData);
} else {
LOG_WARNING("Unknown value data type: %s", field.Type.c_str());
}
} catch (const boost::bad_lexical_cast&) { }
}
EntityFileSAXHandler::EntityFileSAXHandler(const EntityFileHandler* handler, xercesc::SAX2XMLReader* reader) : m_Handler(handler)
@@ -165,7 +171,7 @@ void EntityFileSAXHandler::endElement(const XMLCh* const _uri, const XMLCh* cons
//}
}
if (m_StateStack.top() == State::ComponentField) {
if (m_StateStack.top() == State::ComponentField && name == m_CurrentField) {
m_StateStack.pop();
onEndComponentField(name);
return;
+7 -7
View File
@@ -28,14 +28,14 @@ void EntityFileParser::onStartEntity(EntityID entity, EntityID parent, const std
m_World->SetName(realEntity, name);
}
m_EntityIDMapper[entity] = realEntity;
LOG_DEBUG("Created entity #%i (%i) with parent %i (%i)", entity, realEntity, parent, realParent);
//LOG_DEBUG("Created entity #%i (%i) with parent %i (%i)", entity, realEntity, parent, realParent);
}
void EntityFileParser::onStartComponent(EntityID entity, const std::string& component)
{
EntityID realEntity = m_EntityIDMapper.at(entity);
m_World->AttachComponent(realEntity, component);
LOG_DEBUG("Attached component of type \"%s\" to entity #%i (%i)", component.c_str(), entity, realEntity);
//LOG_DEBUG("Attached component of type \"%s\" to entity #%i (%i)", component.c_str(), entity, realEntity);
}
void EntityFileParser::onStartComponentField(EntityID entity, const std::string& componentType, const std::string& fieldName, const std::map<std::string, std::string>& attributes)
@@ -49,11 +49,11 @@ void EntityFileParser::onStartComponentField(EntityID entity, const std::string&
}
auto& field = fieldIt->second;
LOG_DEBUG("Field \"%s\" type \"%s\"", fieldName.c_str(), field.Type.c_str());
LOG_DEBUG("Attributes:");
for (auto& kv : attributes) {
LOG_DEBUG("\t%s = %s", kv.first.c_str(), kv.second.c_str());
}
//LOG_DEBUG("Field \"%s\" type \"%s\"", fieldName.c_str(), field.Type.c_str());
//LOG_DEBUG("Attributes:");
//for (auto& kv : attributes) {
// LOG_DEBUG("\t%s = %s", kv.first.c_str(), kv.second.c_str());
//}
char* data = component.Data + field.Offset;
EntityFile::WriteAttributeData(data, field, attributes);
+21 -22
View File
@@ -7,23 +7,23 @@ EntityFilePreprocessor::EntityFilePreprocessor(const EntityFile* entityFile)
handler.SetStartComponentCallback(std::bind(&EntityFilePreprocessor::onStartComponent, this, std::placeholders::_1, std::placeholders::_2));
m_EntityFile->Parse(&handler);
LOG_DEBUG("___ COMPONENT DEFINITIONS ___");
for (auto& kv : m_ComponentCounts) {
LOG_DEBUG("%s: %i", kv.first.c_str(), kv.second);
}
//LOG_DEBUG("___ COMPONENT DEFINITIONS ___");
//for (auto& kv : m_ComponentCounts) {
// LOG_DEBUG("%s: %i", kv.first.c_str(), kv.second);
//}
parseComponentInfo();
for (auto& kv : m_ComponentInfo) {
auto& info = kv.second;
LOG_DEBUG("Component: %s (%s)", info.Name.c_str(), info.Meta->Annotation.c_str());
LOG_DEBUG("Stride: %i", info.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.c_str(), kv.first.c_str());
}
}
//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.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.c_str(), kv.first.c_str());
// }
//}
parseDefaults();
}
@@ -50,7 +50,6 @@ void EntityFilePreprocessor::parseComponentInfo()
auto xsModel = grammarPool->getXSModel(whateverTheFuckThisIs);
// Find component xsd element declarations
std::cout << "Enumerating components..." << std::endl;
// <xs:element name="ComponentName">
auto topLevelElements = xsModel->getComponents(XSConstants::ELEMENT_DECLARATION);
for (unsigned int i = 0; i < topLevelElements->getLength(); ++i) {
@@ -73,7 +72,7 @@ void EntityFilePreprocessor::parseComponentInfo()
if (componentAnnotation != nullptr) {
compInfo.Meta->Annotation = parseAnnotationXML(componentAnnotation->getAnnotationString());
} else {
LOG_WARNING("Component \"%s\" is missing an annotation!", compInfo.Name.c_str());
//LOG_WARNING("Component \"%s\" is missing an annotation!", compInfo.Name.c_str());
}
// <xs:complexType>
@@ -91,7 +90,7 @@ void EntityFilePreprocessor::parseComponentInfo()
// <xs:all>
auto modelGroupParticle = complexTypeDefinition->getParticle();
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());
//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();
@@ -103,7 +102,7 @@ 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("Failed to parse a field definition in component \"%s\": Particle wasn't TERM_ELEMENT! Skipping.", compInfo.Name.c_str());
//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();
@@ -129,7 +128,7 @@ void EntityFilePreprocessor::parseComponentInfo()
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());
//LOG_WARNING("Component field \"%s.%s\" is missing an annotation!", compInfo.Name.c_str(), name.c_str());
}
if (effectiveType == "enum") {
@@ -146,8 +145,8 @@ void EntityFilePreprocessor::parseComponentInfo()
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());
compInfo.Meta->FieldEnumDefinitions[name][enumName] = boost::lexical_cast<ComponentInfo::EnumType>(enumValue);
//LOG_DEBUG("ENUM %s = %s", enumName.c_str(), enumValue.c_str());
}
}
}
@@ -190,7 +189,7 @@ void EntityFilePreprocessor::parseDefaults()
//std::string namespaceSchema = schemaLocation.string();
//parser.setExternalNoNamespaceSchemaLocation("Teamasdasdasdasd.xsd");
LOG_DEBUG("Parsing defaults for component %s", componentName.c_str());
//LOG_DEBUG("Parsing defaults for component %s", componentName.c_str());
boost::filesystem::path defaultsFile = "Schema/Components/" + componentName + ".xml";
parser.parse(defaultsFile.string().c_str());
+10 -1
View File
@@ -114,9 +114,18 @@ 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" || field.Type == "enum") {
} else if (field.Type == "int") {
const int& value = c[fieldName];
fieldElement->appendChild(doc->createTextNode(X(boost::lexical_cast<std::string>(value))));
} else if (field.Type == "enum") {
const ComponentInfo::EnumType& value = c[fieldName];
auto& enumDef = c.Info.Meta->FieldEnumDefinitions.at(fieldName);
for (auto& kv : enumDef) {
if (kv.second == value) {
fieldElement->appendChild(doc->createElement(X(kv.first)));
break;
}
}
} else if (field.Type == "float") {
const float& value = c[fieldName];
fieldElement->appendChild(doc->createTextNode(X(boost::lexical_cast<std::string>(value))));
+45 -8
View File
@@ -3,28 +3,65 @@
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)
EntityWrapper EntityWrapper::Parent()
{
if (this->World == nullptr || this->ID == EntityID_Invalid) {
return EntityWrapper::Invalid;
} else {
return EntityWrapper(this->World, this->World->GetParent(this->ID));
}
}
bool EntityWrapper::Valid()
{
if (this->World == nullptr) {
return false;
}
if (this->ID == EntityID_Invalid) {
return false;
}
if (!this->World->ValidEntity(this->ID)) {
this->ID = EntityID_Invalid;
return false;
}
return true;
}
ComponentWrapper EntityWrapper::operator[](const char* 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);
LOG_WARNING("EntityWrapper implicitly attached \"%s\" component to #%i as a result of a fetch request!", componentName, ID);
return World->AttachComponent(ID, componentName);
}
}
EntityWrapper::operator EntityID()
bool EntityWrapper::operator==(const EntityWrapper& e) const
{
return (this->ID == e.ID) && (this->World == e.World);
}
bool EntityWrapper::operator!=(const EntityWrapper& e) const
{
return !this->operator==(e);
}
EntityWrapper::operator EntityID() const
{
return this->ID;
}
EntityWrapper::operator bool()
{
return this->Valid();
}
+6
View File
@@ -34,10 +34,16 @@ void InputManager::Update(double dt)
if (m_CurrentKeyState[i]) {
Events::KeyDown e;
e.KeyCode = i;
e.ModCtrl = glfwGetKey(m_GLFWWindow, GLFW_KEY_LEFT_CONTROL) || glfwGetKey(m_GLFWWindow, GLFW_KEY_RIGHT_CONTROL);
e.ModAlt = glfwGetKey(m_GLFWWindow, GLFW_KEY_LEFT_ALT) || glfwGetKey(m_GLFWWindow, GLFW_KEY_RIGHT_ALT);
e.ModShift = glfwGetKey(m_GLFWWindow, GLFW_KEY_LEFT_SHIFT) || glfwGetKey(m_GLFWWindow, GLFW_KEY_RIGHT_SHIFT);
m_EventBroker->Publish(e);
} else {
Events::KeyUp e;
e.KeyCode = i;
e.ModCtrl = glfwGetKey(m_GLFWWindow, GLFW_KEY_LEFT_CONTROL) || glfwGetKey(m_GLFWWindow, GLFW_KEY_RIGHT_CONTROL);
e.ModAlt = glfwGetKey(m_GLFWWindow, GLFW_KEY_LEFT_ALT) || glfwGetKey(m_GLFWWindow, GLFW_KEY_RIGHT_ALT);
e.ModShift = glfwGetKey(m_GLFWWindow, GLFW_KEY_LEFT_SHIFT) || glfwGetKey(m_GLFWWindow, GLFW_KEY_RIGHT_SHIFT);
m_EventBroker->Publish(e);
}
}
+26 -115
View File
@@ -21,72 +21,11 @@ bool isFirstLower(const ChildInfo& first, const ChildInfo& second)
}
Octree::Octree(const AABB& octTreeBounds, int subDivisions)
: m_Root(new Child(octTreeBounds, subDivisions, m_StaticObjects, m_DynamicObjects))
, m_UpdatedOnce(false)
{ }
Octree::~Octree()
namespace OctSpace
{
delete m_Root;
}
void Octree::AddDynamicObject(const AABB& box)
{
m_Root->AddDynamicObject(box);
m_DynamicObjects.push_back(box);
}
void Octree::AddStaticObject(const AABB& box)
{
m_Root->AddStaticObject(box);
m_StaticObjects.push_back(box);
}
void Octree::BoxesInSameRegion(const AABB& box, std::vector<AABB>& outBoxes)
{
falsifyObjectChecks();
m_Root->BoxesInSameRegion(box, outBoxes);
}
void Octree::ClearObjects()
{
m_StaticObjects.clear();
m_DynamicObjects.clear();
m_Root->ClearObjects();
}
void Octree::ClearDynamicObjects()
{
m_DynamicObjects.clear();
m_Root->ClearDynamicObjects();
}
bool Octree::RayCollides(const Ray& ray, Output& data)
{
falsifyObjectChecks();
data.CollideDistance = -1;
return m_Root->RayCollides(ray, data);
}
bool Octree::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected)
{
falsifyObjectChecks();
return m_Root->BoxCollides(boxToTest, outBoxIntersected);
}
void Octree::falsifyObjectChecks()
{
for (auto& obj : m_StaticObjects) {
obj.Checked = false;
}
for (auto& obj : m_DynamicObjects) {
obj.Checked = false;
}
}
Octree::Child::Child(const AABB& octTreeBounds,
int subDivisions,
Child::Child(const AABB& octTreeBounds,
int subDivisions,
std::vector<ContainedObject>& staticObjects,
std::vector<ContainedObject>& dynamicObjects)
: m_Box(octTreeBounds)
@@ -135,7 +74,7 @@ Octree::Child::Child(const AABB& octTreeBounds,
}
}
Octree::Child::~Child()
Child::~Child()
{
for (Child*& c : m_Children) {
if (c != nullptr) {
@@ -145,7 +84,7 @@ Octree::Child::~Child()
}
}
bool Octree::Child::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const
bool Child::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const
{
if (hasChildren()) {
for (int i : childIndicesContainingBox(boxToTest)) {
@@ -155,7 +94,7 @@ bool Octree::Child::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected)
} else {
for (int i : m_StaticObjIndices) {
if (!m_StaticObjectsRef[i].Checked) {
const AABB& objBox = m_StaticObjectsRef[i].Box;
const AABB& objBox = *m_StaticObjectsRef[i].Box;
if (Collision::AABBVsAABB(boxToTest, objBox)) {
outBoxIntersected = objBox;
return true;
@@ -165,7 +104,7 @@ bool Octree::Child::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected)
}
for (int i : m_DynamicObjIndices) {
if (!m_DynamicObjectsRef[i].Checked) {
const AABB& objBox = m_DynamicObjectsRef[i].Box;
const AABB& objBox = *m_DynamicObjectsRef[i].Box;
if (!Collision::IsSameBoxProbably(boxToTest, objBox) &&
Collision::AABBVsAABB(boxToTest, objBox)) {
outBoxIntersected = objBox;
@@ -178,7 +117,7 @@ bool Octree::Child::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected)
return false;
}
bool Octree::Child::RayCollides(const Ray& ray, Output& data) const
bool Child::RayCollides(const Ray& ray, OctSpace::Output& data) const
{
//If the node AABB is missed, everything it contains is missed.
if (Collision::RayAABBIntr(ray, m_Box)) {
@@ -205,7 +144,7 @@ bool Octree::Child::RayCollides(const Ray& ray, Output& data) const
float dist;
//If we haven't tested against this object before, and the ray hits.
if (!m_StaticObjectsRef[i].Checked &&
Collision::RayVsAABB(ray, m_StaticObjectsRef[i].Box, dist)) {
Collision::RayVsAABB(ray, *m_StaticObjectsRef[i].Box, dist)) {
minDist = std::min(dist, minDist);
intersected = true;
}
@@ -215,7 +154,7 @@ bool Octree::Child::RayCollides(const Ray& ray, Output& data) const
float dist;
//If we haven't tested against this object before, and the ray hits.
if (!m_DynamicObjectsRef[i].Checked &&
Collision::RayVsAABB(ray, m_DynamicObjectsRef[i].Box, dist)) {
Collision::RayVsAABB(ray, *m_DynamicObjectsRef[i].Box, dist)) {
minDist = std::min(dist, minDist);
intersected = true;
}
@@ -230,7 +169,7 @@ bool Octree::Child::RayCollides(const Ray& ray, Output& data) const
}
void Octree::Child::AddDynamicObject(const AABB& box)
void Child::AddDynamicObject(const AABB& box)
{
if (hasChildren()) {
for (auto i : childIndicesContainingBox(box)) {
@@ -242,7 +181,7 @@ void Octree::Child::AddDynamicObject(const AABB& box)
}
}
void Octree::Child::AddStaticObject(const AABB& box)
void Child::AddStaticObject(const AABB& box)
{
if (hasChildren()) {
for (auto i : childIndicesContainingBox(box)) {
@@ -254,41 +193,7 @@ void Octree::Child::AddStaticObject(const AABB& box)
}
}
void Octree::Child::BoxesInSameRegion(const AABB& box, std::vector<AABB>& outBoxes) const
{
if (hasChildren()) {
for (auto i : childIndicesContainingBox(box)) {
m_Children[i]->BoxesInSameRegion(box, outBoxes);
}
} else {
size_t startIndex = outBoxes.size();
int numDuplicates = 0;
outBoxes.resize(outBoxes.size() + m_StaticObjIndices.size() + m_DynamicObjIndices.size());
for (size_t i = 0; i < m_StaticObjIndices.size(); ++i){
ContainedObject& obj = m_StaticObjectsRef[m_StaticObjIndices[i]];
if (obj.Checked) {
++numDuplicates;
} else {
obj.Checked = true;
outBoxes[startIndex + i - numDuplicates] = obj.Box;
}
}
for (size_t i = 0; i < m_DynamicObjIndices.size(); ++i) {
ContainedObject& obj = m_DynamicObjectsRef[m_DynamicObjIndices[i]];
if (obj.Checked) {
++numDuplicates;
} else {
obj.Checked = true;
outBoxes[startIndex + i - numDuplicates] = obj.Box;
}
}
for (size_t i = 0; i < numDuplicates; ++i) {
outBoxes.pop_back();
}
}
}
void Octree::Child::ClearObjects()
void Child::ClearObjects()
{
if (hasChildren()) {
for (Child*& c : m_Children) {
@@ -300,11 +205,11 @@ void Octree::Child::ClearObjects()
}
}
void Octree::Child::ClearDynamicObjects()
void Child::ClearDynamicObjects()
{
if (hasChildren()) {
for (Child*& c : m_Children) {
c->ClearObjects();
c->ClearDynamicObjects();
}
} else {
m_DynamicObjIndices.clear();
@@ -323,13 +228,13 @@ void Octree::Child::ClearDynamicObjects()
// x : - - - - + + + +
// y : - - + + - - + +
// z : - + - + - + - +
int Octree::Child::childIndexContainingPoint(const glm::vec3& point) const
int Child::childIndexContainingPoint(const glm::vec3& point) const
{
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> Octree::Child::childIndicesContainingBox(const AABB& box) const
std::vector<int> Child::childIndicesContainingBox(const AABB& box) const
{
int minInd = childIndexContainingPoint(box.MinCorner());
int maxInd = childIndexContainingPoint(box.MaxCorner());
@@ -352,9 +257,13 @@ std::vector<int> Octree::Child::childIndicesContainingBox(const AABB& box) const
//the dimensions they are responsible for (which octant).
bits.flip();
//At this point the bits necessarily have exactly one bit set.
//Check the same bit in the minInd as the one set in bits.
int setOrUnset = (bits.to_ulong() & minInd);
for (int c = 0; c < 8; ++c) {
//If the child index have the same bit set as the bits, add box to it.
if (bits.to_ulong() & c) {
//Check the same bit in the child index as the one set in bits.
//Enter here if both c and minInd have the bit set, or if neither have it set.
//I.e, if they are on the same side (+ or -) in the dimension marked by the bit in bits.
if (!((bits.to_ulong() & c) ^ setOrUnset)) {
ret.push_back(c);
}
}
@@ -367,7 +276,9 @@ std::vector<int> Octree::Child::childIndicesContainingBox(const AABB& box) const
}
}
inline bool Octree::Child::hasChildren() const
inline bool Child::hasChildren() const
{
return m_Children[0] != nullptr;
}
}
+24
View File
@@ -0,0 +1,24 @@
#include "Core/UniformScaleSystem.h"
UniformScaleSystem::UniformScaleSystem(World* world, EventBroker* eventBroker)
: System(world, eventBroker)
, PureSystem("UniformScale")
{
EVENT_SUBSCRIBE_MEMBER(m_ESetCamera, &UniformScaleSystem::OnSetCamera);
}
void UniformScaleSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& cUniformScale, double dt)
{
if (!m_Camera.Valid()) {
return;
}
float distance = glm::length((glm::vec3)entity["Transform"]["Position"] - (glm::vec3&)m_Camera["Transform"]["Position"]);
entity["Transform"]["Scale"] = (glm::vec3&)cUniformScale["Scale"] * distance;
}
bool UniformScaleSystem::OnSetCamera(const Events::SetCamera& e)
{
m_Camera = e.CameraEntity;
return false;
}
+734
View File
@@ -0,0 +1,734 @@
#include "Editor/EditorGUI.h"
EditorGUI::EditorGUI(World* world, EventBroker* eventBroker)
: m_World(world)
, m_EventBroker(eventBroker)
{
EVENT_SUBSCRIBE_MEMBER(m_EKeyDown, &EditorGUI::OnKeyDown);
}
void EditorGUI::Draw()
{
ImGui::ShowTestWindow();
drawMenu();
drawTools();
drawEntities(m_World);
drawComponents(m_CurrentSelection);
drawModals();
}
void EditorGUI::SelectEntity(EntityWrapper entity)
{
m_CurrentSelection = entity;
if (m_OnEntitySelected != nullptr) {
m_OnEntitySelected(entity);
}
}
void EditorGUI::drawMenu()
{
}
void EditorGUI::drawTools()
{
if (!ImGui::Begin("Tools", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysAutoResize)) {
return;
}
createWidgetToolButton(WidgetMode::Translate);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Translate");
}
ImGui::SameLine();
createWidgetToolButton(WidgetMode::Rotate);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Rotate");
}
ImGui::SameLine();
createWidgetToolButton(WidgetMode::Scale);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Scale");
}
ImGui::SameLine();
ImGui::ItemSize(ImVec2(5, 0));
// Play button
ImGui::SameLine();
static bool paused = false;
if (ImGui::ImageButton((void*)tryLoadTexture("Textures/Icons/Play.png"), ImVec2(24, 24), ImVec2(0, 1), ImVec2(1, 0), -1, ImVec4(0, 0, 0, 0), (!paused) ? ImVec4(0, 1, 0, 1) : ImVec4(1, 1, 1, 1))) {
Events::Resume e;
e.World = m_World;
m_EventBroker->Publish(e);
paused = false;
}
// Pause button
ImGui::SameLine();
if (ImGui::ImageButton((void*)tryLoadTexture("Textures/Icons/Pause.png"), ImVec2(24, 24), ImVec2(0, 1), ImVec2(1, 0), -1, ImVec4(0, 0, 0, 0), (paused) ? ImVec4(0, 1, 0, 1) : ImVec4(1, 1, 1, 1))) {
Events::Pause e;
e.World = m_World;
m_EventBroker->Publish(e);
paused = true;
}
ImGui::End();
}
void EditorGUI::drawEntities(World* world)
{
if (!ImGui::Begin("Entities")) {
ImGui::End();
return;
}
float buttonWidth = (ImGui::GetContentRegionAvailWidth() - 10.f) / 3.f ;
if (ImGui::Button("Create", ImVec2(buttonWidth, 0))) {
entityCreate(world, m_CurrentSelection);
}
ImGui::SameLine(0.f, 5.f);
if (ImGui::Button("Import", ImVec2(buttonWidth, 0))) {
entityImport(world);
}
ImGui::SameLine(0.f, 5.f);
ImGui::ButtonEx("Reference", ImVec2(buttonWidth, 0), ImGuiButtonFlags_Disabled);
// Naming
char buffer[256];
buffer[0] = '\0';
buffer[255] = '\0';
std::size_t nameLength = 0;
ImGuiInputTextFlags flags = ImGuiInputTextFlags_CharsNoBlank | ImGuiInputTextFlags_AutoSelectAll;
if (m_CurrentSelection.Valid()) {
std::string name = world->GetName(m_CurrentSelection.ID);
nameLength = name.length();
if (!name.empty()) {
memcpy(buffer, name.c_str(), std::min(sizeof(buffer) - 1, name.length() + 1));
}
} else {
flags |= ImGuiInputTextFlags_ReadOnly;
}
ImGui::PushItemWidth(ImGui::GetContentRegionAvailWidth() - 7.f);
if (ImGui::InputText("", &buffer[0], sizeof(buffer), flags)) {
if (m_CurrentSelection.Valid()) {
if (m_OnEntityChangeName != nullptr) {
m_OnEntityChangeName(m_CurrentSelection, std::string(buffer));
SetDirty(m_CurrentSelection);
}
}
}
ImGui::PopItemWidth();
ImGui::ItemSize(ImVec2(0, 3));
drawEntitiesRecursive(world, EntityID_Invalid);
ImGui::End();
}
void EditorGUI::drawEntitiesRecursive(World* world, EntityID parent)
{
auto entityChildren = world->GetEntityChildren();
auto range = entityChildren.equal_range(parent);
for (auto it = range.first; it != range.second; it++) {
if (EditorGUI::drawEntityNode(EntityWrapper(world, it->second))) {
drawEntitiesRecursive(world, it->second);
ImGui::TreePop();
}
}
}
bool EditorGUI::drawEntityNode(EntityWrapper entity)
{
// Custom button hitbox to select entities on top of tree node
ImVec2 pos = ImGui::GetCursorScreenPos();
float width = ImGui::GetContentRegionAvailWidth();
ImRect bb(pos + ImVec2(20, 0), pos + ImVec2(width, 14));
auto window = ImGui::GetCurrentWindow();
if (m_CurrentSelection == entity) {
const ImU32 col = window->Color(ImGuiCol_HeaderActive);
window->DrawList->AddRectFilled(bb.Min, bb.Max, col);
}
ImGuiID id = window->GetID((std::string("#SelectButton") + std::to_string(entity.ID)).c_str());
bool hovered = false;
bool held = false;
if (ImGui::ButtonBehavior(bb, id, &hovered, &held)) {
SelectEntity(entity);
}
// Handle entity dragging
if (held) {
ImVec2 entityDragDelta = ImGui::GetMouseDragDelta(0);
if (std::abs(entityDragDelta.x) > 0 && std::abs(entityDragDelta.y) > 0) {
if (m_CurrentlyDragging == EntityWrapper::Invalid) {
m_CurrentlyDragging = entity;
LOG_DEBUG("Started dragging %i", entity.ID);
}
ImGui::SetNextWindowPos(ImGui::GetIO().MousePos + ImVec2(20, 0));
ImGui::Begin("Change parent", nullptr, ImVec2(0, 0), 0.3f, ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoSavedSettings);
ImGui::Text(formatEntityName(entity).c_str());
ImGui::End();
}
}/* else if (m_CurrentlyDragging == entity) {
LOG_DEBUG("Stopped dragging %i", entity.ID);
m_CurrentlyDragging = EntityWrapper::Invalid;
}*/
// Entity context menu
std::string contextMenuUniqueID = std::string("EntityContextMenu") + std::to_string(entity.ID);
if (hovered && ImGui::IsMouseClicked(1)) {
ImGui::OpenPopup(contextMenuUniqueID.c_str());
}
if (ImGui::BeginPopup(contextMenuUniqueID.c_str())) {
ImGui::TextDisabled(formatEntityName(entity).c_str());
if (ImGui::MenuItem("Save", "Ctrl+S")) {
entitySave(entity);
} else
if (ImGui::MenuItem("Save As...", "Ctrl+Shift+S")) {
entitySave(entity, true);
} else
if (ImGui::MenuItem("Delete", "Del")) {
entityDelete(entity);
} else
if (ImGui::MenuItem("Move to root")) {
entityChangeParent(entity, EntityWrapper::Invalid);
}
ImGui::EndPopup();
}
ImGui::SetNextTreeNodeOpened(true, ImGuiSetCond_Once);
if (ImGui::TreeNode(formatEntityName(entity).c_str())) {
// Handle drop events for reparenting
if (m_CurrentlyDragging != EntityWrapper::Invalid && ImGui::IsItemHoveredRect() && ImGui::IsMouseReleased(0)) {
entityChangeParent(m_CurrentlyDragging, entity);
m_CurrentlyDragging = EntityWrapper::Invalid;
}
return true;
} else {
return false;
}
}
void EditorGUI::drawComponents(EntityWrapper entity)
{
std::stringstream title;
title << "Components";
if (entity.Valid()) {
title << " " << formatEntityName(entity);
}
title << "###Components";
if (!ImGui::Begin(title.str().c_str())) {
ImGui::End();
return;
}
if (!entity.Valid()) {
ImGui::End();
return;
}
auto& pools = entity.World->GetComponentPools();
// Create list of component types available to be added
std::vector<const char*> componentTypes;
for (auto& pair : pools) {
// Don't list components the entity already has attached
if (!entity.HasComponent(pair.first)) {
componentTypes.push_back(pair.first.c_str());
}
}
// Draw combo box
ImGui::PushItemWidth(ImGui::GetContentRegionAvailWidth() - 10.f);
int selectedItem = -1;
if (ImGui::Combo("", &selectedItem, componentTypes.data(), componentTypes.size())) {
if (selectedItem != -1) {
if (m_OnComponentAttach != nullptr) {
std::string chosenComponentType(componentTypes.at(selectedItem));
m_OnComponentAttach(entity, chosenComponentType);
SetDirty(entity);
}
}
}
ImGui::PopItemWidth();
for (auto& pair : pools) {
const std::string& componentType = pair.first;
auto pool = pair.second;
// Don't show components the entity doesn't have attached
if (!entity.HasComponent(componentType)) {
continue;
}
// Handle deletion with early out
if (createDeleteButton(componentType)) {
if (m_OnComponentDelete != nullptr) {
m_OnComponentDelete(entity, componentType);
continue;
}
}
// Draw the actual component node
drawComponentNode(entity, pool->ComponentInfo());
}
ImGui::End();
}
bool EditorGUI::drawComponentNode(EntityWrapper entity, const ComponentInfo& ci)
{
if (!ImGui::CollapsingHeader(ci.Name.c_str(), nullptr, true, true)) {
return false;
}
// Show component annotation
const std::string annotation = ci.Meta->Annotation;
if (!annotation.empty()) {
ImGui::TextWrapped(annotation.c_str());
}
// Draw component fields
ComponentWrapper& component = entity.World->GetComponent(entity.ID, ci.Name);
for (auto& kv : ci.Fields) {
const std::string& fieldName = kv.first;
const ComponentInfo::Field_t& field = kv.second;
// Draw the field widget based on its type
bool dirty = drawComponentField(component, field);
if (dirty) {
SetDirty(entity);
}
ImGui::SameLine();
// Draw field name
ImGui::Text(fieldName.c_str());
// Draw potential field annotation
auto fieldAnnotationIt = ci.Meta->FieldAnnotations.find(fieldName);
if (fieldAnnotationIt != ci.Meta->FieldAnnotations.end()) {
ImGui::SameLine();
ImGui::TextDisabled("(?)");
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip(fieldAnnotationIt->second.c_str());
}
}
}
return true;
}
bool EditorGUI::drawComponentField(ComponentWrapper& c, const ComponentInfo::Field_t& field)
{
// Push an unique widget id so different components with fields with equal names are still counted as different
ImGui::PushID((c.Info.Name + field.Name).c_str());
bool dirty = false;
if (field.Type == "Vector") {
dirty = drawComponentField_Vector(c, field);
} else if (field.Type == "Color") {
dirty = drawComponentField_Color(c, field);
//} else if (field.Type == "Quaternion") {
} else if (field.Type == "int") {
dirty = drawComponentField_int(c, field);
} else if (field.Type == "enum") {
dirty = drawComponentField_enum(c, field);
} else if (field.Type == "float") {
dirty = drawComponentField_float(c, field);
} else if (field.Type == "double") {
dirty = drawComponentField_double(c, field);
} else if (field.Type == "bool") {
dirty = drawComponentField_bool(c, field);
} else if (field.Type == "string") {
dirty = drawComponentField_string(c, field);
} else {
ImGui::TextDisabled(field.Type.c_str());
}
ImGui::PopID();
return dirty;
}
bool EditorGUI::drawComponentField_Vector(ComponentWrapper &c, const ComponentInfo::Field_t &field)
{
auto& val = c.Field<glm::vec3>(field.Name);
if (field.Name == "Scale") {
// Limit scale values to a minimum of 0
return ImGui::DragFloat3("", glm::value_ptr(val), 0.1f, 0.f, std::numeric_limits<float>::max());
} else if (field.Name == "Orientation") {
// Make orentations have a period of 2*Pi
glm::vec3 tempVal = glm::fmod(val, glm::vec3(glm::two_pi<float>()));
if (ImGui::SliderFloat3("", glm::value_ptr(tempVal), 0.f, glm::two_pi<float>())) {
val = tempVal;
return true;
} else {
return false;
}
} else {
return ImGui::DragFloat3("", glm::value_ptr(val), 0.1f, std::numeric_limits<float>::lowest(), std::numeric_limits<float>::max());
}
}
bool EditorGUI::drawComponentField_Color(ComponentWrapper &c, const ComponentInfo::Field_t &field)
{
auto& val = c.Field<glm::vec4>(field.Name);
return ImGui::ColorEdit4("", glm::value_ptr(val), true);
}
bool EditorGUI::drawComponentField_int(ComponentWrapper &c, const ComponentInfo::Field_t &field)
{
auto& val = c.Field<int>(field.Name);
return ImGui::InputInt("", &val);
}
bool EditorGUI::drawComponentField_enum(ComponentWrapper &c, const ComponentInfo::Field_t &field)
{
auto fieldEnumDefIt = c.Info.Meta->FieldEnumDefinitions.find(field.Name);
if (fieldEnumDefIt == c.Info.Meta->FieldEnumDefinitions.end()) {
return drawComponentField_int(c, field);
}
auto& val = c.Field<int>(field.Name);
int selectedItem = -1;
std::stringstream enumKeys;
std::vector<int> enumValues;
int i = 0;
for (auto& kv : fieldEnumDefIt->second) {
enumKeys << kv.first << " (" << kv.second << ")" << '\0';
enumValues.push_back(kv.second);
if (val == kv.second) {
selectedItem = i;
}
i++;
}
if (ImGui::Combo("", &selectedItem, enumKeys.str().c_str())) {
val = enumValues.at(selectedItem);
return true;
} else {
return false;
}
}
bool EditorGUI::drawComponentField_float(ComponentWrapper &c, const ComponentInfo::Field_t &field)
{
auto& val = c.Field<float>(field.Name);
return ImGui::InputFloat("", &val, 0.01f, 1.f);
}
bool EditorGUI::drawComponentField_double(ComponentWrapper &c, const ComponentInfo::Field_t &field)
{
float tempVal = static_cast<float>(c.Field<double>(field.Name));
if (ImGui::InputFloat("", &tempVal, 0.01f, 1.f)) {
c.SetField(field.Name, static_cast<double>(tempVal));
return true;
} else {
return false;
}
}
bool EditorGUI::drawComponentField_bool(ComponentWrapper &c, const ComponentInfo::Field_t &field)
{
auto& val = c.Field<bool>(field.Name);
return ImGui::Checkbox("", &val);
}
bool EditorGUI::drawComponentField_string(ComponentWrapper &c, const ComponentInfo::Field_t &field)
{
auto& val = c.Field<std::string>(field.Name);
char tempString[1024]; // Let's just hope this is an sufficiently large buffer for strings :)
tempString[1023] = '\0'; // Null terminator just in case the string is larger than the buffer
// Copy the string into the buffer, taking the null terminator into account
memcpy(tempString, val.c_str(), std::min(val.length() + 1, sizeof(tempString) - 1));
if (ImGui::InputText("", tempString, sizeof(tempString))) {
val = std::string(tempString);
return true;
} else {
return false;
}
// TODO: Handle drag and drop of files
}
void EditorGUI::drawModals()
{
for (auto& modal : m_ModalsToOpen) {
ImGui::OpenPopup(modal.c_str());
}
m_ModalsToOpen.clear();
if (ImGui::BeginPopupModal("Import failed", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Text("Entity import failed. Check console for more information.\n\n");
ImGui::SetCursorPosX(ImGui::GetContentRegionAvailWidth() - 120);
if (ImGui::Button("OK", ImVec2(120, 0))) {
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
if (ImGui::BeginPopupModal("Save failed", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Text("Entity save failed on an exception.\nMessage: %s\n\n", m_LastErrorMessage.c_str());
ImGui::SetCursorPosX(ImGui::GetContentRegionAvailWidth() - 120);
if (ImGui::Button("OK", ImVec2(120, 0))) {
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
if (ImGui::BeginPopupModal("Confirm deletion", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
if (m_ModalData.count("Confirm deletion") == 0) {
ImGui::CloseCurrentPopup();
}
ImGui::Text("Are you sure you want to delete entity \"%s\"?", formatEntityName(m_CurrentSelection).c_str());
ImGui::ItemSize(ImVec2(5.f, 0.f));
ImGui::SetCursorPosX(ImGui::GetContentRegionAvailWidth() - 2*60);
if (ImGui::Button("Delete (Del)", ImVec2(60, 0))) {
entityDelete(boost::any_cast<EntityWrapper>(m_ModalData.at("Confirm deletion")));
ImGui::CloseCurrentPopup();
}
ImGui::SameLine();
if (ImGui::Button("Cancel", ImVec2(60, 0))) {
m_ModalData.erase("Confirm deletion");
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
}
bool EditorGUI::createDeleteButton(const std::string& componentType)
{
float width = ImGui::GetContentRegionAvailWidth();
ImGuiWindow* window = ImGui::GetCurrentWindow();
auto pos = ImGui::GetCursorScreenPos() + ImVec2(width - 14.f, 1);
ImRect bb = ImRect(pos, pos + ImVec2(14.f, 14.f));
std::string idString = "#DELETE";
idString += componentType;
ImGuiID id = window->GetID(idString.c_str());
bool hovered;
bool held;
bool pressed = ImGui::ButtonBehavior(bb, id, &hovered, &held);
//ImU32 col = window->Color((held && hovered) ? ImGuiCol_CloseButtonActive : hovered ? ImGuiCol_CloseButtonHovered : ImGuiCol_CloseButton);
ImU32 col = window->Color((held && hovered) ? ImGuiCol_CloseButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
window->DrawList->AddCircleFilled(bb.GetCenter(), 7.f, col, 16);
return pressed;
}
void EditorGUI::createWidgetToolButton(WidgetMode mode)
{
GLuint texture = 0;
switch (mode) {
case WidgetMode::Translate:
texture = tryLoadTexture("Textures/Icons/Translate.png");
break;
case WidgetMode::Rotate:
texture = tryLoadTexture("Textures/Icons/Rotate.png");
break;
case WidgetMode::Scale:
texture = tryLoadTexture("Textures/Icons/Scale.png");
break;
}
if (ImGui::ImageButton(
(void*)texture,
ImVec2(24, 24),
ImVec2(0, 1),
ImVec2(1, 0),
-1,
ImVec4(0, 0, 0, 0),
(m_CurrentWidgetMode == mode) ? ImVec4(0, 1, 0, 1) : ImVec4(1, 1, 1, 1)
)
) {
if (m_OnWidgetMode != nullptr) {
m_OnWidgetMode(mode);
}
m_CurrentWidgetMode = mode;
}
}
bool EditorGUI::OnKeyDown(const Events::KeyDown& e)
{
if (e.ModCtrl && e.KeyCode == GLFW_KEY_S) {
if (m_CurrentSelection.Valid()) {
EntityWrapper baseParent = m_CurrentSelection;
while (baseParent.Parent().Valid()) {
baseParent = baseParent.Parent();
}
entitySave(baseParent);
}
}
if (e.ModCtrl && e.KeyCode == GLFW_KEY_N) {
entityCreate(m_World, m_CurrentSelection);
}
if (e.ModCtrl && e.KeyCode == GLFW_KEY_O) {
entityImport(m_World);
}
if (e.KeyCode == GLFW_KEY_DELETE) {
if (m_CurrentSelection.Valid()) {
entityDelete(m_CurrentSelection);
}
}
return true;
}
boost::filesystem::path EditorGUI::fileOpenDialog()
{
namespace bfs = boost::filesystem;
nfdchar_t* outPath = nullptr;
nfdresult_t result = NFD_OpenDialog("xml", bfs::absolute(m_DefaultEntityPath).string().c_str(), &outPath);
if (result == NFD_ERROR) {
LOG_ERROR("NFD Error: %s", NFD_GetError());
return bfs::path();
} else if (result == NFD_CANCEL) {
return bfs::path();
} else {
return bfs::absolute(outPath);
}
}
boost::filesystem::path EditorGUI::fileSaveDialog()
{
namespace bfs = boost::filesystem;
nfdchar_t* outPath = nullptr;
nfdresult_t result = NFD_SaveDialog("xml", bfs::absolute(m_DefaultEntityPath).string().c_str(), &outPath);
if (result == NFD_ERROR) {
LOG_ERROR("NFD Error: %s", NFD_GetError());
return bfs::path();
} else if (result == NFD_CANCEL) {
return bfs::path();
} else {
return bfs::absolute(outPath);
}
}
const std::string EditorGUI::formatEntityName(EntityWrapper entity)
{
if (!entity.Valid()) {
return "EntityID_Invalid";
}
std::stringstream name;
std::string entityName = entity.World->GetName(entity.ID);
if (!entityName.empty()) {
name << entityName;
} else {
name << "#" << entity.ID;
}
if (m_EntityFiles.count(entity) == 1) {
name << " (" << m_EntityFiles.at(entity).Path.filename().string() << ")";
if (m_EntityFiles.at(entity).Dirty) {
name << "*";
}
}
return name.str();
}
GLuint EditorGUI::tryLoadTexture(std::string filePath)
{
GLuint texture = 0;
try {
texture = ResourceManager::Load<Texture>(filePath)->m_Texture;
} catch (const std::exception&) { }
return texture;
}
void EditorGUI::openModal(const std::string& modal)
{
m_ModalsToOpen.insert(modal);
}
void EditorGUI::SetDirty(EntityWrapper entity)
{
EntityWrapper baseParent = entity;
while (baseParent.Parent().Valid()) {
baseParent = baseParent.Parent();
}
if (m_EntityFiles.find(baseParent) != m_EntityFiles.end()) {
m_EntityFiles.at(baseParent).Dirty = true;
}
}
void EditorGUI::entityImport(World* world)
{
boost::filesystem::path filePath = fileOpenDialog();
if (filePath.empty()) {
return;
}
EntityWrapper entity = m_OnEntityImport(EntityWrapper(world, EntityID_Invalid), filePath);
if (entity.Valid()) {
m_EntityFiles[entity].Path = filePath;
SelectEntity(entity);
} else {
openModal("Import failed");
}
}
void EditorGUI::entitySave(EntityWrapper entity, bool saveAs /* = false */)
{
boost::filesystem::path filePath;
if (!saveAs && m_EntityFiles.count(entity) == 1) {
filePath = m_EntityFiles.at(entity).Path;
} else {
filePath = fileSaveDialog();
}
if (filePath.empty()) {
return;
}
try {
m_OnEntitySave(entity, filePath);
m_EntityFiles[entity].Path = filePath;
m_EntityFiles[entity].Dirty = false;
} catch (const std::exception& e) {
m_LastErrorMessage = e.what();
openModal("Save failed");
}
}
void EditorGUI::entityCreate(World* world, EntityWrapper parent)
{
if (m_OnEntityCreate != nullptr) {
// Create the new entity in the world we're drawing for
if (parent.World == nullptr) {
parent.World = world;
}
EntityWrapper newEntity = m_OnEntityCreate(parent);
SelectEntity(newEntity);
}
}
void EditorGUI::entityDelete(EntityWrapper entity)
{
std::string modalName = "Confirm deletion";
if (m_ModalData.count(modalName) == 0) {
m_ModalData[modalName] = entity;
openModal(modalName);
} else {
if (boost::any_cast<EntityWrapper>(m_ModalData[modalName]) == entity) {
EntityWrapper parent = entity.Parent();
if (m_OnEntityDelete != nullptr) {
SetDirty(entity);
m_OnEntityDelete(entity);
m_EntityFiles.erase(entity);
}
if (!m_CurrentSelection.Valid()) {
SelectEntity(parent);
}
}
m_ModalData.erase(modalName);
}
}
void EditorGUI::entityChangeParent(EntityWrapper entity, EntityWrapper parent)
{
if (entity == parent) {
return;
}
if (m_OnEntityChangeParent != nullptr) {
SetDirty(entity);
m_OnEntityChangeParent(entity, parent);
LOG_DEBUG("Changed parent of %i to %i", entity.ID, parent.ID);
}
}
+87
View File
@@ -0,0 +1,87 @@
#include "Editor/EditorRenderSystem.h"
EditorRenderSystem::EditorRenderSystem(World* m_World, EventBroker* eventBroker, IRenderer* renderer, RenderFrame* renderFrame)
: System(m_World, eventBroker)
, m_Renderer(renderer)
, m_RenderFrame(renderFrame)
{
EVENT_SUBSCRIBE_MEMBER(m_ESetCamera, &EditorRenderSystem::OnSetCamera);
auto resolution = Rectangle::Rectangle(1280, 720);
m_EditorCamera = new Camera((float)resolution.Width / resolution.Height, glm::radians(45.f), 0.01f, 5000.f);
}
void EditorRenderSystem::Update(double dt)
{
if (m_CurrentCamera) {
ComponentWrapper cameraTransform = m_CurrentCamera["Transform"];
m_EditorCamera->SetPosition(cameraTransform["Position"]);
m_EditorCamera->SetOrientation(glm::quat((const glm::vec3&)cameraTransform["Orientation"]));
}
RenderScene scene;
scene.ClearDepth = true;
scene.Camera = m_EditorCamera;
scene.Viewport = Rectangle(1920, 1080);
auto models = m_World->GetComponents("Model");
if (models != nullptr) {
for (auto& cModel : *models) {
if (!(bool)cModel["Visible"]) {
continue;
}
const std::string& resource = cModel["Resource"];
Model* model;
try {
model = ResourceManager::Load<::Model, true>(resource);
} catch (const Resource::StillLoadingException&) {
continue;
} catch (const std::exception&) {
try {
model = ResourceManager::Load<::Model>("Models/Core/Error.obj");
} catch (const std::exception&) {
continue;
}
}
EntityWrapper entity(m_World, cModel.EntityID);
glm::mat4 modelMatrix = Transform::ModelMatrix(entity.ID, entity.World);
for (auto matGroup : model->MaterialGroups()) {
std::shared_ptr<ModelJob> modelJob = std::make_shared<ModelJob>(model, scene.Camera, modelMatrix, matGroup, cModel, entity.World);
scene.ForwardJobs.push_back(modelJob);
}
}
}
auto pointLights = m_World->GetComponents("PointLight");
if (pointLights != nullptr) {
for (auto& cPointLight : *pointLights) {
bool visible = cPointLight["Visible"];
if (!visible) {
continue;
}
EntityWrapper entity(m_World, cPointLight.EntityID);
ComponentWrapper& cTransform = entity["Transform"];
std::shared_ptr<PointLightJob> pointLightJob = std::make_shared<PointLightJob>(cTransform, cPointLight, entity.World);
scene.PointLightJobs.push_back(pointLightJob);
}
}
m_RenderFrame->Add(scene);
}
bool EditorRenderSystem::OnSetCamera(Events::SetCamera& e)
{
ComponentWrapper cTransform = e.CameraEntity["Transform"];
ComponentWrapper cCamera = e.CameraEntity["Camera"];
m_EditorCamera->SetFOV((double)cCamera["FOV"]);
m_EditorCamera->SetNearClip((double)cCamera["NearClip"]);
m_EditorCamera->SetFarClip((double)cCamera["FarClip"]);
m_EditorCamera->SetPosition(cTransform["Position"]);
m_EditorCamera->SetOrientation(glm::quat((const glm::vec3&)cTransform["Orientation"]));
m_CurrentCamera = e.CameraEntity;
return true;
}
+115
View File
@@ -0,0 +1,115 @@
#include "Editor/EditorStats.h"
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>
#include <psapi.h>
#endif
#include <GL/wglew.h>
EditorStats::EditorStats()
{
m_AveragedSamples.push_back(0.0);
m_CurrentAveragedSampleIndex = 1;
}
void EditorStats::Draw(double dt)
{
if (ImGui::Begin("Stats")) {
drawFPSGraph(dt);
drawRAMUsage(dt);
drawVRAMStats(dt);
}
ImGui::End();
}
void EditorStats::drawFPSGraph(double dt)
{
if (m_FrameCount < m_SampleSize) {
m_FrameTimes.push_back(dt);
} else {
m_FrameTimes[m_FrameCount % m_SampleSize] = dt;
}
m_FrameCount++;
double average = 0.0;
double max = 0.0;
for (double t : m_FrameTimes) {
average += t;
max = std::max(max, t);
}
average /= m_FrameTimes.size();
m_TimeAccumulator += dt;
if (m_TimeAccumulator >= 1.0/m_AveragedSamplesPerSecond) {
if (m_CurrentAveragedSampleIndex < m_AveragedSampleSize) {
m_AveragedSamples.push_back(1.0/average);
} else {
m_AveragedSamples[m_CurrentAveragedSampleIndex % m_AveragedSampleSize] = 1.0/average;
}
m_CurrentAveragedSampleIndex++;
m_TimeAccumulator = 0.0;
}
float maxFPS = 0.f;
ImVector<float> values;
int values_offset = m_CurrentAveragedSampleIndex % m_AveragedSampleSize;
for (double d : m_AveragedSamples) {
values.push_back(static_cast<float>(d));
maxFPS = std::max(maxFPS, static_cast<float>(d));
}
std::stringstream header;
header << std::round(1.0/average) << " FPS (" << std::setprecision(5) << average << " ms)";
ImGui::PlotLines("##FPSGraph", values.Data, values.Size, values_offset, header.str().c_str(), 0.f, maxFPS + maxFPS/5.f, ImVec2(0, 100));
}
void EditorStats::drawRAMUsage(double dt)
{
#ifdef WIN32
PROCESS_MEMORY_COUNTERS_EX ppm;
GetProcessMemoryInfo(GetCurrentProcess(), (PPROCESS_MEMORY_COUNTERS)&ppm, sizeof(ppm));
float megabytes = ppm.WorkingSetSize / (float)std::pow(1024, 2);
ImGui::Text("Memory: ~%f MiB", megabytes);
#endif
}
void EditorStats::drawVRAMStats(double dt)
{
//const unsigned int GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX = 0x9049;
//const unsigned int GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX = 0x9048;
//glm::ivec4 total;
//glGetIntegerv(GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, glm::value_ptr(total));
//if (glGetError() == GL_NO_ERROR) {
// glm::ivec4 available;
// glGetIntegerv(GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, glm::value_ptr(available));
// float megabytes = (total.x - available.x) / 1024.f; // NVidia returns in KiB
// ImGui::Text("VRAM: %f", megabytes);
//}
//GLuint uNoOfGPUs = wglGetGPUIDsAMD(0, 0);
//if (!GLERROR("")) {
// GLuint* uGPUIDs = new GLuint[uNoOfGPUs];
// wglGetGPUIDsAMD(uNoOfGPUs, uGPUIDs);
// GLuint uTotalMemoryInMB = 0;
// wglGetGPUInfoAMD(uGPUIDs[0],
// WGL_GPU_RAM_AMD,
// GL_UNSIGNED_INT,
// sizeof(GLuint),
// &uTotalMemoryInMB);
// GLint nCurAvailMemoryInKB[4];
// glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI,
// &nCurAvailMemoryInKB[0]);
// float usedTexture = (nCurAvailMemoryInKB[0] / 1024.f);
// glGetIntegerv(GL_VBO_FREE_MEMORY_ATI,
// &nCurAvailMemoryInKB[0]);
// float usedVBO = (nCurAvailMemoryInKB[0] / 1024.f);
// glGetIntegerv(GL_RENDERBUFFER_FREE_MEMORY_ATI,
// &nCurAvailMemoryInKB[0]);
// float usedFB = (nCurAvailMemoryInKB[0] / 1024.f);
// ImGui::Text("VRAM: %f MiB ", (float)uTotalMemoryInMB - usedTexture - usedVBO - usedFB);
// ImGui::Text(" Texture: %f MiB", usedTexture);
// ImGui::Text(" VBO: %f MiB", usedVBO);
// ImGui::Text(" Framebuffer: %f MiB", usedFB);
// delete[] uGPUIDs;
//}
}
+140 -690
View File
@@ -1,750 +1,200 @@
#include "Editor/EditorSystem.h"
#define IMGUI_DEFINE_MATH_OPERATORS
#include <imgui/imgui_internal.h>
#include "Core/UniformScaleSystem.h"
#include "Editor/EditorRenderSystem.h"
#include "Editor/EditorWidgetSystem.h"
EditorSystem::EditorSystem(EventBroker* eventBroker, IRenderer* renderer)
: System(eventBroker)
, ImpureSystem()
EditorSystem::EditorSystem(World* world, EventBroker* eventBroker, IRenderer* renderer, RenderFrame* renderFrame)
: System(world, eventBroker)
, m_Renderer(renderer)
, m_RenderFrame(renderFrame)
{
auto config = ResourceManager::Load<ConfigFile>("Config.ini");
m_Enabled = config->Get<bool>("Debug.EditorEnabled", false);
m_Visible = m_Enabled;
m_DefaultEntityDir = boost::filesystem::path("Schema") / boost::filesystem::path("Entities");
m_EditorWorld = new World();
m_EditorWorldSystemPipeline = new SystemPipeline(m_EditorWorld, eventBroker);
m_EditorWorldSystemPipeline->AddSystem<UniformScaleSystem>(0);
m_EditorWorldSystemPipeline->AddSystem<EditorWidgetSystem>(0, m_Renderer);
m_EditorWorldSystemPipeline->AddSystem<EditorRenderSystem>(1, m_Renderer, m_RenderFrame);
m_Camera = importEntity(EntityWrapper(m_EditorWorld, EntityID_Invalid), "Schema/Entities/Empty.xml");
m_EditorWorld->AttachComponent(m_Camera.ID, "Transform");
m_EditorWorld->AttachComponent(m_Camera.ID, "Camera");
m_DebugCameraInputController = new DebugCameraInputController<EditorSystem>(m_EventBroker, -1);
if (!m_Enabled) {
return;
}
m_EditorGUI = new EditorGUI(m_World, m_EventBroker);
m_EditorGUI->SetEntitySelectedCallback(std::bind(&EditorSystem::OnEntitySelected, this, std::placeholders::_1));
m_EditorGUI->SetEntityImportCallback(std::bind(&EditorSystem::importEntity, this, std::placeholders::_1, std::placeholders::_2));
m_EditorGUI->SetEntitySaveCallback(std::bind(&EditorSystem::OnEntitySave, this, std::placeholders::_1, std::placeholders::_2));
m_EditorGUI->SetEntityCreateCallback(std::bind(&EditorSystem::OnEntityCreate, this, std::placeholders::_1));
m_EditorGUI->SetEntityDeleteCallback(std::bind(&EditorSystem::OnEntityDelete, this, std::placeholders::_1));
m_EditorGUI->SetEntityChangeParentCallback(std::bind(&EditorSystem::OnEntityChangeParent, this, std::placeholders::_1, std::placeholders::_2));
m_EditorGUI->SetEntityChangeNameCallback(std::bind(&EditorSystem::OnEntityChangeName, this, std::placeholders::_1, std::placeholders::_2));
m_EditorGUI->SetComponentAttachCallback(std::bind(&EditorSystem::OnComponentAttach, this, std::placeholders::_1, std::placeholders::_2));
m_EditorGUI->SetComponentDeleteCallback(std::bind(&EditorSystem::OnComponentDelete, this, std::placeholders::_1, std::placeholders::_2));
m_EditorGUI->SetWidgetModeCallback(std::bind(&EditorSystem::setWidgetMode, this, std::placeholders::_1));
EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &EditorSystem::OnInputCommand);
EVENT_SUBSCRIBE_MEMBER(m_EMousePress, &EditorSystem::OnMousePress);
EVENT_SUBSCRIBE_MEMBER(m_EMouseRelease, &EditorSystem::OnMouseRelease);
EVENT_SUBSCRIBE_MEMBER(m_EMouseMove, &EditorSystem::OnMouseMove);
EVENT_SUBSCRIBE_MEMBER(m_EFileDropped, &EditorSystem::OnFileDropped);
EVENT_SUBSCRIBE_MEMBER(m_EWidgetDelta, &EditorSystem::OnWidgetDelta);
m_EditorStats = new EditorStats();
Events::SetCamera e;
e.CameraEntity = m_Camera;
m_EventBroker->Publish(e);
}
void EditorSystem::Update(World* world, double dt)
EditorSystem::~EditorSystem()
{
m_World = world;
delete m_EditorStats;
delete m_EditorGUI;
delete m_DebugCameraInputController;
delete m_EditorWorldSystemPipeline;
delete m_EditorWorld;
}
if (!m_Enabled) {
return;
void EditorSystem::Update(double dt)
{
m_EventBroker->Process<EditorGUI>();
m_EditorGUI->Draw();
m_EditorStats->Draw(dt);
if (m_CurrentSelection.Valid() && m_Widget.Valid()) {
(glm::vec3&)m_Widget["Transform"]["Position"] = Transform::AbsolutePosition(m_CurrentSelection.World, m_CurrentSelection.ID);
}
if (!m_Visible) {
return;
}
Picking();
updateWidget();
m_EditorWorldSystemPipeline->Update(dt);
drawUI(world, dt);
m_DebugCameraInputController->Update(dt);
m_Camera["Transform"]["Position"] = m_DebugCameraInputController->Position();
m_Camera["Transform"]["Orientation"] = glm::eulerAngles(m_DebugCameraInputController->Orientation());
}
// Clear drop queue if it wasn't handled by any UI element
if (!m_LastDroppedFile.empty()) {
m_LastDroppedFile = "";
void EditorSystem::OnEntitySelected(EntityWrapper entity)
{
m_CurrentSelection = entity;
setWidgetMode(m_WidgetMode);
}
void EditorSystem::OnEntitySave(EntityWrapper entity, boost::filesystem::path filePath)
{
EntityFileWriter writer(filePath);
writer.WriteEntity(entity.World, entity.ID);
}
EntityWrapper EditorSystem::OnEntityCreate(EntityWrapper parent)
{
EntityID entity = parent.World->CreateEntity(parent.ID);
parent.World->AttachComponent(entity, "Transform");
return EntityWrapper(parent.World, entity);
}
void EditorSystem::OnEntityDelete(EntityWrapper entity)
{
if (entity.Valid()) {
entity.World->DeleteEntity(entity.ID);
}
}
boost::filesystem::path EditorSystem::openDialog(boost::filesystem::path defaultPath)
void EditorSystem::OnEntityChangeParent(EntityWrapper entity, EntityWrapper parent)
{
namespace bfs = boost::filesystem;
auto absolutePath = bfs::absolute(defaultPath);
nfdchar_t* outPath = nullptr;
nfdresult_t result = NFD_OpenDialog(NULL, absolutePath.string().c_str(), &outPath);
if (result == NFD_ERROR) {
LOG_ERROR("NFD Error: %s", NFD_GetError());
return bfs::path();
if (entity.Valid()) {
entity.World->SetParent(entity.ID, parent.ID);
}
return bfs::absolute(outPath);
}
boost::filesystem::path EditorSystem::saveDialog(boost::filesystem::path defaultPath)
void EditorSystem::OnEntityChangeName(EntityWrapper entity, const std::string& name)
{
namespace bfs = boost::filesystem;
auto absolutePath = bfs::absolute(defaultPath);
nfdchar_t* outPath = nullptr;
nfdresult_t result = NFD_SaveDialog(NULL, absolutePath.string().c_str(), &outPath);
if (result == NFD_ERROR) {
LOG_ERROR("NFD Error: %s", NFD_GetError());
return bfs::path();
if (entity.Valid()) {
entity.World->SetName(entity.ID, name);
}
return bfs::absolute(outPath);
}
bool EditorSystem::OnInputCommand(const Events::InputCommand& e)
void EditorSystem::OnComponentAttach(EntityWrapper entity, const std::string& componentType)
{
if (e.Command == "ToggleEditor" && e.Value > 0) {
m_Visible = !m_Visible;
if (entity.Valid()) {
entity.World->AttachComponent(entity.ID, componentType);
}
}
if (e.Command == "EditorToolMove" && e.Value > 0) {
setWidgetMode(WidgetMode::Translate);
void EditorSystem::OnComponentDelete(EntityWrapper entity, const std::string& componentType)
{
if (entity.Valid()) {
entity.World->DeleteComponent(entity.ID, componentType);
}
if (e.Command == "EditorToolRotate" && e.Value > 0) {
setWidgetMode(WidgetMode::Rotate);
}
if (e.Command == "EditorToolScale" && e.Value > 0) {
setWidgetMode(WidgetMode::Scale);
}
if (e.Command == "EditorToggleTransformSpace" && e.Value > 0) {
if (m_WidgetSpace == WidgetSpace::Global) {
setWidgetSpace(WidgetSpace::Local);
} else if (m_WidgetSpace == WidgetSpace::Local) {
setWidgetSpace(WidgetSpace::Global);
}
}
return true;
}
bool EditorSystem::OnMousePress(const Events::MousePress& e)
{
if (e.Button == GLFW_MOUSE_BUTTON_RIGHT) {
m_PickingQueue.push_back(glm::vec2((int)e.X, (int)e.Y));
ImGuiIO& io = ImGui::GetIO();
if (!io.WantCaptureMouse && !io.WantCaptureKeyboard && e.Button == GLFW_MOUSE_BUTTON_1) {
PickData pick = m_Renderer->Pick(glm::vec2(e.X, e.Y));
if (pick.World == m_World) {
m_CurrentSelection = EntityWrapper(m_World, pick.Entity);
m_EditorGUI->SelectEntity(m_CurrentSelection);
}
}
return true;
}
bool EditorSystem::OnMouseMove(const Events::MouseMove& e)
bool EditorSystem::OnWidgetDelta(const Events::WidgetDelta& e)
{
if (m_Widget == EntityID_Invalid) {
return false;
}
if (m_Selection == EntityID_Invalid) {
return false;
}
if (m_Selection == m_Widget) {
return false;
}
// TODO: No widgets for root entity until widgets reside in thier own world,
// or the widgets will move relative to the root entity being moved, which is WEEEIRD.
if (m_Selection == 0) {
return false;
}
if (m_Camera == nullptr) {
return false;
}
auto widgetTransform = m_World->GetComponent(m_Widget, "Transform");
glm::vec3 widgetOrientation = widgetTransform["Orientation"];
glm::quat totalOrientation = m_Camera->Orientation() * glm::inverse(glm::quat(widgetOrientation));
int width;
int height;
glfwGetFramebufferSize(m_Renderer->Window(), &width, &height);
Rectangle res(width, height);
glm::vec2 delta2(res.Width / 2.f + e.DeltaX, res.Height / 2.f + -e.DeltaY);
glm::vec3 deltaWorld = ScreenCoords::ToWorldPos(
delta2,
m_WidgetPickingDepth,
res,
m_Camera->ProjectionMatrix(),
glm::toMat4(glm::inverse(totalOrientation))
);
glm::vec3 origin = ScreenCoords::ToWorldPos(
glm::vec2(res.Width / 2.f, res.Height / 2.f),
m_WidgetPickingDepth,
res,
m_Camera->ProjectionMatrix(),
glm::toMat4(glm::inverse(totalOrientation))
);
deltaWorld = deltaWorld - origin;
glm::vec3 movement = deltaWorld * m_WidgetCurrentAxis;
if (glm::length2(m_WidgetCurrentAxis) > 0.f) {
auto widgetTransform = m_World->GetComponent(m_Widget, "Transform");
if (m_WidgetMode == WidgetMode::Translate) {
if (m_WidgetSpace == WidgetSpace::Global) {
EntityID parent = m_World->GetParent(m_Selection);
glm::quat inverseParentOrientation;
//if (parent != 0) {
inverseParentOrientation = glm::inverse(Transform::AbsoluteOrientation(m_World, parent));
//}
(glm::vec3&)m_World->GetComponent(m_Selection, "Transform")["Position"] += inverseParentOrientation * movement;
} else if (m_WidgetSpace == WidgetSpace::Local) {
auto selectionTransform = m_World->GetComponent(m_Selection, "Transform");
(glm::vec3&)selectionTransform["Position"] += glm::quat((glm::vec3)selectionTransform["Orientation"]) * movement;
}
} else if (m_WidgetMode == WidgetMode::Rotate) {
glm::vec3 finalMovement;
finalMovement.x = -deltaWorld.y * m_WidgetCurrentAxis.x;
finalMovement.y = deltaWorld.x * m_WidgetCurrentAxis.y;
finalMovement.z = deltaWorld.y * m_WidgetCurrentAxis.z;
if (m_WidgetSpace == WidgetSpace::Global) {
EntityID parent = m_World->GetParent(m_Selection);
glm::quat parentOrientation;
//if (parent != 0) {
// parentOrientation = RenderSystem::AbsoluteOrientation(m_World, parent);
//}
glm::vec3& selectionOrientation = m_World->GetComponent(m_Selection, "Transform")["Orientation"];
glm::quat currentOrientation = Transform::AbsoluteOrientation(m_World, m_Selection);
//glm::quat currentOrientation = parentOrientation * glm::quat(selectionOrientation);
glm::quat deltaOrientation(finalMovement);
selectionOrientation = glm::eulerAngles(glm::inverse(parentOrientation) * (deltaOrientation * currentOrientation));
} else if (m_WidgetSpace == WidgetSpace::Local) {
glm::vec3& selectionOrientation = m_World->GetComponent(m_Selection, "Transform")["Orientation"];
glm::quat currentOrientation(selectionOrientation);
glm::quat deltaOrientation(finalMovement);
selectionOrientation = glm::eulerAngles(currentOrientation * deltaOrientation);
}
} else if (m_WidgetMode == WidgetMode::Scale) {
glm::vec3& scaleX = m_World->GetComponent(m_WidgetX, "Transform")["Scale"];
glm::vec3& scaleY = m_World->GetComponent(m_WidgetY, "Transform")["Scale"];
glm::vec3& scaleZ = m_World->GetComponent(m_WidgetZ, "Transform")["Scale"];
if (m_WidgetCurrentAxis.x > 0 && m_WidgetCurrentAxis.y > 0 && m_WidgetCurrentAxis.z > 0) {
float movementLength = glm::length(movement);
float dot = glm::dot((glm::vec3)widgetOrientation, movement);
movement = glm::vec3(movementLength) * glm::sign(dot);
(glm::vec3&)m_World->GetComponent(m_WidgetOrigin, "Transform")["Scale"] += movement;
}
if (m_WidgetCurrentAxis.x > 0) {
scaleX.x += movement.x;
}
if (m_WidgetCurrentAxis.y > 0) {
scaleY.y += movement.y;
}
if (m_WidgetCurrentAxis.z > 0) {
scaleZ.z += movement.z;
}
(glm::vec3&)m_World->GetComponent(m_Selection, "Transform")["Scale"] += movement;
if (m_CurrentSelection.Valid()) {
glm::quat parentOrientation;
EntityWrapper parent = m_CurrentSelection.Parent();
if (parent.Valid()) {
parentOrientation = glm::inverse(Transform::AbsoluteOrientation(parent.World, parent.ID));
}
(glm::vec3&)m_CurrentSelection["Transform"]["Position"] += parentOrientation * e.Translation;
m_EditorGUI->SetDirty(m_CurrentSelection);
}
/*LOG_DEBUG("DELTA %f", e.DeltaX);
if (e.X < 0) {
glfwSetCursorPos(m_Renderer->Window(), width - 1, e.Y);
}
if (e.X >= width) {
glfwSetCursorPos(m_Renderer->Window(), 0, e.Y);
}*/
return true;
}
bool EditorSystem::OnMouseRelease(const Events::MouseRelease& e)
EntityWrapper EditorSystem::importEntity(EntityWrapper parent, boost::filesystem::path filePath)
{
if (glm::length2(m_WidgetCurrentAxis) > 0.f) {
m_WidgetCurrentAxis = glm::vec3(0.f);
//setWidgetMode(m_WidgetMode);
if (parent.World == nullptr) {
LOG_ERROR("Tried to import entity \"%s\" into null world!", filePath.string().c_str());
return EntityWrapper::Invalid;
}
return true;
}
void EditorSystem::Picking()
{
for (auto& pos : m_PickingQueue) {
auto result = m_Renderer->Pick(pos);
EntityID entity = result.Entity;
if (glm::length2(m_WidgetCurrentAxis) > 0.f) {
// ???
} else {
LOG_INFO("Selected %i", entity);
if (entity != EntityID_Invalid) {
EntityID parent = m_World->GetParent(entity);
m_Camera = result.Camera;
if (parent == m_Widget) {
m_WidgetCurrentAxis = glm::vec3(
(entity == m_WidgetX) || (entity == m_WidgetOrigin) || (entity == m_WidgetPlaneY || entity == m_WidgetPlaneZ),
(entity == m_WidgetY) || (entity == m_WidgetOrigin) || (entity == m_WidgetPlaneX || entity == m_WidgetPlaneZ),
(entity == m_WidgetZ) || (entity == m_WidgetOrigin) || (entity == m_WidgetPlaneX || entity == m_WidgetPlaneY)
);
m_WidgetPickingDepth = result.Depth;
//auto widgetTransform = m_World->GetComponent(m_Widget, "Transform");
//auto selectionTransform = m_World->GetComponent(m_Selection, "Transform");
//widgetTransform["Position"] = (glm::vec3)selectionTransform["Position"];
} else {
ImGui::SetActiveID(0, nullptr);
if (m_WidgetMode == WidgetMode::None) {
m_WidgetMode = WidgetMode::Translate;
}
setWidgetMode(m_WidgetMode);
m_Selection = entity;
}
}
}
}
m_PickingQueue.clear();
};
bool EditorSystem::OnFileDropped(const Events::FileDropped& e)
{
m_LastDroppedFile = boost::filesystem::path(e.Path).lexically_relative(boost::filesystem::current_path()).string();
std::replace(m_LastDroppedFile.begin(), m_LastDroppedFile.end(), '\\', '/');
return true;
}
void EditorSystem::createWidget()
{
if (m_Widget == EntityID_Invalid) {
m_Widget = m_World->CreateEntity();
m_World->AttachComponent(m_Widget, "Transform");
m_WidgetX = m_World->CreateEntity(m_Widget);
m_World->AttachComponent(m_WidgetX, "Transform");
m_World->AttachComponent(m_WidgetX, "Model");
m_WidgetPlaneX = m_World->CreateEntity(m_Widget);
m_World->AttachComponent(m_WidgetPlaneX, "Transform");
m_World->AttachComponent(m_WidgetPlaneX, "Model");
#ifdef USING_ASSIMP_AS_IMPORTER
m_World->GetComponent(m_WidgetPlaneX, "Model")["Resource"] = "Models/WidgetPlaneZ.obj"; // 360NoScope widgetPlaneX
#else
m_World->GetComponent(m_WidgetPlaneX, "Model")["Resource"] = "Models/WidgetPlaneZ.mesh";
#endif
m_WidgetY = m_World->CreateEntity(m_Widget);
m_World->AttachComponent(m_WidgetY, "Transform");
m_World->AttachComponent(m_WidgetY, "Model");
m_WidgetPlaneY = m_World->CreateEntity(m_Widget);
m_World->AttachComponent(m_WidgetPlaneY, "Transform");
m_World->AttachComponent(m_WidgetPlaneY, "Model");
#ifdef USING_ASSIMP_AS_IMPORTER
m_World->GetComponent(m_WidgetPlaneY, "Model")["Resource"] = "Models/WidgetPlaneZ.obj"; // 360NoScope widgetPlaneY
#else
m_World->GetComponent(m_WidgetPlaneY, "Model")["Resource"] = "Models/WidgetPlaneZ.mesh";
#endif
m_WidgetZ = m_World->CreateEntity(m_Widget);
m_World->AttachComponent(m_WidgetZ, "Transform");
m_World->AttachComponent(m_WidgetZ, "Model");
m_WidgetPlaneZ = m_World->CreateEntity(m_Widget);
m_World->AttachComponent(m_WidgetPlaneZ, "Transform");
m_World->AttachComponent(m_WidgetPlaneZ, "Model");
#ifdef USING_ASSIMP_AS_IMPORTER
m_World->GetComponent(m_WidgetPlaneZ, "Model")["Resource"] = "Models/WidgetPlaneZ.obj"; // 360NoScope widgetPlaneZ
#else
m_World->GetComponent(m_WidgetPlaneZ, "Model")["Resource"] = "Models/WidgetPlaneZ.mesh";
#endif
m_WidgetOrigin = m_World->CreateEntity(m_Widget);
m_World->AttachComponent(m_WidgetOrigin, "Transform");
m_World->AttachComponent(m_WidgetOrigin, "Model");
setWidgetMode(WidgetMode::None);
try {
auto entityFile = ResourceManager::Load<EntityFile>(filePath.string());
EntityFilePreprocessor fpp(entityFile);
fpp.RegisterComponents(parent.World);
EntityFileParser fp(entityFile);
EntityID newEntity = fp.MergeEntities(parent.World, parent.ID);
return EntityWrapper(parent.World, newEntity);
} catch (const std::exception&) {
return EntityWrapper::Invalid;
}
}
void EditorSystem::updateWidget()
void EditorSystem::setWidgetMode(EditorGUI::WidgetMode mode)
{
if (m_Widget == EntityID_Invalid) {
return;
}
if (m_Selection == m_Widget) {
if (mode == m_WidgetMode && m_Widget.Valid() && m_CurrentSelection.Valid()) {
return;
}
if (m_Selection != EntityID_Invalid) {
auto widgetTransform = m_World->GetComponent(m_Widget, "Transform");
glm::vec3 selectionPosition = Transform::AbsolutePosition(m_World, m_Selection);
widgetTransform["Position"] = selectionPosition;
if (m_WidgetSpace == WidgetSpace::Local) {
widgetTransform["Orientation"] = glm::eulerAngles(Transform::AbsoluteOrientation(m_World, m_Selection));
}
}
}
m_WidgetMode = mode;
void EditorSystem::setWidgetMode(WidgetMode newMode)
{
if (m_Widget == EntityID_Invalid) {
if (m_Widget.Valid()) {
m_Widget.World->DeleteEntity(m_Widget.ID);
m_Widget = EntityWrapper::Invalid;
}
if (!m_CurrentSelection.Valid()) {
return;
}
auto widgetTransform = m_World->GetComponent(m_Widget, "Transform");
widgetTransform["Orientation"] = glm::vec3(0.f);
m_World->GetComponent(m_WidgetX, "Transform")["Scale"] = glm::vec3(1.f);
m_World->GetComponent(m_WidgetPlaneX, "Model")["Visible"] = false;
m_World->GetComponent(m_WidgetY, "Transform")["Scale"] = glm::vec3(1.f);
m_World->GetComponent(m_WidgetPlaneY, "Model")["Visible"] = false;
m_World->GetComponent(m_WidgetZ, "Transform")["Scale"] = glm::vec3(1.f);
m_World->GetComponent(m_WidgetPlaneZ, "Model")["Visible"] = false;
m_World->GetComponent(m_WidgetOrigin, "Transform")["Scale"] = glm::vec3(1.f);
m_World->GetComponent(m_WidgetOrigin, "Model")["Visible"] = false;
if (newMode == WidgetMode::Translate) {
m_World->GetComponent(m_WidgetX, "Model")["Resource"] = "Models/TranslationWidgetX.mesh";
m_World->GetComponent(m_WidgetY, "Model")["Resource"] = "Models/TranslationWidgetY.mesh";
m_World->GetComponent(m_WidgetZ, "Model")["Resource"] = "Models/TranslationWidgetZ.mesh";
// Temporarily disabled for local space until I can figure out what's wrong with the math
if (m_WidgetSpace != WidgetSpace::Local) {
m_World->GetComponent(m_WidgetPlaneX, "Model")["Visible"] = true;
m_World->GetComponent(m_WidgetPlaneY, "Model")["Visible"] = true;
m_World->GetComponent(m_WidgetPlaneZ, "Model")["Visible"] = true;
}
if (m_Selection != EntityID_Invalid) {
if (m_WidgetSpace == WidgetSpace::Local) {
auto selectionTransform = m_World->GetComponent(m_Selection, "Transform");
widgetTransform["Orientation"] = glm::eulerAngles(Transform::AbsoluteOrientation(m_World, m_Selection));
}
}
} else if (newMode == WidgetMode::Scale) {
m_World->GetComponent(m_WidgetX, "Model")["Resource"] = "Models/ScaleWidgetX.mesh";
m_World->GetComponent(m_WidgetY, "Model")["Resource"] = "Models/ScaleWidgetY.mesh";
m_World->GetComponent(m_WidgetZ, "Model")["Resource"] = "Models/ScaleWidgetZ.mesh";
m_World->GetComponent(m_WidgetOrigin, "Model")["Visible"] = true;
m_World->GetComponent(m_WidgetOrigin, "Model")["Resource"] = "Models/ScaleWidgetOrigin.mesh";
if (m_Selection != EntityID_Invalid) {
auto selectionTransform = m_World->GetComponent(m_Selection, "Transform");
widgetTransform["Orientation"] = glm::eulerAngles(Transform::AbsoluteOrientation(m_World, m_Selection));
}
} else if (newMode == WidgetMode::Rotate) {
m_World->GetComponent(m_WidgetX, "Model")["Resource"] = "Models/RotationWidgetX.mesh";
m_World->GetComponent(m_WidgetY, "Model")["Resource"] = "Models/RotationWidgetY.mesh";
m_World->GetComponent(m_WidgetZ, "Model")["Resource"] = "Models/RotationWidgetZ.mesh";
if (m_Selection != EntityID_Invalid) {
auto selectionTransform = m_World->GetComponent(m_Selection, "Transform");
if (m_WidgetSpace == WidgetSpace::Local) {
widgetTransform["Orientation"] = glm::eulerAngles(Transform::AbsoluteOrientation(m_World, m_Selection));
}
}
switch (mode) {
case EditorGUI::WidgetMode::Translate:
m_Widget = importEntity(EntityWrapper(m_EditorWorld, EntityID_Invalid), "Schema/Entities/EditorWidgetTranslate.xml");
break;
case EditorGUI::WidgetMode::Rotate:
m_Widget = importEntity(EntityWrapper(m_EditorWorld, EntityID_Invalid), "Schema/Entities/EditorWidgetRotate.xml");
break;
case EditorGUI::WidgetMode::Scale:
m_Widget = importEntity(EntityWrapper(m_EditorWorld, EntityID_Invalid), "Schema/Entities/EditorWidgetScale.xml");
break;
}
m_WidgetMode = newMode;
}
void EditorSystem::setWidgetSpace(WidgetSpace space)
{
m_WidgetSpace = space;
setWidgetMode(m_WidgetMode);
}
void EditorSystem::drawUI(World* world, double dt)
{
namespace bfs = boost::filesystem;
ImGui::ShowTestWindow();
//ImGui::ShowStyleEditor();
if (ImGui::BeginMainMenuBar()) {
if (ImGui::BeginMenu("File")) {
//if (ImGui::MenuItem("New")) { }
if (ImGui::MenuItem("Import", "Ctrl+O")) {
fileImport(world);
}
if (ImGui::MenuItem("Save", "Ctrl+S")) {
fileSave(world);
}
if (ImGui::MenuItem("Save As...", "Ctrl+Shift+S")) {
fileSaveAs(world);
}
ImGui::Separator();
if (ImGui::MenuItem("Close Editor", "F1")) { }
ImGui::EndMenu();
}
ImGui::SameLine();
if (ImGui::Button("Move")) {
setWidgetMode(WidgetMode::Translate);
}
ImGui::SameLine();
if (ImGui::Button("Rotate")) {
setWidgetMode(WidgetMode::Rotate);
}
ImGui::SameLine();
if (ImGui::Button("Scale")) {
setWidgetMode(WidgetMode::Scale);
}
ImGui::SameLine();
if (m_WidgetSpace == WidgetSpace::Global) {
if (ImGui::Button("(Global)")) {
setWidgetSpace(WidgetSpace::Local);
}
} else if (m_WidgetSpace == WidgetSpace::Local) {
if (ImGui::Button("(Local)")) {
setWidgetSpace(WidgetSpace::Global);
}
}
ImGui::EndMainMenuBar();
}
std::string title = std::string("Components #") + std::to_string(m_Selection) + std::string("###Components");
if (ImGui::Begin(title.c_str())) {
if (m_Selection != EntityID_Invalid) {
auto& pools = world->GetComponentPools();
std::vector<const char*> componentTypes;
for (auto& pair : pools) {
// Only add components the entity doesn't already have
if (!pair.second->KnowsEntity(m_Selection)) {
componentTypes.push_back(pair.first.c_str());
}
}
int item = -1;
ImGui::PushItemWidth(ImGui::GetWindowContentRegionWidth() - 5.f);
if (ImGui::Combo("", &item, componentTypes.data(), componentTypes.size())) {
if (item != -1) {
std::string chosenType = std::string(componentTypes.at(item));
world->AttachComponent(m_Selection, chosenType);
}
}
ImGui::PopItemWidth();
for (auto& pair : pools) {
const std::string& componentType = pair.first;
auto pool = pair.second;
if (!pool->KnowsEntity(m_Selection)) {
continue;
}
auto& ci = pool->ComponentInfo();
bool deletePressed = createDeleteButton(componentType);
if (deletePressed) {
world->DeleteComponent(m_Selection, componentType);
continue;
}
if (ImGui::CollapsingHeader(componentType.c_str())) {
if (!ci.Meta->Annotation.empty()) {
ImGui::Text(ci.Meta->Annotation.c_str());
}
auto& component = world->GetComponent(m_Selection, componentType);
for (auto& kv : ci.Fields) {
const std::string& fieldName = kv.first;
auto& field = kv.second;
std::string uniqueID = componentType + fieldName;
ImGui::PushID(uniqueID.c_str());
if (field.Type == "Vector") {
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") {
glm::vec3 tempVal = glm::fmod(val, glm::vec3(glm::two_pi<float>()));
if (ImGui::SliderFloat3("", glm::value_ptr(tempVal), 0.f, glm::two_pi<float>())) {
val = tempVal;
}
} else {
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.Field<glm::vec4>(fieldName);
ImGui::ColorEdit4("", glm::value_ptr(val), true);
} else if (field.Type == "string") {
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))) {
val = std::string(tempString);
LOG_DEBUG("%s::%s changed!", componentType.c_str(), fieldName.c_str());
}
// DROP STUFF
if (ImGui::IsItemHovered() && !m_LastDroppedFile.empty()) {
val = m_LastDroppedFile;
m_LastDroppedFile = "";
}
} else if (field.Type == "double") {
float tempVal = static_cast<float>(component.Field<double>(fieldName));
if (ImGui::InputFloat("", &tempVal, 0.01f, 1.f)) {
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.Field<bool>(fieldName);
ImGui::Checkbox("", &val);
} else {
ImGui::TextDisabled(field.Type.c_str());
}
ImGui::PopID();
ImGui::SameLine();
ImGui::Text(fieldName.c_str());
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("field annotation goes here");
}
}
}
}
}
}
ImGui::End();
if (ImGui::Begin("Entities")) {
auto entityChildren = world->GetEntityChildren();
std::function<void(EntityID)> recurse = [&](EntityID parent) {
auto range = entityChildren.equal_range(parent);
for (auto it = range.first; it != range.second; it++) {
if (createEntityNode(world, it->second)) {
recurse(it->second);
ImGui::TreePop();
}
}
};
recurse(EntityID_Invalid);
}
ImGui::End();
}
bool EditorSystem::createEntityNode(World* world, EntityID entity)
{
// HACK: Don't show the widget entities in the entity tree
if (entity == m_Widget) {
return false;
}
ImVec2 pos = ImGui::GetCursorScreenPos();
float width = ImGui::GetContentRegionAvailWidth();
ImRect bb(pos + ImVec2(20, 0), pos + ImVec2(width, 13));
auto window = ImGui::GetCurrentWindow();
if (m_Selection == entity) {
const ImU32 col = window->Color(ImGuiCol_HeaderActive);
window->DrawList->AddRectFilled(bb.Min, bb.Max, col);
}
ImGuiID id = window->GetID((std::string("#SelectButton") + std::to_string(entity)).c_str());
bool hovered = false;
bool held = false;
if (ImGui::ButtonBehavior(bb, id, &hovered, &held)) {
m_Selection = entity;
}
if (held) {
ImVec2 entityDragDelta = ImGui::GetMouseDragDelta(0);
if (std::abs(entityDragDelta.x) > 0 && std::abs(entityDragDelta.y) > 0) {
if (m_UIDraggingEntity == EntityID_Invalid) {
m_UIDraggingEntity = entity;
LOG_DEBUG("Started drag of entity %i", m_UIDraggingEntity);
}
ImGui::SetNextWindowPos(ImGui::GetIO().MousePos + ImVec2(20, 0));
ImGui::Begin("Change parent", nullptr, ImVec2(0, 0), 0.3f, ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoSavedSettings);
ImGui::Text("#%i", m_UIDraggingEntity);
ImGui::End();
}
}
ImGui::SetNextTreeNodeOpened(true, ImGuiSetCond_Once);
std::string nodeTitle;
const std::string& entityName = world->GetName(entity);
if (!entityName.empty()) {
nodeTitle = entityName;
} else {
nodeTitle = std::string("#") + std::to_string(entity);
}
if (ImGui::TreeNode(nodeTitle.c_str())) {
if (m_UIDraggingEntity != EntityID_Invalid && ImGui::IsItemHoveredRect() && ImGui::IsMouseReleased(0)) {
LOG_DEBUG("Changed parent of %i to %i", m_UIDraggingEntity, entity);
changeParent(m_UIDraggingEntity, entity);
m_UIDraggingEntity = EntityID_Invalid;
}
if (ImGui::BeginPopupContextItem("item context menu")) {
if (ImGui::Button("Add")) {
EntityID newEntity = world->CreateEntity(entity);
world->AttachComponent(newEntity, "Transform");
}
ImGui::SameLine();
if (ImGui::Button("Delete")) {
world->DeleteEntity(entity);
ImGui::CloseCurrentPopup();
if (!world->ValidEntity(m_Selection)) {
m_Selection = EntityID_Invalid;
}
}
ImGui::EndPopup();
}
return true;
} else {
return false;
}
}
bool EditorSystem::createDeleteButton(std::string componentType)
{
float width = ImGui::GetContentRegionAvailWidth();
ImGuiWindow* window = ImGui::GetCurrentWindow();
auto pos = ImGui::GetCursorScreenPos() + ImVec2(width - 14.f, 1);
ImRect bb = ImRect(pos, pos + ImVec2(14.f, 14.f));
std::string idString = "#DELETE";
idString += componentType;
ImGuiID id = window->GetID(idString.c_str());
bool hovered;
bool held;
bool pressed = ImGui::ButtonBehavior(bb, id, &hovered, &held);
//ImU32 col = window->Color((held && hovered) ? ImGuiCol_CloseButtonActive : hovered ? ImGuiCol_CloseButtonHovered : ImGuiCol_CloseButton);
ImU32 col = window->Color((held && hovered) ? ImGuiCol_CloseButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
window->DrawList->AddCircleFilled(bb.GetCenter(), 7.f, col, 16);
return pressed;
}
void EditorSystem::changeParent(EntityID entity, EntityID newParent)
{
if (entity == newParent) {
return;
}
// An entity can't be a child to one of its own children
auto children = m_World->GetEntityChildren().equal_range(entity);
for (auto it = children.first; it != children.second; it++) {
if (it->second == newParent) {
return;
}
}
m_World->SetParent(entity, newParent);
}
void EditorSystem::fileImport(World* world)
{
m_CurrentFile = openDialog(m_DefaultEntityDir);
auto file = ResourceManager::Load<EntityFile>(m_CurrentFile.string());
EntityFilePreprocessor fpp(file);
fpp.RegisterComponents(world);
EntityFileParser fp(file);
fp.MergeEntities(world);
createWidget();
updateWidget();
}
void EditorSystem::fileSave(World* world)
{
if (boost::filesystem::exists(m_CurrentFile)) {
// HACK: Delete the widgets so they don't appear in the saved file
world->DeleteEntity(m_Widget);
m_Widget = EntityID_Invalid;
EntityFileWriter writer(m_CurrentFile.string());
writer.WriteWorld(world);
createWidget();
} else {
fileSaveAs(world);
}
}
void EditorSystem::fileSaveAs(World* world)
{
auto filePath = saveDialog(m_DefaultEntityDir);
if (filePath.empty()) {
return;
}
// HACK: Delete the widgets so they don't appear in the saved file
world->DeleteEntity(m_Widget);
m_Widget = EntityID_Invalid;
EntityFileWriter writer(filePath.string());
writer.WriteWorld(world);
createWidget();
m_Widget["Transform"]["Position"] = Transform::AbsolutePosition(m_CurrentSelection.World, m_CurrentSelection.ID);
}
+75
View File
@@ -0,0 +1,75 @@
#include "Editor/EditorWidgetSystem.h"
EditorWidgetSystem::EditorWidgetSystem(World* world, EventBroker* eventBroker, IRenderer* renderer)
: System(world, eventBroker)
, PureSystem("EditorWidget")
, m_Renderer(renderer)
{
EVENT_SUBSCRIBE_MEMBER(m_EMouseMove, &EditorWidgetSystem::OnMouseMove);
EVENT_SUBSCRIBE_MEMBER(m_EMousePress, &EditorWidgetSystem::OnMousePress);
EVENT_SUBSCRIBE_MEMBER(m_EMouseRelease, &EditorWidgetSystem::OnMouseRelease);
}
void EditorWidgetSystem::Update(double dt)
{
// Pick at current mouse position
}
void EditorWidgetSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& cEditorWidget, double dt)
{
if (!m_PickEntity.Valid() || m_PickEntity != entity) {
return;
}
Events::WidgetDelta e;
EntityWrapper moveEntity = entity.Parent();
if (!moveEntity.Valid()) {
moveEntity = entity;
}
auto camera = m_PickData.Camera;
glm::vec3 axis = cEditorWidget["Axis"];
glm::vec2 axisScreen = camera->WorldToScreen(axis, m_Renderer->Resolution()) - camera->WorldToScreen(glm::vec3(0, 0, 0), m_Renderer->Resolution());
float dot = glm::dot(m_MouseDelta, glm::normalize(axisScreen)) / glm::length(axisScreen);
glm::vec3 worldMovement = dot * axis;
ComponentWrapper::SubscriptProxy& type = cEditorWidget["Type"];
if ((ComponentInfo::EnumType)type == type.Enum("Translate")) {
e.Translation += worldMovement;
m_EventBroker->Publish(e);
} else if ((ComponentInfo::EnumType)type == type.Enum("Rotate")) {
//if (glm::length(worldMovement) > 0) {
// glm::vec3& orientation = moveEntity["Transform"]["Orientation"];
// glm::quat q = glm::quat(orientation);
// q *= glm::quat(glm::vec3(worldMovement));
// orientation = glm::eulerAngles(q);
//}
}
m_MouseDelta = glm::vec2(0);
}
bool EditorWidgetSystem::OnMouseMove(const Events::MouseMove& e)
{
m_MouseDelta = glm::vec2((float)e.DeltaX, (float)-e.DeltaY);
return false;
}
bool EditorWidgetSystem::OnMousePress(const Events::MousePress & e)
{
ImGuiIO& io = ImGui::GetIO();
if (!io.WantCaptureMouse && !io.WantCaptureKeyboard && e.Button == GLFW_MOUSE_BUTTON_1) {
m_PickData = m_Renderer->Pick(glm::vec2(e.X, e.Y));
if (m_PickData.Entity != EntityID_Invalid && m_PickData.World == m_World) {
m_PickEntity = EntityWrapper(m_World, m_PickData.Entity);
}
}
return true;
}
bool EditorWidgetSystem::OnMouseRelease(const Events::MouseRelease& e)
{
m_PickEntity = EntityWrapper::Invalid;
return true;
}
+154 -130
View File
@@ -5,28 +5,27 @@ using namespace boost::asio::ip;
Client::Client(ConfigFile* config) : m_Socket(m_IOService)
{
// Asumes root node is EntityID 0
insertIntoServerClientMaps(0, 0);
// Default is local host
std::string address = config->Get<std::string>("Networking.Address", "127.0.0.1");
int port = config->Get<int>("Networking.Port", 13);
m_ReceiverEndpoint = udp::endpoint(boost::asio::ip::address::from_string(address), port);
// Set up network stream
m_PlayerName = config->Get<std::string>("Networking.Name", "Raptorcopter");
m_NextSnapshot.InputForward = "";
m_NextSnapshot.InputRight = "";
}
Client::~Client()
{
}
{ }
void Client::Start(World* world, EventBroker* eventBroker)
{
m_WasStarted = true;
m_EventBroker = eventBroker;
m_World = world;
// Subscribe to events
EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &Client::OnInputCommand);
EVENT_SUBSCRIBE_MEMBER(m_EPlayeDamage, &Client::OnPlayerDamage);
m_Socket.connect(m_ReceiverEndpoint);
LOG_INFO("I am client. BIP BOP");
@@ -34,7 +33,11 @@ void Client::Start(World* world, EventBroker* eventBroker)
void Client::Update()
{
m_EventBroker->Process<Client>();
readFromServer();
if (m_IsConnected) {
hasServerTimedOut();
}
}
void Client::readFromServer()
@@ -46,58 +49,7 @@ void Client::readFromServer()
parseMessageType(packet);
}
}
std::clock_t currentTime = std::clock();
if (snapshotInterval < (1000 * (currentTime - previousSnapshotMessage) / (double)CLOCKS_PER_SEC)) {
if (isConnected()) {
//sendSnapshotToServer();
}
previousSnapshotMessage = currentTime;
}
}
void Client::sendSnapshotToServer()
{
// Reset previous key state in snapshot.
m_NextSnapshot.InputForward = "";
m_NextSnapshot.InputRight = "";
auto player = m_World->GetComponent(m_PlayerDefinitions[m_PlayerID].EntityID, "Player");
// See if any movement keys are down
// We dont care if it's overwritten by later
// if statement. Watcha gonna do, right!
if (player["Forward"]) {
m_NextSnapshot.InputForward = "+Forward";
}
if (player["Left"]) {
m_NextSnapshot.InputRight = "-Right";
}
if (player["Back"]) {
m_NextSnapshot.InputForward = "-Forward";
}
if (player["Right"]) {
m_NextSnapshot.InputRight = "+Right";
}
if (m_NextSnapshot.InputForward != "") {
Packet packet(MessageType::Event, m_SendPacketID);
packet.WriteString(m_NextSnapshot.InputForward);
send(packet);
} else {
Packet packet(MessageType::Event, m_SendPacketID);
packet.WriteString("0Forward");
send(packet);
}
if (m_NextSnapshot.InputRight != "") {
Packet packet(MessageType::Event, m_SendPacketID);
packet.WriteString(m_NextSnapshot.InputRight);
send(packet);
} else {
Packet packet(MessageType::Event, m_SendPacketID);
packet.WriteString("0Right");
send(packet);
}
sendInputCommands();
}
void Client::parseMessageType(Packet& packet)
@@ -108,9 +60,7 @@ void Client::parseMessageType(Packet& packet)
// Read packet ID
m_PreviousPacketID = m_PacketID; // Set previous packet id
m_PacketID = packet.ReadPrimitive<int>(); //Read new packet id
if (m_PacketID <= m_PreviousPacketID)
return;
//IdentifyPacketLoss();
identifyPacketLoss();
switch (static_cast<MessageType>(messageType)) {
case MessageType::Connect:
@@ -129,9 +79,8 @@ void Client::parseMessageType(Packet& packet)
break;
case MessageType::Disconnect:
break;
case MessageType::Event:
parseEventMessage(packet);
break;
case MessageType::PlayerConnected:
parsePlayerConnected(packet);
default:
break;
}
@@ -139,34 +88,52 @@ void Client::parseMessageType(Packet& packet)
void Client::parseConnect(Packet& packet)
{
m_PlayerID = packet.ReadPrimitive<int>();
LOG_INFO("%i: I am player: %i", m_PacketID, m_PlayerID);
// Map ServerEntityID and your PlayerID
LOG_INFO("I be connected PogChamp");
}
void Client::parsePlayerConnected(Packet & packet)
{
// Map ServerEntityID and other player's PlayerID
LOG_INFO("A Player connected");
}
void Client::parsePing()
{
m_DurationOfPingTime = 1000 * (std::clock() - m_StartPingTime) / static_cast<double>(CLOCKS_PER_SEC);
LOG_INFO("%i: response time with ctime(ms): %f", m_PacketID, m_DurationOfPingTime);
}
void Client::parseServerPing()
{
// Might miss connect message so set it here instead.
m_IsConnected = true;
// Time since last ping was received
m_DurationOfPingTime = 1000 * (std::clock() - m_StartPingTime) / static_cast<double>(CLOCKS_PER_SEC);
LOG_INFO("%i: response time with ctime(ms): %f", m_PacketID, m_DurationOfPingTime);
m_StartPingTime = std::clock();
Packet packet(MessageType::ServerPing, m_SendPacketID);
packet.WriteString("Ping recieved");
send(packet);
}
void Client::parseEventMessage(Packet& packet)
// Fields with strings will not work right now
void Client::InterpolateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID, const std::string& componentType)
{
int Id = -1;
std::string command = packet.ReadString();
if (command.find("+Player") != std::string::npos) {
Id = packet.ReadPrimitive<int>();
// Sett Player name
m_PlayerDefinitions[Id].Name = command.erase(0, 7);
} else {
LOG_INFO("%i: Event message: %s", m_PacketID, command.c_str());
int sizeOfFields = 0;
for (auto field : componentInfo.FieldsInOrder) {
ComponentInfo::Field_t fieldInfo = componentInfo.Fields.at(field);
sizeOfFields += fieldInfo.Stride;
}
// Is the size correct?
boost::shared_array<char> eventData(new char[componentInfo.Stride]);
memcpy(eventData.get(), packet.ReadData(componentInfo.Stride), componentInfo.Stride);
//Send event to interpolat system
Events::Interpolate e;
e.Entity = entityID;
e.DataArray = eventData;
m_EventBroker->Publish(e);
}
void Client::updateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID, const std::string& componentType)
@@ -182,17 +149,27 @@ void Client::updateFields(Packet& packet, const ComponentInfo& componentInfo, co
}
}
// Field parse
void Client::parseSnapshot(Packet& packet)
{
std::string componentType = packet.ReadString();
while (packet.DataReadSize() < packet.Size()) {
EntityID entityID = packet.ReadPrimitive<EntityID>();
// Components EntityID
EntityID receivedEntityID = packet.ReadPrimitive<EntityID>();
// Parents EntityID
EntityID receivedParentEntityID = packet.ReadPrimitive<EntityID>();
ComponentInfo componentInfo = m_World->GetComponents(componentType)->ComponentInfo();
if (m_World->ValidEntity(entityID)) {
// Check if the received EntityID is mapped to one of our local EntityIDs
if (serverClientMapsHasEntity(receivedEntityID)) {
// Get the local EntityID
EntityID entityID = m_ServerIDToClientID.at(receivedEntityID);
// Check if the component exists
if (m_World->HasComponent(entityID, componentType)) {
// If the entity and the component exists update it
updateFields(packet, componentInfo, entityID, componentType);
if (componentType == "Transform") {
InterpolateFields(packet, componentInfo, entityID, componentType);
} else {
updateFields(packet, componentInfo, entityID, componentType);
}
// if entity exists but not the component
} else {
// Create component
@@ -202,11 +179,12 @@ void Client::parseSnapshot(Packet& packet)
}
// If the entity dosent exist nor the component
} else {
//Create Entity
// Create Entity
// If entity dosen't exist
EntityID newEntityID = m_World->CreateEntity();
insertIntoServerClientMaps(receivedEntityID, newEntityID);
// Check if EntityIDs are out of sync
if (newEntityID != entityID) {
if (newEntityID != receivedEntityID) {
LOG_INFO("Client::parseSnapshot(Packet& packet): Newly created EntityID is not the \
same as the one sent by server (EntityIDs are out of sync)");
}
@@ -215,6 +193,21 @@ void Client::parseSnapshot(Packet& packet)
// Copy data to newly created component
updateFields(packet, componentInfo, newEntityID, componentType);
}
// Parent Logic
// Don't need to check if receivedEntityID is mapped. (It should have been set)
if (receivedParentEntityID != std::numeric_limits<EntityID>::max()) {
if (serverClientMapsHasEntity(receivedParentEntityID)) {
m_World->SetParent(m_ServerIDToClientID.at(receivedEntityID), m_ServerIDToClientID.at(receivedParentEntityID));
// If Parent dosen't exist create one and map receivedParentEntityID to it.
} else {
// Create the new parent and add it to map
EntityID newParentEntityID = m_World->CreateEntity();
insertIntoServerClientMaps(receivedParentEntityID, newParentEntityID);
// Set the newly created Entity as parent.
m_World->SetParent(m_ServerIDToClientID.at(receivedEntityID), newParentEntityID);
}
}
}
}
@@ -228,9 +221,8 @@ int Client::receive(char* data, size_t length)
0, error);
if (error) {
LOG_ERROR("receive: %s", error.message().c_str());
//LOG_ERROR("receive: %s", error.message().c_str());
}
return bytesReceived;
}
@@ -252,76 +244,72 @@ void Client::connect()
void Client::disconnect()
{
Packet packet(MessageType::Connect, m_SendPacketID);
packet.WriteString("+Disconnect");
m_PreviousPacketID = 0;
m_PacketID = 0;
Packet packet(MessageType::Disconnect, m_SendPacketID);
send(packet);
}
void Client::ping()
{
Packet packet(MessageType::Connect, m_SendPacketID);
packet.WriteString("Ping");
m_StartPingTime = std::clock();
send(packet);
}
void Client::moveMessageHead(char*& data, size_t& length, size_t stepSize)
{
data += stepSize;
length -= stepSize;
//Packet packet(MessageType::Connect, m_SendPacketID);
//packet.WriteString("Ping");
//m_StartPingTime = std::clock();
//send(packet);
}
bool Client::OnInputCommand(const Events::InputCommand & e)
{
if (isConnected()) {
ComponentWrapper& player = m_World->GetComponent(m_PlayerDefinitions[m_PlayerID].EntityID, "Player");
if (e.Command == "Forward") {
if (e.Value > 0) {
(bool&)player["Forward"] = true;
(bool&)player["Back"] = false;
} else if (e.Value < 0) {
(bool&)player["Back"] = true;
(bool&)player["Forward"] = false;
} else {
(bool&)player["Forward"] = false;
(bool&)player["Back"] = false;
}
}
if (e.Command == "Right") {
if (e.Value > 0) {
(bool&)player["Right"] = true;
(bool&)player["Left"] = false;
} else if (e.Value < 0) {
(bool&)player["Left"] = true;
(bool&)player["Right"] = false;
} else {
(bool&)player["Left"] = false;
(bool&)player["Right"] = false;
}
}
}
if (e.Command == "ConnectToServer") { // Connect for now
connect();
if (e.Value > 0) {
connect();
}
//LOG_DEBUG("Client::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID);
return true;
} else if (e.Command == "DisconnectFromServer") {
if (e.Value > 0) {
disconnect();
}
return true;
} else if (e.Command == "SwitchToPlayer") {
if (e.Value > 0) {
becomePlayer();
}
} else {
m_InputCommandBuffer.push_back(e);
//LOG_DEBUG("Client::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID);
return true;
}
return false;
}
bool Client::OnPlayerDamage(const Events::PlayerDamage & e)
{
Packet packet(MessageType::OnInputCommand, m_SendPacketID);
packet.WritePrimitive(e.DamageAmount);
packet.WritePrimitive(e.PlayerDamagedID);
send(packet);
return false;
}
void Client::identifyPacketLoss()
{
// if no packets lost, difference should be equal to 1
int difference = m_PacketID - m_PreviousPacketID;
if (difference != 1) {
LOG_INFO("%i Packet(s) were lost...", difference);
LOG_INFO("%i Packet(s) were lost...", difference - 1);
}
}
bool Client::isConnected()
bool Client::hasServerTimedOut()
{
if (m_PlayerID != -1) {
if (m_PlayerDefinitions[m_PlayerID].EntityID != -1) {
return true;
}
// Time in ms
float timeSincePing = 1000 * (std::clock() - m_StartPingTime) / static_cast<double>(CLOCKS_PER_SEC);
if (timeSincePing > TIMEOUTMS) {
// Clear everything and go to menu.
LOG_INFO("Server has timed out, returning to menu, Beep Boop.");
m_IsConnected = false;
return true;
}
return false;
}
@@ -335,3 +323,39 @@ EntityID Client::createPlayer()
ComponentWrapper player = m_World->AttachComponent(entityID, "Player");
return entityID;
}
void Client::sendInputCommands()
{
if (m_InputCommandBuffer.size() > 0) {
Packet packet(MessageType::OnInputCommand, m_SendPacketID);
for (int i = 0; i < m_InputCommandBuffer.size(); i++) {
packet.WriteString(m_InputCommandBuffer[i].Command);
packet.WritePrimitive(m_InputCommandBuffer[i].Value);
}
send(packet);
m_InputCommandBuffer.clear();
}
}
void Client::becomePlayer()
{
Packet packet = Packet(MessageType::BecomePlayer, m_SendPacketID);
send(packet);
}
bool Client::clientServerMapsHasEntity(EntityID clientEntityID)
{
return m_ClientIDToServerID.find(clientEntityID) != m_ClientIDToServerID.end();
}
bool Client::serverClientMapsHasEntity(EntityID serverEntityID)
{
return m_ServerIDToClientID.find(serverEntityID) != m_ServerIDToClientID.end();
}
void Client::insertIntoServerClientMaps(EntityID serverEntityID, EntityID clientEntityID)
{
m_ServerIDToClientID.insert(std::make_pair(serverEntityID, clientEntityID));
m_ClientIDToServerID.insert(std::make_pair(clientEntityID, serverEntityID));
}
+21 -8
View File
@@ -17,20 +17,26 @@ Packet::Packet(char* data, const int sizeOfPacket)
m_Offset = sizeOfPacket;
}
Packet::Packet(MessageType type)
{
m_Data = new char[m_MaxPacketSize];
unsigned int dummy = 0;
Init(type, dummy);
}
Packet::~Packet()
{
delete[] m_Data;
}
void Packet::Init(MessageType type, unsigned int & packetID)
{
{
m_ReturnDataOffset = 0;
m_Offset = 0;
// Create message header
// Add message type
int messageType = static_cast<int>(type);
Packet::WritePrimitive<int>(messageType);
packetID = packetID % 1000; // Packet id modulos
Packet::WritePrimitive<int>(packetID);
packetID++;
}
@@ -40,7 +46,7 @@ void Packet::WriteString(const std::string& str)
// Message, add one extra byte for null terminator
int sizeOfString = str.size() + 1;
if (m_Offset + sizeOfString > m_MaxPacketSize) {
LOG_WARNING("Package::WriteString(): Data size in packet exceeded maximum package size. New size is %i bytes\n", m_MaxPacketSize*2);
//LOG_WARNING("Package::WriteString(): Data size in packet exceeded maximum package size. New size is %i bytes\n", m_MaxPacketSize*2);
resizeData();
}
memcpy(m_Data + m_Offset, str.data(), sizeOfString * sizeof(char));
@@ -50,7 +56,7 @@ void Packet::WriteString(const std::string& str)
void Packet::WriteData(char * data, int sizeOfData)
{
if (m_Offset + sizeOfData > m_MaxPacketSize) {
LOG_WARNING("Packet::WriteData(): Data size in packet exceeded maximum packet size. New size is %i bytes\n", m_MaxPacketSize*2);
//LOG_WARNING("Packet::WriteData(): Data size in packet exceeded maximum packet size. New size is %i bytes\n", m_MaxPacketSize*2);
resizeData();
}
memcpy(m_Data + m_Offset, data, sizeOfData);
@@ -61,7 +67,7 @@ std::string Packet::ReadString()
{
std::string returnValue(m_Data + m_ReturnDataOffset);
if (m_Offset < m_ReturnDataOffset + returnValue.size()) {
LOG_WARNING("packet ReadString(): Oh no! You are trying to remove things outside my memory kingdom");
//LOG_WARNING("packet ReadString(): Oh no! You are trying to remove things outside my memory kingdom");
return "PopFrontString Failed";
}
// +1 for null terminator.
@@ -72,7 +78,7 @@ std::string Packet::ReadString()
char * Packet::ReadData(int SizeOfData)
{
if (m_Offset < m_ReturnDataOffset + SizeOfData) {
LOG_WARNING("packet ReadData(): Oh no! You are trying to remove things outside my memory kingdom");
//LOG_WARNING("packet ReadData(): Oh no! You are trying to remove things outside my memory kingdom");
return nullptr;
}
unsigned int oldReturnDataOffset = m_ReturnDataOffset;
@@ -80,14 +86,21 @@ char * Packet::ReadData(int SizeOfData)
return (m_Data + oldReturnDataOffset);
}
void Packet::ChangePacketID(unsigned int & packetID)
{
packetID = packetID + 1;
// Overwrite old PacketID
memcpy(m_Data + sizeof(int), &packetID, sizeof(int));
}
void Packet::resizeData()
{
{
// Allocate memory to store our data in
char* holdData = new char[m_MaxPacketSize];
// Copy our data to the newly allocated memory
memcpy(holdData, m_Data, m_Offset);
// Increase max packet size
// Increase max packet size
m_MaxPacketSize = m_MaxPacketSize * 2;
// Delete our data
delete m_Data;
+150 -130
View File
@@ -8,13 +8,14 @@ Server::~Server()
}
void Server::Start(World* world, EventBroker* eventBroker)
{
m_World = world;
m_EventBroker = eventBroker;
// Subscribe to events
EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &Server::OnInputCommand);
for (size_t i = 0; i < MAXCONNECTIONS; i++) {
m_StopTimes[i] = std::clock();
m_PlayerDefinitions[i].StopTime = std::clock();
}
LOG_INFO("I am Server. BIP BOP\n");
}
@@ -22,8 +23,10 @@ void Server::Start(World* world, EventBroker* eventBroker)
void Server::Update()
{
readFromClients();
m_EventBroker->Process<Server>();
}
void Server::readFromClients()
{
while (m_Socket.available()) {
@@ -50,7 +53,7 @@ void Server::readFromClients()
// Time out logic
if (checkTimeOutInterval < (1000 * (currentTime - timOutTimer) / (double)CLOCKS_PER_SEC)) {
//checkForTimeOuts();
checkForTimeOuts();
timOutTimer = currentTime;
}
}
@@ -62,7 +65,7 @@ void Server::parseMessageType(Packet& packet)
// Read packet ID
m_PreviousPacketID = m_PacketID; // Set previous packet id
m_PacketID = packet.ReadPrimitive<int>(); //Read new packet id
//IdentifyPacketLoss();
//identifyPacketLoss();
switch (static_cast<MessageType>(messageType)) {
case MessageType::Connect:
parseConnect(packet);
@@ -76,13 +79,18 @@ void Server::parseMessageType(Packet& packet)
case MessageType::Message:
break;
case MessageType::Snapshot:
parseSnapshot(packet);
break;
case MessageType::Disconnect:
parseDisconnect();
break;
case MessageType::Event:
parseEvent(packet);
case MessageType::OnInputCommand:
parseOnInputCommand(packet);
break;
case MessageType::OnPlayerDamage:
parseOnPlayerDamage(packet);
break;
case MessageType::BecomePlayer:
createPlayer();
break;
default:
break;
@@ -98,11 +106,11 @@ int Server::receive(char * data, size_t length)
return length;
}
void Server::send(Packet& packet, int playerID)
void Server::send(Packet& packet, int userID)
{
int bytesSent = m_Socket.send_to(
boost::asio::buffer(packet.Data(), packet.Size()),
m_PlayerDefinitions[playerID].Endpoint,
m_ConnectedUsers[userID].Endpoint,
0);
}
@@ -116,27 +124,11 @@ void Server::send(Packet & packet)
0);
}
void Server::moveMessageHead(char *& data, size_t & length, size_t stepSize)
{
data += stepSize;
length -= stepSize;
}
void Server::broadcast(std::string message)
{
Packet packet(MessageType::Event, m_SendPacketID);
packet.WriteString(message);
for (int i = 0; i < MAXCONNECTIONS; i++) {
if (m_PlayerDefinitions[i].Endpoint.address() != boost::asio::ip::address()) {
send(packet, i);
}
}
}
void Server::broadcast(Packet& packet)
{
for (int i = 0; i < MAXCONNECTIONS; ++i) {
if (m_PlayerDefinitions[i].Endpoint.address() != boost::asio::ip::address()) {
for (int i = 0; i < m_ConnectedUsers.size(); i++) {
if (m_ConnectedUsers[i].Endpoint.address() != boost::asio::ip::address()) {
packet.ChangePacketID(m_ConnectedUsers[i].PacketID);
send(packet, i);
}
}
@@ -148,14 +140,16 @@ void Server::sendSnapshot()
// Should time this
std::unordered_map<std::string, ComponentPool*> worldComponentPools = m_World->GetComponentPools();
for (auto& it : worldComponentPools) {
Packet packet(MessageType::Snapshot, m_SendPacketID);
std::string componentType = it.first;
Packet packet(MessageType::Snapshot);
ComponentPool* componentPool = it.second;
ComponentInfo componentInfo = componentPool->ComponentInfo();
// Component Type
packet.WriteString(componentInfo.Name);
for (auto& componentWrapper : *componentPool) {
// Components EntityID
packet.WritePrimitive(componentWrapper.EntityID);
// Parents EntityID
packet.WritePrimitive(m_World->GetParent(componentWrapper.EntityID));
for (auto& componentField : componentWrapper.Info.FieldsInOrder) {
ComponentInfo::Field_t fieldInfo = componentInfo.Fields.at(componentField);
if (fieldInfo.Type == "string") {
@@ -173,14 +167,14 @@ void Server::sendSnapshot()
void Server::sendPing()
{
// Prints connected players ping
for (size_t i = 0; i < MAXCONNECTIONS; i++) {
if (m_PlayerDefinitions[i].Endpoint.address() != boost::asio::ip::address()) {
int ping = 1000 * (m_StopTimes[i] - m_StartPingTime) / static_cast<double>(CLOCKS_PER_SEC);
LOG_INFO("Last packetID received %i: Player %i's ping: %i", m_PacketID, i, ping);
for (int i = 0; i < m_ConnectedUsers.size(); i++) {
if (m_ConnectedUsers[i].Endpoint.address() != boost::asio::ip::address()) {
int ping = 1000 * (m_ConnectedUsers[i].StopTime - m_StartPingTime) / static_cast<double>(CLOCKS_PER_SEC);
LOG_INFO("Last packetID received %i: User %i's ping: %i", m_ConnectedUsers[i].PacketID, i, std::abs(ping));
}
}
// Create ping message
Packet packet(MessageType::ServerPing, m_SendPacketID);
Packet packet(MessageType::ServerPing);
packet.WriteString("Ping from server");
// Time message
m_StartPingTime = std::clock();
@@ -190,16 +184,15 @@ void Server::sendPing()
void Server::checkForTimeOuts()
{
int timeOutTimeMs = 5000;
int startPing = 1000 * m_StartPingTime
/ static_cast<double>(CLOCKS_PER_SEC);
for (size_t i = 0; i < MAXCONNECTIONS; i++) {
if (m_PlayerDefinitions[i].Endpoint.address() != boost::asio::ip::address()) {
int stopPing = 1000 * m_StopTimes[i]
/ static_cast<double>(CLOCKS_PER_SEC);
if (startPing > stopPing + timeOutTimeMs) {
LOG_INFO("Player %i timed out!", i);
for (int i = 0; i < m_ConnectedUsers.size(); i++) {
if (m_ConnectedUsers[i].Endpoint.address() != boost::asio::ip::address()) {
int stopPing = 1000 * m_ConnectedUsers[i].StopTime /
static_cast<double>(CLOCKS_PER_SEC);
if (startPing > stopPing + TIMEOUTMS) {
LOG_INFO("User %i timed out!", i);
disconnect(i);
}
}
@@ -208,92 +201,88 @@ void Server::checkForTimeOuts()
void Server::disconnect(int i)
{
broadcast("A player disconnected");
LOG_INFO("Player %i disconnected/timed out", i);
// Remove enteties and stuff
//broadcast("A player disconnected");
LOG_INFO("User %s disconnected/timed out", m_PlayerDefinitions[i].Name.c_str());
// Remove enteties and stuff (When we can remove entity, remove it and tell clients to remove the copy they have)
m_PlayerDefinitions[i].Endpoint = boost::asio::ip::udp::endpoint();
m_PlayerDefinitions[i].EntityID = -1;
m_PlayerDefinitions[i].Name = "";
m_PlayerDefinitions[i].PacketID = 0;
m_ConnectedUsers.erase(m_ConnectedUsers.begin() + i);
}
void Server::parseEvent(Packet& packet)
void Server::parseOnInputCommand(Packet& packet)
{
size_t i;
for (i = 0; i < MAXCONNECTIONS; i++) {
if (m_PlayerDefinitions[i].Endpoint.address() == m_ReceiverEndpoint.address()) {
int playerID = -1;
// Check which player it was who sent the message
for (int i = 0; i < MAXCONNECTIONS; i++) {
// if the player is connected set playerID to the correct PlayerID
if (m_PlayerDefinitions[i].Endpoint.address() == m_ReceiverEndpoint.address()
&& m_PlayerDefinitions[i].Endpoint.port() == m_ReceiverEndpoint.port()) {
playerID = i;
break;
}
}
// If no player matches the address return.
if (i >= 8)
return;
if (playerID != -1) {
while (packet.DataReadSize() < packet.Size()) {
Events::InputCommand e;
e.Command = packet.ReadString();
e.PlayerID = playerID; // Set correct player id
e.Value = packet.ReadPrimitive<float>();
m_EventBroker->Publish(e);
//LOG_INFO("Server::parseOnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID);
}
}
}
unsigned int entityId = m_PlayerDefinitions[i].EntityID;
std::string eventString = packet.ReadString();
if ("+Forward" == eventString) {
m_World->GetComponent(entityId, "Player")["Forward"] = true;
m_World->GetComponent(entityId, "Player")["Back"] = false;
} else if ("-Forward" == eventString) {
m_World->GetComponent(entityId, "Player")["Forward"] = false;
m_World->GetComponent(entityId, "Player")["Back"] = true;
} else if ("0Forward" == eventString) {
m_World->GetComponent(entityId, "Player")["Forward"] = false;
m_World->GetComponent(entityId, "Player")["Back"] = false;
}
if ("+Right" == eventString) {
m_World->GetComponent(entityId, "Player")["Left"] = false;
m_World->GetComponent(entityId, "Player")["Right"] = true;
} else if ("-Right" == eventString) {
m_World->GetComponent(entityId, "Player")["Right"] = false;
m_World->GetComponent(entityId, "Player")["Left"] = true;
} else if ("0Right" == eventString) {
m_World->GetComponent(entityId, "Player")["Right"] = false;
m_World->GetComponent(entityId, "Player")["Left"] = false;
}
void Server::parseOnPlayerDamage(Packet & packet)
{
Events::PlayerDamage e;
e.DamageAmount = packet.ReadPrimitive<double>();
e.PlayerDamagedID = packet.ReadPrimitive<EntityID>();
m_EventBroker->Publish(e);
//LOG_DEBUG("Server::parseOnPlayerDamage: Command is %s. Value is %f. PlayerID is %i.", e.DamageAmount, e.PlayerDamagedID, e.TypeOfDamage.c_str());
}
void Server::parseConnect(Packet& packet)
{
LOG_INFO("Parsing connections");
// Check if player is already connected
for (int i = 0; i < MAXCONNECTIONS; i++) {
if (m_PlayerDefinitions[i].Endpoint.address() == m_ReceiverEndpoint.address()) {
if (GetPlayerIDFromEndpoint(m_ReceiverEndpoint) != -1) {
return;
}
for (int i = 0; i < m_ConnectedUsers.size(); i++) {
if (m_ConnectedUsers[i].Endpoint.address() == m_ReceiverEndpoint.address() &&
m_ConnectedUsers[i].Endpoint.port() == m_ReceiverEndpoint.port()) {
// Already connected
return;
}
}
// Create a new player
PlayerDefinition pd;
pd.EntityID = 0; // Overlook this
pd.Endpoint = m_ReceiverEndpoint;
pd.Name = packet.ReadString();
pd.PacketID = 0;
pd.StopTime = std::clock();
m_ConnectedUsers.push_back(pd);
LOG_INFO("Spectator \"%s\" connected on IP: %s", pd.Name.c_str(), pd.Endpoint.address().to_string().c_str());
for (int i = 0; i < MAXCONNECTIONS; i++) {
if (m_PlayerDefinitions[i].Endpoint.address() == boost::asio::ip::address()) {
// Create new player
m_PlayerDefinitions[i].EntityID = createPlayer();
m_PlayerDefinitions[i].Endpoint = m_ReceiverEndpoint;
m_PlayerDefinitions[i].Name = packet.ReadString();
// Send a message to the player that connected
Packet connnectPacket(MessageType::Connect, m_ConnectedUsers[m_ConnectedUsers.size() - 1].PacketID);
send(connnectPacket);
m_StopTimes[i] = std::clock();
LOG_INFO("Player \"%s\" connected on IP: %s", m_PlayerDefinitions[i].Name.c_str(), m_PlayerDefinitions[i].Endpoint.address().to_string().c_str());
Packet packet(MessageType::Connect, m_SendPacketID);
packet.WritePrimitive<int>(i); // Player ID
send(packet, i);
// Send notification that a player has connected
std::string str = m_PacketID + "Player " + m_PlayerDefinitions[i].Name + " connected on: "
+ m_PlayerDefinitions[i].Endpoint.address().to_string();
broadcast(str);
break;
}
}
// Send notification that a player has connected
Packet notificationPacket(MessageType::PlayerConnected);
broadcast(notificationPacket);
}
void Server::parseDisconnect()
{
LOG_INFO("%i: Parsing disconnect", m_PacketID);
for (int i = 0; i < MAXCONNECTIONS; i++) {
if (m_PlayerDefinitions[i].Endpoint.address() == m_ReceiverEndpoint.address()) {
for (int i = 0; i < m_ConnectedUsers.size(); i++) {
if (m_ConnectedUsers[i].Endpoint.address() == m_ReceiverEndpoint.address()) {
disconnect(i);
break;
}
@@ -303,37 +292,26 @@ void Server::parseDisconnect()
void Server::parseClientPing()
{
LOG_INFO("%i: Parsing ping", m_PacketID);
int playerID = GetPlayerIDFromEndpoint(m_ReceiverEndpoint);
if (playerID == -1) {
return;
}
// Return ping
Packet packet(MessageType::ClientPing, m_SendPacketID);
Packet packet(MessageType::ClientPing, m_PlayerDefinitions[playerID].PacketID);
packet.WriteString("Ping received");
send(packet); // This dosen't work for multiple users
send(packet);
}
void Server::parseServerPing()
{
for (int i = 0; i < MAXCONNECTIONS; i++) {
if (m_PlayerDefinitions[i].Endpoint.address() == m_ReceiverEndpoint.address()) {
m_StopTimes[i] = std::clock();
for (int i = 0; i < m_ConnectedUsers.size(); i++) {
if (m_ConnectedUsers[i].Endpoint.address() == m_ReceiverEndpoint.address()) {
m_ConnectedUsers[i].StopTime = std::clock();
break;
}
}
}
// NOT USED
void Server::parseSnapshot(Packet& packet)
{
// Does no logic. Returns snapshot if client request one
// The snapshot is not a real snapshot tho...
for (int i = 0; i < MAXCONNECTIONS; i++) {
if (m_PlayerDefinitions[i].Endpoint.address() != boost::asio::ip::address()) {
m_Socket.send_to(
boost::asio::buffer("I'm sending a snapshot to you guys!"),
m_PlayerDefinitions[i].Endpoint,
0);
}
}
}
void Server::identifyPacketLoss()
{
// if no packets lost, difference should be equal to 1
@@ -343,14 +321,56 @@ void Server::identifyPacketLoss()
}
}
EntityID Server::createPlayer()
void Server::createPlayer()
{
EntityID entityID = m_World->CreateEntity();
ComponentWrapper transform = m_World->AttachComponent(entityID, "Transform");
transform["Position"] = glm::vec3(-1.5f, 0.f, 0.f);
ComponentWrapper model = m_World->AttachComponent(entityID, "Model");
if (GetPlayerIDFromEndpoint(m_ReceiverEndpoint) != -1) {
// Already connected as player
LOG_WARNING("Already connected!");
return;
}
int userIndex;
for (userIndex = 0; userIndex < m_ConnectedUsers.size(); userIndex++) {
if (m_ConnectedUsers[userIndex].Endpoint.address() == m_ReceiverEndpoint.address() &&
m_ConnectedUsers[userIndex].Endpoint.port() == m_ReceiverEndpoint.port()) {
// Found user
break;
}
}
if (userIndex == m_ConnectedUsers.size()) {
LOG_WARNING("Not a recognized user!");
return;
}
for (int playerIndex = 0; playerIndex < MAXCONNECTIONS; playerIndex++) {
if (m_PlayerDefinitions[playerIndex].Endpoint.address() == boost::asio::ip::address()) {
m_PlayerDefinitions[playerIndex] = m_ConnectedUsers[userIndex];
EntityID entityID = m_World->CreateEntity();
ComponentWrapper transform = m_World->AttachComponent(entityID, "Transform");
transform["Position"] = glm::vec3(-1.5f, 0.f, 0.f);
ComponentWrapper model = m_World->AttachComponent(entityID, "Model");
model["Resource"] = "Models/Core/UnitSphere.mesh";
model["Color"] = glm::vec4(rand()%255 / 255.f, rand()%255 / 255.f, rand() %255 / 255.f, 1.f);
ComponentWrapper player = m_World->AttachComponent(entityID, "Player");
return entityID;
model["Color"] = glm::vec4(rand()%255 / 255.f, rand()%255 / 255.f, rand() %255 / 255.f, 1.f);
ComponentWrapper player = m_World->AttachComponent(entityID, "Player");
m_PlayerDefinitions[playerIndex].EntityID = entityID;
return;
}
}
LOG_WARNING("Server is full!");
}
int Server::GetPlayerIDFromEndpoint(boost::asio::ip::udp::endpoint endpoint)
{
for (int i = 0; i < MAXCONNECTIONS; i++) {
if (m_PlayerDefinitions[i].Endpoint.address() == endpoint.address() &&
m_PlayerDefinitions[i].Endpoint.port() == endpoint.port()) {
return i;
}
}
return -1;
}
bool Server::OnInputCommand(const Events::InputCommand & e)
{
//LOG_DEBUG("Server::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID);
return true;
}
+13
View File
@@ -79,6 +79,19 @@ void Camera::UpdateProjectionMatrix()
m_ProjectionMatrix = glm::perspective(m_FOV, m_AspectRatio, m_NearClip, m_FarClip);
}
glm::vec2 Camera::WorldToScreen(glm::vec3 worldCoord, Rectangle resolution)
{
glm::vec4 screenCoord = m_ProjectionMatrix * m_ViewMatrix * glm::vec4(worldCoord, 1.f);
if (screenCoord.w != 0) {
screenCoord.x /= screenCoord.w;
screenCoord.y /= screenCoord.w;
screenCoord.z /= screenCoord.w;
}
screenCoord.x = screenCoord.x * (resolution.Width / 2.f);
screenCoord.y = screenCoord.y * (resolution.Height / 2.f);
return glm::vec2(screenCoord);
}
void Camera::UpdateViewMatrix()
{
m_ViewMatrix = glm::toMat4(glm::inverse(m_Orientation))
+134
View File
@@ -0,0 +1,134 @@
#include "Rendering/DrawBloomPass.h"
DrawBloomPass::DrawBloomPass(IRenderer* renderer)
{
m_Renderer = renderer;
m_ScreenQuad = ResourceManager::Load<Model>("Models/Core/ScreenQuad.obj");
InitializeTextures();
InitializeBuffers();
InitializeShaderPrograms();
}
void DrawBloomPass::InitializeTextures()
{
m_WhiteTexture = ResourceManager::Load<Texture>("Textures/Core/Blank.png");
}
void DrawBloomPass::InitializeShaderPrograms()
{
m_GaussianProgram_horiz = ResourceManager::Load<ShaderProgram>("##GaussianProgramHoriz");
m_GaussianProgram_horiz->AddShader(std::shared_ptr<Shader>(new VertexShader("Shaders/Gaussian_horiz.vert.glsl")));
m_GaussianProgram_horiz->AddShader(std::shared_ptr<Shader>(new FragmentShader("Shaders/Gaussian_horiz.frag.glsl")));
m_GaussianProgram_horiz->Compile();
m_GaussianProgram_horiz->Link();
m_GaussianProgram_vert = ResourceManager::Load<ShaderProgram>("##GaussianProgramVert");
m_GaussianProgram_vert->AddShader(std::shared_ptr<Shader>(new VertexShader("Shaders/Gaussian_vert.vert.glsl")));
m_GaussianProgram_vert->AddShader(std::shared_ptr<Shader>(new FragmentShader("Shaders/Gaussian_vert.frag.glsl")));
m_GaussianProgram_vert->Compile();
m_GaussianProgram_vert->Link();
}
void DrawBloomPass::InitializeBuffers()
{
GenerateTexture(&m_GaussianTexture_horiz, GL_CLAMP_TO_EDGE, GL_LINEAR, glm::vec2(m_Renderer->Resolution().Width, m_Renderer->Resolution().Height), GL_RGB16F, GL_RGB, GL_FLOAT);
m_GaussianFrameBuffer_horiz.AddResource(std::shared_ptr<BufferResource>(new Texture2D(&m_GaussianTexture_horiz, GL_COLOR_ATTACHMENT0)));
m_GaussianFrameBuffer_horiz.Generate();
GenerateTexture(&m_GaussianTexture_vert, GL_CLAMP_TO_EDGE, GL_LINEAR, glm::vec2(m_Renderer->Resolution().Width, m_Renderer->Resolution().Height), GL_RGB16F, GL_RGB, GL_FLOAT);
m_GaussianFrameBuffer_vert.AddResource(std::shared_ptr<BufferResource>(new Texture2D(&m_GaussianTexture_vert, GL_COLOR_ATTACHMENT0)));
m_GaussianFrameBuffer_vert.Generate();
}
void DrawBloomPass::ClearBuffer()
{
m_GaussianFrameBuffer_horiz.Bind();
glClearColor(0.f, 0.f, 0.f, 0.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
m_GaussianFrameBuffer_horiz.Unbind();
m_GaussianFrameBuffer_vert.Bind();
glClearColor(0.f, 0.f, 0.f, 0.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
m_GaussianFrameBuffer_vert.Unbind();
}
void DrawBloomPass::Draw(GLuint texture)
{
GLERROR("DrawBloomPass::Draw: Pre");
DrawBloomPassState state;
GLuint shaderHandle_horiz = m_GaussianProgram_horiz->GetHandle();
GLuint shaderHandle_vert = m_GaussianProgram_vert->GetHandle();
//Horizontal pass, first use the given texture then save it to the horizontal framebuffer.
m_GaussianFrameBuffer_horiz.Bind();
m_GaussianProgram_horiz->Bind();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glBindVertexArray(m_ScreenQuad->VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ScreenQuad->ElementBuffer);
glDrawElementsBaseVertex(GL_TRIANGLES, m_ScreenQuad->MaterialGroups()[0].EndIndex - m_ScreenQuad->MaterialGroups()[0].StartIndex +1
, GL_UNSIGNED_INT, 0, m_ScreenQuad->MaterialGroups()[0].StartIndex);
//Iterate some times to make it more gaussian.
for (int i = 1; i < m_iterations; i++) {
//Vertical pass
m_GaussianFrameBuffer_vert.Bind();
m_GaussianProgram_vert->Bind();
glBindTexture(GL_TEXTURE_2D, m_GaussianTexture_horiz);
glBindVertexArray(m_ScreenQuad->VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ScreenQuad->ElementBuffer);
glDrawElementsBaseVertex(GL_TRIANGLES, m_ScreenQuad->MaterialGroups()[0].EndIndex - m_ScreenQuad->MaterialGroups()[0].StartIndex +1
, GL_UNSIGNED_INT, 0, m_ScreenQuad->MaterialGroups()[0].StartIndex);
//horizontal pass
m_GaussianFrameBuffer_horiz.Bind();
m_GaussianProgram_horiz->Bind();
glBindTexture(GL_TEXTURE_2D, m_GaussianTexture_vert);
glBindVertexArray(m_ScreenQuad->VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ScreenQuad->ElementBuffer);
glDrawElementsBaseVertex(GL_TRIANGLES, m_ScreenQuad->MaterialGroups()[0].EndIndex - m_ScreenQuad->MaterialGroups()[0].StartIndex +1
, GL_UNSIGNED_INT, 0, m_ScreenQuad->MaterialGroups()[0].StartIndex);
}
//final vertical gaussian after the iterations are done
m_GaussianFrameBuffer_vert.Bind();
m_GaussianProgram_vert->Bind();
glBindTexture(GL_TEXTURE_2D, m_GaussianTexture_horiz);
glBindVertexArray(m_ScreenQuad->VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ScreenQuad->ElementBuffer);
glDrawElementsBaseVertex(GL_TRIANGLES, m_ScreenQuad->MaterialGroups()[0].EndIndex - m_ScreenQuad->MaterialGroups()[0].StartIndex +1
, GL_UNSIGNED_INT, 0, m_ScreenQuad->MaterialGroups()[0].StartIndex);
GLERROR("DrawBloomPass::Draw: END");
}
void DrawBloomPass::GenerateTexture(GLuint* texture, GLenum wrapping, GLenum filtering, glm::vec2 dimensions, GLint internalFormat, GLint format, GLenum type) const
{
glGenTextures(1, texture);
glBindTexture(GL_TEXTURE_2D, *texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapping);
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, nullptr);//TODO: Renderer: Fix the precision and Resolution
GLERROR("Texture initialization failed");
}
@@ -0,0 +1,15 @@
#include "Rendering/DrawBloomPassState.h"
DrawBloomPassState::DrawBloomPassState()
{
//BindFramebuffer(0);
Disable(GL_BLEND);
Disable(GL_DEPTH_TEST);
Disable(GL_CULL_FACE);
}
DrawBloomPassState::~DrawBloomPassState()
{
}
@@ -0,0 +1,41 @@
#include "Rendering/DrawColorCorrectionPass.h"
DrawColorCorrectionPass::DrawColorCorrectionPass(IRenderer* renderer)
{
m_Renderer = renderer;
m_ScreenQuad = ResourceManager::Load<Model>("Models/Core/ScreenQuad.obj");
m_Exposure = 1; //TODO: Renderer: Fixa så att denna går att ändra på genom komponent eller setting.
InitializeShaderPrograms();
}
void DrawColorCorrectionPass::InitializeShaderPrograms()
{
m_ColorCorrectionProgram = ResourceManager::Load<ShaderProgram>("#ColorCorrectionProgram");
m_ColorCorrectionProgram->AddShader(std::shared_ptr<Shader>(new VertexShader("Shaders/DrawColorCorrection.vert.glsl")));
m_ColorCorrectionProgram->AddShader(std::shared_ptr<Shader>(new FragmentShader("Shaders/DrawColorCorrection.frag.glsl")));
m_ColorCorrectionProgram->Compile();
m_ColorCorrectionProgram->Link();
}
void DrawColorCorrectionPass::Draw(GLuint sceneTexture, GLuint bloomTexture)
{
//glBindFramebuffer(GL_FRAMEBUFFER, 0);
GLERROR("DrawScreenQuadPass::Draw: Pre");
DrawScreenQuadPassState state = DrawScreenQuadPassState();
m_ColorCorrectionProgram->Bind();
glClear(GL_COLOR_BUFFER_BIT);
glUniform1f(glGetUniformLocation(m_ColorCorrectionProgram->GetHandle(), "Exposure"), m_Exposure);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, sceneTexture);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, bloomTexture);
glBindVertexArray(m_ScreenQuad->VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ScreenQuad->ElementBuffer);
glDrawElementsBaseVertex(GL_TRIANGLES, m_ScreenQuad->MaterialGroups()[0].EndIndex - m_ScreenQuad->MaterialGroups()[0].StartIndex +1
, GL_UNSIGNED_INT, 0, m_ScreenQuad->MaterialGroups()[0].StartIndex);
}
+75 -5
View File
@@ -6,11 +6,31 @@ DrawFinalPass::DrawFinalPass(IRenderer* renderer, LightCullingPass* lightCulling
m_LightCullingPass = lightCullingPass;
InitializeTextures();
InitializeShaderPrograms();
InitializeFrameBuffers();
}
void DrawFinalPass::InitializeTextures()
{
m_WhiteTexture = ResourceManager::Load<Texture>("Textures/Core/Blank.png");
m_BlackTexture = ResourceManager::Load<Texture>("Textures/Core/Black.png");
}
void DrawFinalPass::InitializeFrameBuffers()
{
glGenRenderbuffers(1, &m_DepthBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, m_DepthBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, m_Renderer->Resolution().Width, m_Renderer->Resolution().Height);
GenerateTexture(&m_SceneTexture, GL_CLAMP_TO_EDGE, GL_LINEAR, glm::vec2(m_Renderer->Resolution().Width, m_Renderer->Resolution().Height), GL_RGB16F, GL_RGB, GL_FLOAT);
//GenerateTexture(&m_BloomTexture, GL_CLAMP_TO_EDGE, GL_LINEAR, glm::vec2(m_Renderer->Resolution().Width, m_Renderer->Resolution().Height), GL_RGB16F, GL_RGB, GL_FLOAT);
GenerateTexture(&m_BloomTexture, GL_CLAMP_TO_EDGE, GL_LINEAR, glm::vec2(m_Renderer->Resolution().Width, m_Renderer->Resolution().Height), GL_RGB16F, GL_RGB, GL_FLOAT);
//GenerateMipMapTexture(&m_BloomTexture, GL_CLAMP_TO_EDGE, glm::vec2(m_Renderer->Resolution().Width, m_Renderer->Resolution().Height), GL_RGB16F, GL_FLOAT, 4);
m_FinalPassFrameBuffer.AddResource(std::shared_ptr<BufferResource>(new RenderBuffer(&m_DepthBuffer, GL_DEPTH_ATTACHMENT)));
m_FinalPassFrameBuffer.AddResource(std::shared_ptr<BufferResource>(new Texture2D(&m_SceneTexture, GL_COLOR_ATTACHMENT0)));
m_FinalPassFrameBuffer.AddResource(std::shared_ptr<BufferResource>(new Texture2D(&m_BloomTexture, GL_COLOR_ATTACHMENT1)));
m_FinalPassFrameBuffer.Generate();
}
void DrawFinalPass::InitializeShaderPrograms()
@@ -19,6 +39,8 @@ void DrawFinalPass::InitializeShaderPrograms()
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->BindFragDataLocation(0, "sceneColor");
m_ForwardPlusProgram->BindFragDataLocation(1, "bloomColor");
m_ForwardPlusProgram->Link();
}
static double tempTime = 0.0;
@@ -26,16 +48,21 @@ void DrawFinalPass::Draw(RenderScene& scene)
{
GLERROR("DrawFinalPass::Draw: Pre");
DrawFinalPassState state;
DrawFinalPassState* state = new DrawFinalPassState(m_FinalPassFrameBuffer.GetHandle());
m_ForwardPlusProgram->Bind();
GLuint shaderHandle = m_ForwardPlusProgram->GetHandle();
if (scene.ClearDepth) {
glClear(GL_DEPTH_BUFFER_BIT);
}
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()));
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "V"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ViewMatrix()));
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "P"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ProjectionMatrix()));
glUniform2f(glGetUniformLocation(shaderHandle, "ScreenDimensions"), m_Renderer->Resolution().Width, m_Renderer->Resolution().Height);
//TODO: Render: Add code for more jobs than modeljobs.
@@ -47,11 +74,10 @@ void DrawFinalPass::Draw(RenderScene& scene)
glUniform4fv(glGetUniformLocation(shaderHandle, "Color"), 1, glm::value_ptr(modelJob->Color));
glUniform4fv(glGetUniformLocation(shaderHandle, "DiffuseColor"), 1, glm::value_ptr(modelJob->DiffuseColor));
glActiveTexture(GL_TEXTURE0);
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);
}
tempTime += 0.01f;
@@ -62,6 +88,14 @@ void DrawFinalPass::Draw(RenderScene& scene)
std::vector<glm::mat4> frameBones = modelJob->Model->m_RawModel->m_Skeleton->GetFrameBones(
*animation,
tempTime
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, m_BlackTexture->m_Texture);
/*if(modelJob->GlowMap != nullptr) {
glBindTexture(GL_TEXTURE_2D, modelJob->GlowMap->m_Texture);
} else {
glBindTexture(GL_TEXTURE_2D, m_BlackTexture->m_Texture);
}*/
);
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0]));
}
@@ -72,6 +106,42 @@ void DrawFinalPass::Draw(RenderScene& scene)
glDrawElements(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, (void*)(modelJob->StartIndex * sizeof(unsigned int)));
}
}
m_FinalPassFrameBuffer.Unbind();
GLERROR("DrawFinalPass::Draw: END");
delete state;
}
void DrawFinalPass::ClearBuffer()
{
m_FinalPassFrameBuffer.Bind();
glClearColor(0.f, 0.f, 0.f, 0.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
m_FinalPassFrameBuffer.Unbind();
}
void DrawFinalPass::GenerateTexture(GLuint* texture, GLenum wrapping, GLenum filtering, glm::vec2 dimensions, GLint internalFormat, GLint format, GLenum type) const
{
glGenTextures(1, texture);
glBindTexture(GL_TEXTURE_2D, *texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapping);
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, nullptr);//TODO: Renderer: Fix the precision and Resolution
GLERROR("Texture initialization failed");
}
void DrawFinalPass::GenerateMipMapTexture(GLuint* texture, GLenum wrapping, glm::vec2 dimensions, GLint format, GLenum type, GLint numMipMaps) const
{
glGenTextures(1, texture);
glBindTexture(GL_TEXTURE_2D, *texture);
glTexStorage2D(GL_TEXTURE_2D, numMipMaps, GL_RGBA8, dimensions.x, dimensions.y);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, dimensions.x, dimensions.y, format, type, texture);
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapping);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapping);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
GLERROR("MipMap Texture initialization failed");
}
+3 -4
View File
@@ -1,15 +1,14 @@
#include "Rendering/DrawFinalPassState.h"
DrawFinalPassState::DrawFinalPassState()
DrawFinalPassState::DrawFinalPassState(GLuint frameBuffer)
{
BindFramebuffer(0);
BindFramebuffer(frameBuffer);
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);
ClearColor(glm::vec4(0.f, 0.f, 0.f, 0.f));
}
DrawFinalPassState::~DrawFinalPassState()
-62
View File
@@ -1,62 +0,0 @@
#include "Rendering/DrawScenePass.h"
DrawScenePass::DrawScenePass(IRenderer* renderer)
{
m_Renderer = renderer;
InitializeTextures();
InitializeShaderPrograms();
}
void DrawScenePass::InitializeTextures()
{
m_WhiteTexture = ResourceManager::Load<Texture>("Textures/Core/Blank.png");
}
void DrawScenePass::InitializeShaderPrograms()
{
m_BasicForwardProgram = ResourceManager::Load<ShaderProgram>("#BasicForwardProgram");
m_BasicForwardProgram->AddShader(std::shared_ptr<Shader>(new VertexShader("Shaders/BasicForward.vert.glsl")));
m_BasicForwardProgram->AddShader(std::shared_ptr<Shader>(new FragmentShader("Shaders/BasicForward.frag.glsl")));
m_BasicForwardProgram->Compile();
m_BasicForwardProgram->Link();
}
void DrawScenePass::Draw(RenderScene& scene)
{
//glBindFramebuffer(GL_FRAMEBUFFER, 0);
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();
//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()));
glUniformMatrix4fv(glGetUniformLocation(ShaderHandle, "P"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ProjectionMatrix()));
glUniform4fv(glGetUniformLocation(ShaderHandle, "Color"), 1, glm::value_ptr(modelJob->Color));
//TODO: Renderer: bättre textur felhantering samt fler texturer stöd
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("DrawScenePass::Draw: End");
}
@@ -1,20 +0,0 @@
#include "Rendering/DrawScenePassState.h"
DrawScenePassState::DrawScenePassState()
{
GLERROR("---");
BindFramebuffer(0);
GLERROR("---");
Enable(GL_DEPTH_TEST);
Enable(GL_CULL_FACE);
Enable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// ClearColor(glm::vec4(255.f / 255, 163.f / 255, 176.f / 255, 0.f));
// Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
DrawScenePassState::~DrawScenePassState()
{
}
@@ -0,0 +1,37 @@
#include "Rendering/DrawScreenQuadPass.h"
DrawScreenQuadPass::DrawScreenQuadPass(IRenderer* renderer)
{
m_Renderer = renderer;
m_ScreenQuad = ResourceManager::Load<Model>("Models/Core/ScreenQuad.obj");
InitializeShaderPrograms();
}
void DrawScreenQuadPass::InitializeShaderPrograms()
{
m_DrawQuadProgram = ResourceManager::Load<ShaderProgram>("#DrawScreenQuadProgram");
m_DrawQuadProgram->AddShader(std::shared_ptr<Shader>(new VertexShader("Shaders/DrawScreenQuad.vert.glsl")));
m_DrawQuadProgram->AddShader(std::shared_ptr<Shader>(new FragmentShader("Shaders/DrawScreenQuad.frag.glsl")));
m_DrawQuadProgram->Compile();
m_DrawQuadProgram->Link();
}
void DrawScreenQuadPass::Draw(GLuint texture)
{
//glBindFramebuffer(GL_FRAMEBUFFER, 0);
GLERROR("DrawScreenQuadPass::Draw: Pre");
DrawScreenQuadPassState state = DrawScreenQuadPassState();
m_DrawQuadProgram->Bind();
glClear(GL_COLOR_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glBindVertexArray(m_ScreenQuad->VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ScreenQuad->ElementBuffer);
glDrawElementsBaseVertex(GL_TRIANGLES, m_ScreenQuad->MaterialGroups()[0].EndIndex - m_ScreenQuad->MaterialGroups()[0].StartIndex +1
, GL_UNSIGNED_INT, 0, m_ScreenQuad->MaterialGroups()[0].StartIndex);
}
@@ -0,0 +1,18 @@
#include "Rendering/DrawScreenQuadPassState.h"
DrawScreenQuadPassState::DrawScreenQuadPassState()
{
GLERROR("---");
BindFramebuffer(0);
GLERROR("---");
Disable(GL_DEPTH_TEST);
Disable(GL_CULL_FACE);
Disable(GL_BLEND);
ClearColor(glm::vec4(0.f));
}
DrawScreenQuadPassState::~DrawScreenQuadPassState()
{
}
+108
View File
@@ -0,0 +1,108 @@
#include "Rendering/Font.h"
Font::Font(std::string path)
{
typedef boost::tokenizer<boost::char_separator<char>> tokenizer;
boost::char_separator<char> sep(",");
tokenizer tok(path, sep);
tokenizer::iterator it = tok.begin();
std::string filePath = "";
if (it != tok.end()) {
filePath = (*it).c_str();
it++;
if (it != tok.end()) {
if((*it).c_str() == "") {
throw std::runtime_error("");
}
try {
FontSize = boost::lexical_cast<int>((*it).c_str());
} catch (boost::bad_lexical_cast const&) {
LOG_ERROR("input string did not have a valid font resolution");
throw std::runtime_error("");
}
}
} else {
throw std::runtime_error("");;
}
FT_Library library;
FT_Face face;
if (FT_Init_FreeType(&library)) {
LOG_ERROR("FreeType error: init failed");
throw std::runtime_error("");;
}
if (FT_New_Face(library, filePath.c_str(), 0, &face)) {
LOG_ERROR("FreeType error: loading font");
throw std::runtime_error("");;
}
FT_Set_Char_Size(face, 0, FontSize*64, 300, 300); // temp
FT_Set_Pixel_Sizes(face, 0, FontSize); //
if (FT_Load_Char(face, 'X', FT_LOAD_RENDER)) {
LOG_ERROR("FreeType error: loading char");
throw std::runtime_error("");;
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
for (GLubyte c = 0; c < 128; c++) {
//Load character glyph
if (FT_Load_Char(face, c, FT_LOAD_RENDER)) {
continue;
}
//Generate texture
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RED,
face->glyph->bitmap.width,
face->glyph->bitmap.rows,
0,
GL_RED,
GL_UNSIGNED_BYTE,
face->glyph->bitmap.buffer
);
// Set texture options
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Now store character for later use
Character character = {
texture,
glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows),
glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top),
face->glyph->advance.x
};
m_Characters.insert(std::pair<GLchar, Character>(c, character));
}
FT_Done_Face(face);
FT_Done_FreeType(library);
GLERROR("Font Load");
}
Font::~Font()
{
for (auto c : m_Characters) {
glDeleteTextures(1, &c.second.TextureID);
}
}
+3 -4
View File
@@ -55,8 +55,9 @@ void FrameBuffer::Generate()
glFramebufferRenderbuffer(GL_FRAMEBUFFER, (*it)->m_Attachment, (*it)->m_ResourceType, *(*it)->m_ResourceHandle);
GLERROR("FrameBuffer generate: glFramebufferRenderbuffer");
if ( (*it)->m_Attachment != GL_COLOR_ATTACHMENT0 ||
(*it)->m_Attachment != GL_COLOR_ATTACHMENT1 ||
(*it)->m_Attachment != GL_DEPTH_ATTACHMENT ||
(*it)->m_Attachment != GL_STENCIL_ATTACHMENT)
(*it)->m_Attachment != GL_STENCIL_ATTACHMENT) //TODO: Viktor: Fixa detta
{
LOG_ERROR("RenderBuffer Attachment not valid.");
}
@@ -69,10 +70,8 @@ void FrameBuffer::Generate()
}
}
GLenum* bufferTextures = &attachments[0];
glDrawBuffers(1, bufferTextures);
glDrawBuffers(attachments.size(), bufferTextures);
if (GLenum frameBufferStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
LOG_ERROR("FrameBuffer incomplete: 0x%x\n", frameBufferStatus);
+4 -4
View File
@@ -105,7 +105,7 @@ void ImGuiRenderPass::Draw()
if (pcmd->UserCallback) {
pcmd->UserCallback(cmd_list, pcmd);
} else {
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
glBindTexture(GL_TEXTURE_2D, (GLuint)pcmd->TextureId);
glScissor((int)pcmd->ClipRect.x, (int)(fb_height - pcmd->ClipRect.w), (int)(pcmd->ClipRect.z - pcmd->ClipRect.x), (int)(pcmd->ClipRect.w - pcmd->ClipRect.y));
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset);
}
@@ -190,7 +190,7 @@ bool ImGuiRenderPass::createDeviceObjects()
"{\n"
" Frag_UV = UV;\n"
" Frag_Color = Color;\n"
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
" gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n"
"}\n";
const GLchar* fragment_shader =
@@ -201,7 +201,7 @@ bool ImGuiRenderPass::createDeviceObjects()
"out vec4 Out_Color;\n"
"void main()\n"
"{\n"
" Out_Color = Frag_Color * texture( Texture, Frag_UV.st);\n"
" Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
"}\n";
g_ShaderHandle = glCreateProgram();
@@ -271,7 +271,7 @@ bool ImGuiRenderPass::createFontsTexture()
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
// Store our identifier
io.Fonts->TexID = (void *)(intptr_t)g_FontTexture;
io.Fonts->TexID = (void*)g_FontTexture;
// Restore state
glBindTexture(GL_TEXTURE_2D, last_texture);
+34 -37
View File
@@ -46,60 +46,57 @@ void PickingPass::InitializeShaderPrograms()
void PickingPass::Draw(RenderScene& scene)
{
PickingPassState* state = new PickingPassState(m_PickingBuffer.GetHandle());
//TODO: Render: Add code for more jobs than modeljobs.
GLuint ShaderHandle = m_PickingProgram->GetHandle();
m_PickingProgram->Bind();
if (scene.ClearDepth) {
glClear(GL_DEPTH_BUFFER_BIT);
}
m_Camera = scene.Camera;
m_Camera = scene.Camera;
for (auto &job : scene.ForwardJobs) {
auto modelJob = std::dynamic_pointer_cast<ModelJob>(job);
for (auto &job : scene.ForwardJobs) {
auto modelJob = std::dynamic_pointer_cast<ModelJob>(job);
if (modelJob) {
int pickColor[2] = { m_ColorCounter[0], m_ColorCounter[1] };
if (modelJob) {
int pickColor[2] = { m_ColorCounter[0], m_ColorCounter[1] };
PickingInfo pickInfo;
pickInfo.Entity = modelJob->Entity;
pickInfo.World = modelJob->World;
pickInfo.Camera = scene.Camera;
PickingInfo pickInfo;
pickInfo.Entity = modelJob->Entity;
pickInfo.World = modelJob->World;
pickInfo.Camera = scene.Camera;
auto color = m_EntityColors.find(std::make_tuple(pickInfo.Entity, pickInfo.World, pickInfo.Camera));
if (color != m_EntityColors.end()) {
pickColor[0] = color->second[0];
pickColor[1] = color->second[1];
auto color = m_EntityColors.find(std::make_tuple(pickInfo.Entity, pickInfo.World, pickInfo.Camera));
if (color != m_EntityColors.end()) {
pickColor[0] = color->second[0];
pickColor[1] = color->second[1];
} else {
m_EntityColors[std::make_tuple(pickInfo.Entity, pickInfo.World, pickInfo.Camera)] = glm::ivec2(pickColor[0], pickColor[1]);
if (m_ColorCounter[0] > 255) {
m_ColorCounter[0] = 0;
m_ColorCounter[1]++;
} else {
m_EntityColors[std::make_tuple(pickInfo.Entity, pickInfo.World, pickInfo.Camera)] = glm::ivec2(pickColor[0], pickColor[1]);
if (m_ColorCounter[0] > 255) {
m_ColorCounter[0] = 0;
m_ColorCounter[1]++;;
} else {
m_ColorCounter[0]++;;
}
m_ColorCounter[0]++;
}
m_PickingColorsToEntity[glm::ivec2(pickColor[0], pickColor[1])] = pickInfo;
glUniformMatrix4fv(glGetUniformLocation(ShaderHandle, "M"), 1, GL_FALSE, glm::value_ptr(modelJob->Matrix));
glUniformMatrix4fv(glGetUniformLocation(ShaderHandle, "V"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ViewMatrix()));
glUniformMatrix4fv(glGetUniformLocation(ShaderHandle, "P"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ProjectionMatrix()));
glUniform2fv(glGetUniformLocation(ShaderHandle, "PickingColor"), 1, glm::value_ptr(glm::vec2(pickColor[0], pickColor[1])));
glBindVertexArray(modelJob->Model->VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, modelJob->Model->ElementBuffer);
glDrawElementsBaseVertex(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, nullptr, modelJob->StartIndex);
}
m_PickingColorsToEntity[glm::ivec2(pickColor[0], pickColor[1])] = pickInfo;
glUniformMatrix4fv(glGetUniformLocation(ShaderHandle, "M"), 1, GL_FALSE, glm::value_ptr(modelJob->Matrix));
glUniformMatrix4fv(glGetUniformLocation(ShaderHandle, "V"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ViewMatrix()));
glUniformMatrix4fv(glGetUniformLocation(ShaderHandle, "P"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ProjectionMatrix()));
glUniform2fv(glGetUniformLocation(ShaderHandle, "PickingColor"), 1, glm::value_ptr(glm::vec2(pickColor[0], pickColor[1])));
glBindVertexArray(modelJob->Model->VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, modelJob->Model->ElementBuffer);
glDrawElementsBaseVertex(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, nullptr, modelJob->StartIndex);
}
}
m_PickingBuffer.Unbind();
GLERROR("PickingPass Error");
delete state;
}
@@ -8,6 +8,7 @@ PickingPassState::PickingPassState(GLuint frameBuffer)
GLERROR("---3");
Enable(GL_DEPTH_TEST);
Enable(GL_CULL_FACE);
Disable(GL_BLEND);
glm::vec4 clearColor = glm::vec4(0.f);
//ClearColor(clearColor);
+9 -6
View File
@@ -44,12 +44,6 @@ bool RenderState::ClearColor(glm::vec4 color)
return !GLERROR("RenderState::ClearColor");
}
bool RenderState::Clear(GLbitfield mask)
{
glClear(mask);
return !GLERROR("RenderState::Clear");
}
bool RenderState::BindFramebuffer(GLint framebuffer)
{
GLint originalRead;
@@ -91,6 +85,15 @@ bool RenderState::BlendFunc(GLenum sfactor, GLenum dfactor)
return !GLERROR("RenderState::BlendFunc");
}
bool RenderState::DepthMask(GLboolean flag)
{
GLboolean original;
glGetBooleanv(GL_DEPTH_WRITEMASK, &original);
m_ResetFunctions.push_back(std::bind(glDepthMask, original));
glDepthMask(flag);
return !GLERROR("RenderState::DepthMask");
}
RenderState::~RenderState()
{
for (auto& f : m_ResetFunctions) {
+63 -142
View File
@@ -1,7 +1,7 @@
#include "Rendering/RenderSystem.h"
RenderSystem::RenderSystem(EventBroker* eventBroker, const IRenderer* renderer, RenderFrame* renderFrame)
: System(eventBroker)
RenderSystem::RenderSystem(World* world, EventBroker* eventBroker, const IRenderer* renderer, RenderFrame* renderFrame)
: System(world, eventBroker)
, m_Renderer(renderer)
, m_RenderFrame(renderFrame)
{
@@ -9,74 +9,29 @@ RenderSystem::RenderSystem(EventBroker* eventBroker, const IRenderer* renderer,
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>(eventBroker, -1);
}
RenderSystem::~RenderSystem()
{
delete m_Camera;
delete m_DebugCameraInputController;
}
bool RenderSystem::OnSetCamera(const Events::SetCamera &event)
bool RenderSystem::OnSetCamera(Events::SetCamera& e)
{
auto cameras = m_World->GetComponents("Camera");
if (cameras != nullptr) {
for (auto it = cameras->begin(); it != cameras->end(); it++) {
if ((std::string)(*it)["Name"] == event.Name) {
switchCamera((*it).EntityID);
}
}
}
ComponentWrapper cTransform = e.CameraEntity["Transform"];
ComponentWrapper cCamera = e.CameraEntity["Camera"];
m_Camera->SetFOV((double)cCamera["FOV"]);
m_Camera->SetNearClip((double)cCamera["NearClip"]);
m_Camera->SetFarClip((double)cCamera["FarClip"]);
m_Camera->SetPosition(cTransform["Position"]);
m_Camera->SetOrientation(glm::quat((const glm::vec3&)cTransform["Orientation"]));
m_CurrentCamera = e.CameraEntity;
return true;
}
void RenderSystem::switchCamera(EntityID entity)
void RenderSystem::fillModels(std::list<std::shared_ptr<RenderJob>>& jobs)
{
if(m_World->HasComponent(entity, "Camera")) {
if (m_CurrentCamera != EntityID_Invalid) {
if (m_World->HasComponent(m_CurrentCamera, "Model")) {
m_World->GetComponent(m_CurrentCamera, "Model")["Visible"] = true;
}
if (m_World->HasComponent(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;
} else {
LOG_ERROR("Entity %i does not have a CameraComponent", entity);
m_SwitchCamera = false;
}
}
void RenderSystem::updateProjectionMatrix(ComponentWrapper& cameraComponent)
{
double fov = cameraComponent["FOV"];
double aspectRatio = (float)m_Renderer->Resolution().Width / m_Renderer->Resolution().Height;
double nearClip = cameraComponent["NearClip"];
double farClip = cameraComponent["FarClip"];
m_Camera->SetFOV(glm::radians(fov));
m_Camera->SetAspectRatio(aspectRatio);
m_Camera->SetNearClip(nearClip);
m_Camera->SetFarClip(farClip);
m_Camera->UpdateProjectionMatrix();
}
void RenderSystem::fillModels(std::list<std::shared_ptr<RenderJob>>& jobs, World* world)
{
auto models = world->GetComponents("Model");
auto models = m_World->GetComponents("Model");
if (models == nullptr) {
return;
}
@@ -113,18 +68,17 @@ void RenderSystem::fillModels(std::list<std::shared_ptr<RenderJob>>& jobs, World
}
}
glm::mat4 modelMatrix = Transform::ModelMatrix(modelComponent.EntityID, world);
glm::mat4 modelMatrix = Transform::ModelMatrix(modelComponent.EntityID, m_World);
for (auto matGroup : model->MaterialGroups()) {
std::shared_ptr<ModelJob> modelJob = std::shared_ptr<ModelJob>(new ModelJob(model, m_Camera, modelMatrix, matGroup, modelComponent, world));
std::shared_ptr<ModelJob> modelJob = std::shared_ptr<ModelJob>(new ModelJob(model, m_Camera, modelMatrix, matGroup, modelComponent, m_World));
jobs.push_back(modelJob);
}
}
}
void RenderSystem::fillPointLights(std::list<std::shared_ptr<RenderJob>>& jobs, World* world)
{
auto pointLights = world->GetComponents("PointLight");
auto pointLights = m_World->GetComponents("PointLight");
if (pointLights != nullptr) {
for (auto& pointlightC : *pointLights) {
bool visible = pointlightC["Visible"];
@@ -164,98 +118,65 @@ void RenderSystem::fillDirectionalLights(std::list<std::shared_ptr<RenderJob>>&
}
}
bool RenderSystem::OnInputCommand(const Events::InputCommand& e)
void RenderSystem::fillText(std::list<std::shared_ptr<RenderJob>>& jobs, World* world)
{
if (e.Command == "SwitchCamera" && e.Value > 0) {
m_SwitchCamera = true;
return true;
} else {
return false;
auto texts = world->GetComponents("Text");
if (texts == nullptr) {
return;
}
for (auto& textComponent : *texts) {
bool visible = textComponent["Visible"];
if (!visible) {
continue;
}
std::string resource = textComponent["Resource"];
if (resource.empty()) {
continue;
}
Font* font;
try {
font = ResourceManager::Load<Font>(resource);
} catch (const std::exception&) {
try {
font = ResourceManager::Load<Font>("Fonts/DroidSans.ttf,16");
} catch (const std::exception&) {
continue;
}
}
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);
}
}
void RenderSystem::Update(World* world, double dt)
bool RenderSystem::OnInputCommand(const Events::InputCommand& e)
{
return false;
}
void RenderSystem::Update(double dt)
{
m_World = world;
m_EventBroker->Process<RenderSystem>();
updateCamera(world, dt);
if (m_CurrentCamera) {
ComponentWrapper cameraTransform = m_CurrentCamera["Transform"];
m_Camera->SetPosition(cameraTransform["Position"]);
m_Camera->SetOrientation(glm::quat((const glm::vec3&)cameraTransform["Orientation"]));
}
//Only supports opaque geometry atm
m_RenderFrame->Clear();
RenderScene scene;
scene.Camera = m_Camera;
scene.Viewport = Rectangle(1280, 720);
fillModels(scene.ForwardJobs, world);
fillPointLights(scene.PointLightJobs, world);
fillDirectionalLights(scene.DirectionalLightJobs, world);
fillModels(scene.ForwardJobs);
fillPointLights(scene.PointLightJobs, m_World);
fillDirectionalLights(scene.DirectionalLightJobs, m_World);
fillText(scene.TextJobs, m_World);
m_RenderFrame->Add(scene);
}
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++;
if (it != cameras->end()) {
switchCamera((*it).EntityID);
} else {
switchCamera((*cameras->begin()).EntityID);
}
break;
}
}
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"]);
}
}
if (m_World->ValidEntity(m_CurrentCamera)) {
if (world->HasComponent(m_CurrentCamera, "Camera") && world->HasComponent(m_CurrentCamera, "Transform")) {
ComponentWrapper& cameraComponent = world->GetComponent(m_CurrentCamera, "Camera");
ComponentWrapper& cameraTransform = world->GetComponent(m_CurrentCamera, "Transform");
m_DebugCameraInputController->Update(dt);
(glm::vec3&)cameraTransform["Orientation"] = glm::eulerAngles(m_DebugCameraInputController->Orientation());
(glm::vec3&)cameraTransform["Position"] = m_DebugCameraInputController->Position();
glm::vec3 position = Transform::AbsolutePosition(world, m_CurrentCamera);
glm::quat orientation = Transform::AbsoluteOrientation(world, m_CurrentCamera);
m_Camera->SetPosition(position);
m_Camera->SetOrientation(orientation);
updateProjectionMatrix(cameraComponent);
}
} else {
m_Camera = m_Camera;
auto cameras = world->GetComponents("Camera");
if (cameras != nullptr) {
if (cameras->begin() != cameras->end()) {
ComponentWrapper& cameraC = *cameras->begin();
switchCamera(cameraC.EntityID);
ComponentWrapper& cameraComponent = world->GetComponent(m_CurrentCamera, "Camera");
ComponentWrapper& cameraTransform = world->GetComponent(m_CurrentCamera, "Transform");
m_DebugCameraInputController->SetOrientation(glm::quat((glm::vec3)cameraTransform["Orientation"]));
m_DebugCameraInputController->SetPosition(cameraTransform["Position"]);
}
}
}
m_Camera->UpdateViewMatrix();
}
+35 -43
View File
@@ -9,21 +9,15 @@ void Renderer::Initialize()
glfwSwapInterval(m_VSYNC);
InitializeShaders();
InitializeTextures();
m_TextPass = new TextPass();
m_TextPass->Initialize();
/* m_ScreenQuad = ResourceManager::Load<Model>("Models/Core/ScreenQuad.obj");
m_UnitQuad = ResourceManager::Load<Model>("Models/Core/UnitQuad.obj");
m_UnitSphere = ResourceManager::Load<Model>("Models/Core/UnitSphere.obj");*/
m_ImGuiRenderPass = new ImGuiRenderPass(this, m_EventBroker);
// Create default camera
m_DefaultCamera = new ::Camera((float)m_Resolution.Width / m_Resolution.Height, glm::radians(45.f), 0.01f, 5000.f);
m_DefaultCamera->SetPosition(glm::vec3(0, 0, 10));
if (m_Camera == nullptr) {
m_Camera = m_DefaultCamera;
}
}
void Renderer::InitializeWindow()
@@ -69,12 +63,6 @@ void Renderer::InitializeWindow()
void Renderer::InitializeShaders()
{
m_BasicForwardProgram = ResourceManager::Load<ShaderProgram>("#m_BasicForwardProgram");
m_DrawScreenQuadProgram = ResourceManager::Load<ShaderProgram>("#DrawScreenQuadProgram");
m_DrawScreenQuadProgram->AddShader(std::shared_ptr<Shader>(new VertexShader("Shaders/DrawScreenQuad.vert.glsl")));
m_DrawScreenQuadProgram->AddShader(std::shared_ptr<Shader>(new FragmentShader("Shaders/DrawScreenQuad.frag.glsl")));
m_DrawScreenQuadProgram->Compile();
m_DrawScreenQuadProgram->Link();
}
void Renderer::InputUpdate(double dt)
@@ -86,28 +74,51 @@ void Renderer::Update(double dt)
{
m_EventBroker->Process<Renderer>();
InputUpdate(dt);
m_TextPass->Update();
m_ImGuiRenderPass->Update(dt);
}
void Renderer::Draw(RenderFrame& frame)
{
glClearColor(255.f / 255, 163.f / 255, 176.f / 255, 0.f);
ImGui::Combo("Draw textures", &m_DebugTextureToDraw, "Final\0Scene\0Bloom\0Gaussian\0Picking");
//clear buffer 0
glClearColor(0.f, 0.f, 0.f, 0.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//Clear other buffers
m_PickingPass->ClearPicking();
m_DrawFinalPass->ClearBuffer();
m_DrawBloomPass->ClearBuffer();
for (auto scene : frame.RenderScenes){
m_Camera = scene->Camera; // remove renderer camera when Editor uses the render scene cameras.
SortRenderJobsByDepth(*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);
GLERROR("Renderer::Draw m_DrawScenePass->Draw");
m_TextPass->Draw(*scene, *m_DrawFinalPass->FinalPassFrameBuffer());
}
m_DrawBloomPass->Draw(m_DrawFinalPass->BloomTexture());
if(m_DebugTextureToDraw == 0) {
m_DrawColorCorrectionPass->Draw(m_DrawFinalPass->SceneTexture(), m_DrawBloomPass->GaussianTexture());
}
if (m_DebugTextureToDraw == 1) {
m_DrawScreenQuadPass->Draw(m_DrawFinalPass->SceneTexture());
}
if (m_DebugTextureToDraw == 2) {
m_DrawScreenQuadPass->Draw(m_DrawFinalPass->BloomTexture());
}
if (m_DebugTextureToDraw == 3) {
m_DrawScreenQuadPass->Draw(m_DrawBloomPass->GaussianTexture());
}
if (m_DebugTextureToDraw == 4) {
m_DrawScreenQuadPass->Draw(m_PickingPass->PickingTexture());
}
m_ImGuiRenderPass->Draw();
@@ -119,27 +130,6 @@ PickData Renderer::Pick(glm::vec2 screenCoord)
return m_PickingPass->Pick(screenCoord);
}
void Renderer::DrawScreenQuad(GLuint textureToDraw)
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glClearColor(0.f, 0.f, 0.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT);
m_DrawScreenQuadProgram->Bind();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureToDraw);
glBindVertexArray(m_ScreenQuad->VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ScreenQuad->ElementBuffer);
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");
@@ -167,8 +157,10 @@ void Renderer::GenerateTexture(GLuint* texture, GLenum wrapping, GLenum filterin
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);
}
m_DrawScreenQuadPass = new DrawScreenQuadPass(this);
m_DrawBloomPass = new DrawBloomPass(this);
m_DrawColorCorrectionPass = new DrawColorCorrectionPass(this);
}
+113
View File
@@ -0,0 +1,113 @@
#include "Rendering/TextPass.h"
TextPass::TextPass()
{
}
void TextPass::Initialize()
{
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 6 * 4, NULL, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
m_TextProgram = ResourceManager::Load<ShaderProgram>("#TextProgram");
m_TextProgram->AddShader(std::shared_ptr<Shader>(new VertexShader("Shaders/Text.vert.glsl")));
m_TextProgram->AddShader(std::shared_ptr<Shader>(new FragmentShader("Shaders/Text.frag.glsl")));
m_TextProgram->Compile();
m_TextProgram->BindFragDataLocation(0, "sceneColor");
m_TextProgram->BindFragDataLocation(1, "bloomColor");
m_TextProgram->Link();
}
void TextPass::Update()
{
}
void TextPass::Draw(RenderScene& scene, FrameBuffer& frameBuffer)
{
GLERROR("Derp1");
TextPassState* state = new TextPassState(frameBuffer.GetHandle());
for (auto &job : scene.TextJobs) {
auto textJob = std::dynamic_pointer_cast<TextJob>(job);
if (textJob) {
renderText(textJob->Content, textJob->Resource, textJob->Alignment, textJob->Color, textJob->Matrix, scene.Camera->ProjectionMatrix(), scene.Camera->ViewMatrix());
}
}
GLERROR("Derp2");
delete state;
}
void TextPass::renderText(std::string text, Font* font, TextJob::AlignmentEnum alignment, glm::vec4 color, glm::mat4 modelMatrix, glm::mat4 projectionMatrix, glm::mat4 viewMatrix)
{
GLfloat penX = 0;
GLfloat penY = 0;
GLfloat scale = 1.0/font->FontSize;
GLfloat stringWidth = 0.f;
for (std::string::const_iterator c = text.begin(); c != text.end(); c++) {
Font::Character ch = font->m_Characters[*c];
stringWidth += (ch.Advance >> 6) * scale;
}
if(alignment == TextJob::AlignmentEnum::Center) {
penX = -stringWidth/2.f;
} else if (alignment == TextJob::AlignmentEnum::Right) {
penX = -stringWidth;
} else {
penX = 0;
}
m_TextProgram->Bind();
glUniform4fv(glGetUniformLocation(m_TextProgram->GetHandle(), "textColor"), 1, glm::value_ptr(color));
glUniformMatrix4fv(glGetUniformLocation(m_TextProgram->GetHandle(), "M"), 1, GL_FALSE, glm::value_ptr(modelMatrix));
glUniformMatrix4fv(glGetUniformLocation(m_TextProgram->GetHandle(), "V"), 1, GL_FALSE, glm::value_ptr(viewMatrix));
glUniformMatrix4fv(glGetUniformLocation(m_TextProgram->GetHandle(), "P"), 1, GL_FALSE, glm::value_ptr(projectionMatrix));
glActiveTexture(GL_TEXTURE0);
glBindVertexArray(VAO);
for (std::string::const_iterator c = text.begin(); c != text.end(); c++) {
Font::Character ch = font->m_Characters[*c];
GLfloat xpos = penX + ch.Bearing.x * scale;
GLfloat ypos = penY - (ch.Size.y - ch.Bearing.y) * scale;
GLfloat w = ch.Size.x * scale;
GLfloat h = ch.Size.y * scale;
GLfloat vertices[6][4] = {
{ xpos, ypos + h, 0.0, 0.0 },
{ xpos, ypos, 0.0, 1.0 },
{ xpos + w, ypos, 1.0, 1.0 },
{ xpos, ypos + h, 0.0, 0.0 },
{ xpos + w, ypos, 1.0, 1.0 },
{ xpos + w, ypos + h, 1.0, 0.0 }
};
glBindTexture(GL_TEXTURE_2D, ch.TextureID);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDrawArrays(GL_TRIANGLES, 0, 6);
penX += (ch.Advance >> 6) * scale; // Bitshift by 6 to get value in pixels (2^6 = 64)
}
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
GLERROR("Text rendering Error");
}
+16
View File
@@ -0,0 +1,16 @@
#include "Rendering/TextPassState.h"
TextPassState::TextPassState(GLuint frameBuffer)
{
BindFramebuffer(frameBuffer);
glEnable(GL_BLEND);
glDisable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
TextPassState::~TextPassState()
{
}
@@ -0,0 +1,2 @@
#include "Rendering/Util/CommonFunctions.h"