Merge branch 'master' into Importer

# Conflicts:
#	src/Engine/Collision/Collision.cpp
#	src/Engine/Collision/CollisionSystem.cpp
#	src/Engine/Rendering/DrawFinalPass.cpp
#	src/Game/Systems/SpawnerSystem.cpp
This commit is contained in:
William Moberg
2016-03-14 00:42:07 +01:00
447 changed files with 112716 additions and 6296 deletions
+68 -33
View File
@@ -155,9 +155,9 @@ bool RayVsModel(const Ray& ray,
}
for (int i = 0; i < modelIndices.size();) {
glm::vec3 v0 = Transform::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix);
glm::vec3 v1 = Transform::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix);
glm::vec3 v2 = Transform::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix);
glm::vec3 v0 = TransformSystem::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix);
glm::vec3 v1 = TransformSystem::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix);
glm::vec3 v2 = TransformSystem::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix);
if (RayVsTriangle(ray, v0, v1, v2)) {
return true;
}
@@ -212,9 +212,9 @@ bool RayVsModel(const Ray& ray,
outDistance = INFINITY;
bool hit = false;
for (int i = 0; i < modelIndices.size();) {
glm::vec3 v0 = Transform::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix);
glm::vec3 v1 = Transform::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix);
glm::vec3 v2 = Transform::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix);
glm::vec3 v0 = TransformSystem::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix);
glm::vec3 v1 = TransformSystem::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix);
glm::vec3 v2 = TransformSystem::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix);
float dist = outDistance;
float u;
float v;
@@ -372,7 +372,14 @@ constexpr bool FaceIsGround(float faceNormalY)
//An array containing 3 int pairs { 0, 2 }, { 0, 1 }, { 1, 2 }
constexpr std::array<std::pair<int, int>, 3> dimensionPairs({ std::pair<int, int>(0, 2), std::pair<int, int>(0, 1), std::pair<int, int>(1, 2) });
bool AABBvsTriangle(const AABB& box,
enum class BoxTriRes
{
Front,
Behind,
Intersect
};
BoxTriRes AABBvsTriangle(const AABB& box,
const std::array<glm::vec3, 3>& triPos,
const glm::vec3& originalBoxVelocity,
float verticalStepHeight,
@@ -386,7 +393,7 @@ bool AABBvsTriangle(const AABB& box,
//Less checks, and we should be able to walk out from models if we are trapped inside.
glm::vec3 triNormal = glm::cross(triPos[1] - triPos[0], triPos[2] - triPos[0]);
if (!vectorHasLength(triNormal) || (glm::dot(triNormal, originalBoxVelocity) > 0)) {
return false;
return BoxTriRes::Behind;
}
triNormal = glm::normalize(triNormal);
@@ -421,6 +428,9 @@ bool AABBvsTriangle(const AABB& box,
const glm::vec3& min = box.MinCorner();
const glm::vec3& max = box.MaxCorner();
// If there is no intersection, whether the box center is in front of or behind the triangle.
BoxTriRes noIntersection = glm::dot(triNormal, origin - triPos[0]) > 0 ? BoxTriRes::Front : BoxTriRes::Behind;
//For each projection in xy-, xz-, and yx-planes.
for (std::pair<int, int> dim : dimensionPairs) {
//2D Triangle.
@@ -438,7 +448,7 @@ bool AABBvsTriangle(const AABB& box,
bool pushedFromTriangleLine;
//if projections don't overlap, return false.
if (!rectangleVsTriangle(boxMin, boxMax, t2D, resolutionVector, resolutionDist, pushedFromTriangleLine)) {
return false;
return noIntersection;
} else if (resolveCollision) {
//Overwrite the smallest resolution if this is smaller.
if (resolutionDist < resolveShortest.DistanceSq) {
@@ -474,14 +484,15 @@ bool AABBvsTriangle(const AABB& box,
float t = glm::dot(triNormal, triPos[0] - origin) / glm::dot(triNormal, diagonal);
//If intersection point between plane and diagonal is within the box.
if (glm::abs(t) > 1) {
return false;
return noIntersection;
}
if (!resolveCollision) {
return true;
return BoxTriRes::Intersect;
}
glm::vec3 cornerResolution = (1+t) * diagonal;
cornerResolution = glm::dot(cornerResolution, triNormal) * triNormal;
//Overwrite the smallest resolution if cornerResolution is smaller.
float lenSq = glm::length2(cornerResolution);
if (lenSq < resolveShortest.DistanceSq) {
@@ -510,7 +521,7 @@ bool AABBvsTriangle(const AABB& box,
case ResolveDimZ:
//If we get here, the resolution is along one coordinate axis.
//set velocity to 0 in y if it is along y-axis.
return true;
return BoxTriRes::Intersect;
case Line:
projNorm = glm::normalize(outResolution);
break;
@@ -545,10 +556,10 @@ bool AABBvsTriangle(const AABB& box,
boxVelocity = boxVelocity - glm::dot(boxVelocity, projNorm) * projNorm;
}
}
return true;
return BoxTriRes::Intersect;
}
bool AABBvsTriangles(const AABB& box,
Output AABBvsTriangles(const AABB& box,
const RawModel::Vertex* modelVertices,
const std::vector<unsigned int>& modelIndices,
const glm::mat4& modelMatrix,
@@ -558,38 +569,44 @@ bool AABBvsTriangles(const AABB& box,
glm::vec3& outResolutionVector,
bool resolveCollision)
{
if (!modelVertices) {
return false;
}
bool hit = false;
if (!modelVertices) {
return false;
}
bool intersect = false;
Output out = Output::OutContained;
bool everHitTheGround = false;
AABB newBox = box;
outResolutionVector = glm::vec3(0.f);
glm::vec3 originalBoxVelocity(boxVelocity);
for (int i = 0; i < modelIndices.size(); ) {
std::array<glm::vec3, 3> triVertices = {
Transform::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix),
Transform::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix),
Transform::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix)
TransformSystem::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix),
TransformSystem::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix),
TransformSystem::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix)
};
glm::vec3 outVec;
bool collideWithGround = isOnGround;
if (AABBvsTriangle(newBox, triVertices, originalBoxVelocity, verticalStepHeight, collideWithGround, boxVelocity, outVec, resolveCollision)) {
hit = true;
switch (AABBvsTriangle(newBox, triVertices, originalBoxVelocity, verticalStepHeight, collideWithGround, boxVelocity, outVec, resolveCollision)) {
case Collision::BoxTriRes::Front:
out = Output::OutSeparated;
break;
case Collision::BoxTriRes::Intersect:
intersect = true;
outResolutionVector += outVec;
newBox = AABB::FromOriginSize(newBox.Origin() + outVec, newBox.Size());
if (collideWithGround) {
everHitTheGround = isOnGround = true;
}
break;
default:
break;
}
}
if (!everHitTheGround) {
isOnGround = false;
}
return hit;
return intersect ? Output::OutIntersecting : out;
}
bool AABBvsTriangles(const AABB& box,
@@ -609,13 +626,31 @@ bool AABBvsTriangles(const AABB& box,
verticalStepHeight,
isOnGround,
outResolutionVector,
true);
true) == Output::OutIntersecting;
}
bool AABBvsTriangles(const AABB& box,
const RawModel::Vertex* modelVertices,
const std::vector<unsigned int>& modelIndices,
const glm::mat4& modelMatrix)
{
glm::vec3 vel, outres;
bool g;
return AABBvsTriangles(box,
modelVertices,
modelIndices,
modelMatrix,
vel,
0.f,
g,
outres,
false) == Output::OutIntersecting;
}
Output AABBvsTrianglesWContainment(const AABB& box,
const RawModel::Vertex* modelVertices,
const std::vector<unsigned int>& modelIndices,
const glm::mat4& modelMatrix)
{
glm::vec3 vel, outres;
bool g;
@@ -635,9 +670,9 @@ boost::optional<EntityAABB> EntityAbsoluteAABB(EntityWrapper& entity, bool takeM
AABB modelSpaceBox;
if (entity.HasComponent("AABB") && !takeModelBox) {
ComponentWrapper& cAABB = entity["AABB"];
modelSpaceBox = EntityAABB::FromOriginSize((glm::vec3)cAABB["Origin"], (glm::vec3)cAABB["Size"]);
modelSpaceBox = EntityAABB::FromOriginSize((const glm::vec3&)cAABB["Origin"], (const glm::vec3&)cAABB["Size"]);
} else if (entity.HasComponent("Model")) {
std::string res = entity["Model"]["Resource"];
const std::string& res = entity["Model"]["Resource"];
if (res.empty()) {
return boost::none;
}
@@ -654,7 +689,7 @@ boost::optional<EntityAABB> EntityAbsoluteAABB(EntityWrapper& entity, bool takeM
return boost::none;
}
glm::mat4 modelMat = Transform::AbsoluteTransformation(entity);
glm::mat4 modelMat = TransformSystem::ModelMatrix(entity);
glm::vec3 mini(INFINITY);
glm::vec3 maxi(-INFINITY);
glm::vec3 maxCorner = modelSpaceBox.MaxCorner();
@@ -665,7 +700,7 @@ boost::optional<EntityAABB> EntityAbsoluteAABB(EntityWrapper& entity, bool takeM
corner.x = bits.test(0) ? maxCorner.x : minCorner.x;
corner.y = bits.test(1) ? maxCorner.y : minCorner.y;
corner.z = bits.test(2) ? maxCorner.z : minCorner.z;
corner = Transform::TransformPoint(corner, modelMat);
corner = TransformSystem::TransformPoint(corner, modelMat);
mini = glm::min(mini, corner);
maxi = glm::max(maxi, corner);
}
@@ -683,7 +718,7 @@ boost::optional<EntityAABB> AbsoluteAABBExplosionEffect(EntityWrapper& entity)
if (!modelBox) {
return boost::none;
}
bool isRandom = (bool)entity["ExplosionEffect"]["Randomness"];
Field<bool> isRandom = entity["ExplosionEffect"]["Randomness"];
float random = isRandom ? (float)(double)entity["ExplosionEffect"]["RandomnessScalar"] : 0;
glm::vec3 origin = (glm::vec3)entity["ExplosionEffect"]["ExplosionOrigin"];
glm::vec3 randomVel = (glm::vec3)entity["ExplosionEffect"]["Velocity"];
@@ -721,7 +756,7 @@ boost::optional<EntityAABB> EntityFirstHitByRay(const Ray& ray, std::vector<Enti
continue;
}
float u, v;
if (RayVsModel(ray, model->CollisionVertices(), model->CollisionIndices(), Transform::ModelMatrix(entityBox.Entity), outDistance, u, v)) {
if (RayVsModel(ray, model->CollisionVertices(), model->CollisionIndices(), TransformSystem::ModelMatrix(entityBox.Entity), outDistance, u, v)) {
outIntersectPos = ray.Origin() + outDistance * ray.Direction();
return entityBox;
}
+91 -82
View File
@@ -17,105 +17,114 @@ void CollisionSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& c
EntityAABB& boxA = *boundingBox;
bool everHitTheGround = false;
auto prevPosIt = m_PrevPositions.find(entity);
if (prevPosIt != m_PrevPositions.end()) {
glm::vec3 size = boxA.Size();
float diameter = std::min(size.x, size.z);
glm::vec3 prevOrigin = prevPosIt->second;
glm::vec3 toCurrentPos = boxA.Origin() - prevOrigin;
float rayLength = glm::length(toCurrentPos) + 0.5f*diameter;
//If the entity has moved farther than the size of its box, we need to handle it specially.
if (rayLength > diameter) {
Ray ray(prevOrigin, toCurrentPos);
m_OctreeResult.clear();
m_Octree->ObjectsPossiblyHitByRay(ray, m_OctreeResult);
for (auto& boxB : m_OctreeResult) {
if (boxA.Entity == boxB.Entity) {
continue;
}
bool hit;
float dist;
if (boxB.Entity.HasComponent("Model")) {
RawModel* model;
std::string res = (std::string)boxB.Entity["Model"]["Resource"];
try {
model = ResourceManager::Load<RawModel, true>(res);
} catch (const std::exception&) {
if (entity == LocalPlayer) {
auto prevPosIt = m_PrevPositions.find(entity);
if (prevPosIt != m_PrevPositions.end()) {
glm::vec3 size = boxA.Size();
float diameter = std::min(size.x, size.z);
glm::vec3 prevOrigin = prevPosIt->second;
glm::vec3 toCurrentPos = boxA.Origin() - prevOrigin;
float rayLength = glm::length(toCurrentPos) + 0.5f*diameter;
//If the entity has moved farther than the size of its box, we need to handle it specially.
if (rayLength > diameter) {
Ray ray(prevOrigin, toCurrentPos);
m_OctreeResult.clear();
m_Octree->ObjectsPossiblyHitByRay(ray, m_OctreeResult);
for (auto& boxB : m_OctreeResult) {
if (boxA.Entity == boxB.Entity) {
continue;
}
float u, v;
hit = Collision::RayVsModel(ray, model->CollisionVertices(), model->CollisionIndices(), Transform::ModelMatrix(boxB.Entity), dist, u, v);
} else {
hit = Collision::RayVsAABB(ray, boxB, dist);
}
if (hit && dist < rayLength) {
//Set the entity to where it was colliding, minus the maximum box size.
//TODO: Perhaps this should be done slightly more properly.
glm::vec3 newOriginPos = ray.Origin() + (dist - 0.707107f*diameter) * ray.Direction();
glm::vec3 resolve = newOriginPos - boxA.Origin();
(glm::vec3&)cTransform["Position"] += resolve;
boxA = *Collision::EntityAbsoluteAABB(entity);
if (resolve.y > 0) {
everHitTheGround = true;
(bool)cPhysics["IsOnGround"] = true;
((glm::vec3&)cPhysics["Velocity"]).y = 0.f;
bool hit;
float dist;
if (boxB.Entity.HasComponent("Model")) {
if (!((bool)boxB.Entity["Model"]["Visible"])) {
// Don't collide against invisible models.
continue;
}
RawModel* model;
std::string res = (std::string)boxB.Entity["Model"]["Resource"];
try {
model = ResourceManager::Load<RawModel, true>(res);
} catch (const std::exception&) {
continue;
}
float u, v;
hit = Collision::RayVsModel(ray, model->CollisionVertices(), model->CollisionIndices(), TransformSystem::ModelMatrix(boxB.Entity), dist, u, v);
} else {
hit = Collision::RayVsAABB(ray, boxB, dist);
}
if (hit && dist < rayLength) {
//Set the entity to where it was colliding, minus the maximum box size.
//TODO: Perhaps this should be done slightly more properly.
glm::vec3 newOriginPos = ray.Origin() + (dist - 0.707107f*diameter) * ray.Direction();
glm::vec3 resolve = newOriginPos - boxA.Origin();
(Field<glm::vec3>)cTransform["Position"] += resolve;
boxA = *Collision::EntityAbsoluteAABB(entity);
if (resolve.y > 0) {
everHitTheGround = true;
cPhysics["IsOnGround"] = true;
((Field<glm::vec3>)cPhysics["Velocity"]).y(0.f);
}
break;
}
break;
}
}
}
}
// Collide against octree items
m_OctreeResult.clear();
m_Octree->ObjectsInSameRegion(*boundingBox, m_OctreeResult);
for (auto& boxB : m_OctreeResult) {
glm::vec3 resolutionVector;
if (boxA.Entity == boxB.Entity) {
continue;
}
if (boxB.Entity.HasComponent("Model") && Collision::AABBVsAABB(boxA, boxB)) {
//Here we know boxB is a entity with Collideable, AABB, and Model.
RawModel* model;
try {
model = ResourceManager::Load<RawModel, true>(boxB.Entity["Model"]["Resource"]);
} catch (const std::exception&) {
// Collide against octree items
m_OctreeResult.clear();
m_Octree->ObjectsInSameRegion(*boundingBox, m_OctreeResult);
for (auto& boxB : m_OctreeResult) {
glm::vec3 resolutionVector;
if (boxA.Entity == boxB.Entity) {
continue;
}
glm::mat4 modelMatrix = Transform::ModelMatrix(boxB.Entity);
if (boxB.Entity.HasComponent("Model") && Collision::AABBVsAABB(boxA, boxB)) {
// Here we know boxB is a entity with Collideable, AABB, and Model.
if (!((const bool&)boxB.Entity["Model"]["Visible"])) {
// Don't collide against invisible models.
continue;
}
RawModel* model;
try {
model = ResourceManager::Load<RawModel, true>(boxB.Entity["Model"]["Resource"]);
} catch (const std::exception&) {
continue;
}
glm::vec3 inOutVelocity = (glm::vec3)cPhysics["Velocity"];
bool notMovingxz = glm::all(glm::lessThan(glm::abs(glm::vec2(inOutVelocity.x, inOutVelocity.z)), glm::vec2(0.01f))) && prevPosIt != m_PrevPositions.end();
bool isOnGround = (bool)cPhysics["IsOnGround"];
float verticalStepHeight = (float)(double)cPhysics["VerticalStepHeight"];
if (Collision::AABBvsTriangles(boxA, model->CollisionVertices(), model->CollisionIndices(), modelMatrix, inOutVelocity, verticalStepHeight, isOnGround, resolutionVector)) {
//Move the position to previous position if it is not moving in the xz-plane, else resolve with the resolution vector.
(glm::vec3&)cTransform["Position"] += notMovingxz ? prevPosIt->second - boxA.Origin() : resolutionVector;
glm::mat4 modelMatrix = TransformSystem::ModelMatrix(boxB.Entity);
glm::vec3 inOutVelocity = (glm::vec3)cPhysics["Velocity"];
bool isOnGround = (bool)cPhysics["IsOnGround"];
float verticalStepHeight = (float)(double)cPhysics["VerticalStepHeight"];
if (Collision::AABBvsTriangles(boxA, model->CollisionVertices(), model->CollisionIndices(), modelMatrix, inOutVelocity, verticalStepHeight, isOnGround, resolutionVector)) {
//Move the position to previous position if it is not moving in the xz-plane, else resolve with the resolution vector.
(Field<glm::vec3>)cTransform["Position"] += resolutionVector;
boxA = *Collision::EntityAbsoluteAABB(entity);
cPhysics["Velocity"] = inOutVelocity;
if (isOnGround) {
everHitTheGround = true;
(bool)cPhysics["IsOnGround"] = true;
}
}
} else if (Collision::AABBVsAABB(boxA, boxB, resolutionVector)) {
//Enter here if boxB has no Model.
(Field<glm::vec3>)cTransform["Position"] += resolutionVector;
boxA = *Collision::EntityAbsoluteAABB(entity);
cPhysics["Velocity"] = inOutVelocity;
if (isOnGround) {
if (resolutionVector.y > 0) {
everHitTheGround = true;
(bool)cPhysics["IsOnGround"] = true;
((Field<glm::vec3>)cPhysics["Velocity"]).y(0.f);
}
}
} else if (Collision::AABBVsAABB(boxA, boxB, resolutionVector)) {
//Enter here if boxB has no Model.
(glm::vec3&)cTransform["Position"] += resolutionVector;
boxA = *Collision::EntityAbsoluteAABB(entity);
if (resolutionVector.y > 0) {
everHitTheGround = true;
(bool)cPhysics["IsOnGround"] = true;
((glm::vec3&)cPhysics["Velocity"]).y = 0.f;
}
}
}
//This should apply air friction and such, iff zero models were hit.
if (!everHitTheGround) {
(bool)cPhysics["IsOnGround"] = false;
}
//This should apply air friction and such, iff zero models were hit.
if (!everHitTheGround) {
(bool)cPhysics["IsOnGround"] = false;
}
m_PrevPositions[entity] = boxA.Origin();
m_PrevPositions[entity] = boxA.Origin();
}
}
+31 -10
View File
@@ -10,6 +10,16 @@ void TriggerSystem::UpdateComponent(EntityWrapper& triggerEntity, ComponentWrapp
return;
}
RawModel* triggerModel = nullptr;
glm::mat4 triggerModelMat;
if (triggerEntity.HasComponent("Model")) {
try {
triggerModel = ResourceManager::Load<RawModel, true>(triggerEntity["Model"]["Resource"]);
triggerModelMat = TransformSystem::ModelMatrix(triggerEntity);
} catch (const std::exception&) {
}
}
m_OctreeOut.clear();
m_Octree->ObjectsInSameRegion(*triggerBox, m_OctreeOut);
@@ -22,7 +32,17 @@ void TriggerSystem::UpdateComponent(EntityWrapper& triggerEntity, ComponentWrapp
if (colliderFitsInTrigger) {
completelyInsideBox = AABB::FromOriginSize((*triggerBox).Origin(), (*triggerBox).Size() - 2.0f * colliderBox.Size());
}
if (colliderFitsInTrigger && Collision::AABBVsAABB(completelyInsideBox, colliderBox)) {
// We know the entity is inside the trigger box, but perhaps not the model yet.
Collision::Output out = triggerModel == nullptr
? Collision::Output::OutContained
: Collision::AABBvsTrianglesWContainment(
colliderBox,
triggerModel->Vertices(),
triggerModel->m_Indices,
triggerModelMat);
if (colliderFitsInTrigger && Collision::AABBVsAABB(completelyInsideBox, colliderBox) && out == Collision::Output::OutContained) {
// Entity is completely inside the trigger.
// If it was only touching before, it is erased.
m_EntitiesTouchingTrigger[triggerEntity].erase(colliderEntity);
@@ -32,7 +52,8 @@ void TriggerSystem::UpdateComponent(EntityWrapper& triggerEntity, ComponentWrapp
completeSet.insert(colliderEntity);
publish<Events::TriggerEnter>(colliderEntity, triggerEntity);
}
} else {
continue;
} else if (out != Collision::Output::OutSeparated) {
// Entity is only touching the trigger.
auto& touchSet = m_EntitiesTouchingTrigger[triggerEntity];
auto& completeSet = m_EntitiesCompletelyInTrigger[triggerEntity];
@@ -47,17 +68,17 @@ void TriggerSystem::UpdateComponent(EntityWrapper& triggerEntity, ComponentWrapp
touchSet.insert(colliderEntity);
}
// Else, it was touching the trigger last frame too and nothing is done.
}
} else {
// Entity is not touching the trigger,
// Throw event if it was previously.
if (throwLeaveIfWasInTrigger(m_EntitiesTouchingTrigger[triggerEntity], colliderEntity, triggerEntity)) {
continue;
}
// This only occurs if the entity was completely inside the trigger one frame,
// then completely outside the trigger, e.g. when dying and respawning.
throwLeaveIfWasInTrigger(m_EntitiesCompletelyInTrigger[triggerEntity], colliderEntity, triggerEntity);
}
// Only get here if entity is not touching the trigger,
// throw event if it was touching previously.
if (throwLeaveIfWasInTrigger(m_EntitiesTouchingTrigger[triggerEntity], colliderEntity, triggerEntity)) {
continue;
}
// This only occurs if the entity was completely inside the trigger one frame,
// then completely outside the trigger, e.g. when dying and respawning.
throwLeaveIfWasInTrigger(m_EntitiesCompletelyInTrigger[triggerEntity], colliderEntity, triggerEntity);
}
}
+19 -8
View File
@@ -1,9 +1,17 @@
#include "Core/ComponentPool.h"
ComponentPoolForwardIterator::ComponentPoolForwardIterator(ComponentPool* pool, const MemoryPool<char>::iterator begin, const MemoryPool<char>::iterator end)
: m_ComponentPool(pool)
, m_ComponentInfo(pool->m_ComponentInfo)
, m_MemoryPoolIterator(begin)
, m_MemoryPoolEnd(end)
{ }
ComponentWrapper ComponentPoolForwardIterator::operator*() const
{
char* data = &(*m_MemoryPoolIterator);
ComponentWrapper wrapper(m_ComponentInfo, data);
EntityID entity = *reinterpret_cast<EntityID*>(data);
ComponentWrapper wrapper(m_ComponentInfo, data, &m_ComponentPool->m_DirtySet[entity], m_ComponentPool->m_World);
return wrapper;
}
@@ -44,7 +52,7 @@ ComponentPool::ComponentPool(const ComponentPool& other)
// Duplicate strings
for (auto& name : m_ComponentInfo.StringFields) {
for (auto& c : *this) {
std::string& val = c[name];
Field<std::string> val = c[name];
ComponentWrapper::SolidifyStrings(c);
}
}
@@ -71,7 +79,7 @@ ComponentWrapper ComponentPool::Allocate(EntityID entity)
memcpy(data, &entity, sizeof(EntityID));
m_EntityToComponent[entity] = data;
ComponentWrapper component(m_ComponentInfo, data);
ComponentWrapper component(m_ComponentInfo, data, &m_DirtySet[entity], m_World);
// Copy defaults
memcpy(component.Data, m_ComponentInfo.Defaults.get(), m_ComponentInfo.Stride);
@@ -82,7 +90,9 @@ ComponentWrapper ComponentPool::Allocate(EntityID entity)
ComponentWrapper ComponentPool::GetByEntity(EntityID ent)
{
return ComponentWrapper(m_ComponentInfo, m_EntityToComponent.at(ent));
auto data = m_EntityToComponent.at(ent);
auto bitField = &m_DirtySet[ent];
return ComponentWrapper(m_ComponentInfo, data, bitField, m_World);
}
bool ComponentPool::KnowsEntity(EntityID ent)
@@ -95,16 +105,17 @@ void ComponentPool::Delete(ComponentWrapper& wrapper)
ComponentWrapper::Destroy(wrapper.Info, wrapper.Data);
m_EntityToComponent.erase(wrapper.EntityID);
m_Pool.Free(wrapper.Data - sizeof(EntityID));
m_DirtySet.erase(wrapper.EntityID);
}
ComponentPool::iterator ComponentPool::begin() const
ComponentPool::iterator ComponentPool::begin()
{
return iterator(m_ComponentInfo, m_Pool.begin(), m_Pool.end());
return iterator(this, m_Pool.begin(), m_Pool.end());
}
ComponentPool::iterator ComponentPool::end() const
ComponentPool::iterator ComponentPool::end()
{
return iterator(m_ComponentInfo, m_Pool.end(), m_Pool.end());
return iterator(this, m_Pool.end(), m_Pool.end());
}
size_t ComponentPool::size() const
+59
View File
@@ -0,0 +1,59 @@
#include "Core/World.h"
#include "Core/ComponentWrapper.h"
ComponentWrapper::ComponentWrapper(const ComponentInfo& componentInfo, char* data, ::DirtyBitField* dirtyBitField, World* world)
: Info(componentInfo)
, EntityID(*reinterpret_cast<::EntityID*>(data))
, Data(data + componentInfo.GetHeaderSize())
, DirtyBitField(dirtyBitField)
, m_World(world)
{}
ComponentInfo::EnumType ComponentWrapper::Enum(const char* fieldName, const char* enumKey)
{
return Info.Meta->FieldEnumDefinitions.at(fieldName).at(enumKey);
}
bool ComponentWrapper::Dirty(DirtySetType type, const std::string& fieldName)
{
if (DirtyBitField == nullptr) {
return true;
} else {
auto& field = Info.Fields.at(fieldName);
return DirtyBitField->operator[](type).count(field.Index) == 1;
}
}
void ComponentWrapper::SetDirty(DirtySetType type, const std::string& fieldName, bool dirty /* = true */)
{
if (DirtyBitField == nullptr) {
return;
}
auto& field = Info.Fields.at(fieldName);
if (dirty) {
DirtyBitField->operator[](type).insert(field.Index);
// Because parents affects children when altered, we also need to flag all children as dirty.
if (type == DirtySetType::Transform && m_World != nullptr) {
auto children = m_World->GetDirectChildren(EntityID);
for (auto kv = children.first; kv != children.second; ++kv) {
const auto& child = kv->second;
if (m_World->HasComponent(child, Info.Name)) {
m_World->GetComponent(child, Info.Name).SetDirty(DirtySetType::Transform, fieldName, true);
if (fieldName == "Orientation" || fieldName == "Scale") {
m_World->GetComponent(child, Info.Name).SetDirty(DirtySetType::Transform, "Position", true);
}
}
}
}
} else {
DirtyBitField->operator[](type).erase(field.Index);
}
}
void ComponentWrapper::SetAllDirty(const std::string& fieldName, bool dirty /* = true */)
{
for (auto& kv : *DirtyBitField) {
SetDirty(kv.first, fieldName);
}
}
+14 -280
View File
@@ -1,291 +1,25 @@
#include "Core/EntityFile.h"
EntityFile::EntityFile(boost::filesystem::path path)
: m_FilePath(path)
EntityFile::EntityFile(std::string path)
{
using namespace xercesc;
XMLPlatformUtils::Initialize();
m_GrammarPool = new XMLGrammarPoolImpl();
m_SAX2XMLReader = XMLReaderFactory::createXMLReader(XMLPlatformUtils::fgMemoryManager, m_GrammarPool);
}
EntityXMLFile* xml = ResourceManager::Load<EntityXMLFile>(path);
EntityFile::~EntityFile()
{
delete m_SAX2XMLReader;
delete m_GrammarPool;
xercesc::XMLPlatformUtils::Terminate();
}
EntityXMLFilePreprocessor preprocessor(xml);
preprocessor.RegisterComponents(this);
void EntityFile::Parse(const EntityFileHandler* handler) const
{
using namespace xercesc;
EntityXMLFileParser parser(xml);
m_RootEntity = parser.MergeEntities(this);
EntityFileSAXHandler saxHandler(handler, m_SAX2XMLReader);
setReaderFeatures(m_SAX2XMLReader);
m_SAX2XMLReader->setContentHandler(&saxHandler);
m_SAX2XMLReader->setErrorHandler(&saxHandler);
m_SAX2XMLReader->setDeclarationHandler(&saxHandler);
m_SAX2XMLReader->parse(m_FilePath.string().c_str());
}
void EntityFile::setReaderFeatures(xercesc::SAX2XMLReader* reader)
{
using namespace xercesc;
reader->setFeature(XMLUni::fgXercesCacheGrammarFromParse, true);
reader->setFeature(XMLUni::fgXercesUseCachedGrammarInParse, true);
reader->setFeature(XMLUni::fgSAX2CoreValidation, true);
reader->setFeature(XMLUni::fgSAX2CoreNameSpaces, true);
reader->setFeature(XMLUni::fgXercesSchema, true);
reader->setFeature(XMLUni::fgXercesSchemaFullChecking, true);
reader->setFeature(XMLUni::fgXercesCalculateSrcOfs, true);
reader->setFeature(XMLUni::fgXercesIdentityConstraintChecking, true);
}
unsigned int EntityFile::GetTypeStride(std::string typeName)
{
std::map<std::string, unsigned int> typeStrides{
{ "bool", sizeof(bool) },
{ "int", sizeof(int) },
{ "float", sizeof(float) },
{ "double", sizeof(double) },
{ "string", sizeof(std::string) },
{ "enum", sizeof(ComponentInfo::EnumType) },
{ "Vector", sizeof(glm::vec3) },
{ "Quaternion", sizeof(glm::quat) },
{ "Color", sizeof(glm::vec4) }
};
auto it = typeStrides.find(typeName);
return (it != typeStrides.end()) ? it->second : 0;
}
void EntityFile::WriteAttributeData(char* outData, const ComponentInfo::Field_t& field, const std::map<std::string, std::string>& attributes)
{
if (field.Type == "Vector") {
glm::vec3 vec;
vec.x = boost::lexical_cast<float>(attributes.at("X"));
vec.y = boost::lexical_cast<float>(attributes.at("Y"));
vec.z = boost::lexical_cast<float>(attributes.at("Z"));
memcpy(outData, reinterpret_cast<char*>(&vec), field.Stride);
} else if (field.Type == "Color") {
glm::vec4 vec;
vec.r = boost::lexical_cast<float>(attributes.at("R"));
vec.g = boost::lexical_cast<float>(attributes.at("G"));
vec.b = boost::lexical_cast<float>(attributes.at("B"));
vec.a = boost::lexical_cast<float>(attributes.at("A"));
memcpy(outData, reinterpret_cast<char*>(&vec), field.Stride);
} else if (field.Type == "Quaternion") {
glm::quat q;
q.x = boost::lexical_cast<float>(attributes.at("X"));
q.y = boost::lexical_cast<float>(attributes.at("Y"));
q.z = boost::lexical_cast<float>(attributes.at("Z"));
q.w = boost::lexical_cast<float>(attributes.at("W"));
memcpy(outData, reinterpret_cast<char*>(&q), field.Stride);
} else if (!attributes.empty()) {
LOG_WARNING("%i attributes not handled by any type conversion!", attributes.size());
}
}
void EntityFile::WriteValueData(char* outData, const ComponentInfo::Field_t& field, const char* valueData)
{
// 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)
, m_Reader(reader)
{
// 0 is imaginary base parent
m_EntityStack.push(0);
m_StateStack.push(State::Unknown);
}
void EntityFileSAXHandler::startElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname, const xercesc::Attributes& attrs)
{
std::string name = XS::ToString(_localName);
if (m_StateStack.top() == State::Unknown || m_StateStack.top() == State::Entity) {
if (name == "Entity") {
m_StateStack.push(State::Entity);
onStartEntity(attrs);
return;
}
if (name == "EntityRef") {
onStartEntityRef(attrs);
return;
}
if (m_RootEntity == EntityID_Invalid) {
ResourceManager::Release("EntityXMLFile", path);
throw Resource::FailedLoadingException("Failed to merge entities; root entity is invalid");
}
std::string uri = XS::ToString(_uri);
if (m_StateStack.top() == State::Entity) {
if (uri == "components") {
m_StateStack.push(State::Component);
onStartComponent(name);
return;
}
}
if (m_StateStack.top() == State::Component) {
m_StateStack.push(State::ComponentField);
onStartComponentField(name, attrs);
return;
}
ResourceManager::Release("EntityXMLFile", path);
}
void EntityFileSAXHandler::endElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname)
EntityWrapper EntityFile::MergeInto(World* other)
{
std::string name = XS::ToString(_localName);
if (m_StateStack.top() == State::Entity) {
if (name == "Entity") {
m_StateStack.pop();
onEndEntity();
return;
}
}
std::string uri = XS::ToString(_uri);
if (m_StateStack.top() == State::Component) {
//if (uri == "components") {
m_StateStack.pop();
onEndComponent(name);
return;
//}
}
if (m_StateStack.top() == State::ComponentField && name == m_CurrentField) {
m_StateStack.pop();
onEndComponentField(name);
return;
}
}
void EntityFileSAXHandler::characters(const XMLCh* const chars, const XMLSize_t length)
{
if (m_StateStack.top() == State::ComponentField) {
char* transcoded = xercesc::XMLString::transcode(chars);
onFieldData(transcoded);
}
}
void EntityFileSAXHandler::fatalError(const xercesc::SAXParseException& e)
{
std::string message = XS::ToString(e.getMessage());
std::string systemId = XS::ToString(e.getSystemId());
XMLFileLoc line = e.getLineNumber();
XMLFileLoc column = e.getColumnNumber();
LOG_ERROR("SAXParseException\n\tLocation: %s:%i:%i\n\tFatal Error: %s", systemId.c_str(), line, column, message.c_str());
}
void EntityFileSAXHandler::error(const xercesc::SAXParseException& e)
{
std::string message = XS::ToString(e.getMessage());
std::string systemId = XS::ToString(e.getSystemId());
XMLFileLoc line = e.getLineNumber();
XMLFileLoc column = e.getColumnNumber();
LOG_ERROR("SAXParseException\n\tLocation: %s:%i:%i\n\tError: %s", systemId.c_str(), line, column, message.c_str());
}
void EntityFileSAXHandler::warning(const xercesc::SAXParseException& e)
{
std::string message = XS::ToString(e.getMessage());
std::string systemId = XS::ToString(e.getSystemId());
XMLFileLoc line = e.getLineNumber();
XMLFileLoc column = e.getColumnNumber();
LOG_ERROR("SAXParseException\n\tLocation: %s:%i:%i\n\tWarning: %s", systemId.c_str(), line, column, message.c_str());
}
void EntityFileSAXHandler::onStartEntity(const xercesc::Attributes& attrs)
{
EntityID parent = m_EntityStack.top();
if (m_Handler->m_OnStartEntityCallback) {
std::string name;
auto xName = attrs.getValue(XS::ToXMLCh("name"));
if (xName != nullptr) {
name = XS::ToString(xName);
}
m_Handler->m_OnStartEntityCallback(m_NextEntityID, parent, name);
}
m_EntityStack.push(m_NextEntityID);
m_NextEntityID++;
}
void EntityFileSAXHandler::onEndEntity()
{
m_EntityStack.pop();
}
void EntityFileSAXHandler::onStartEntityRef(const xercesc::Attributes& attrs)
{
std::string path = XS::ToString(attrs.getValue(XS::ToXMLCh("file")));
xercesc::SAX2XMLReader* reader = xercesc::XMLReaderFactory::createXMLReader();
EntityFile::setReaderFeatures(reader);
reader->setContentHandler(this);
reader->setErrorHandler(this);
reader->parse(path.c_str());
delete reader;
}
void EntityFileSAXHandler::onStartComponentField(const std::string& field, const xercesc::Attributes& attrs)
{
//LOG_DEBUG(" Field: %s", field.c_str());
m_CurrentField = field;
m_CurrentAttributes.clear();
for (int i = 0; i < attrs.getLength(); i++) {
auto name = attrs.getQName(i);
auto value = attrs.getValue(name);
//LOG_DEBUG(" %s = %s", (char*)XS::ToString(name), (char*)XS::ToString(value));
m_CurrentAttributes[XS::ToString(name).operator std::string()] = XS::ToString(value).operator std::string();
}
if (m_Handler->m_OnStartFieldCallback) {
m_Handler->m_OnStartFieldCallback(m_EntityStack.top(), m_CurrentComponent, field, m_CurrentAttributes);
}
}
void EntityFileSAXHandler::onEndComponent(const std::string& name) { }
void EntityFileSAXHandler::onStartComponent(const std::string& name)
{
//LOG_DEBUG(" Component: %s", name.c_str());
m_CurrentComponent = name;
if (m_Handler->m_OnStartComponentCallback) {
m_Handler->m_OnStartComponentCallback(m_EntityStack.top(), name);
}
}
void EntityFileSAXHandler::onEndComponentField(const std::string& field) { }
void EntityFileSAXHandler::onFieldData(char* data)
{
//LOG_DEBUG(" Data: %s", data);
if (m_Handler->m_OnStartFieldDataCallback) {
m_Handler->m_OnStartFieldDataCallback(m_EntityStack.top(), m_CurrentComponent, m_CurrentField, data);
}
xercesc::XMLString::release(&data);
}
auto mapping = other->Merge(this);
return EntityWrapper(other, mapping.at(m_RootEntity));
}
-74
View File
@@ -1,74 +0,0 @@
#include "Core/EntityFileParser.h"
EntityFileParser::EntityFileParser(const EntityFile* entityFile)
: m_EntityFile(entityFile)
{
m_Handler.SetStartEntityCallback(std::bind(&EntityFileParser::onStartEntity, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
m_Handler.SetStartComponentCallback(std::bind(&EntityFileParser::onStartComponent, this, std::placeholders::_1, std::placeholders::_2));
m_Handler.SetStartFieldCallback(std::bind(&EntityFileParser::onStartComponentField, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
m_Handler.SetStartFieldDataCallback(std::bind(&EntityFileParser::onFieldData, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
}
EntityID EntityFileParser::MergeEntities(World* world, EntityID baseParent /*= EntityID_Invalid */)
{
m_World = world;
m_EntityIDMapper[0] = baseParent;
m_EntityFile->Parse(&m_Handler);
return m_FirstEntity;
}
void EntityFileParser::onStartEntity(EntityID entity, EntityID parent, const std::string& name)
{
EntityID realParent = m_EntityIDMapper.at(parent);
EntityID realEntity = m_World->CreateEntity(realParent);
if (m_FirstEntity == EntityID_Invalid) {
m_FirstEntity = realEntity;
}
if (!name.empty()) {
m_World->SetName(realEntity, name);
}
m_EntityIDMapper[entity] = realEntity;
//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);
}
void EntityFileParser::onStartComponentField(EntityID entity, const std::string& componentType, const std::string& fieldName, const std::map<std::string, std::string>& attributes)
{
EntityID realEntity = m_EntityIDMapper.at(entity);
ComponentWrapper component = m_World->GetComponent(realEntity, componentType);
auto fieldIt = component.Info.Fields.find(fieldName);
if (fieldIt == component.Info.Fields.end()) {
LOG_ERROR("Tried to set unknown field \"%s\" of component type \"%s\"! Ignoring.", fieldName.c_str(), componentType.c_str());
return;
}
auto& field = fieldIt->second;
//LOG_DEBUG("Field \"%s\" type \"%s\"", fieldName.c_str(), field.Type.c_str());
//LOG_DEBUG("Attributes:");
//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);
}
void EntityFileParser::onFieldData(EntityID entity, const std::string& componentType, const std::string& fieldName, const char* fieldData)
{
EntityID realEntity = m_EntityIDMapper.at(entity);
ComponentWrapper component = m_World->GetComponent(realEntity, componentType);
auto fieldIt = component.Info.Fields.find(fieldName);
if (fieldIt == component.Info.Fields.end()) {
return;
}
auto& field = fieldIt->second;
char* data = component.Data + field.Offset;
EntityFile::WriteValueData(data, field, fieldData);
}
+107 -28
View File
@@ -3,7 +3,7 @@
const EntityWrapper EntityWrapper::Invalid = EntityWrapper(nullptr, EntityID_Invalid);
const std::string EntityWrapper::Name()
const std::string EntityWrapper::Name() const
{
return World->GetName(ID);
}
@@ -27,20 +27,69 @@ void EntityWrapper::AttachComponent(const char* componentName)
EntityWrapper EntityWrapper::Parent()
{
if (this->World == nullptr || this->ID == EntityID_Invalid) {
if (!Valid()) {
return EntityWrapper::Invalid;
} else {
return EntityWrapper(this->World, this->World->GetParent(this->ID));
}
}
EntityWrapper EntityWrapper::FirstParentByName(const std::string& parentEntityName)
{
if (!Valid()) {
return EntityWrapper::Invalid;
}
EntityWrapper entity = *this;
while (entity.Parent().Valid()) {
entity = entity.Parent();
if (entity.Name() == parentEntityName) {
return entity;
}
}
return EntityWrapper::Invalid;
}
EntityWrapper EntityWrapper::FirstChildByName(const std::string& name)
{
if (!Valid()) {
return EntityWrapper::Invalid;
}
return firstChildByNameRecursive(name, this->ID);
}
EntityWrapper EntityWrapper::FirstLevelChildByName(const std::string& name)
{
EntityID parent = this->ID;
if (!this->World->ValidEntity(parent)) {
return EntityWrapper::Invalid;
}
auto itPair = this->World->GetDirectChildren(parent);
if (itPair.first == itPair.second) {
return EntityWrapper::Invalid;
}
for (auto it = itPair.first; it != itPair.second; ++it) {
std::string itName = this->World->GetName(it->second);
if (itName == name) {
return EntityWrapper(this->World, it->second);
} else if (it->second != EntityID_Invalid) {
continue;
}
}
return EntityWrapper::Invalid;
}
EntityWrapper EntityWrapper::FirstParentWithComponent(const std::string& componentType)
{
if (!Valid()) {
return EntityWrapper::Invalid;
}
EntityWrapper entity = *this;
while (entity.Parent().Valid()) {
entity = entity.Parent();
@@ -57,8 +106,30 @@ EntityWrapper EntityWrapper::Clone(EntityWrapper parent /*= Invalid*/)
return EntityWrapper::Invalid;
}
EntityWrapper clone = cloneRecursive(*this, EntityWrapper::Invalid);
this->World->SetParent(clone.ID, parent.ID);
// Create a relationship map of children of this entity
std::unordered_multimap<EntityWrapper, EntityWrapper> relationships;
fillRelationships(relationships, *this);
::World* targetWorld = this->World;
if (parent.Valid()) {
targetWorld = parent.World;
}
// Create root entity
EntityWrapper clone(targetWorld, targetWorld->CreateEntity(parent.ID));
// Copy name
clone.World->SetName(clone.ID, this->Name());
// Clone components
for (auto& kv : this->World->GetComponentPools()) {
if (kv.second->KnowsEntity(this->ID)) {
ComponentWrapper c1 = kv.second->GetByEntity(this->ID);
ComponentWrapper c2 = clone.World->AttachComponent(clone.ID, kv.first);
c1.Copy(c2);
}
}
// Recreate entity tree
recreateRelationships(relationships, *this, clone);
return clone;
}
@@ -170,30 +241,6 @@ EntityWrapper EntityWrapper::firstChildByNameRecursive(const std::string& name,
return EntityWrapper::Invalid;
}
EntityWrapper EntityWrapper::cloneRecursive(EntityWrapper entity, EntityWrapper parent)
{
EntityWrapper clone = EntityWrapper(entity.World, entity.World->CreateEntity(parent.ID));
entity.World->SetName(clone.ID, entity.Name());
// Clone components
for (auto& kv : entity.World->GetComponentPools()) {
if (kv.second->KnowsEntity(entity.ID)) {
ComponentWrapper c1 = kv.second->GetByEntity(entity.ID);
ComponentWrapper c2 = entity.World->AttachComponent(clone.ID, kv.first);
c1.Copy(c2);
}
}
// Clone children
auto children = entity.World->GetDirectChildren(entity.ID);
for (auto it = children.first; it != children.second; ++it) {
EntityWrapper child(entity.World, it->second);
cloneRecursive(child, clone);
}
return clone;
}
void EntityWrapper::childrenWithComponentRecursive(const std::string& componentType, EntityWrapper& entity, std::vector<EntityWrapper>& childrenWithComponent)
{
auto itPair = this->World->GetDirectChildren(entity.ID);
@@ -209,3 +256,35 @@ void EntityWrapper::childrenWithComponentRecursive(const std::string& componentT
childrenWithComponentRecursive(componentType, child, childrenWithComponent);
}
}
void EntityWrapper::fillRelationships(std::unordered_multimap<EntityWrapper, EntityWrapper>& relationMap, EntityWrapper entity)
{
auto children = entity.World->GetDirectChildren(entity.ID);
for (auto it = children.first; it != children.second; ++it) {
EntityWrapper child(entity.World, it->second);
relationMap.insert(std::make_pair(entity, child));
fillRelationships(relationMap, child);
}
}
void EntityWrapper::recreateRelationships(const std::unordered_multimap<EntityWrapper, EntityWrapper>& relationMap, EntityWrapper templateEntity, EntityWrapper parent /*= EntityWrapper::Invalid*/)
{
// Recursively create children
auto children = relationMap.equal_range(templateEntity);
for (auto it = children.first; it != children.second; ++it) {
EntityWrapper child = it->second;
// Create clone entity
EntityWrapper clone(parent.World, parent.World->CreateEntity(parent.ID));
// Copy name
clone.World->SetName(clone.ID, child.Name());
// Clone components
for (auto& kv : child.World->GetComponentPools()) {
if (kv.second->KnowsEntity(child.ID)) {
ComponentWrapper c1 = kv.second->GetByEntity(child.ID);
ComponentWrapper c2 = clone.World->AttachComponent(clone.ID, kv.first);
c1.Copy(c2);
}
}
recreateRelationships(relationMap, child, clone);
}
}
+291
View File
@@ -0,0 +1,291 @@
#include "Core/EntityXMLFile.h"
EntityXMLFile::EntityXMLFile(boost::filesystem::path path)
: m_FilePath(path)
{
using namespace xercesc;
XMLPlatformUtils::Initialize();
m_GrammarPool = new XMLGrammarPoolImpl();
m_SAX2XMLReader = XMLReaderFactory::createXMLReader(XMLPlatformUtils::fgMemoryManager, m_GrammarPool);
}
EntityXMLFile::~EntityXMLFile()
{
delete m_SAX2XMLReader;
delete m_GrammarPool;
xercesc::XMLPlatformUtils::Terminate();
}
void EntityXMLFile::Parse(const EntityFileHandler* handler) const
{
using namespace xercesc;
EntityFileSAXHandler saxHandler(handler, m_SAX2XMLReader);
setReaderFeatures(m_SAX2XMLReader);
m_SAX2XMLReader->setContentHandler(&saxHandler);
m_SAX2XMLReader->setErrorHandler(&saxHandler);
m_SAX2XMLReader->setDeclarationHandler(&saxHandler);
m_SAX2XMLReader->parse(m_FilePath.string().c_str());
}
void EntityXMLFile::setReaderFeatures(xercesc::SAX2XMLReader* reader)
{
using namespace xercesc;
reader->setFeature(XMLUni::fgXercesCacheGrammarFromParse, true);
reader->setFeature(XMLUni::fgXercesUseCachedGrammarInParse, true);
reader->setFeature(XMLUni::fgSAX2CoreValidation, true);
reader->setFeature(XMLUni::fgSAX2CoreNameSpaces, true);
reader->setFeature(XMLUni::fgXercesSchema, true);
reader->setFeature(XMLUni::fgXercesSchemaFullChecking, true);
reader->setFeature(XMLUni::fgXercesCalculateSrcOfs, true);
reader->setFeature(XMLUni::fgXercesIdentityConstraintChecking, true);
}
unsigned int EntityXMLFile::GetTypeStride(std::string typeName)
{
std::map<std::string, unsigned int> typeStrides{
{ "bool", sizeof(bool) },
{ "int", sizeof(int) },
{ "float", sizeof(float) },
{ "double", sizeof(double) },
{ "string", sizeof(std::string) },
{ "enum", sizeof(ComponentInfo::EnumType) },
{ "Vector", sizeof(glm::vec3) },
{ "Quaternion", sizeof(glm::quat) },
{ "Color", sizeof(glm::vec4) }
};
auto it = typeStrides.find(typeName);
return (it != typeStrides.end()) ? it->second : 0;
}
void EntityXMLFile::WriteAttributeData(char* outData, const ComponentInfo::Field_t& field, const std::map<std::string, std::string>& attributes)
{
if (field.Type == "Vector") {
glm::vec3 vec;
vec.x = boost::lexical_cast<float>(attributes.at("X"));
vec.y = boost::lexical_cast<float>(attributes.at("Y"));
vec.z = boost::lexical_cast<float>(attributes.at("Z"));
memcpy(outData, reinterpret_cast<char*>(&vec), field.Stride);
} else if (field.Type == "Color") {
glm::vec4 vec;
vec.r = boost::lexical_cast<float>(attributes.at("R"));
vec.g = boost::lexical_cast<float>(attributes.at("G"));
vec.b = boost::lexical_cast<float>(attributes.at("B"));
vec.a = boost::lexical_cast<float>(attributes.at("A"));
memcpy(outData, reinterpret_cast<char*>(&vec), field.Stride);
} else if (field.Type == "Quaternion") {
glm::quat q;
q.x = boost::lexical_cast<float>(attributes.at("X"));
q.y = boost::lexical_cast<float>(attributes.at("Y"));
q.z = boost::lexical_cast<float>(attributes.at("Z"));
q.w = boost::lexical_cast<float>(attributes.at("W"));
memcpy(outData, reinterpret_cast<char*>(&q), field.Stride);
} else if (!attributes.empty()) {
LOG_WARNING("%i attributes not handled by any type conversion!", attributes.size());
}
}
void EntityXMLFile::WriteValueData(char* outData, const ComponentInfo::Field_t& field, const char* valueData)
{
// 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)
, m_Reader(reader)
{
// 0 is imaginary base parent
m_EntityStack.push(0);
m_StateStack.push(State::Unknown);
}
void EntityFileSAXHandler::startElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname, const xercesc::Attributes& attrs)
{
std::string name = XS::ToString(_localName);
if (m_StateStack.top() == State::Unknown || m_StateStack.top() == State::Entity) {
if (name == "Entity") {
m_StateStack.push(State::Entity);
onStartEntity(attrs);
return;
}
if (name == "EntityRef") {
onStartEntityRef(attrs);
return;
}
}
std::string uri = XS::ToString(_uri);
if (m_StateStack.top() == State::Entity) {
if (uri == "components") {
m_StateStack.push(State::Component);
onStartComponent(name);
return;
}
}
if (m_StateStack.top() == State::Component) {
m_StateStack.push(State::ComponentField);
onStartComponentField(name, attrs);
return;
}
}
void EntityFileSAXHandler::endElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname)
{
std::string name = XS::ToString(_localName);
if (m_StateStack.top() == State::Entity) {
if (name == "Entity") {
m_StateStack.pop();
onEndEntity();
return;
}
}
std::string uri = XS::ToString(_uri);
if (m_StateStack.top() == State::Component) {
//if (uri == "components") {
m_StateStack.pop();
onEndComponent(name);
return;
//}
}
if (m_StateStack.top() == State::ComponentField && name == m_CurrentField) {
m_StateStack.pop();
onEndComponentField(name);
return;
}
}
void EntityFileSAXHandler::characters(const XMLCh* const chars, const XMLSize_t length)
{
if (m_StateStack.top() == State::ComponentField) {
char* transcoded = xercesc::XMLString::transcode(chars);
onFieldData(transcoded);
}
}
void EntityFileSAXHandler::fatalError(const xercesc::SAXParseException& e)
{
std::string message = XS::ToString(e.getMessage());
std::string systemId = XS::ToString(e.getSystemId());
XMLFileLoc line = e.getLineNumber();
XMLFileLoc column = e.getColumnNumber();
LOG_ERROR("SAXParseException\n\tLocation: %s:%i:%i\n\tFatal Error: %s", systemId.c_str(), line, column, message.c_str());
}
void EntityFileSAXHandler::error(const xercesc::SAXParseException& e)
{
std::string message = XS::ToString(e.getMessage());
std::string systemId = XS::ToString(e.getSystemId());
XMLFileLoc line = e.getLineNumber();
XMLFileLoc column = e.getColumnNumber();
LOG_ERROR("SAXParseException\n\tLocation: %s:%i:%i\n\tError: %s", systemId.c_str(), line, column, message.c_str());
}
void EntityFileSAXHandler::warning(const xercesc::SAXParseException& e)
{
std::string message = XS::ToString(e.getMessage());
std::string systemId = XS::ToString(e.getSystemId());
XMLFileLoc line = e.getLineNumber();
XMLFileLoc column = e.getColumnNumber();
LOG_ERROR("SAXParseException\n\tLocation: %s:%i:%i\n\tWarning: %s", systemId.c_str(), line, column, message.c_str());
}
void EntityFileSAXHandler::onStartEntity(const xercesc::Attributes& attrs)
{
EntityID parent = m_EntityStack.top();
if (m_Handler->m_OnStartEntityCallback) {
std::string name;
auto xName = attrs.getValue(XS::ToXMLCh("name"));
if (xName != nullptr) {
name = XS::ToString(xName);
}
m_Handler->m_OnStartEntityCallback(m_NextEntityID, parent, name);
}
m_EntityStack.push(m_NextEntityID);
m_NextEntityID++;
}
void EntityFileSAXHandler::onEndEntity()
{
m_EntityStack.pop();
}
void EntityFileSAXHandler::onStartEntityRef(const xercesc::Attributes& attrs)
{
std::string path = XS::ToString(attrs.getValue(XS::ToXMLCh("file")));
xercesc::SAX2XMLReader* reader = xercesc::XMLReaderFactory::createXMLReader();
EntityXMLFile::setReaderFeatures(reader);
reader->setContentHandler(this);
reader->setErrorHandler(this);
reader->parse(path.c_str());
delete reader;
}
void EntityFileSAXHandler::onStartComponentField(const std::string& field, const xercesc::Attributes& attrs)
{
//LOG_DEBUG(" Field: %s", field.c_str());
m_CurrentField = field;
m_CurrentAttributes.clear();
for (int i = 0; i < attrs.getLength(); i++) {
auto name = attrs.getQName(i);
auto value = attrs.getValue(name);
//LOG_DEBUG(" %s = %s", (char*)XS::ToString(name), (char*)XS::ToString(value));
m_CurrentAttributes[XS::ToString(name).operator std::string()] = XS::ToString(value).operator std::string();
}
if (m_Handler->m_OnStartFieldCallback) {
m_Handler->m_OnStartFieldCallback(m_EntityStack.top(), m_CurrentComponent, field, m_CurrentAttributes);
}
}
void EntityFileSAXHandler::onEndComponent(const std::string& name) { }
void EntityFileSAXHandler::onStartComponent(const std::string& name)
{
//LOG_DEBUG(" Component: %s", name.c_str());
m_CurrentComponent = name;
if (m_Handler->m_OnStartComponentCallback) {
m_Handler->m_OnStartComponentCallback(m_EntityStack.top(), name);
}
}
void EntityFileSAXHandler::onEndComponentField(const std::string& field) { }
void EntityFileSAXHandler::onFieldData(char* data)
{
//LOG_DEBUG(" Data: %s", data);
if (m_Handler->m_OnStartFieldDataCallback) {
m_Handler->m_OnStartFieldDataCallback(m_EntityStack.top(), m_CurrentComponent, m_CurrentField, data);
}
xercesc::XMLString::release(&data);
}
+84
View File
@@ -0,0 +1,84 @@
#include "Core/EntityXMLFileParser.h"
EntityXMLFileParser::EntityXMLFileParser(const EntityXMLFile* entityFile)
: m_EntityFile(entityFile)
{
m_Handler.SetStartEntityCallback(std::bind(&EntityXMLFileParser::onStartEntity, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
m_Handler.SetStartComponentCallback(std::bind(&EntityXMLFileParser::onStartComponent, this, std::placeholders::_1, std::placeholders::_2));
m_Handler.SetStartFieldCallback(std::bind(&EntityXMLFileParser::onStartComponentField, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
m_Handler.SetStartFieldDataCallback(std::bind(&EntityXMLFileParser::onFieldData, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
}
EntityID EntityXMLFileParser::MergeEntities(World* world, EntityID baseParent /*= EntityID_Invalid */)
{
m_World = world;
m_EntityIDMapper[0] = baseParent;
m_EntityFile->Parse(&m_Handler);
return m_FirstEntity;
}
void EntityXMLFileParser::onStartEntity(EntityID entity, EntityID parent, const std::string& name)
{
EntityID realParent = m_EntityIDMapper.at(parent);
EntityID realEntity = m_World->CreateEntity(realParent);
if (m_FirstEntity == EntityID_Invalid) {
m_FirstEntity = realEntity;
}
if (!name.empty()) {
m_World->SetName(realEntity, name);
}
m_EntityIDMapper[entity] = realEntity;
//LOG_DEBUG("Created entity #%i (%i) with parent %i (%i)", entity, realEntity, parent, realParent);
}
void EntityXMLFileParser::onStartComponent(EntityID entity, const std::string& component)
{
if (m_World->GetComponentPools().count(component) != 0) {
EntityID realEntity = m_EntityIDMapper.at(entity);
m_World->AttachComponent(realEntity, component);
} else {
LOG_ERROR("Tried to attach unregistered component \"%s\"! to entity #%i. Ignoring.", component.c_str(), entity);
}
//LOG_DEBUG("Attached component of type \"%s\" to entity #%i (%i)", component.c_str(), entity, realEntity);
}
void EntityXMLFileParser::onStartComponentField(EntityID entity, const std::string& componentType, const std::string& fieldName, const std::map<std::string, std::string>& attributes)
{
if (m_World->GetComponentPools().count(componentType) == 0) {
return;
}
EntityID realEntity = m_EntityIDMapper.at(entity);
ComponentWrapper component = m_World->GetComponent(realEntity, componentType);
auto fieldIt = component.Info.Fields.find(fieldName);
if (fieldIt == component.Info.Fields.end()) {
LOG_ERROR("Tried to set unknown field \"%s\" of component type \"%s\"! Ignoring.", fieldName.c_str(), componentType.c_str());
return;
}
auto& field = fieldIt->second;
//LOG_DEBUG("Field \"%s\" type \"%s\"", fieldName.c_str(), field.Type.c_str());
//LOG_DEBUG("Attributes:");
//for (auto& kv : attributes) {
// LOG_DEBUG("\t%s = %s", kv.first.c_str(), kv.second.c_str());
//}
char* data = component.Data + field.Offset;
EntityXMLFile::WriteAttributeData(data, field, attributes);
}
void EntityXMLFileParser::onFieldData(EntityID entity, const std::string& componentType, const std::string& fieldName, const char* fieldData)
{
if (m_World->GetComponentPools().count(componentType) == 0) {
return;
}
EntityID realEntity = m_EntityIDMapper.at(entity);
ComponentWrapper component = m_World->GetComponent(realEntity, componentType);
auto fieldIt = component.Info.Fields.find(fieldName);
if (fieldIt == component.Info.Fields.end()) {
return;
}
auto& field = fieldIt->second;
char* data = component.Data + field.Offset;
EntityXMLFile::WriteValueData(data, field, fieldData);
}
@@ -1,10 +1,10 @@
#include "Core/EntityFilePreprocessor.h"
#include "Core/EntityXMLFilePreprocessor.h"
EntityFilePreprocessor::EntityFilePreprocessor(const EntityFile* entityFile)
EntityXMLFilePreprocessor::EntityXMLFilePreprocessor(const EntityXMLFile* entityFile)
: m_EntityFile(entityFile)
{
EntityFileHandler handler;
handler.SetStartComponentCallback(std::bind(&EntityFilePreprocessor::onStartComponent, this, std::placeholders::_1, std::placeholders::_2));
handler.SetStartComponentCallback(std::bind(&EntityXMLFilePreprocessor::onStartComponent, this, std::placeholders::_1, std::placeholders::_2));
m_EntityFile->Parse(&handler);
//LOG_DEBUG("___ COMPONENT DEFINITIONS ___");
@@ -28,20 +28,20 @@ EntityFilePreprocessor::EntityFilePreprocessor(const EntityFile* entityFile)
parseDefaults();
}
void EntityFilePreprocessor::RegisterComponents(World* world)
void EntityXMLFilePreprocessor::RegisterComponents(World* world)
{
for (auto& kv : m_ComponentInfo) {
world->RegisterComponent(kv.second);
}
}
void EntityFilePreprocessor::onStartComponent(EntityID entity, std::string type)
void EntityXMLFilePreprocessor::onStartComponent(EntityID entity, std::string type)
{
//LOG_DEBUG("Component: %s", type.c_str());
m_ComponentCounts[type]++;
}
void EntityFilePreprocessor::parseComponentInfo()
void EntityXMLFilePreprocessor::parseComponentInfo()
{
using namespace xercesc;
EntityFileXMLErrorHandler errorHandler;
@@ -125,6 +125,7 @@ void EntityFilePreprocessor::parseComponentInfo()
auto modelGroup = modelGroupParticle->getModelGroupTerm();
// <xs:element...
unsigned char fieldIndex = 0;
unsigned int fieldOffset = 0;
auto particles = modelGroup->getParticles();
for (unsigned int i = 0; i < particles->size(); ++i) {
@@ -141,9 +142,9 @@ void EntityFilePreprocessor::parseComponentInfo()
std::string baseType = XS::ToString(elementDeclaration->getTypeDefinition()->getBaseType()->getName());
std::string effectiveType = type;
unsigned int stride = EntityFile::GetTypeStride(type);
unsigned int stride = EntityXMLFile::GetTypeStride(type);
if (stride == 0) {
stride = EntityFile::GetTypeStride(baseType);
stride = EntityXMLFile::GetTypeStride(baseType);
if (stride == 0) {
LOG_WARNING("Field \"%s\" in component \"%s\" uses unexpected field type \"%s\" with base type \"%s\". Skipping.", name.c_str(), compInfo.Name.c_str(), type.c_str(), baseType.c_str());
continue;
@@ -182,12 +183,14 @@ void EntityFilePreprocessor::parseComponentInfo()
auto& field = compInfo.Fields[name];
field.Name = name;
field.Type = effectiveType;
field.Index = fieldIndex;
field.Offset = fieldOffset;
field.Stride = stride;
compInfo.FieldsInOrder.push_back(name);
if (field.Type == "string") {
compInfo.StringFields.push_back(name);
}
fieldIndex += 1;
fieldOffset += stride;
}
@@ -196,7 +199,7 @@ void EntityFilePreprocessor::parseComponentInfo()
}
}
void EntityFilePreprocessor::parseDefaults()
void EntityXMLFilePreprocessor::parseDefaults()
{
using namespace xercesc;
@@ -261,7 +264,7 @@ void EntityFilePreprocessor::parseDefaults()
auto attribItem = attributeMap->item(i);
attributes[XS::ToString(attribItem->getNodeName())] = XS::ToString(attribItem->getNodeValue());
}
EntityFile::WriteAttributeData(data, field, attributes);
EntityXMLFile::WriteAttributeData(data, field, attributes);
}
auto childNode = fieldElement->getFirstChild();
@@ -278,14 +281,14 @@ void EntityFilePreprocessor::parseDefaults()
// Handle potential field values
if (childNode->getNodeType() == DOMNode::TEXT_NODE) {
char* cstrValue = XMLString::transcode(childNode->getNodeValue());
EntityFile::WriteValueData(data, field, cstrValue);
EntityXMLFile::WriteValueData(data, field, cstrValue);
XMLString::release(&cstrValue);
}
}
}
}
std::string EntityFilePreprocessor::parseAnnotationXML(const XMLCh* xml)
std::string EntityXMLFilePreprocessor::parseAnnotationXML(const XMLCh* xml)
{
using namespace xercesc;
@@ -1,13 +1,13 @@
#include "Core/EntityFileWriter.h"
#include "Core/EntityXMLFileWriter.h"
#define X(str) XS::ToXMLCh(str)
void EntityFileWriter::WriteWorld(World* world)
void EntityXMLFileWriter::WriteWorld(World* world)
{
WriteEntity(world, 0);
}
void EntityFileWriter::WriteEntity(World* world, EntityID entity)
void EntityXMLFileWriter::WriteEntity(World* world, EntityID entity)
{
using namespace xercesc;
DOMDocument* doc = m_DOMImplementation->createDocument(nullptr, X("Entity"), nullptr);
@@ -41,7 +41,7 @@ void EntityFileWriter::WriteEntity(World* world, EntityID entity)
doc->release();
}
void EntityFileWriter::appendEntityChildren(xercesc::DOMElement* parentElement, const World* world, EntityID entity)
void EntityXMLFileWriter::appendEntityChildren(xercesc::DOMElement* parentElement, const World* world, EntityID entity)
{
using namespace xercesc;
DOMDocument* doc = parentElement->getOwnerDocument();
@@ -67,7 +67,7 @@ void EntityFileWriter::appendEntityChildren(xercesc::DOMElement* parentElement,
}
}
void EntityFileWriter::appentEntityComponents(xercesc::DOMElement* parentElement, const World* world, EntityID entity)
void EntityXMLFileWriter::appentEntityComponents(xercesc::DOMElement* parentElement, const World* world, EntityID entity)
{
using namespace xercesc;
DOMDocument* doc = parentElement->getOwnerDocument();
+15
View File
@@ -1,7 +1,10 @@
#include "Core/PerformanceTimer.h"
#ifdef DEBUG
#include <ctime>
#include <fstream>
cpu_timer PerformanceTimer::m_Timer;
std::map<std::string, cpu_timer> PerformanceTimer::timers;
std::string PerformanceTimer::currentTimerRunning = "";
@@ -74,3 +77,15 @@ void PerformanceTimer::CreateExcelData()
}
someFileStream.close();
}
#else
void PerformanceTimer::StartTimer(std::string nameOfTimer) {};
void PerformanceTimer::StartTimerAndStopPrevious(std::string nameOfTimer) {};
void PerformanceTimer::StopTimer(std::string nameOfTimer) {};
void PerformanceTimer::SetFrameNumber(int frameNumber) {};
void PerformanceTimer::ResetAllTimers() {};
void PerformanceTimer::CreateExcelData() {};
#endif //DEBUG
-103
View File
@@ -1,103 +0,0 @@
#include "Core/Transform.h"
glm::mat4 Transform::AbsoluteTransformation(EntityWrapper entity)
{
glm::mat4 t = glm::mat4(1.f);
while (entity.Valid()) {
t = glm::translate((glm::vec3&)entity["Transform"]["Position"]) * glm::toMat4(glm::quat((glm::vec3&)entity["Transform"]["Orientation"])) * glm::scale((glm::vec3&)entity["Transform"]["Scale"]) * t;
entity = entity.Parent();
}
return t;
}
glm::vec3 Transform::AbsolutePosition(EntityWrapper entity)
{
return AbsolutePosition(entity.World, entity.ID);
}
glm::vec3 Transform::AbsolutePosition(World* world, EntityID entity)
{
glm::vec3 position;
while (entity != EntityID_Invalid) {
ComponentWrapper transform = world->GetComponent(entity, "Transform");
EntityID parent = world->GetParent(entity);
position += Transform::AbsoluteOrientation(world, parent) * (glm::vec3)transform["Position"];
entity = parent;
}
return position;
}
glm::vec3 Transform::AbsoluteOrientationEuler(EntityWrapper entity)
{
glm::vec3 orientation;
while (entity.Valid()) {
ComponentWrapper transform = entity["Transform"];
orientation += (glm::vec3)transform["Orientation"];
entity = entity.Parent();
}
return orientation;
}
glm::quat Transform::AbsoluteOrientation(EntityWrapper entity)
{
return AbsoluteOrientation(entity.World, entity.ID);
}
glm::quat Transform::AbsoluteOrientation(World* world, EntityID entity)
{
glm::quat orientation;
while (entity != EntityID_Invalid) {
ComponentWrapper transform = world->GetComponent(entity, "Transform");
orientation = glm::quat((glm::vec3)transform["Orientation"]) * orientation;
entity = world->GetParent(entity);
}
return orientation;
}
glm::vec3 Transform::AbsoluteScale(EntityWrapper entity)
{
return AbsoluteScale(entity.World, entity.ID);
}
glm::vec3 Transform::AbsoluteScale(World* world, EntityID entity)
{
glm::vec3 scale(1.f);
while (entity != EntityID_Invalid) {
ComponentWrapper transform = world->GetComponent(entity, "Transform");
scale *= (glm::vec3)transform["Scale"];
entity = world->GetParent(entity);
}
return scale;
}
glm::mat4 Transform::ModelMatrix(EntityWrapper entity)
{
return ModelMatrix(entity.ID, entity.World);
}
glm::mat4 Transform::ModelMatrix(EntityID entity, World* world)
{
return AbsoluteTransformation(EntityWrapper(world, entity));
glm::vec3 position = Transform::AbsolutePosition(world, entity);
glm::quat orientation = Transform::AbsoluteOrientation(world, entity);
glm::vec3 scale = Transform::AbsoluteScale(world, entity);
glm::mat4 modelMatrix = glm::translate(glm::mat4(), position) * glm::toMat4(orientation) * glm::scale(scale);
return modelMatrix;
}
glm::vec3 Transform::TransformPoint(const glm::vec3& point, const glm::mat4& matrix)
{
return glm::vec3(matrix * glm::vec4(point.x, point.y, point.z, 1));
}
+162
View File
@@ -0,0 +1,162 @@
#include "Core/TransformSystem.h"
std::unordered_map<EntityWrapper, glm::vec3> TransformSystem::PositionCache;
std::unordered_map<EntityWrapper, glm::quat> TransformSystem::OrientationCache;
std::unordered_map<EntityWrapper, glm::vec3> TransformSystem::ScaleCache;
std::unordered_map<EntityWrapper, glm::mat4> TransformSystem::MatrixCache;
int TransformSystem::RecalculatedPositions = 0;
int TransformSystem::RecalculatedOrientations = 0;
int TransformSystem::RecalculatedScales = 0;
TransformSystem::TransformSystem(SystemParams params)
: System(params)
{
EVENT_SUBSCRIBE_MEMBER(m_EEntityDeleted, &TransformSystem::OnEntityDeleted);
}
bool TransformSystem::OnEntityDeleted(const Events::EntityDeleted& e)
{
// Clean up deleted entity
PositionCache.erase(e.DeletedEntity);
OrientationCache.erase(e.DeletedEntity);
ScaleCache.erase(e.DeletedEntity);
MatrixCache.erase(e.DeletedEntity);
return true;
}
//glm::mat4 Transform::AbsoluteTransformation(EntityWrapper entity)
//{
// glm::mat4 t = glm::mat4(1.f);
//
// while (entity.Valid()) {
// t = glm::translate((const glm::vec3&)entity["Transform"]["Position"]) * glm::toMat4(glm::quat((const glm::vec3&)entity["Transform"]["Orientation"])) * glm::scale((const glm::vec3&)entity["Transform"]["Scale"]) * t;
// entity = entity.Parent();
// }
//
// return t;
//}
glm::vec3 TransformSystem::AbsolutePosition(World* world, EntityID entity)
{
return TransformSystem::AbsolutePosition(EntityWrapper(world, entity));
}
glm::vec3 TransformSystem::AbsolutePosition(EntityWrapper entity)
{
if (!entity.Valid()) {
return glm::vec3();
}
auto cacheIt = PositionCache.find(entity);
ComponentWrapper cTransform = entity["Transform"];
ComponentWrapper::SubscriptProxy cTransformPosition = cTransform["Position"];
if (cacheIt != PositionCache.end() && !cTransformPosition.Dirty(DirtySetType::Transform)) {
return cacheIt->second;
} else {
EntityWrapper parent = entity.Parent();
// Calculate position
glm::vec3 position = AbsolutePosition(parent) + TransformSystem::AbsoluteOrientation(parent) * (TransformSystem::AbsoluteScale(parent) * (const glm::vec3&)cTransformPosition);
// Cache it
PositionCache[entity] = position;
RecalculatedPositions++;
// Unset dirty flag
cTransformPosition.SetDirty(DirtySetType::Transform, false);
return position;
}
}
glm::vec3 TransformSystem::AbsoluteOrientationEuler(EntityWrapper entity)
{
glm::vec3 orientation;
while (entity.Valid()) {
ComponentWrapper transform = entity["Transform"];
orientation += (Field<glm::vec3>)transform["Orientation"];
entity = entity.Parent();
}
return orientation;
}
glm::quat TransformSystem::AbsoluteOrientation(World* world, EntityID entity)
{
return TransformSystem::AbsoluteOrientation(EntityWrapper(world, entity));
}
glm::quat TransformSystem::AbsoluteOrientation(EntityWrapper entity)
{
if (!entity.Valid()) {
return glm::quat();
}
auto cacheIt = OrientationCache.find(entity);
ComponentWrapper cTransform = entity["Transform"];
ComponentWrapper::SubscriptProxy cTransformOrientation = cTransform["Orientation"];
if (cacheIt != OrientationCache.end() && !cTransformOrientation.Dirty(DirtySetType::Transform)) {
return cacheIt->second;
} else {
EntityWrapper parent = entity.Parent();
// Calculate orientation
glm::quat orientation = AbsoluteOrientation(parent) * glm::quat((const glm::vec3&)cTransformOrientation);
// Cache it
OrientationCache[entity] = orientation;
RecalculatedOrientations++;
// Unset dirty flag
cTransformOrientation.SetDirty(DirtySetType::Transform, false);
return orientation;
}
}
glm::vec3 TransformSystem::AbsoluteScale(World* world, EntityID entity)
{
return TransformSystem::AbsoluteScale(EntityWrapper(world, entity));
}
glm::vec3 TransformSystem::AbsoluteScale(EntityWrapper entity)
{
if (!entity.Valid()) {
return glm::vec3(1.f);
}
auto cacheIt = ScaleCache.find(entity);
ComponentWrapper cTransform = entity["Transform"];
ComponentWrapper::SubscriptProxy cTransformScale = cTransform["Scale"];
if (cacheIt != ScaleCache.end() && !cTransformScale.Dirty(DirtySetType::Transform)) {
return cacheIt->second;
} else {
EntityWrapper parent = entity.Parent();
// Calculate scale
glm::vec3 scale = AbsoluteScale(parent) * (const glm::vec3&)cTransformScale;
// Cache it
ScaleCache[entity] = scale;
RecalculatedPositions++;
// Unset dirty flag
cTransformScale.SetDirty(DirtySetType::Transform, false);
return scale;
}
}
glm::mat4 TransformSystem::ModelMatrix(EntityID entityID, World* world)
{
return ModelMatrix(EntityWrapper(world, entityID));
}
glm::mat4 TransformSystem::ModelMatrix(EntityWrapper entity)
{
//auto cacheIt = MatrixCache.find(entity);
//ComponentWrapper cTransform = entity["Transform"];
//bool isDirty = cTransform["Position"].Dirty(DirtySetType::Transform) || cTransform["Orientation"].Dirty(DirtySetType::Transform) || cTransform["Scale"].Dirty(DirtySetType::Transform);
//if (cacheIt != MatrixCache.end() && !isDirty && false) {
// return cacheIt->second;
//} else {
glm::mat4 matrix = glm::translate(AbsolutePosition(entity)) * glm::toMat4(AbsoluteOrientation(entity)) * glm::scale(AbsoluteScale(entity));
// MatrixCache[entity] = matrix;
return matrix;
//}
}
glm::vec3 TransformSystem::TransformPoint(const glm::vec3& point, const glm::mat4& matrix)
{
return glm::vec3(matrix * glm::vec4(point.x, point.y, point.z, 1));
}
+2 -2
View File
@@ -13,8 +13,8 @@ void UniformScaleSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper
return;
}
float distance = glm::length((glm::vec3)entity["Transform"]["Position"] - (glm::vec3&)m_Camera["Transform"]["Position"]);
entity["Transform"]["Scale"] = (glm::vec3&)cUniformScale["Scale"] * distance;
float distance = glm::length((glm::vec3)entity["Transform"]["Position"] - (const glm::vec3&)m_Camera["Transform"]["Position"]);
entity["Transform"]["Scale"] = (const glm::vec3&)cUniformScale["Scale"] * distance;
}
bool UniformScaleSystem::OnSetCamera(const Events::SetCamera& e)
+2 -2
View File
@@ -33,8 +33,8 @@ void _LOG(_LOG_LEVEL logLevel, const char* file, const char* func, unsigned int
va_end(args);
if (logLevel == LOG_LEVEL_ERROR) {
//std::cerr << file << ":" << line << " " << func << std::endl;
//std::cerr << _LOG_LEVEL_PREFIX[logLevel] << message << std::endl;
std::cerr << file << ":" << line << " " << func << std::endl;
std::cerr << _LOG_LEVEL_PREFIX[logLevel] << message << std::endl;
} else {
std::cout << _LOG_LEVEL_PREFIX[logLevel] << message << std::endl;
}
+61 -4
View File
@@ -1,6 +1,7 @@
#include "Core/World.h"
#include "Core/EEntityDeleted.h"
#include "Core/EComponentDeleted.h"
#include "Core/EntityWrapper.h"
World::~World()
{
@@ -44,10 +45,10 @@ bool World::ValidEntity(EntityID entity) const
return m_EntityParents.find(entity) != m_EntityParents.end();
}
void World::RegisterComponent(ComponentInfo& ci)
void World::RegisterComponent(const ComponentInfo& ci)
{
if (m_ComponentPools.find(ci.Name) == m_ComponentPools.end()) {
m_ComponentPools[ci.Name] = new ComponentPool(ci);
m_ComponentPools[ci.Name] = new ComponentPool(ci, this);
}
}
@@ -94,7 +95,7 @@ void World::DeleteComponent(EntityID entity, const std::string& componentType)
}
}
const ComponentPool* World::GetComponents(const std::string& componentType)
ComponentPool* World::GetComponents(const std::string& componentType)
{
auto it = m_ComponentPools.find(componentType);
return (it != m_ComponentPools.end()) ? it->second : nullptr;
@@ -151,6 +152,62 @@ std::string World::GetName(EntityID entity) const
}
}
EntityWrapper World::GetFirstEntityByName(const std::string& name)
{
auto itPair = GetDirectChildren(EntityID_Invalid);
for (auto it = itPair.first; it != itPair.second; it++) {
EntityID childEntityID = it->second;
EntityWrapper childEntity(this, childEntityID);
if (!childEntity.Valid()) {
continue;
}
EntityWrapper entityWithName = childEntity.Name() == name ? childEntity : childEntity.FirstChildByName(name);
if (entityWithName.Valid()) {
return entityWithName;
}
}
return EntityWrapper::Invalid;
}
std::unordered_map<EntityID, EntityID> World::Merge(const World* other)
{
std::unordered_map<EntityID, EntityID> oldToNew;
// Create new entities
for (auto& kv : other->m_EntityParents) {
EntityID entity = kv.first;
EntityID newEntity = CreateEntity();
SetName(newEntity, other->GetName(entity));
oldToNew[entity] = newEntity;
}
// Fix relationships
for (auto& kv : other->m_EntityParents) {
EntityID entity = kv.first;
EntityID parent = kv.second;
if (parent != EntityID_Invalid) {
SetParent(oldToNew.at(entity), oldToNew.at(parent));
}
}
// Transfer components
for (auto& kv : other->m_ComponentPools) {
auto& componentType = kv.first;
ComponentPool* pool = kv.second;
// Register pool if it's not present in world
if (m_ComponentPools.count(componentType) == 0) {
RegisterComponent(pool->ComponentInfo());
}
// Copy components
for (auto component : *pool) {
ComponentWrapper newComponent = AttachComponent(oldToNew.at(component.EntityID), componentType);
component.Copy(newComponent);
}
}
return oldToNew;
}
EntityID World::generateEntityID()
{
// TODO: Make EntityID generation smarter
@@ -166,7 +223,7 @@ void World::deleteEntityRecursive(EntityID entity, bool cascaded /*= false*/)
if (m_EventBroker != nullptr) {
Events::EntityDeleted e;
e.DeletedEntity = entity;
e.DeletedEntity = EntityWrapper(this, entity);
e.Cascaded = cascaded;
m_EventBroker->Publish(e);
}
+62 -8
View File
@@ -157,7 +157,7 @@ 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))) {
if (drawEntityNode(EntityWrapper(world, it->second))) {
drawEntitiesRecursive(world, it->second);
ImGui::TreePop();
}
@@ -217,6 +217,7 @@ bool EditorGUI::drawEntityNode(EntityWrapper entity)
ImGui::EndPopup();
}
ImGui::PushID(("EntityNode" + std::to_string(entity.ID)).c_str());
ImGui::SetNextTreeNodeOpened(true, ImGuiSetCond_Once);
if (ImGui::TreeNode(formatEntityName(entity).c_str())) {
// Handle drop events for reparenting
@@ -224,8 +225,10 @@ bool EditorGUI::drawEntityNode(EntityWrapper entity)
entityChangeParent(m_CurrentlyDragging, entity);
m_CurrentlyDragging = EntityWrapper::Invalid;
}
ImGui::PopID();
return true;
} else {
ImGui::PopID();
return false;
}
}
@@ -338,6 +341,15 @@ bool EditorGUI::drawComponentNode(EntityWrapper entity, const ComponentInfo& ci)
}
}
if (ci.Name == "Spawner") {
if (ImGui::Button("Activate")) {
Events::SpawnerSpawn e;
e.Spawner = entity;
e.Parent = entity;
m_EventBroker->Publish(e);
}
}
return true;
}
@@ -369,6 +381,10 @@ bool EditorGUI::drawComponentField(ComponentWrapper& c, const ComponentInfo::Fie
ImGui::TextDisabled(field.Type.c_str());
}
if (dirty) {
c[field.Name].SetAllDirty();
}
ImGui::PopID();
return dirty;
@@ -381,14 +397,52 @@ bool EditorGUI::drawComponentField_Vector(ComponentWrapper &c, const ComponentIn
// 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;
//glm::vec3 tempVal = val;
glm::vec3 originalVal = val;
ImVec2 cursorPos = ImGui::GetCursorScreenPos();
glm::tvec3<bool> isSnapping(false, false, false);
bool changed = ImGui::DragFloat3("", glm::value_ptr(val), 0.066666f);
if (changed) {
// Make orentations have a period of 2*Pi
val = glm::fmod(val, glm::vec3(glm::two_pi<float>()));
for (int i = 0; i < 3; i++) {
if (val[i] < 0) {
val[i] += glm::two_pi<float>();
}
}
}
// Snap to angle
//float snapRange = glm::pi<float>() / 15.f;
//float snapAngle = glm::quarter_pi<float>();
//glm::vec3 snap = glm::fmod(val, glm::vec3(snapAngle));
//for (int i = 0; i < 3; i++) {
// isSnapping[i] = glm::abs(snap[i] - (snapRange / 2.f)) < snapRange;
//}
//if (changed && ImGui::IsMouseDown(0)) {
// glm::vec3 change = val - originalVal;
// for (int i = 0; i < 3; i++) {
// if (isSnapping[i] && glm::abs(change[i]) < snapRange) {
// val[i] -= snap[i] - snapRange;
// }
// }
//}
// Draw snapping outline
float width = ImGui::CalcItemWidth() / 3.f;;
float spacing = GImGui->Style.ItemInnerSpacing.x;
for (int i = 0; i < 3; i++) {
if (isSnapping[i]) {
ImVec2 pos = cursorPos + ImVec2(i * (width + spacing), 0.f);
ImRect bb(pos - ImVec2(1, 1), pos + ImVec2(width, 17));
auto window = ImGui::GetCurrentWindow();
const ImU32 col = window->Color(ImGuiCol_HeaderActive);
window->DrawList->AddRect(bb.Min, bb.Max, col, 3.f);
}
}
return changed;
} else {
return ImGui::DragFloat3("", glm::value_ptr(val), 0.1f, std::numeric_limits<float>::lowest(), std::numeric_limits<float>::max());
}
+4 -4
View File
@@ -7,7 +7,7 @@ EditorRenderSystem::EditorRenderSystem(SystemParams params, IRenderer* renderer,
{
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);
m_EditorCamera = new Camera((float)resolution.Width / resolution.Height, glm::radians(45.f), 0.001f, 500.f);
}
void EditorRenderSystem::Update(double dt)
@@ -52,9 +52,9 @@ void EditorRenderSystem::Update(double dt)
}
EntityWrapper entity(m_World, cModel.EntityID);
glm::mat4 modelMatrix = Transform::ModelMatrix(entity.ID, entity.World);
glm::mat4 modelMatrix = TransformSystem::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, glm::vec4(0), 0.f, false);
std::shared_ptr<ModelJob> modelJob = std::make_shared<ModelJob>(model, scene.Camera, modelMatrix, matGroup, cModel, entity.World, glm::vec4(0), 0.f, false, false);
if (cModel["Transparent"]) {
scene.Jobs.TransparentObjects.push_back(modelJob);
} else {
@@ -86,7 +86,7 @@ bool EditorRenderSystem::OnSetCamera(Events::SetCamera& e)
{
ComponentWrapper cTransform = e.CameraEntity["Transform"];
ComponentWrapper cCamera = e.CameraEntity["Camera"];
m_EditorCamera->SetFOV(static_cast<float>((double)cCamera["FOV"]));
m_EditorCamera->SetFOV(glm::radians(static_cast<float>((double)cCamera["FOV"])));
m_EditorCamera->SetNearClip(static_cast<float>((double)cCamera["NearClip"]));
m_EditorCamera->SetFarClip(static_cast<float>((double)cCamera["FarClip"]));
m_EditorCamera->SetPosition(cTransform["Position"]);
+49 -24
View File
@@ -2,8 +2,9 @@
#include "Core/UniformScaleSystem.h"
#include "Editor/EditorRenderSystem.h"
#include "Editor/EditorWidgetSystem.h"
#include "Core/EntityFile.h"
EditorSystem::EditorSystem(SystemParams params, IRenderer* renderer, RenderFrame* renderFrame)
EditorSystem::EditorSystem(SystemParams params, IRenderer* renderer, RenderFrame* renderFrame)
: System(params)
, m_Renderer(renderer)
, m_RenderFrame(renderFrame)
@@ -13,12 +14,12 @@ EditorSystem::EditorSystem(SystemParams params, IRenderer* renderer, RenderFrame
m_EditorWorldSystemPipeline->AddSystem<UniformScaleSystem>(0);
m_EditorWorldSystemPipeline->AddSystem<EditorWidgetSystem>(0, m_Renderer);
m_EditorWorldSystemPipeline->AddSystem<EditorRenderSystem>(1, m_Renderer, m_RenderFrame);
m_EditorCamera = importEntity(EntityWrapper(m_EditorWorld, EntityID_Invalid), "Schema/Entities/Empty.xml");
m_ActualCamera = m_EditorCamera;
m_EditorWorld->AttachComponent(m_EditorCamera.ID, "Transform");
m_EditorWorld->AttachComponent(m_EditorCamera.ID, "Camera");
m_EditorCameraInputController = new EditorCameraInputController<EditorSystem>(m_EventBroker, -1);
m_EditorCameraInputController = new EditorCameraInputController<EditorSystem>(m_EventBroker, -1, EntityWrapper::Invalid);
m_EditorGUI = new EditorGUI(m_World, m_EventBroker);
m_EditorGUI->SetEntitySelectedCallback(std::bind(&EditorSystem::OnEntitySelected, this, std::placeholders::_1));
@@ -46,6 +47,7 @@ EditorSystem::EditorSystem(SystemParams params, IRenderer* renderer, RenderFrame
Enable();
} else {
Disable();
m_EventBroker->Publish(Events::UnlockMouse());
}
}
@@ -70,21 +72,23 @@ void EditorSystem::Update(double dt)
m_EditorStats->Draw(actualDelta);
if (m_CurrentSelection.Valid() && m_Widget.Valid()) {
(glm::vec3&)m_Widget["Transform"]["Position"] = Transform::AbsolutePosition(m_CurrentSelection);
if (isAnyParentMissingTransform(m_CurrentSelection.ID)) {
return;
}
(Field<glm::vec3>)m_Widget["Transform"]["Position"] = TransformSystem::AbsolutePosition(m_CurrentSelection);
if (m_WidgetSpace == EditorGUI::WidgetSpace::Local) {
(glm::vec3&)m_Widget["Transform"]["Orientation"] = Transform::AbsoluteOrientationEuler(m_CurrentSelection);
m_Widget["Transform"]["Orientation"] = TransformSystem::AbsoluteOrientationEuler(m_CurrentSelection);
} else {
(glm::vec3&)m_Widget["Transform"]["Orientation"] = glm::vec3(0, 0, 0);
m_Widget["Transform"]["Orientation"] = glm::vec3(0, 0, 0);
}
}
m_EditorWorldSystemPipeline->Update(actualDelta);
ComponentWrapper& cameraTransform = m_EditorCamera["Transform"];
glm::vec3& ori = cameraTransform["Orientation"];
ori.x = m_EditorCameraInputController->Rotation().x;
ori.y = m_EditorCameraInputController->Rotation().y;
glm::vec3& pos = cameraTransform["Position"];
Field<glm::vec3> ori = cameraTransform["Orientation"];
ori.x(m_EditorCameraInputController->Rotation().x);
ori.y(m_EditorCameraInputController->Rotation().y);
Field<glm::vec3> pos = cameraTransform["Position"];
pos += m_EditorCameraInputController->Movement() * glm::inverse(glm::quat(ori)) * (float)actualDelta;
}
}
@@ -100,7 +104,7 @@ void EditorSystem::Enable()
eSetCamera.CameraEntity = m_EditorCamera;
m_EventBroker->Publish(eSetCamera);
if (m_ActualCamera.Valid()) {
(glm::vec3&)m_EditorCamera["Transform"]["Position"] = Transform::AbsolutePosition(m_ActualCamera);
(Field<glm::vec3>)m_EditorCamera["Transform"]["Position"] = TransformSystem::AbsolutePosition(m_ActualCamera);
}
// Pause the world we're editing
@@ -129,7 +133,7 @@ void EditorSystem::OnEntitySelected(EntityWrapper entity)
void EditorSystem::OnEntitySave(EntityWrapper entity, boost::filesystem::path filePath)
{
EntityFileWriter writer(filePath);
EntityXMLFileWriter writer(filePath);
writer.WriteEntity(entity.World, entity.ID);
}
@@ -201,17 +205,27 @@ bool EditorSystem::OnMousePress(const Events::MousePress& e)
bool EditorSystem::OnWidgetDelta(const Events::WidgetDelta& e)
{
if (m_CurrentSelection.Valid()) {
if (isAnyParentMissingTransform(m_CurrentSelection.ID)) {
return false;
}
if (m_WidgetSpace == EditorGUI::WidgetSpace::Global) {
glm::quat parentOrientation;
glm::vec3 parentScale(1.f);
EntityWrapper parent = m_CurrentSelection.Parent();
if (parent.Valid()) {
parentOrientation = glm::inverse(Transform::AbsoluteOrientation(parent));
parentOrientation = glm::inverse(TransformSystem::AbsoluteOrientation(parent));
parentScale = TransformSystem::AbsoluteScale(parent);
}
(glm::vec3&)m_CurrentSelection["Transform"]["Position"] += parentOrientation * e.Translation;
(Field<glm::vec3>)m_CurrentSelection["Transform"]["Position"] += parentOrientation * e.Translation / parentScale;
} else if (m_WidgetSpace == EditorGUI::WidgetSpace::Local) {
glm::vec3 parentScale(1.f);
EntityWrapper parent = m_CurrentSelection.Parent();
if (parent.Valid()) {
parentScale = TransformSystem::AbsoluteScale(parent);
}
glm::quat selectionOri = glm::quat((glm::vec3)m_CurrentSelection["Transform"]["Orientation"]);
glm::vec3 localTranslation = selectionOri * e.Translation;
(glm::vec3&)m_CurrentSelection["Transform"]["Position"] += localTranslation;
glm::vec3 localTranslation = selectionOri * e.Translation / parentScale;
(Field<glm::vec3>)m_CurrentSelection["Transform"]["Position"] += localTranslation;
}
m_EditorGUI->SetDirty(m_CurrentSelection);
}
@@ -260,12 +274,11 @@ EntityWrapper EditorSystem::importEntity(EntityWrapper parent, boost::filesystem
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&) {
EntityWrapper newEntity = entityFile->MergeInto(parent.World);
parent.World->SetParent(newEntity.ID, parent.ID);
return newEntity;
} catch (const std::exception& e) {
LOG_ERROR("Failed to import entity \"%s\": \"%s\"", filePath.string().c_str(), e.what());
return EntityWrapper::Invalid;
}
}
@@ -299,5 +312,17 @@ void EditorSystem::setWidgetMode(EditorGUI::WidgetMode mode)
break;
}
m_Widget["Transform"]["Position"] = Transform::AbsolutePosition(m_CurrentSelection.World, m_CurrentSelection.ID);
m_Widget["Transform"]["Position"] = TransformSystem::AbsolutePosition(m_CurrentSelection.World, m_CurrentSelection.ID);
}
bool EditorSystem::isAnyParentMissingTransform(EntityID entityID)
{
EntityWrapper entity(m_World, entityID);
while (entity.Parent().Valid()) {
if (!entity.HasComponent("Transform")) {
return true;
}
entity = entity.Parent();
}
return false;
}
+29 -8
View File
@@ -1,4 +1,5 @@
#include "GUI/ButtonSystem.h"
#include "Input/EInputCommand.h"
ButtonSystem::ButtonSystem(SystemParams params, IRenderer* renderer)
: System(params)
@@ -37,10 +38,20 @@ bool ButtonSystem::OnMousePress(const Events::MousePress& e)
m_PickEntity = EntityWrapper(m_World, m_PickData.Entity);
//You have clicked on a button entity, send pressed event.
Events::ButtonPressed ePressed;
ePressed.Entity = m_PickEntity;
ePressed.EntityName = m_PickEntity.Name();
m_EventBroker->Publish(ePressed);
if (m_World->HasComponent(m_PickData.Entity, "InputCmdButton")) {
Events::InputCommand eInputCmd;
eInputCmd.PlayerID = -1;
eInputCmd.Player = LocalPlayer;
EntityWrapper button = EntityWrapper(m_World, m_PickData.Entity);
eInputCmd.Command = (std::string)button["InputCmdButton"]["Command"];
eInputCmd.Value = (float)button["InputCmdButton"]["PressValue"];
m_EventBroker->Publish(eInputCmd);
} else {
Events::ButtonPressed ePressed;
ePressed.Entity = m_PickEntity;
ePressed.EntityName = m_PickEntity.Name();
m_EventBroker->Publish(ePressed);
}
}
}
}
@@ -55,10 +66,20 @@ bool ButtonSystem::OnMouseRelease(const Events::MouseRelease& e)
if(m_PickData.Entity != EntityID_Invalid && m_PickData.World == m_World) {
EntityWrapper ent = EntityWrapper(m_World, m_PickData.Entity);
Events::ButtonReleased eReleased;
eReleased.EntityName = m_PickEntity.Name();
eReleased.Entity = m_PickEntity;
m_EventBroker->Publish(eReleased);
if (m_World->HasComponent(m_PickData.Entity, "InputCmdButton")) {
Events::InputCommand eInputCmd;
eInputCmd.PlayerID = -1;
eInputCmd.Player = LocalPlayer;
EntityWrapper button = EntityWrapper(m_World, m_PickData.Entity);
eInputCmd.Command = (std::string)button["InputCmdButton"]["Command"];
eInputCmd.Value = 0;
m_EventBroker->Publish(eInputCmd);
} else {
Events::ButtonReleased eReleased;
eReleased.EntityName = m_PickEntity.Name();
eReleased.Entity = m_PickEntity;
m_EventBroker->Publish(eReleased);
}
if(m_World->HasComponent(m_PickData.Entity, "Button")) {
if (ent == m_PickEntity) {
-57
View File
@@ -1,57 +0,0 @@
#include "GUI/MainMenuSystem.h"
MainMenuSystem::MainMenuSystem(SystemParams params, IRenderer* renderer)
: System(params)
, ImpureSystem()
, m_Renderer(renderer)
{
EVENT_SUBSCRIBE_MEMBER(m_EPressed, &MainMenuSystem::OnButtonPress);
EVENT_SUBSCRIBE_MEMBER(m_EReleased, &MainMenuSystem::OnButtonRelease);
EVENT_SUBSCRIBE_MEMBER(m_EClicked, &MainMenuSystem::OnButtonClick);
}
void MainMenuSystem::Update(double dt)
{
}
bool MainMenuSystem::OnButtonClick(const Events::ButtonClicked& e)
{
if(e.EntityName == "Play") {
//Run play code
} else if(e.EntityName == "Connect") {
//Run connect code
} else if(e.EntityName == "Host") {
//Run host code
} else if(e.EntityName == "Quit") {
printf("No, you stay");
} else if (e.EntityName == "Res1080") {
glfwSetWindowSize(m_Renderer->Window(), 1920, 1080);
printf("\n1080");
} else if (e.EntityName == "Res720") {
glfwSetWindowSize(m_Renderer->Window(), 1280, 720);
glViewport(0, 0, 1280, 720);
printf("\n720");
} else if (e.EntityName == "Res480") {
glfwSetWindowSize(m_Renderer->Window(), 854, 480);
glViewport(0, 0, 854, 480);
printf("\n480");
} else if (e.EntityName == "FullScreen") {
printf("No fullscreen for now");
}
return true;
}
bool MainMenuSystem::OnButtonRelease(const Events::ButtonReleased& e)
{
return true;
}
bool MainMenuSystem::OnButtonPress(const Events::ButtonPressed& e)
{
return true;
}
+9 -5
View File
@@ -45,7 +45,7 @@ void InputProxy::Update(double dt)
}
}
void InputProxy::Process()
void InputProxy::Process(bool suppressNewEvents /*= false*/)
{
for (auto& pair : m_CommandHandlers) {
const std::string& command = pair.first;
@@ -62,8 +62,10 @@ void InputProxy::Process()
e.PlayerID = -1;
e.Command = command;
e.Value = currentValue;
m_EventBroker->Publish(e);
//LOG_DEBUG("Input: Published command %s=%f for player %i", e.Command.c_str(), e.Value, e.PlayerID);
if (!suppressNewEvents || e.Value == 0) {
m_EventBroker->Publish(e);
//LOG_DEBUG("Input: Published command %s=%f for player %i", e.Command.c_str(), e.Value, e.PlayerID);
}
m_LastCommandValues[command] = currentValue;
}
}
@@ -78,8 +80,10 @@ void InputProxy::Process()
e.Value += value;
}
//e.Value = std::max(-1.f, std::min(e.Value, 1.f));
m_EventBroker->Publish(e);
//LOG_DEBUG("Input: Published command %s=%f for player %i", e.Command.c_str(), e.Value, e.PlayerID);
if (!suppressNewEvents || e.Value == 0) {
m_EventBroker->Publish(e);
//LOG_DEBUG("Input: Published command %s=%f for player %i", e.Command.c_str(), e.Value, e.PlayerID);
}
}
m_CommandQueue.clear();
}
+143 -35
View File
@@ -1,4 +1,5 @@
#include "Network/Client.h"
using namespace boost::asio::ip;
Client::Client(World* world, EventBroker* eventBroker)
@@ -11,7 +12,7 @@ Client::Client(World* world, EventBroker* eventBroker)
auto config = ResourceManager::Load<ConfigFile>("Config.ini");
m_PlayerName = config->Get<std::string>("Networking.Name", "Raptorcopter");
m_SendInputIntervalMs = config->Get<int>("Networking.SendInputIntervalMs", 33);
m_SendInputInterval = config->Get<int>("Networking.SendInputIntervalMs", 33) / 1000.0;
LOG_INFO("Client initialized");
m_ServerlistRequest.Connect(m_PlayerName, "192.168.1.255", 32554);
@@ -33,7 +34,9 @@ void Client::Connect(std::string address, int port)
EVENT_SUBSCRIBE_MEMBER(m_EPlayerDamage, &Client::OnPlayerDamage);
EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &Client::OnPlayerSpawned);
EVENT_SUBSCRIBE_MEMBER(m_EDoubleJump, &Client::OnDoubleJump);
EVENT_SUBSCRIBE_MEMBER(m_EDashAbility, &Client::OnDashAbility);
EVENT_SUBSCRIBE_MEMBER(m_ESearchForServers, &Client::OnSearchForServers);
EVENT_SUBSCRIBE_MEMBER(m_EConnectRequest, &Client::OnConnectRequest);
auto config = ResourceManager::Load<ConfigFile>("Config.ini");
m_Address = address;
if (address.empty()) {
@@ -45,19 +48,22 @@ void Client::Connect(std::string address, int port)
}
}
void Client::Update()
void Client::Update(double dt)
{
m_EventBroker->Process<Client>();
while (m_Unreliable.IsSocketAvailable()) {
// Packet will get real data in receive
Packet packet(MessageType::Invalid);
m_Unreliable.Receive(packet);
if (packet.GetMessageType() == MessageType::Connect) {
parseUDPConnect(packet);
m_Unreliable.ReceivePackets();
}
// Packet will get real data in GetNextPacket()
Packet parsedPacket(MessageType::Invalid);
while (m_Unreliable.GetNextPacket(parsedPacket)) {
if (parsedPacket.GetMessageType() == MessageType::Connect) {
parseUDPConnect(parsedPacket);
} else {
parseMessageType(packet);
parseMessageType(parsedPacket);
}
}
while (m_Reliable.IsSocketAvailable()) {
// Packet will get real data in receive
Packet packet(MessageType::Invalid);
@@ -79,30 +85,45 @@ void Client::Update()
}
if (m_SearchingForServers) {
if (m_SearchingTime < (1000* (std::clock() - m_StartSearchTime) / (double)CLOCKS_PER_SEC)) {
m_TimeSearched += dt;
if (m_SearchingTime < m_TimeSearched) {
m_TimeSearched = 0;
m_SearchingForServers = false;
displayServerlist();
//displayServerlist();
Events::DisplayServerlist e;
e.Serverlist = m_Serverlist;
m_EventBroker->Publish(e);
}
}
if (m_IsConnected) {
// Don't send 1 input in 1 packet, bunch em up.
if (m_SendInputIntervalMs < (1000 * (std::clock() - m_TimeSinceSentInputs) / (double)CLOCKS_PER_SEC)) {
m_TimeSinceSentInputs += dt;
if (m_SendInputInterval < m_TimeSinceSentInputs) {
sendInputCommands();
m_TimeSinceSentInputs = std::clock();
m_TimeSinceSentInputs = 0;
}
// HACK: Send absolute player positions for now to avoid desync until we have reliable messages
sendLocalPlayerTransform();
hasServerTimedOut();
}
//Network::Update();
if (ImGui::BeginPopupModal("Disconnected", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Text("You have been disconnected from server.\n\n");
ImGui::SetCursorPosX(ImGui::GetContentRegionAvailWidth() - 120);
if (ImGui::Button("OK", ImVec2(120, 0))) {
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
}
void Client::parseMessageType(Packet& packet)
{
// Pop packetSize
packet.ReadPrimitive<int>();
// Pop packetSize, sequenceNumber and packetsInSequence.
popNetworkSegmentOfHeader(packet);
int messageType = packet.ReadPrimitive<int>();
if (messageType == -1)
return;
@@ -143,9 +164,18 @@ void Client::parseMessageType(Packet& packet)
case MessageType::OnDoubleJump:
parseDoubleJump(packet);
break;
case MessageType::OnDashEffect:
parseDashEffect(packet);
break;
case MessageType::AmmoPickup:
parseAmmoPickup(packet);
break;
case MessageType::RemoveWorld:
parseRemoveWorld(packet);
break;
case MessageType::KD:
parseKDEvent(packet);
break;
default:
break;
}
@@ -154,27 +184,30 @@ void Client::parseMessageType(Packet& packet)
void Client::parseUDPConnect(Packet& packet)
{
// Map ServerEntityID and your PlayerID
// TODO: If this is not received send a new connect message.
LOG_INFO("I be connected PogChamp");
}
void Client::parseTCPConnect(Packet& packet)
{
LOG_INFO("Received TCP connect from server");
// Pop size of message int
packet.ReadPrimitive<int>();
// Pop packetSize, group, groupIndex and groupSize.
popNetworkSegmentOfHeader(packet);
int messageType = packet.ReadPrimitive<int>();
// Read packet ID
m_PreviousPacketID = m_PacketID; // Set previous packet id
m_PacketID = packet.ReadPrimitive<int>(); //Read new packet id
// parse player id and other stuff
m_PlayerID = packet.ReadPrimitive<int>();
m_PlayerID = packet.ReadPrimitive<int>();
LOG_INFO("A Player connected");
// TODO: If this is not received send a new connect message.
Packet UnreliablePacket(MessageType::Connect, m_SendPacketID);
// Add player id and other stuff
packet.WritePrimitive(m_PlayerID);
m_Unreliable.Send(packet);
LOG_INFO("Sent UDP Connect Server");
// LOG_INFO("Sent UDP Connect Server");
}
void Client::parsePlayerConnected(Packet & packet)
@@ -200,10 +233,11 @@ void Client::parsePing()
void Client::parseServerlist(Packet& packet)
{
// Pop size, message type, and ID
packet.ReadPrimitive<int>();
// Pop packetSize, group, groupIndex and groupSize.
popNetworkSegmentOfHeader(packet);
packet.ReadPrimitive<int>();
packet.ReadPrimitive<int>();
std::string address = packet.ReadString();
int port = packet.ReadPrimitive<int>();
std::string serverName = packet.ReadString();
@@ -216,7 +250,7 @@ void Client::parseServerlist(Packet& packet)
void Client::parseKick()
{
LOG_WARNING("You have been kicked from the server.");
m_IsConnected = false;
disconnect();
}
void Client::parseSpawnEvents()
@@ -262,7 +296,7 @@ void Client::parseEntityDeletion(Packet & packet)
if (m_ServerIDToClientID.find(entityToDelete) != m_ServerIDToClientID.end()) {
EntityID localEntity = m_ServerIDToClientID.at(entityToDelete);
if (m_World->ValidEntity(localEntity)) {
if (m_World->HasComponent(localEntity,"Player")) {
if (m_World->HasComponent(localEntity, "Player")) {
Events::PlayerDeath e;
e.Player = EntityWrapper(m_World, localEntity);
m_EventBroker->Publish(e);
@@ -297,14 +331,51 @@ void Client::parseDoubleJump(Packet & packet)
}
}
void Client::parseDashEffect(Packet& packet)
{
EntityID serverID = packet.ReadPrimitive<EntityID>();
if (!serverClientMapsHasEntity(serverID)) {
return;
}
Events::DashAbility e;
e.Player = m_ServerIDToClientID.at(serverID);
if (e.Player != m_LocalPlayer.ID) {
m_EventBroker->Publish(e);
}
}
void Client::parseAmmoPickup(Packet & packet)
{
{
Events::AmmoPickup e;
e.AmmoGain = packet.ReadPrimitive<int>();
e.Player = m_LocalPlayer;
m_EventBroker->Publish(e);
}
void Client::parseRemoveWorld(Packet & packet)
{
removeWorld();
Events::Reset e;
m_EventBroker->Publish(e);
}
void Client::parseKDEvent(Packet & packet)
{
Events::KillDeath e;
e.Casualty = packet.ReadPrimitive<int>();
e.CasualtyClass = packet.ReadPrimitive<int>();
e.CasualtyName = packet.ReadString();
e.CasualtyTeam = packet.ReadPrimitive<int>();
e.Killer = packet.ReadPrimitive<int>();
e.KillerClass = packet.ReadPrimitive<int>();
e.KillerName = packet.ReadString();
e.KillerTeam = packet.ReadPrimitive<int>();
m_EventBroker->Publish(e);
}
void Client::updateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID)
{
for (auto field : componentInfo.FieldsInOrder) {
@@ -388,7 +459,7 @@ void Client::parseSnapshot(Packet& packet)
if (m_SnapshotFilter != nullptr) {
shouldApply = m_SnapshotFilter->FilterComponent(localEntity, newComponent);
}
if (shouldApply) {
if (shouldApply) {
ComponentWrapper currentComponent = m_World->GetComponent(localEntityID, componentType);
memcpy(currentComponent.Data, newComponent.Data, componentInfo.Stride);
}
@@ -435,22 +506,23 @@ void Client::parseSnapshot(Packet& packet)
void Client::disconnect()
{
removeWorld();
m_IsConnected = false;
m_PreviousPacketID = 0;
m_PacketID = 0;
Packet packet(MessageType::Disconnect, m_SendPacketID);
m_Reliable.Send(packet);
m_Unreliable.Disconnect();
m_Reliable.Disconnect();
Events::PlayerDisconnected e;
e.Entity = m_LocalPlayer.ID;
e.PlayerID = -1;
m_EventBroker->Publish(e);
createMainMenu();
}
bool Client::OnInputCommand(const Events::InputCommand & e)
{
// TEMP
if (e.Command == "SearchForServers" && e.Value > 0) {
Events::SearchForServers e;
m_EventBroker->Publish(e);
}
if (e.PlayerID != -1) {
return false;
}
@@ -518,12 +590,41 @@ bool Client::OnPlayerSpawned(const Events::PlayerSpawned& e)
return true;
}
bool Client::OnDashAbility(const Events::DashAbility& e)
{
if (!clientServerMapsHasEntity(e.Player) || e.Player != m_LocalPlayer.ID) {
return false;
}
Packet packet(MessageType::OnDashEffect);
packet.WritePrimitive(m_ClientIDToServerID.at(e.Player));
m_Reliable.Send(packet);
return true;
}
bool Client::OnConnectRequest(const Events::ConnectRequest& e)
{
removeWorld();
if (m_Reliable.Connect(m_PlayerName, e.IP, e.Port)) {
m_Unreliable.Connect(m_PlayerName, e.IP, e.Port);
// The client sent a successful connect message
return true;
} else {
// The client could not send a successful connect message
createMainMenu();
// Load the main menu again ?
return false;
}
return false;
}
bool Client::OnSearchForServers(const Events::SearchForServers& e)
{
m_SearchingForServers = true;
m_StartSearchTime = std::clock();
m_TimeSearched = 0;
m_Serverlist.clear();
LOG_INFO("Searching for LAN servers...\n");
Packet packet(MessageType::ServerlistRequest);
m_ServerlistRequest.Broadcast(packet, 13); // TODO: Config
return true;
@@ -566,8 +667,8 @@ void Client::sendLocalPlayerTransform()
Packet packet(MessageType::PlayerTransform, m_SendPacketID);
ComponentWrapper cTransform = m_LocalPlayer["Transform"];
glm::vec3& position = cTransform["Position"];
glm::vec3& orientation = cTransform["Orientation"];
const glm::vec3& position = cTransform["Position"];
const glm::vec3& orientation = cTransform["Orientation"];
packet.WritePrimitive(position.x);
packet.WritePrimitive(position.y);
packet.WritePrimitive(position.z);
@@ -602,6 +703,7 @@ void Client::hasServerTimedOut()
if (timeSincePing > m_TimeoutMs) {
// Clear everything and go to menu.
LOG_INFO("Server has timed out, returning to menu, Beep Boop.");
ImGui::OpenPopup("Disconnected");
disconnect();
}
}
@@ -645,6 +747,12 @@ void Client::displayServerlist()
}
}
void Client::createMainMenu()
{
auto entityFile = ResourceManager::Load<EntityFile>("Schema/Entities/StartMenu.xml");
entityFile->MergeInto(m_World);
}
bool Client::clientServerMapsHasEntity(EntityID clientEntityID)
{
if (m_ClientIDToServerID.find(clientEntityID) != m_ClientIDToServerID.end()) {
+22 -1
View File
@@ -9,7 +9,7 @@ Network::Network(World* world, EventBroker* eventBroker)
m_TimeoutMs = config->Get<int>("Networking.TimeoutMs", 20000);
}
void Network::Update()
void Network::Update(double dt)
{
updateNetworkData();
}
@@ -83,3 +83,24 @@ void Network::updateNetworkData()
m_NetworkData.DataReceivedThisInterval = 0;
}
}
void Network::popNetworkSegmentOfHeader(Packet & packet)
{
// Pop packetSize, group, groupIndex and groupSize.
packet.ReadPrimitive<int>();
packet.ReadPrimitive<int>();
packet.ReadPrimitive<int>();
packet.ReadPrimitive<int>();
}
void Network::removeWorld()
{
std::vector<EntityID> childrenToBeDeleted;
auto rootEntites = m_World->GetDirectChildren(EntityID_Invalid);
for (auto it = rootEntites.first; it != rootEntites.second; it++) {
childrenToBeDeleted.push_back(it->second);
}
for (int i = 0; i < childrenToBeDeleted.size(); ++i) {
m_World->DeleteEntity(childrenToBeDeleted[i]);
}
}
+72 -14
View File
@@ -3,16 +3,22 @@
Packet::Packet(MessageType type, unsigned int& packetID)
{
m_Data = new char[m_MaxPacketSize];
Init(type, packetID);
Init(type, packetID, 1, 1, -1);
}
// Create message
Packet::Packet(char* data, const size_t sizeOfPacket)
{
// Create message header
// allocate memory for size of packet, sequenceNumber and totalPacketesInSequence
m_ReturnDataOffset = 0;
m_Offset = 0;
// Resize message
m_MaxPacketSize = sizeOfPacket;
// Copy data newly allocated memory
m_Data = new char[sizeOfPacket];
unsigned int dummy = 0;
Init(MessageType::Invalid, dummy, 0, 0, 0);
memcpy(m_Data, data, sizeOfPacket);
m_Offset = sizeOfPacket;
}
@@ -21,7 +27,7 @@ Packet::Packet(MessageType type)
{
m_Data = new char[m_MaxPacketSize];
unsigned int dummy = 0;
Init(type, dummy);
Init(type, dummy, 1, 1, -1);
}
Packet::~Packet()
@@ -29,16 +35,30 @@ Packet::~Packet()
delete[] m_Data;
}
void Packet::Init(MessageType type, unsigned int & packetID)
void Packet::Init(MessageType type, unsigned int & packetID,
int groupIndex, int groupSize, int group)
{
m_ReturnDataOffset = 0;
m_Offset = 0;
// Create message header
// allocate memory for size of packet(only used in tcp)
// allocate memory for size of packet, sequenceNumber and totalPacketesInSequence
packetSizeOffset = m_Offset;
WritePrimitive<int>(0);
// packetGroup is the group the packet is in
groupOffset = m_Offset;
WritePrimitive<int>(group);
// What index the packet has in the packetGroup
groupIndexOffset = m_Offset;
WritePrimitive(groupIndex);
// The total amount of packets in a packetGroup
groupSizeOffset = m_Offset;
WritePrimitive(groupSize);
// Add message type
int messageType = static_cast<int>(type);
messageTypeOffset = m_Offset;
WritePrimitive<int>(messageType);
// Packet ID
packetIDOffset = m_Offset;
WritePrimitive<int>(packetID);
packetID++;
m_HeaderSize = m_Offset;
@@ -49,18 +69,24 @@ void Packet::WriteString(const std::string& str)
// Message, add one extra byte for null terminator
size_t 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);
if (m_MaxPacketSize >= 32000) {
//LOG_WARNING("Package::WriteString(): New size is huge %i bytes\n", m_MaxPacketSize*2);
}
resizeData();
}
memcpy(m_Data + m_Offset, str.data(), sizeOfString * sizeof(char));
m_Offset += sizeOfString * sizeof(char);
memcpy(m_Data + m_Offset, str.data(), str.size() * sizeof(char));
m_Offset += str.size() * sizeof(char);
m_Data[m_Offset] = '\0';
m_Offset += 1;
}
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);
if (m_MaxPacketSize >= 32000) {
//LOG_WARNING("Package::WriteData(): New size is huge %i bytes\n", m_MaxPacketSize*2);
}
while (m_Offset + sizeOfData > m_MaxPacketSize) {
resizeData();
}
@@ -98,8 +124,7 @@ void Packet::ReconstructFromData(char * data, size_t sizeOfData)
void Packet::UpdateSize()
{
int whatisoffset = m_Offset;
memcpy(m_Data, &m_Offset, sizeof(int));
memcpy(m_Data + packetSizeOffset, &m_Offset, sizeof(int));
}
char * Packet::ReadData(int sizeOfData)
@@ -117,14 +142,47 @@ void Packet::ChangePacketID(unsigned int & packetID)
{
packetID = packetID + 1;
// Overwrite old PacketID
memcpy(m_Data + 2*sizeof(int), &packetID, sizeof(int));
memcpy(m_Data + packetIDOffset, &packetID, sizeof(int));
}
void Packet::ChangeGroupIndex(int groupIndex)
{
memcpy(m_Data + groupIndexOffset, &groupIndex, sizeof(int));
}
void Packet::ChangeGroupSize(int groupSize)
{
memcpy(m_Data + groupSizeOffset, &groupSize, sizeof(int));
}
void Packet::ChangeGroup(int group)
{
memcpy(m_Data + groupOffset, &group, sizeof(int));
}
MessageType Packet::GetMessageType()
{
MessageType messagType;
memcpy(&messagType, m_Data + sizeof(int), sizeof(int));
return messagType;
return *reinterpret_cast<MessageType*>(m_Data + messageTypeOffset);
}
size_t Packet::Group()
{
return *reinterpret_cast<size_t*>(m_Data + groupOffset);
}
size_t Packet::GroupIndex()
{
return *reinterpret_cast<size_t*>(m_Data + groupIndexOffset);
}
size_t Packet::GroupSize()
{
return *reinterpret_cast<size_t*>(m_Data + groupSizeOffset);
}
size_t Packet::PacketID()
{
return *reinterpret_cast<size_t*>(m_Data + packetIDOffset);
}
void Packet::resizeData()
+162 -52
View File
@@ -5,8 +5,10 @@ Server::Server(World* world, EventBroker* eventBroker, int port)
, m_ServerlistRequest(13)
{
ConfigFile* config = ResourceManager::Load<ConfigFile>("Config.ini");
snapshotInterval = 1000 * config->Get<float>("Networking.SnapshotInterval", 0.05f);
pingIntervalMs = config->Get<float>("Networking.PingIntervalMs", 1000);
snapshotInterval = config->Get<float>("Networking.SnapshotInterval", 0.05);
pingInterval = config->Get<float>("Networking.PingIntervalMs", 1000) / 1000.0;
m_ServerName = config->Get<std::string>("Networking.Name", "Unnamed");
// Subscribe to events
EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &Server::OnInputCommand);
EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &Server::OnPlayerSpawned);
@@ -14,6 +16,8 @@ Server::Server(World* world, EventBroker* eventBroker, int port)
EVENT_SUBSCRIBE_MEMBER(m_EComponentDeleted, &Server::OnComponentDeleted);
EVENT_SUBSCRIBE_MEMBER(m_EPlayerDamage, &Server::OnPlayerDamage);
EVENT_SUBSCRIBE_MEMBER(m_EAmmoPickup, &Server::OnAmmoPickup);
EVENT_SUBSCRIBE_MEMBER(m_EPlayerDeath, &Server::OnPlayerDeath);
EVENT_SUBSCRIBE_MEMBER(m_EWin, &Server::OnWin);
// BindWW
if (port == 0) {
port = config->Get<float>("Networking.Port", 27666);
@@ -27,7 +31,7 @@ Server::~Server()
}
void Server::Update()
void Server::Update(double dt)
{
m_Reliable.AcceptNewConnections(m_NextPlayerID, m_ConnectedPlayers);
@@ -66,9 +70,11 @@ void Server::Update()
localArea.Endpoint = boost::asio::ip::udp::endpoint();
m_ServerlistRequest.Receive(packet, localArea);
if (packet.GetMessageType() == MessageType::ServerlistRequest) {
packet.ReadPrimitive<int>(); // Pop size
packet.ReadPrimitive<int>(); // Pop MsgType
packet.ReadPrimitive<int>(); // Pop packet ID
// Pop header
popNetworkSegmentOfHeader(packet);
packet.ReadPrimitive<int>();
packet.ReadPrimitive<int>();
int port = packet.ReadPrimitive<int>();
std::string address = localArea.Endpoint.address().to_string();
parseServerlistRequest(boost::asio::ip::udp::endpoint(boost::asio::ip::address().from_string(address), port));
@@ -81,34 +87,52 @@ void Server::Update()
}
m_PlayersToDisconnect.clear();
std::clock_t currentTime = std::clock();
// Send snapshot
if (snapshotInterval < (1000 * (currentTime - previousSnapshotMessage) / (double)CLOCKS_PER_SEC)) {
previousSnapshotMessage += dt;
if (snapshotInterval < previousSnapshotMessage) {
sendSnapshot();
previousSnapshotMessage = currentTime;
previousSnapshotMessage = 0;
}
// Send pings each
if (pingIntervalMs < (1000 * (currentTime - previousePingMessage) / (double)CLOCKS_PER_SEC)) {
previousPingMessage += dt;
if (pingInterval < previousPingMessage) {
sendPing();
previousePingMessage = currentTime;
previousPingMessage = 0;
}
// Time out logic
if (checkTimeOutInterval < (1000 * (currentTime - timOutTimer) / (double)CLOCKS_PER_SEC)) {
timeOutTimer += dt;
if (checkTimeOutInterval < timeOutTimer) {
checkForTimeOuts();
timOutTimer = currentTime;
timeOutTimer = 0;
}
m_EventBroker->Process<Server>();
if (isReadingData) {
Network::Update();
Network::Update(dt);
}
if (m_GameIsOver) {
auto pool = m_World->GetComponents("CapturePointGameMode");
if (pool != nullptr && pool->size() > 0) {
// Take the first CapturePointGameMode component found.
ComponentWrapper& modeComponent = *pool->begin();
// Decrease timer.
Field<double> timer = modeComponent["ResetCountdown"];
timer -= dt;
if (timer < 0) {
resetMap();
}
} else {
resetMap();
}
}
}
void Server::parseMessageType(Packet& packet)
{
// Pop packetSize which is used by TCP Client to
// Pop packetSize, sequenceNumber and packetsInSequence.
// create a packet of the correct size
packet.ReadPrimitive<int>();
popNetworkSegmentOfHeader(packet);
int messageType = packet.ReadPrimitive<int>(); // Read what type off message was sent from server
// Read packet ID
@@ -141,6 +165,9 @@ void Server::parseMessageType(Packet& packet)
case MessageType::OnDoubleJump:
parseDoubleJump(packet);
break;
case MessageType::OnDashEffect:
parseDashEffect(packet);
break;
default:
break;
}
@@ -156,10 +183,7 @@ void Server::reliableBroadcast(Packet& packet)
void Server::unreliableBroadcast(Packet& packet)
{
for (auto& kv : m_ConnectedPlayers) {
packet.ChangePacketID(kv.second.PacketID);
m_Unreliable.Send(packet, kv.second);
}
m_Unreliable.SendToConnectedPlayers(packet, m_ConnectedPlayers);
}
// Send snapshot fields
@@ -171,6 +195,13 @@ void Server::sendSnapshot()
unreliableBroadcast(packet);
}
// Send snapshot fields
void Server::createWorldSnapshot(Packet& packet)
{
addInputCommandsToPacket(packet);
addChildrenToPacket(packet, EntityID_Invalid);
}
void Server::addInputCommandsToPacket(Packet& packet)
{
// Number of input commands
@@ -218,7 +249,7 @@ void Server::addPlayersToPacket(Packet & packet, EntityID entityID)
for (auto& componentField : componentWrapper.Info.FieldsInOrder) {
ComponentInfo::Field_t fieldInfo = componentWrapper.Info.Fields.at(componentField);
if (fieldInfo.Type == "string") {
std::string& value = componentWrapper[componentField];
const std::string& value = componentWrapper[componentField];
packet.WriteString(value);
} else {
packet.WriteData(componentWrapper.Data + fieldInfo.Offset, fieldInfo.Stride);
@@ -262,7 +293,7 @@ void Server::addChildrenToPacket(Packet & packet, EntityID entityID)
for (auto& componentField : componentWrapper.Info.FieldsInOrder) {
ComponentInfo::Field_t fieldInfo = componentWrapper.Info.Fields.at(componentField);
if (fieldInfo.Type == "string") {
std::string& value = componentWrapper[componentField];
const std::string& value = componentWrapper[componentField];
packet.WriteString(value);
} else {
packet.WriteData(componentWrapper.Data + fieldInfo.Offset, fieldInfo.Stride);
@@ -293,8 +324,6 @@ void Server::sendPing()
reliableBroadcast(packet);
}
void Server::checkForTimeOuts()
{
double startPing = 1000 * m_StartPingTime
@@ -311,22 +340,21 @@ void Server::checkForTimeOuts()
}
}
}
for (size_t i = 0; i < playersToRemove.size(); i++) {
for (int i = playersToRemove.size() - 1; i >= 0; i--) {
disconnect(playersToRemove.at(i));
}
}
void Server::parseUDPConnect(Packet & packet)
{
// Pop size of message int
packet.ReadPrimitive<int>();
//Pop packetSize, sequenceNumber and packetsInSequence.
popNetworkSegmentOfHeader(packet);
int messageType = packet.ReadPrimitive<int>();
// Read packet ID
m_PreviousPacketID = m_PacketID; // Set previous packet id
m_PacketID = packet.ReadPrimitive<int>(); //Read new packet id
// parse player id and other stuff
PlayerID playerID = packet.ReadPrimitive<int>();
// Do something here?
boost::asio::ip::udp::endpoint endpoint(m_Address, m_Port);
m_ConnectedPlayers.at(playerID).Endpoint = endpoint;
LOG_INFO("parseUDPConnect: Spectator \"%s\" connected on IP: %s", m_ConnectedPlayers.at(playerID).Name.c_str(), m_ConnectedPlayers.at(playerID).Endpoint.address().to_string().c_str());
@@ -338,8 +366,9 @@ void Server::parseUDPConnect(Packet & packet)
void Server::parseTCPConnect(Packet & packet)
{
// Pop size of message int
packet.ReadPrimitive<int>();
// Pop packetSize, sequenceNumber and packetsInSequence.
popNetworkSegmentOfHeader(packet);
int messageType = packet.ReadPrimitive<int>();
// Read packet ID
m_PreviousPacketID = m_PacketID; // Set previous packet id
@@ -347,9 +376,9 @@ void Server::parseTCPConnect(Packet & packet)
LOG_INFO("Parsing connections");
// Check if player is already connected
// Ska vara till lagd i TCPServer receive
PlayerID playerID = GetPlayerIDFromEndpoint();
PlayerID playerID = getPlayerIDFromEndpoint();
if (playerID == -1) {
LOG_INFO("Server::parseTCPConnect: Not connected");
return;
}
// Create a new player
@@ -360,6 +389,11 @@ void Server::parseTCPConnect(Packet & packet)
m_ConnectedPlayers.at(playerID).TCPAddress = m_Address;
m_ConnectedPlayers.at(playerID).TCPPort = m_Port;
Events::PlayerConnected e;
e.PlayerID = playerID;
e.PlayerName = m_ConnectedPlayers.at(playerID).Name;
m_EventBroker->Publish(e);
LOG_INFO("parseTCPConnect: Spectator \"%s\" connected on IP: %s", m_ConnectedPlayers.at(playerID).Name.c_str(),
m_ConnectedPlayers.at(playerID).TCPAddress.to_string().c_str());
@@ -367,11 +401,10 @@ void Server::parseTCPConnect(Packet & packet)
Packet connnectPacket(MessageType::Connect, m_ConnectedPlayers.at(playerID).PacketID);
// Write playerID to packet
connnectPacket.WritePrimitive(playerID);
m_Reliable.Send(connnectPacket);
m_Reliable.Send(connnectPacket, m_ConnectedPlayers.at(playerID));
Packet firstSnapshot(MessageType::Snapshot);
addInputCommandsToPacket(firstSnapshot);
addChildrenToPacket(firstSnapshot, EntityID_Invalid);
createWorldSnapshot(firstSnapshot);
m_Reliable.Send(firstSnapshot);
// Send notification that a player has connected
@@ -398,7 +431,7 @@ void Server::parseServerlistRequest(boost::asio::ip::udp::endpoint endpoint)
Packet packet(MessageType::ServerlistRequest);
packet.WriteString(m_Reliable.Address());
packet.WritePrimitive<int>(m_Reliable.Port());
packet.WriteString("SERVERNAME");
packet.WriteString(m_ServerName);
packet.WritePrimitive<int>(m_ConnectedPlayers.size());
m_ServerlistRequest.Send(packet);
}
@@ -480,7 +513,7 @@ bool Server::OnEntityDeleted(const Events::EntityDeleted & e)
{
if (!e.Cascaded) {
Packet packet = Packet(MessageType::EntityDeleted);
packet.WritePrimitive<EntityID>(e.DeletedEntity);
packet.WritePrimitive<EntityID>(e.DeletedEntity.ID);
reliableBroadcast(packet);
}
return false;
@@ -523,10 +556,66 @@ bool Server::OnAmmoPickup(const Events::AmmoPickup & e)
return true;
}
bool Server::OnPlayerDeath(const Events::PlayerDeath& e)
{
Events::KillDeath eKD;
auto entity = e;
eKD.Casualty = getPlayerIDFromEntityID(e.Player.ID);
eKD.Killer = getPlayerIDFromEntityID(e.Killer.ID);
eKD.CasualtyName = m_ConnectedPlayers.at(getPlayerIDFromEntityID(e.Player.ID)).Name;
eKD.KillerName = m_ConnectedPlayers.at(getPlayerIDFromEntityID(e.Killer.ID)).Name;
if(entity.Player.HasComponent("Team")) {
eKD.CasualtyTeam = (const int&)entity.Player["Team"]["Team"];
}
if (entity.Killer.HasComponent("Team")) {
eKD.KillerTeam = (const int&)entity.Killer["Team"]["Team"];
}
if(entity.Player.HasComponent("DashAbility")) {
eKD.CasualtyClass = 1;
} else if (entity.Player.HasComponent("ShieldAbility")) {
eKD.CasualtyClass = 2;
} else if (entity.Player.HasComponent("SprintAbility")) {
eKD.CasualtyClass = 3;
}
if (entity.Killer.HasComponent("DashAbility")) {
eKD.KillerClass = 1;
} else if (entity.Killer.HasComponent("ShieldAbility")) {
eKD.KillerClass = 2;
} else if (entity.Killer.HasComponent("SprintAbility")) {
eKD.KillerClass = 3;
}
m_EventBroker->Publish(eKD);
Packet kdPacket(MessageType::KD);
kdPacket.WritePrimitive(eKD.Casualty);
kdPacket.WritePrimitive(eKD.CasualtyClass);
kdPacket.WriteString(eKD.CasualtyName);
kdPacket.WritePrimitive(eKD.CasualtyTeam);
kdPacket.WritePrimitive(eKD.Killer);
kdPacket.WritePrimitive(eKD.KillerClass);
kdPacket.WriteString(eKD.KillerName);
kdPacket.WritePrimitive(eKD.KillerTeam);
reliableBroadcast(kdPacket);
return false;
}
bool Server::OnWin(const Events::Win & e)
{
// Postpone the gameover reset
m_GameIsOver = true;
return true;
}
void Server::parseClientPing()
{
LOG_INFO("%i: Parsing ping", m_PacketID);
PlayerID player = GetPlayerIDFromEndpoint();
PlayerID player = getPlayerIDFromEndpoint();
if (player == -1) {
return;
}
@@ -555,11 +644,16 @@ bool Server::parseDoubleJump(Packet & packet)
return true;
}
void Server::parseDashEffect(Packet& packet)
{
reliableBroadcast(packet);
}
void Server::parseOnInputCommand(Packet& packet)
{
PlayerID player = -1;
// Check which player it was who sent the message
player = GetPlayerIDFromEndpoint();
player = getPlayerIDFromEndpoint();
if (player != -1) {
while (packet.DataReadSize() < packet.Size()) {
Events::InputCommand e;
@@ -578,7 +672,7 @@ void Server::parseOnInputCommand(Packet& packet)
void Server::parsePlayerTransform(Packet& packet)
{
PlayerID playerID = GetPlayerIDFromEndpoint();
PlayerID playerID = getPlayerIDFromEndpoint();
if (playerID == -1) {
return;
}
@@ -614,20 +708,10 @@ void Server::parsePlayerTransform(Packet& packet)
bool Server::shouldSendToClient(EntityWrapper childEntity)
{
auto children = m_World->GetDirectChildren(childEntity.ID);
for (auto it = children.first; it != children.second; it++) {
EntityWrapper child(m_World, it->second);
if (child.HasComponent("CapturePoint") || child.HasComponent("HealthPickup")
|| child.HasComponent("AmmoPickup")) {
return true;
}
}
return childEntity.HasComponent("Player") || childEntity.FirstParentWithComponent("Player").Valid()
|| childEntity.HasComponent("CapturePoint") || childEntity.HasComponent("HealthPickup")
|| childEntity.HasComponent("AmmoPickup");
return childEntity.HasComponent("NetworkComponent") || childEntity.FirstParentWithComponent("NetworkComponent").Valid();
}
PlayerID Server::GetPlayerIDFromEndpoint()
PlayerID Server::getPlayerIDFromEndpoint()
{
// check both tcp and udp connection
for (auto& kv : m_ConnectedPlayers) {
@@ -639,4 +723,30 @@ PlayerID Server::GetPlayerIDFromEndpoint()
}
}
return -1;
}
PlayerID Server::getPlayerIDFromEntityID(EntityID entityID)
{
for (auto& kv : m_ConnectedPlayers) {
if (entityID == kv.second.EntityID) {
return kv.first;
}
}
return -1;
}
void Server::resetMap()
{
m_GameIsOver = false;
Events::Reset reset;
m_EventBroker->Publish(reset);
Packet removeMap(MessageType::RemoveWorld);
reliableBroadcast(removeMap);
removeWorld();
// Hardcoded for now.
auto entityFile = ResourceManager::Load<EntityFile>("Schema/Entities/CP_Rocky2.xml");
entityFile->MergeInto(m_World);
Packet newWorld(MessageType::Snapshot);
createWorldSnapshot(newWorld);
reliableBroadcast(newWorld);
}
+22 -30
View File
@@ -3,24 +3,14 @@
using namespace boost::asio::ip;
TCPClient::TCPClient()
{
}
{ }
TCPClient::~TCPClient()
{
}
{ }
void TCPClient::Connect(std::string playerName, std::string address, int port)
bool TCPClient::Connect(std::string playerName, std::string address, int port)
{
if (m_Socket) {
if (m_IsConnected) {
Packet packet(MessageType::Connect, m_SendPacketID);
packet.WriteString(playerName);
Send(packet);
LOG_INFO("Connect message sent again!");
}
}
else if (!m_IsConnected) {
if (!m_Socket) {
boost::system::error_code error = boost::asio::error::host_not_found;
m_Endpoint = tcp::endpoint(boost::asio::ip::address::from_string(address), port);
m_Socket = std::unique_ptr<tcp::socket>(new tcp::socket(m_IOService));
@@ -34,24 +24,20 @@ void TCPClient::Connect(std::string playerName, std::string address, int port)
packet.WriteString(playerName);
Send(packet);
LOG_INFO("Connect message sent!");
}
// If error
else {
return true;
} else { // If error
m_Socket->close();
m_Socket = nullptr;
return false;
}
}
}
void TCPClient::Disconnect()
{
if (!m_IsConnected) {
return;
}
{
m_Socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both);
m_Socket->close();
m_Socket = nullptr;
m_IsConnected = false;
}
void TCPClient::Receive(Packet& packet)
@@ -63,7 +49,7 @@ void TCPClient::Receive(Packet& packet)
}
size_t TCPClient::readBuffer()
{
{
if (!m_Socket) {
return 0;
}
@@ -74,7 +60,10 @@ size_t TCPClient::readBuffer()
boost::asio::ip::tcp::socket::message_peek, error);
unsigned int sizeOfPacket = 0;
memcpy(&sizeOfPacket, m_ReadBuffer, sizeof(int));
if (sizeOfPacket > m_Socket->available()) {
LOG_WARNING("TCPClient::readBuffer(): We haven't got the whole packet yet.");
//return 0;
}
// if the buffer is to small increase the size of it
// TODO if message is huge 1 time the buffer will not decrease.
if (sizeOfPacket > m_BufferSize) {
@@ -82,12 +71,15 @@ size_t TCPClient::readBuffer()
m_ReadBuffer = new char[sizeOfPacket];
m_BufferSize = sizeOfPacket;
}
// Read the rest of the message
size_t bytesReceived = m_Socket->read_some(boost
::asio::buffer((void*)(m_ReadBuffer), sizeOfPacket),
error);
if (error) {
//LOG_ERROR("receive: %s", error.message().c_str());
size_t bytesReceived = 0;
while (sizeOfPacket > bytesReceived) {
// Read the rest of the message
bytesReceived += m_Socket->read_some(boost
::asio::buffer((void*)(m_ReadBuffer + bytesReceived), sizeOfPacket - bytesReceived),
error);
if (error) {
//LOG_ERROR("receive: %s", error.message().c_str());
}
}
if (sizeOfPacket > 1000000)
LOG_WARNING("The packets received are bigger than 1MB");
+5 -1
View File
@@ -48,6 +48,7 @@ void TCPServer::Send(Packet & packet, PlayerDefinition & playerDefinition)
{
packet.UpdateSize();
try {
// Crashed once TCPSocket was NULL
int bytesSent = playerDefinition.TCPSocket->send(
boost::asio::buffer(packet.Data(), packet.Size()),
0);
@@ -106,7 +107,10 @@ int TCPServer::readBuffer(PlayerDefinition & playerDefinition)
boost::asio::ip::tcp::socket::message_peek, error);
unsigned int sizeOfPacket = 0;
memcpy(&sizeOfPacket, m_ReadBuffer, sizeof(int));
if (sizeOfPacket > playerDefinition.TCPSocket->available()) {
LOG_WARNING("TCPServer::readBuffer(): We haven't got the whole packet yet.");
return 0;
}
// if the buffer is to small increase the size of it
if (sizeOfPacket > m_BufferSize) {
delete[] m_ReadBuffer;
+142 -13
View File
@@ -1,38 +1,51 @@
#include "Network/UDPClient.h"
#include "boost/asio/basic_datagram_socket.hpp"
using namespace boost::asio::ip;
UDPClient::UDPClient()
{
}
{ }
UDPClient::~UDPClient()
{
}
{ }
void UDPClient::Connect(std::string playerName, std::string address, int port)
bool UDPClient::Connect(std::string playerName, std::string address, int port)
{
if (m_Socket) {
return;
return false;
}
m_ReceiverEndpoint = udp::endpoint(boost::asio::ip::address().from_string(address), port);
m_Socket = boost::shared_ptr<boost::asio::ip::udp::socket>(new boost::asio::ip::udp::socket(m_IOService));
m_Socket->open(boost::asio::ip::udp::v4());
boost::asio::socket_base::receive_buffer_size option(m_SizeOfSocketBuffer);
m_Socket->set_option(option);
return true;
}
void UDPClient::Disconnect()
{
m_Socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both);
m_Socket->close();
m_Socket = nullptr;
m_LastReceivedSnapshotGroup = 0;
m_PacketSegmentMap.clear();
PacketID m_SendPacketID = 0;
}
void UDPClient::Receive(Packet& packet)
{
int bytesRead = readBuffer();
if (bytesRead > 0) {
if (bytesRead > 0) {
packet.ReconstructFromData(m_ReadBuffer, bytesRead);
}
}
void UDPClient::ReceivePackets()
{
readPartOfPacket();
}
int UDPClient::readBuffer()
{
if (!m_Socket) {
@@ -40,12 +53,15 @@ int UDPClient::readBuffer()
}
boost::system::error_code error;
// Read size of packet
m_Socket->receive(boost
m_Socket->receive(boost
::asio::buffer((void*)m_ReadBuffer, sizeof(int)),
boost::asio::ip::udp::socket::message_peek, error);
boost::asio::ip::udp::socket::message_peek, error);
int sizeOfPacket = 0;
memcpy(&sizeOfPacket, m_ReadBuffer, sizeof(int));
if (sizeOfPacket > m_Socket->available()) {
LOG_WARNING("UDPClient::readBuffer(): We haven't got the whole packet yet.");
//return 0;
}
// if the buffer is to small increase the size of it
if (sizeOfPacket > m_BufferSize) {
delete[] m_ReadBuffer;
@@ -68,6 +84,72 @@ int UDPClient::readBuffer()
return bytesReceived;
}
void UDPClient::readPartOfPacket()
{
if (!m_Socket) {
return;
}
boost::system::error_code error;
// Peek header
m_Socket->receive(boost
::asio::buffer((void*)m_ReadBuffer, 5 * sizeof(int)),
boost::asio::ip::udp::socket::message_peek, error);
int sizeOfPacket = 0;
memcpy(&sizeOfPacket, m_ReadBuffer, sizeof(int));
if (sizeOfPacket == 0) {
return;
}
int packetGroup = *reinterpret_cast<int*>(m_ReadBuffer + sizeof(int));
int packetGroupIndex = *reinterpret_cast<int*>(m_ReadBuffer + 2 * sizeof(int));
int packetGroupSize = *reinterpret_cast<int*>(m_ReadBuffer + 3 * sizeof(int));
//LOG_INFO("Packet group: %i. Group index: %i. Group size: %i. Packet size: %i.", packetGroup, packetGroupIndex, packetGroupSize, sizeOfPacket);
if (sizeOfPacket > m_Socket->available()) {
LOG_WARNING("UDPClient::readBuffer(): We haven't got the whole packet yet.");
// return;
}
// if the buffer is to small increase the size of it
boost::shared_ptr<char> packetData(new char[sizeOfPacket]);
// Read the message
size_t bytesReceived = m_Socket->receive_from(boost
::asio::buffer((void*)(packetData.get()),
sizeOfPacket),
m_ReceiverEndpoint, 0, error);
if (error) {
LOG_ERROR("UDPClient::readPartOfPacket: %s", error.message().c_str());
}
// Might want to do this earlier when i figure out a good way to
// remove data from network buffer.
if (hasReceivedPacket(packetGroup, packetGroupIndex)) {
return;
}
// If group exists
PacketMap::iterator it;
it = m_PacketSegmentMap.find(packetGroup);
if (it != m_PacketSegmentMap.end()) {
it->second.push_back(std::make_pair(packetGroupIndex, std::move(packetData)));
} else { // Create group and add element
m_PacketSegmentMap[packetGroup].push_back(std::make_pair(packetGroupIndex, std::move(packetData)));
}
return;
}
bool UDPClient::hasReceivedPacket(int packetGroup, int groupIndex)
{
PacketMap::iterator it;
it = m_PacketSegmentMap.find(packetGroup);
if (it != m_PacketSegmentMap.end()) {
const std::vector<std::pair<int, boost::shared_ptr<char>>>& loopPacketGroup = it->second;
for (size_t i = 0; i < loopPacketGroup.size(); i++) {
if (loopPacketGroup.at(i).first == groupIndex) {
return true;
}
}
}
return false;
}
void UDPClient::Send(Packet& packet)
{
packet.UpdateSize();
@@ -75,7 +157,7 @@ void UDPClient::Send(Packet& packet)
packet.Data(),
packet.Size()),
m_ReceiverEndpoint, 0);
}
}
void UDPClient::Broadcast(Packet& packet, int port)
{
@@ -91,8 +173,55 @@ void UDPClient::Broadcast(Packet& packet, int port)
bool UDPClient::IsSocketAvailable()
{
if (!m_Socket) {
if (!m_Socket) {
return false;
}
return m_Socket->available();
}
}
bool UDPClient::GetNextPacket(Packet & packet)
{
// A duplicate packet should not be present in the vector!
// Soo we will assume that this is true and only look if size
// of vector is correct.
PacketMap::iterator it = m_PacketSegmentMap.begin();
while (it != m_PacketSegmentMap.end()) {
// pair(Group index, packetData)
std::vector<std::pair<int, boost::shared_ptr<char>>>& currentVector = it->second;
Packet headerInfoPacket(currentVector.at(0).second.get(), packet.HeaderSize());
int groupSize = headerInfoPacket.GroupSize();
//LOG_INFO("UDPClient::GetNextPacket: Packet group : %i.Group index : %i.Group size : %i. lastReceivedSnapshotGroup: %i. MessageType(Ples 4): %i", headerInfoPacket.Group(), headerInfoPacket.GroupIndex(), groupSize, lastReceivedSnapshotGroup, headerInfoPacket.GetMessageType());
//LOG_INFO("UDPClient::GetNextPacket: Packet group : %i.lastReceivedSnapshotGroup: %i. MessageType(Ples 4): %i", headerInfoPacket.Group(), lastReceivedSnapshotGroup, headerInfoPacket.GetMessageType());
int mapSize = m_PacketSegmentMap.size();
if (mapSize > 5) {
it = m_PacketSegmentMap.erase(it);
LOG_INFO("The map is increasing in size, size is %i", mapSize);
continue;
}
if (headerInfoPacket.GetMessageType() == MessageType::Snapshot && m_LastReceivedSnapshotGroup > headerInfoPacket.Group()) {
it = m_PacketSegmentMap.erase(it);
continue;
//LOG_INFO("Deleted old entry");
}
if (currentVector.size() == groupSize) {
std::sort(currentVector.begin(), currentVector.end());
// Add the first packet in vector
packet.ReconstructFromData(currentVector.at(0).second.get(), packet.HeaderSize());
// Add the rest of the packets.
int sizeOfData = 0;
for (auto& packetSegment : currentVector) {
memcpy(&sizeOfData, packetSegment.second.get(), sizeof(int));
packet.WriteData(packetSegment.second.get() + packet.HeaderSize(), sizeOfData - packet.HeaderSize());
}
if (headerInfoPacket.GetMessageType() == MessageType::Snapshot) {
m_LastReceivedSnapshotGroup = packet.Group();
}
// No need to get next it as we are returning.
m_PacketSegmentMap.erase(it);
return true;
} else {
++it;
}
}
return false;
}
+103 -17
View File
@@ -12,42 +12,123 @@ UDPServer::UDPServer(int port)
UDPServer::~UDPServer()
{ }
void UDPServer::Send(Packet& packet, PlayerDefinition & playerDefinition)
// TODO: Fix correct groups
void UDPServer::Send(Packet& packet, PlayerDefinition& playerDefinition)
{
packet.UpdateSize();
try {
int bytesSent = m_Socket->send_to(
boost::asio::buffer(packet.Data(), packet.Size()),
playerDefinition.Endpoint,
0);
// Remove header from packet.
packet.ReadData(packet.HeaderSize());
int totalBytesSent = 0;
int groupIndex = 1;
int groupSize = std::ceil((float)packet.Size() / MAXPACKETSIZE);
int packetDataSent = 0;
int packetDataSize = packet.Size() - packet.HeaderSize();
while (packetDataSize > packetDataSent) {
Packet splitPacket(packet.GetMessageType(), playerDefinition.PacketID);
splitPacket.ChangeGroupIndex(groupIndex);
splitPacket.ChangeGroupSize(groupSize);
splitPacket.ChangeGroup(playerDefinition.PacketGroup);
int amountToSend = packetDataSize - packetDataSent;
if (amountToSend > MAXPACKETSIZE) {
amountToSend = MAXPACKETSIZE;
}
splitPacket.WriteData(packet.ReadData(amountToSend), amountToSend);
splitPacket.UpdateSize();
// Remove header size from bytes sent soo that we only
// count data in the packet
int bytesSent = 0;
bytesSent = m_Socket->send_to(
boost::asio::buffer(splitPacket.Data(), splitPacket.Size()),
playerDefinition.Endpoint,
0);
packetDataSent += bytesSent - splitPacket.HeaderSize();
totalBytesSent += bytesSent;
//LOG_INFO("bytesSent size %i, groupIndex: %i. Number of packets: %i", bytesSent, sequenceNumber, totalMessages);
++groupIndex;
}
playerDefinition.PacketGroup++;
} catch (const boost::system::system_error& e) {
LOG_INFO(e.what());
// TODO: Clean up invalid endpoints out of m_ConnectedPlayers later
playerDefinition.Endpoint = boost::asio::ip::udp::endpoint();
}
}
void UDPServer::SendToConnectedPlayers(Packet& packet, std::map<PlayerID, PlayerDefinition>& playersTosendTo)
{
packet.UpdateSize();
// Remove header from packet.
packet.ReadData(packet.HeaderSize());
int totalBytesSent = 0;
int groupIndex = 1;
int groupSize = std::ceil((float)packet.Size() / MAXPACKETSIZE);
int packetDataSent = 0;
int packetDataSize = packet.Size() - packet.HeaderSize();
while (packetDataSize > packetDataSent) {
Packet splitPacket(packet.GetMessageType());
splitPacket.ChangeGroupIndex(groupIndex);
splitPacket.ChangeGroupSize(groupSize);
int amountToSend = packetDataSize - packetDataSent;
if (amountToSend > MAXPACKETSIZE) {
amountToSend = MAXPACKETSIZE;
}
splitPacket.WriteData(packet.ReadData(amountToSend), amountToSend);
splitPacket.UpdateSize();
// Remove header size from bytes sent soo that we only
// count data in the packet
int bytesSent = 0;
for (auto& kv : playersTosendTo) {
try {
splitPacket.ChangeGroup(kv.second.PacketGroup);
bytesSent = m_Socket->send_to(
boost::asio::buffer(splitPacket.Data(), splitPacket.Size()),
kv.second.Endpoint,
0);
// LOG_INFO("bytesSent: %i", bytesSent);
} catch (const boost::system::system_error& e) {
LOG_INFO("UDPServer::SendToConnectedPlayers: Disconnected client. %s", e.what());
// TODO: Clean up invalid endpoints out of m_ConnectedPlayers later
kv.second.Endpoint = boost::asio::ip::udp::endpoint();
}
}
packetDataSent += splitPacket.Size() - splitPacket.HeaderSize();
totalBytesSent += splitPacket.Size();
//LOG_INFO("bytesSent size %i, groupIndex: %i. Number of packets: %i", bytesSent, sequenceNumber, totalMessages);
++groupIndex;
}
for (auto& kv : playersTosendTo) {
kv.second.PacketGroup++;
}
}
// Send back to endpoint of received packet
void UDPServer::Send(Packet & packet)
{
packet.UpdateSize();
m_Socket->send_to(
size_t bytesSent = m_Socket->send_to(
boost::asio::buffer(
packet.Data(),
packet.Size()),
m_ReceiverEndpoint,
0);
//LOG_INFO("Size of packet is %i", bytesSent);
}
// Broadcasting respond specific logic
void UDPServer::Send(Packet & packet, boost::asio::ip::udp::endpoint endpoint)
{
packet.UpdateSize();
m_Socket->send_to(
size_t bytesSent = m_Socket->send_to(
boost::asio::buffer(
packet.Data(),
packet.Size()),
endpoint,
0);
//LOG_INFO("Size of packet is %i", bytesSent);
}
// Broadcasting
@@ -55,11 +136,11 @@ void UDPServer::Broadcast(Packet & packet, int port)
{
packet.UpdateSize();
m_Socket->set_option(boost::asio::socket_base::broadcast(true));
m_Socket->send_to(
size_t bytesSent = m_Socket->send_to(
boost::asio::buffer(
packet.Data(),
packet.Size()),
boost::asio::ip::udp::endpoint(boost::asio::ip::address_v4().broadcast(),port),
boost::asio::ip::udp::endpoint(boost::asio::ip::address_v4().broadcast(), port),
0);
m_Socket->set_option(boost::asio::socket_base::broadcast(false));
}
@@ -86,12 +167,17 @@ int UDPServer::readBuffer()
int addasdasd = m_Socket->available();
boost::system::error_code error;
// Read size of packet
m_Socket->receive_from(boost
m_Socket->receive_from(boost
::asio::buffer((void*)m_ReadBuffer, sizeof(int)),
m_ReceiverEndpoint, boost::asio::ip::udp::socket::message_peek, error);
unsigned int sizeOfPacket = 0;
memcpy(&sizeOfPacket, m_ReadBuffer, sizeof(int));
if (sizeOfPacket > m_Socket->available()) {
LOG_WARNING("UDPServer::readBuffer(): We haven't got the whole packet yet.");
//return 0;
}
// if the buffer is to small increase the size of it
if (sizeOfPacket > m_BufferSize) {
delete[] m_ReadBuffer;
@@ -104,13 +190,13 @@ int UDPServer::readBuffer()
::asio::buffer((void*)(m_ReadBuffer),
sizeOfPacket),
m_ReceiverEndpoint, 0, error);
if (error) {
//LOG_ERROR("receive: %s", error.message().c_str());
}
if (sizeOfPacket > 1000000)
LOG_WARNING("The packets received are bigger than 1MB");
if (error) {
//LOG_ERROR("receive: %s", error.message().c_str());
}
if (sizeOfPacket > 1000000)
LOG_WARNING("The packets received are bigger than 1MB");
return bytesReceived;
return bytesReceived;
}
void UDPServer::AcceptNewConnections(int& nextPlayerID, std::map<PlayerID, PlayerDefinition>& connectedPlayers)
+331 -47
View File
@@ -1,71 +1,355 @@
#include "Rendering/AnimationSystem.h"
void AnimationSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& animationComponent, double dt)
AnimationSystem::AnimationSystem(SystemParams params)
: System(params)
{
if(!entity.HasComponent("Model")) {
EVENT_SUBSCRIBE_MEMBER(m_EAutoAnimationBlend, &AnimationSystem::OnAutoAnimationBlend);
EVENT_SUBSCRIBE_MEMBER(m_EEntityDeleted, &AnimationSystem::OnEntityDeleted);
EVENT_SUBSCRIBE_MEMBER(m_ESetBlendWeight, &AnimationSystem::OnSetBlendWeight);
}
void AnimationSystem::Update(double dt)
{
UpdateAnimations(dt);
CreateBlendTrees();
UpdateWeights(dt);
for(auto& autoBlendQueue : m_AutoBlendQueues) {
autoBlendQueue.second.UpdateTime(dt);
}
}
void AnimationSystem::CreateBlendTrees()
{
auto modelComponents = m_World->GetComponents("Model");
if (modelComponents == nullptr) {
return;
}
for (auto& modelC : *modelComponents) {
EntityWrapper entity = EntityWrapper(m_World, modelC.EntityID);
Model* model;
try {
model = ResourceManager::Load<::Model, true>(entity["Model"]["Resource"]);
} catch (const std::exception&) {
continue;;
}
Skeleton* skeleton = model->m_RawModel->m_Skeleton;
if (skeleton == nullptr) {
continue;
}
if (entity.HasComponent("Blend") || entity.HasComponent("BlendOverride") ||
entity.HasComponent("BlendAdditive") || entity.HasComponent("Animation"))
{
std::shared_ptr<BlendTree> blendTree = std::shared_ptr<BlendTree>(new BlendTree(entity, skeleton));
if(blendTree->IsValid()) {
skeleton->BlendTrees[entity] = blendTree;
}
}
}
}
void AnimationSystem::UpdateAnimations(double dt)
{
auto animationComponents = m_World->GetComponents("Animation");
if(animationComponents == nullptr) {
return;
}
for (auto& animationC : *animationComponents) {
EntityWrapper entity = EntityWrapper(m_World, animationC.EntityID);
EntityWrapper modelEntity;
if(!entity.HasComponent("Model")) {
modelEntity = entity.FirstParentWithComponent("Model");
} else {
modelEntity = entity;
}
Model* model;
try {
Field<std::string> res = modelEntity["Model"]["Resource"];
model = ResourceManager::Load<::Model, true>(res);
} catch (const std::exception&) {
continue;
}
Skeleton* skeleton = model->m_RawModel->m_Skeleton;
if (skeleton == nullptr) {
continue;
}
const Skeleton::Animation* animation = skeleton->GetAnimation(animationC["AnimationName"]);
if (animation == nullptr) {
continue;
}
double animationSpeed = (const double&)animationC["Speed"];
if((const bool&)animationC["Reverse"]) {
animationSpeed *= -1;
}
if ((const bool&)animationC["Play"]) {
double nextTime = (Field<double>)animationC["Time"] + animationSpeed * dt;
if (!(Field<bool>)animationC["Loop"]) {
if (nextTime > animation->Duration) {
nextTime = animation->Duration;
(Field<bool>)animationC["Play"] = false;
} else if (nextTime < 0) {
nextTime = 0;
(Field<bool>)animationC["Play"] = false;
}
} else {
if (nextTime > animation->Duration) {
while (nextTime > animation->Duration) {
nextTime -= animation->Duration;
}
} else if (nextTime < 0) {
while (nextTime < 0) {
nextTime += animation->Duration;
}
}
}
(Field<double>)animationC["Time"] = nextTime;
}
}
}
void AnimationSystem::UpdateWeights(double dt)
{
for (auto it = m_AutoBlendQueues.begin(); it != m_AutoBlendQueues.end(); ) {
//LOG_INFO("%s", it->first.Name().c_str());
//it->second.PrintQueue();
if(it->second.HasActiveBlendJob()) {
AutoBlendQueue::AutoBlendJob& blendJob = it->second.GetActiveBlendJob();
//LOG_INFO("%s", blendJob.RootNode.Name().c_str());
std::shared_ptr<BlendTree> blendTree = it->second.GetBlendTree();
if (blendTree != nullptr) {
if (blendJob.Duration != 0.0) {
blendJob.BlendInfo.progress = glm::clamp(blendJob.CurrentTime / blendJob.Duration, 0.0, 1.0);
} else {
blendJob.BlendInfo.progress = 1.0;
}
blendJob.BlendInfo = blendTree->AutoBlendStep(blendJob.BlendInfo);
} else {
it = m_AutoBlendQueues.erase(it);
}
it++;
} else {
if (it->second.Empty()) {
it = m_AutoBlendQueues.erase(it);
} else {
it++;
}
}
}
}
bool AnimationSystem::OnAutoAnimationBlend(Events::AutoAnimationBlend& e)
{
if (!e.RootNode.Valid()) {
LOG_ERROR("%s, RootNode invalid %s", e.NodeName, e.RootNode.Name().c_str());
return false;
}
if (!e.RootNode.HasComponent("Model")) {
LOG_ERROR("%s, RootNode has no model %s", e.NodeName, e.RootNode.Name().c_str());
return false;
}
Model* model;
try {
model = ResourceManager::Load<::Model, true>(entity["Model"]["Resource"]);
model = ResourceManager::Load<::Model, true>((std::string)e.RootNode["Model"]["Resource"]);
} catch (const std::exception&) {
return;
LOG_ERROR("%s, RootNode model not finished loading %s", e.NodeName, e.RootNode.Name().c_str());
return false;
}
Skeleton* skeleton = model->m_RawModel->m_Skeleton;
if(skeleton == nullptr) {
return;
if (skeleton == nullptr) {
LOG_ERROR("%s, RootNode skeleton invalid %s", e.NodeName, e.RootNode.Name().c_str());
return false;
}
for (int i = 1; i <= 3; i++) {
const Skeleton::Animation* animation = skeleton->GetAnimation(animationComponent["AnimationName" + std::to_string(i)]);
std::shared_ptr<BlendTree> blendTree;
if (skeleton->BlendTrees.find(e.RootNode) != skeleton->BlendTrees.end()) {
blendTree = skeleton->BlendTrees.at(e.RootNode);
} else {
LOG_ERROR("%s, No blendtree was found invalid %s", e.NodeName, e.RootNode.Name().c_str());
return false;
}
if (animation == nullptr) {
continue;;
EntityWrapper subTreeRoot;
if (e.SingleLevelBlend) {
subTreeRoot = blendTree->GetSubTreeRoot(e.NodeName);
if (!subTreeRoot.Valid()) {
LOG_ERROR("%s, subTreeRoot invalid", e.NodeName);
return false;
}
double animationSpeed = (double)animationComponent["Speed" + std::to_string(i)];
AutoBlendQueue::AutoBlendJob abj;
abj.AnimationEntity = e.AnimationEntity;
abj.CurrentTime = 0.0;
abj.Delay = e.Delay;
abj.Duration = e.Duration;
abj.RootNode = e.RootNode;
if (animationSpeed != 0.0) {
double nextTime = (double)animationComponent["Time" + std::to_string(i)] + animationSpeed * dt;
abj.BlendInfo.NodeName = e.NodeName;
abj.BlendInfo.progress = 0.0;
abj.BlendInfo.Start = e.Start;
abj.BlendInfo.SingleBlend = e.SingleLevelBlend;
abj.BlendInfo.Weight = e.Weight;
std::vector<EntityWrapper> animationEntities = blendTree->GetEntitesByName(e.NodeName); // more than one
for(auto entity : animationEntities)
if (entity.Valid()) {
if (entity.HasComponent("Animation")) {
const Skeleton::Animation* animation = skeleton->GetAnimation(entity["Animation"]["AnimationName"]);
(Field<bool>)entity["Animation"]["Reverse"] = e.Reverse;
if (!(bool)animationComponent["Loop" + std::to_string(i)]) {
if (nextTime > animation->Duration) {
nextTime = animation->Duration;
Events::AnimationComplete e;
e.Entity = entity;
e.Name = (std::string)animationComponent["AnimationName" + std::to_string(i)];
m_EventBroker->Publish(e);
} else if (nextTime < 0) {
Events::AnimationComplete e;
e.Entity = entity;
e.Name = (std::string)animationComponent["AnimationName" + std::to_string(i)];
m_EventBroker->Publish(e);
nextTime = 0;
}
(double&)animationComponent["Speed" + std::to_string(i)] = 0.0;
} else {
if (nextTime > animation->Duration) {
Events::AnimationComplete e;
e.Entity = entity;
e.Name = (std::string)animationComponent["AnimationName" + std::to_string(i)];
m_EventBroker->Publish(e);
nextTime -= animation->Duration;
} else if (nextTime < 0) {
Events::AnimationComplete e;
e.Entity = entity;
e.Name = (std::string)animationComponent["AnimationName" + std::to_string(i)];
m_EventBroker->Publish(e);
nextTime += animation->Duration;
if (e.Restart) {
if (animation != nullptr) {
if (e.Restart) {
if (e.Reverse) {
(Field<double>)entity["Animation"]["Time"] = animation->Duration;
} else {
(Field<double>)entity["Animation"]["Time"] = 0.0;
}
}
}
}
}
(double&)animationComponent["Time" + std::to_string(i)] = nextTime;
}
}
m_AutoBlendQueues[subTreeRoot].Insert(abj);
} else {
std::vector<EntityWrapper> subtreeroots = blendTree->GetSingleLevelRoots(e.NodeName);
for(auto entity : subtreeroots) {
subTreeRoot = entity;
if (!subTreeRoot.Valid()) {
LOG_ERROR("%s, subTreeRoot invalid", e.NodeName);
return false;
}
AutoBlendQueue::AutoBlendJob abj;
abj.AnimationEntity = e.AnimationEntity;
abj.CurrentTime = 0.0;
abj.Delay = e.Delay;
abj.Duration = e.Duration;
abj.RootNode = e.RootNode;
abj.BlendInfo.NodeName = e.NodeName;
abj.BlendInfo.progress = 0.0;
abj.BlendInfo.Start = e.Start;
abj.BlendInfo.SingleBlend = e.SingleLevelBlend;
abj.BlendInfo.Weight = e.Weight;
m_AutoBlendQueues[subTreeRoot].Insert(abj);
}
std::vector<EntityWrapper> animationEntities = blendTree->GetEntitesByName(e.NodeName); // more than one
for (auto entity : animationEntities)
if (entity.Valid()) {
if (entity.HasComponent("Animation")) {
const Skeleton::Animation* animation = skeleton->GetAnimation(entity["Animation"]["AnimationName"]);
entity["Animation"]["Reverse"] = e.Reverse;
if (e.Restart) {
if (animation != nullptr) {
if (e.Restart) {
if (e.Reverse) {
entity["Animation"]["Time"] = animation->Duration;
} else {
entity["Animation"]["Time"] = 0.0;
}
}
}
}
}
}
}
return true;
}
bool AnimationSystem::OnEntityDeleted(Events::EntityDeleted& e)
{
EntityWrapper entity = e.DeletedEntity;
if (entity.HasComponent("Model")) {
Model* model;
try {
model = ResourceManager::Load<::Model, true>(entity["Model"]["Resource"]);
} catch (const std::exception&) {
return false;
}
Skeleton* skeleton = model->m_RawModel->m_Skeleton;
if (skeleton == nullptr) {
return false;
}
if (skeleton->BlendTrees.find(entity) != skeleton->BlendTrees.end()) {
skeleton->BlendTrees.erase(entity);
}
}
}
bool AnimationSystem::OnSetBlendWeight(Events::SetBlendWeight& e)
{
if (!e.RootNode.Valid()) {
return false;
}
if (!e.RootNode.HasComponent("Model")) {
return false;
}
Model* model;
try {
model = ResourceManager::Load<::Model, true>((std::string)e.RootNode["Model"]["Resource"]);
} catch (const std::exception&) {
return false;
}
Skeleton* skeleton = model->m_RawModel->m_Skeleton;
if (skeleton == nullptr) {
return false;
}
std::shared_ptr<BlendTree> blendTree;
if (skeleton->BlendTrees.find(e.RootNode) != skeleton->BlendTrees.end()) {
blendTree = skeleton->BlendTrees.at(e.RootNode);
} else {
return false;
}
if(e.Weight >= 0 && e.Weight <= 1) {
blendTree->SetWeightByName(e.NodeName, e.Weight);
return true;
} else {
return false;
}
}
+197
View File
@@ -0,0 +1,197 @@
#include "Rendering/AutoBlendQueue.h"
void AutoBlendQueue::Insert(AutoBlendJob autoBlendJob)
{
if(!autoBlendJob.RootNode.HasComponent("Model")) {
return;
}
AutoblendNode blendNode;
blendNode.BlendJob = autoBlendJob;
blendNode.StartTime = autoBlendJob.Delay;
blendNode.EndTime = autoBlendJob.Delay + autoBlendJob.Duration;
if (autoBlendJob.AnimationEntity.Valid()) {
if (autoBlendJob.AnimationEntity.HasComponent("Animation")) {
Model* model;
try {
model = ResourceManager::Load<::Model, true>((std::string)autoBlendJob.RootNode["Model"]["Resource"]);
} catch (const std::exception&) {
return;
}
Skeleton* skeleton = model->m_RawModel->m_Skeleton;
if (skeleton == nullptr) {
return;
}
const Skeleton::Animation* animation = skeleton->GetAnimation((std::string)autoBlendJob.AnimationEntity["Animation"]["AnimationName"]);
if (animation == nullptr) {
return;
}
double AnimationDuration = 0.0;
double animationSpeed = (double)autoBlendJob.AnimationEntity["Animation"]["Speed"];
double animationTime = (double)autoBlendJob.AnimationEntity["Animation"]["Time"];
if (animationSpeed != 0) {
if ((bool)autoBlendJob.AnimationEntity["Animation"]["Reverse"]) {
AnimationDuration = (animation->Duration / animationSpeed) - (animation->Duration - animationTime);
} else {
AnimationDuration = (animation->Duration / animationSpeed) - animationTime;
}
} else {
return;
}
blendNode.StartTime += AnimationDuration;
blendNode.EndTime += AnimationDuration;
if (m_BlendQueue.size() == 0) {
m_BlendQueue.push_back(blendNode);
} else {
for (auto it = m_BlendQueue.begin(); it != m_BlendQueue.end(); it++) {
auto next = std::next(it, 1);
if (it->BlendJob.BlendInfo.NodeName == autoBlendJob.BlendInfo.NodeName) {
(*it) = blendNode;
}
if (next != m_BlendQueue.end()) {
if (it->StartTime >= blendNode.StartTime && next->StartTime <= blendNode.StartTime) {
m_BlendQueue.insert(next, blendNode);
return;
}
} else if(it->StartTime > blendNode.StartTime){
m_BlendQueue.push_front(blendNode);
return;
} else if (it->StartTime <= blendNode.StartTime) {
m_BlendQueue.push_back(blendNode);
return;
}
}
}
}
}
m_BlendQueue.clear();
m_BlendQueue.push_back(blendNode);
}
void AutoBlendQueue::UpdateTime(double dt)
{
for (auto it = m_BlendQueue.begin(); it != m_BlendQueue.end();) {
if (it->EndTime <= 0) {
it = m_BlendQueue.erase(it);
} else {
it->EndTime -= dt;
it->StartTime -= dt;
it++;
}
}
}
void AutoBlendQueue::PrintQueue()
{
for (auto it = m_BlendQueue.begin(); it != m_BlendQueue.end(); it++) {
LOG_INFO("Start: %f End: %f \t %s", it->StartTime, it->EndTime, it->BlendJob.BlendInfo.NodeName.c_str());
}
}
bool AutoBlendQueue::HasActiveBlendJob()
{
if(m_BlendQueue.empty()) {
return false;
} else {
AutoblendNode blendNode = m_BlendQueue.front();
if (blendNode.StartTime <= 0) {
AutoBlendJob blendJob = blendNode.BlendJob;
if (!blendJob.RootNode.Valid()) {
m_BlendQueue.pop_front();
return false;
}
if (!blendJob.RootNode.HasComponent("Model")) {
m_BlendQueue.pop_front();
return HasActiveBlendJob();
}
Model* model;
try {
model = ResourceManager::Load<::Model, true>(blendJob.RootNode["Model"]["Resource"]);
} catch (const std::exception&) {
//m_BlendQueue.pop_front();
return HasActiveBlendJob();
}
Skeleton* skeleton = model->m_RawModel->m_Skeleton;
if (skeleton == nullptr) {
m_BlendQueue.pop_front();
return HasActiveBlendJob();
}
if (skeleton->BlendTrees.find(blendJob.RootNode) != skeleton->BlendTrees.end()) {
return true;
} else {
m_BlendQueue.pop_front();
return HasActiveBlendJob();
}
} else {
return false;
}
}
}
std::shared_ptr<BlendTree> AutoBlendQueue::GetBlendTree()
{
AutoblendNode blendNode = m_BlendQueue.front();
AutoBlendJob blendJob = blendNode.BlendJob;
if (!blendJob.RootNode.Valid()) {
m_BlendQueue.pop_front();
return false;
}
if (!blendJob.RootNode.HasComponent("Model")) {
return nullptr;
}
Model* model;
try {
model = ResourceManager::Load<::Model, true>(blendJob.RootNode["Model"]["Resource"]);
} catch (const std::exception&) {
return nullptr;
}
Skeleton* skeleton = model->m_RawModel->m_Skeleton;
if (skeleton == nullptr) {
return nullptr;
}
if (skeleton->BlendTrees.find(blendJob.RootNode) != skeleton->BlendTrees.end()) {
return skeleton->BlendTrees.at(blendJob.RootNode);
} else {
return nullptr;
}
}
AutoBlendQueue::AutoBlendJob& AutoBlendQueue::GetActiveBlendJob()
{
AutoblendNode& blendNode = m_BlendQueue.front();
blendNode.BlendJob.CurrentTime = -blendNode.StartTime;
return blendNode.BlendJob;
}
+546
View File
@@ -0,0 +1,546 @@
#include "Rendering/BlendTree.h"
BlendTree::BlendTree(EntityWrapper ModelEntity, Skeleton* skeleton)
{
m_Skeleton = skeleton;
if (ModelEntity.HasComponent("Animation")) {
const Skeleton::Animation* animation = skeleton->GetAnimation(ModelEntity["Animation"]["AnimationName"]);
if (animation == nullptr) {
return;
}
m_Root = new Node();
m_Root->Entity = ModelEntity;
m_Root->Name = ModelEntity.Name();
m_Root->Pose = m_Skeleton->GetFrameBones(animation, (const double&)ModelEntity["Animation"]["Time"], (const bool&)ModelEntity["Animation"]["Additive"]);
m_Root->Parent = nullptr;
m_Root->Type = NodeType::Animation;
} else if (ModelEntity.HasComponent("Blend")) {
m_Root = new Node();
m_Root->Entity = ModelEntity;
m_Root->Name = ModelEntity.Name();
m_Root->Parent = nullptr;
m_Root->Type = NodeType::Blend;
m_Root->Weight = (const double&)ModelEntity["Blend"]["Weight"];
m_Root->SubTreeRoot = (const bool&)ModelEntity["Blend"]["SubTreeRoot"];
ModelEntity["Blend"]["Weight"] = glm::clamp((const double&)ModelEntity["Blend"]["Weight"], 0.0, 1.0);
m_Root->Child[0] = FillTreeByName(m_Root, (std::string)ModelEntity["Blend"]["Pose1"], ModelEntity);
m_Root->Child[1] = FillTreeByName(m_Root, (std::string)ModelEntity["Blend"]["Pose2"], ModelEntity);
} else if (ModelEntity.HasComponent("BlendOverride")) {
m_Root = new Node();
m_Root->Entity = ModelEntity;
m_Root->Name = ModelEntity.Name();
m_Root->Parent = nullptr;
m_Root->Type = NodeType::Override;
m_Root->Child[0] = FillTreeByName(m_Root, (std::string)ModelEntity["BlendOverride"]["Master"], ModelEntity);
m_Root->Child[1] = FillTreeByName(m_Root, (std::string)ModelEntity["BlendOverride"]["Slave"], ModelEntity);
} else if (ModelEntity.HasComponent("BlendAdditive")) {
m_Root = new Node();
m_Root->Entity = ModelEntity;
m_Root->Name = ModelEntity.Name();
m_Root->Parent = nullptr;
m_Root->Type = NodeType::Additive;
m_Root->Child[0] = FillTreeByName(m_Root, (std::string)ModelEntity["BlendAdditive"]["Adder"], ModelEntity);
m_Root->Child[1] = FillTreeByName(m_Root, (std::string)ModelEntity["BlendAdditive"]["Receiver"], ModelEntity);
}
m_FinalPose = AccumulateFinalPose();
// PrintTree();
}
BlendTree::~BlendTree()
{
Node* currentNode = m_Root;
if (currentNode != nullptr) {
while (currentNode->Child[0] != nullptr) {
currentNode = currentNode->Child[0];
}
std::list<Node*> m_NodesToRemove;
while (currentNode != nullptr) {
m_NodesToRemove.push_back(currentNode);
currentNode = currentNode->Next();
}
for (auto it = m_NodesToRemove.begin(); it != m_NodesToRemove.end(); it++) {
delete (*it);
}
}
}
glm::mat4 BlendTree::GetBoneTransform(int boneID)
{
if(m_FinalBoneTransforms.find(boneID) != m_FinalBoneTransforms.end()) {
return m_FinalBoneTransforms.at(boneID);
} else {
return glm::mat4(1);
}
}
void BlendTree::PrintTree()
{
Node* currentNode = m_Root;
LOG_INFO("\n\n");
while(currentNode->Child[0] != nullptr) {
currentNode = currentNode->Child[0];
}
while (currentNode != nullptr)
{
LOG_INFO("%s", currentNode->Name.c_str());
currentNode = currentNode->Next();
}
}
BlendTree::Node* BlendTree::FillTreeByName(Node* parentNode, std::string name, EntityWrapper parentEntity)
{
EntityWrapper childEntity = parentEntity.FirstLevelChildByName(name); // Make first level child by name
if (!childEntity.Valid()) {
return nullptr;
}
if (childEntity.HasComponent("Animation")) {
const Skeleton::Animation* animation = m_Skeleton->GetAnimation(childEntity["Animation"]["AnimationName"]);
if (animation == nullptr) {
return nullptr;
}
Node* node = new Node();
node->Entity = childEntity;
node->Name = childEntity.Name();
node->Pose = m_Skeleton->GetFrameBones(animation, (const double&)childEntity["Animation"]["Time"], (const bool&)childEntity["Animation"]["Additive"]);
node->Parent = parentNode;
node->Type = NodeType::Animation;
return node;
} else if (childEntity.HasComponent("Blend")) {
Node* node = new Node();
node->Entity = childEntity;
node->Name = childEntity.Name();
node->Parent = parentNode;
node->Type = NodeType::Blend;
childEntity["Blend"]["Weight"] = glm::clamp((const double&)childEntity["Blend"]["Weight"], 0.0, 1.0);
node->Weight = (const double&)childEntity["Blend"]["Weight"];
node->SubTreeRoot = (const bool&)childEntity["Blend"]["SubTreeRoot"];
//if (node->Weight < 1.f && node->Weight > 0.f) {
node->Child[0] = FillTreeByName(node, (std::string)childEntity["Blend"]["Pose1"], childEntity);
node->Child[1] = FillTreeByName(node, (std::string)childEntity["Blend"]["Pose2"], childEntity);
/* } else if (node->Weight == 1.f) {
node->Child[0] = FillTreeByName(node, (std::string)childEntity["Blend"]["Pose1"], childEntity);
} else if (node->Weight == 0.f) {
node->Child[1] = FillTreeByName(node, (std::string)childEntity["Blend"]["Pose2"], childEntity);
}*/
if(node->Child[0] == nullptr && node->Child[1] == nullptr) {
return nullptr;
} else {
return node;
}
} else if (childEntity.HasComponent("BlendOverride")) {
Node* node = new Node();
node->Entity = childEntity;
node->Name = childEntity.Name();
node->Parent = parentNode;
node->Type = NodeType::Override;
node->Child[0] = FillTreeByName(node, (std::string)childEntity["BlendOverride"]["Master"], childEntity);
node->Child[1] = FillTreeByName(node, (std::string)childEntity["BlendOverride"]["Slave"], childEntity);
if (node->Child[0] == nullptr && node->Child[1] == nullptr) {
return nullptr;
} else {
return node;
}
} else if (childEntity.HasComponent("BlendAdditive")) {
Node* node = new Node();
node->Entity = childEntity;
node->Name = childEntity.Name();
node->Parent = parentNode;
node->Type = NodeType::Additive;
node->Child[0] = FillTreeByName(node, (std::string)childEntity["BlendAdditive"]["Adder"], childEntity);
node->Child[1] = FillTreeByName(node, (std::string)childEntity["BlendAdditive"]["Receiver"], childEntity);
if(node->Child[0] == nullptr && node->Child[1] == nullptr) {
return nullptr;
} else {
return node;
}
}
return nullptr;
}
std::vector<BlendTree::Node*> BlendTree::FindNodesByName(std::string name)
{
std::vector<Node*> Nodes;
Node* currentNode = m_Root;
while (currentNode->Child[0] != nullptr) {
currentNode = currentNode->Child[0];
}
while (currentNode != nullptr) {
if(currentNode->Name == name) {
Nodes.push_back(currentNode);
}
currentNode = currentNode->Next();
}
return Nodes;
}
BlendTree::AutoBlendInfo BlendTree::AutoBlendStep(AutoBlendInfo blendInfo)
{
std::vector<Node*> goalNodes = FindNodesByName(blendInfo.NodeName);
if(blendInfo.Weight >= 0 && blendInfo.Weight <= 1.0) {
for (auto it = goalNodes.begin(); it != goalNodes.end(); it++) {
EntityWrapper entity = (*it)->Entity;
if (entity.Valid()) {
if (entity.HasComponent("Blend")) {
entity["Blend"]["Weight"] = blendInfo.Weight;
}
}
}
return blendInfo;
}
if (blendInfo.Start) {
for (auto it = goalNodes.begin(); it != goalNodes.end(); it++) {
EntityWrapper entity = (*it)->Entity;
if (entity.Valid()) {
if (entity.HasComponent("Animation")) {
entity["Animation"]["Play"] = true;
}
}
}
}
if(goalNodes.size() == 0) {
return blendInfo;
} else if(goalNodes.size() == 1) {
Node* currentNode = goalNodes[0]->Parent;
Node* lastNode = goalNodes[0];
while (currentNode != nullptr)
{
if(!currentNode->Entity.HasComponent("Blend")) {
return blendInfo;
}
double startWeight;
if(blendInfo.StartWeights.find(currentNode->Entity) != blendInfo.StartWeights.end()) {
startWeight = blendInfo.StartWeights.at(currentNode->Entity);
} else {
startWeight = currentNode->Weight;
blendInfo.StartWeights[currentNode->Entity] = startWeight;
}
double goalWeight;
if(currentNode->Child[0] == lastNode) {
goalWeight = 0.0;
} else if (currentNode->Child[1] == lastNode) {
goalWeight = 1.0;
}
double weight = ((goalWeight - startWeight) * blendInfo.progress) + startWeight;
currentNode->Entity["Blend"]["Weight"] = weight;
currentNode->Weight = weight;
lastNode = currentNode;
currentNode = currentNode->Parent;
if (blendInfo.SingleBlend) {
return blendInfo;;
}
}
} else if(goalNodes.size() >= 2) {
std::vector<Node*> sharedParents;
std::vector<Node*> nodes = goalNodes;
for (auto it = nodes.begin(); it != nodes.end(); it++) {
auto next = std::next(it, 1);
if (next != nodes.end()) {
Node* commonParent = FirstCommonParent((*it), (*next));
sharedParents.push_back(commonParent);
(*next) = commonParent;
nodes.erase(it);
it = nodes.begin();
}
}
for (auto it = goalNodes.begin(); it != goalNodes.end(); it++) {
Node* currentNode = (*it)->Parent;
Node* lastNode = (*it);
while (currentNode != nullptr) {
if (!currentNode->Entity.HasComponent("Blend")) {
return blendInfo;
}
bool ShouldBreak = false;
for (auto it = sharedParents.begin(); it != sharedParents.end(); it++) {
if(currentNode == (*it)) {
ShouldBreak = true;
}
}
if(ShouldBreak) {
break;
}
double startWeight;
if (blendInfo.StartWeights.find(currentNode->Entity) != blendInfo.StartWeights.end()) {
startWeight = blendInfo.StartWeights.at(currentNode->Entity);
} else {
startWeight = currentNode->Weight;
blendInfo.StartWeights[currentNode->Entity] = startWeight;
}
double goalWeight;
if (currentNode->Child[0] == lastNode) {
goalWeight = 0.0;
} else if (currentNode->Child[1] == lastNode) {
goalWeight = 1.0;
}
double weight = ((goalWeight - startWeight) * blendInfo.progress) + startWeight;
currentNode->Entity["Blend"]["Weight"] = weight;
currentNode->Weight = weight;
lastNode = currentNode;
currentNode = currentNode->Parent;
if (blendInfo.SingleBlend) {
return blendInfo;
}
}
}
}
return blendInfo;
}
BlendTree::Node* BlendTree::GetCommonParent(std::string NodeName1, std::string NodeName2)
{
std::vector<Node*> nodes1 = FindNodesByName(NodeName1);
std::vector<Node*> nodes2 = FindNodesByName(NodeName2);
for (auto it = nodes1.begin(); it != nodes1.end(); it++) {
auto next = std::next(it, 1);
if(next != nodes1.end()) {
Node* commonParent = FirstCommonParent((*it), (*next));
(*next) = commonParent;
nodes1.erase(it);
it = nodes1.begin();
}
}
for (auto it = nodes2.begin(); it != nodes2.end(); it++) {
auto next = std::next(it, 1);
if (next != nodes2.end()) {
Node* commonParent = FirstCommonParent((*it), (*next));
(*next) = commonParent;
nodes2.erase(it);
it = nodes2.begin();
}
}
return FirstCommonParent(nodes1.front(), nodes2.front());;
}
BlendTree::Node* BlendTree::FirstCommonParent(Node* node1, Node* node2)
{
std::list<Node*> node1Parents;
Node* currentNode = node1;
while (currentNode != nullptr) {
node1Parents.push_back(currentNode);
currentNode = currentNode->Parent;
}
currentNode = node2;
while (currentNode != nullptr) {
for (auto it = node1Parents.begin(); it != node1Parents.end(); it++) {
if (currentNode == (*it)) {
return currentNode;
}
}
currentNode = currentNode->Parent;
}
return nullptr;
}
EntityWrapper BlendTree::GetSubTreeRoot(std::string nodeName)
{
std::vector<Node*> nodes = FindNodesByName(nodeName);
if (nodes.size() == 0) {
return EntityWrapper::Invalid;
}
std::vector<Node*> subTreeRoots;
for (auto it = nodes.begin(); it != nodes.end(); it++) {
Node* currentNode = (*it)->Parent;
while (!currentNode->SubTreeRoot) {
currentNode = currentNode->Parent;
}
subTreeRoots.push_back(currentNode);
}
for (auto it = subTreeRoots.begin(); it != subTreeRoots.end(); it++) {
auto next = std::next(it, 1);
if (next != subTreeRoots.end()) {
Node* commonParent = FirstCommonParent((*it), (*next));
(*next) = commonParent;
subTreeRoots.erase(it);
it = subTreeRoots.begin();
}
}
return subTreeRoots.front()->Entity;
}
std::vector<EntityWrapper> BlendTree::GetSingleLevelRoots(std::string name)
{
std::vector<Node*> nodes = FindNodesByName(name);
std::vector<EntityWrapper> entities;
for (auto it = nodes.begin(); it != nodes.end(); it++) {
Node* currentNode = (*it)->Parent;
if(currentNode->Entity.Valid()) {
entities.push_back(currentNode->Entity);
}
}
return entities;
}
std::vector<EntityWrapper> BlendTree::GetEntitesByName(std::string name)
{
std::vector<Node*> nodes = FindNodesByName(name);
std::vector<EntityWrapper> entities;
for (auto it = nodes.begin(); it != nodes.end(); it++) {
Node* currentNode = (*it);
if (currentNode->Entity.Valid()) {
entities.push_back(currentNode->Entity);
}
}
return entities;
}
void BlendTree::SetWeightByName(std::string name, double weight)
{
std::vector<Node*> nodes = FindNodesByName(name);
for (auto node : nodes) {
EntityWrapper entity = node->Entity;
if(entity.HasComponent("Blend")) {
entity["Blend"]["Weight"] = weight;
node->Weight = weight;
}
}
}
void BlendTree::Blend(std::map<int, Skeleton::PoseData>& pose)
{
Node* currentNode;
Node* start = m_Root;
while (start->Child[0] != nullptr) {
start = start->Child[0];
}
currentNode = start;
while (m_Root->Pose.size() == 0) {
if(currentNode->Pose.size() == 0) {
if (currentNode->Child[0] != nullptr && currentNode->Child[1] != nullptr) {
if (currentNode->Child[0]->Pose.size() != 0 && currentNode->Child[1]->Pose.size() != 0) {
switch (currentNode->Type) {
case BlendTree::NodeType::Additive:
currentNode->Pose = m_Skeleton->BlendPoseAdditive(currentNode->Child[0]->Pose, currentNode->Child[1]->Pose);
break;
case BlendTree::NodeType::Blend:
currentNode->Pose = m_Skeleton->BlendPoses(currentNode->Child[0]->Pose, currentNode->Child[1]->Pose, currentNode->Weight);
break;
case BlendTree::NodeType::Override:
currentNode->Pose = m_Skeleton->OverridePose(currentNode->Child[0]->Pose, currentNode->Child[1]->Pose);
break;
case BlendTree::NodeType::Animation:
// do nothing
break;
}
}
} else if (currentNode->Child[0] != nullptr) {
if (currentNode->Child[0]->Pose.size() != 0) {
currentNode->Pose = currentNode->Child[0]->Pose;
}
} else if (currentNode->Child[1] != nullptr) {
if (currentNode->Child[1]->Pose.size() != 0) {
currentNode->Pose = currentNode->Child[1]->Pose;
}
}
}
currentNode = currentNode->Next();
if (currentNode == nullptr) {
currentNode = start;
}
}
pose = m_Root->Pose;
}
std::vector<glm::mat4> BlendTree::AccumulateFinalPose()
{
std::vector<glm::mat4> finalPose;
if (m_Skeleton == nullptr || m_Root == nullptr || (m_Root->Child[0] == nullptr && m_Root->Child[1] == nullptr)) {
for (int i = 0; i < m_Skeleton->Bones.size(); i++) {
finalPose.push_back(glm::mat4(1));
}
return finalPose;
}
std::map<int, Skeleton::PoseData> pose;
Blend(pose);
m_Skeleton->GetFinalPose(pose, finalPose, m_FinalBoneTransforms);
return finalPose;
}
+302
View File
@@ -0,0 +1,302 @@
#include "Rendering/BlurHUD.h"
BlurHUD::BlurHUD(IRenderer* renderer)
: m_Renderer(renderer)
{
InitializeShaderPrograms();
InitializeBuffers();
InitializeTextures();
}
void BlurHUD::InitializeTextures()
{
m_BlackTexture = CommonFunctions::TryLoadResource<Texture, false>("Textures/Core/Black.png");
m_ScreenQuad = ResourceManager::Load<Model>("Models/Core/ScreenQuad.mesh");
}
void BlurHUD::InitializeShaderPrograms()
{
m_GaussianProgram_horiz = ResourceManager::Load<ShaderProgram>("##GaussianProgramHoriz");
if (m_GaussianProgram_horiz->GetHandle() == 0) {
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->BindFragDataLocation(0, "fragmentColor");
m_GaussianProgram_horiz->Link();
}
m_GaussianProgram_vert = ResourceManager::Load<ShaderProgram>("##GaussianProgramVert");
if (m_GaussianProgram_vert->GetHandle() == 0) {
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->BindFragDataLocation(0, "fragmentColor");
m_GaussianProgram_vert->Link();
}
m_FillDepthStencilProgram = ResourceManager::Load<ShaderProgram>("#FillDepthStencilProgram");
if (m_FillDepthStencilProgram->GetHandle() == 0) {
m_FillDepthStencilProgram->AddShader(std::shared_ptr<Shader>(new VertexShader("Shaders/FillDepthBuffer.vert.glsl")));
m_FillDepthStencilProgram->Compile();
m_FillDepthStencilProgram->Link();
}
m_CombineTexturesProgram = ResourceManager::Load<ShaderProgram>("#CombineTexturesProgram");
if (m_CombineTexturesProgram->GetHandle() == 0) {
m_CombineTexturesProgram->AddShader(std::shared_ptr<Shader>(new VertexShader("Shaders/CombineTexture.vert.glsl")));
m_CombineTexturesProgram->AddShader(std::shared_ptr<Shader>(new FragmentShader("Shaders/CombineTexture.frag.glsl")));
m_CombineTexturesProgram->Compile();
m_CombineTexturesProgram->BindFragDataLocation(0, "sceneColor");
m_CombineTexturesProgram->BindFragDataLocation(1, "bloomColor");
m_CombineTexturesProgram->Link();
}
GLERROR("Creating DepthFill program");
}
void BlurHUD::InitializeBuffers()
{
glm::vec2 res = glm::vec2(m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height);
glm::vec2 res2 = glm::vec2(m_Renderer->GetViewportSize().Width/m_BlurQuality, m_Renderer->GetViewportSize().Height/m_BlurQuality);
CommonFunctions::GenerateTexture(&m_DepthStencil_horiz, GL_CLAMP_TO_BORDER, GL_NEAREST,
res2, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8);
CommonFunctions::GenerateTexture(&m_GaussianTexture_horiz, GL_CLAMP_TO_EDGE, GL_NEAREST,
res2, GL_RGBA16F, GL_RGBA, GL_FLOAT);
if (m_GaussianFrameBuffer_horiz.GetHandle() == 0) {
m_GaussianFrameBuffer_horiz.AddResource(std::shared_ptr<BufferResource>(new Texture2D(&m_DepthStencil_horiz, GL_DEPTH_STENCIL_ATTACHMENT)));
m_GaussianFrameBuffer_horiz.AddResource(std::shared_ptr<BufferResource>(new Texture2D(&m_GaussianTexture_horiz, GL_COLOR_ATTACHMENT0)));
}
m_GaussianFrameBuffer_horiz.Generate();
//CommonFunctions::GenerateTexture(&m_DepthStencil_vert, GL_CLAMP_TO_BORDER, GL_NEAREST,
// res2, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8);
CommonFunctions::GenerateTexture(&m_GaussianTexture_vert, GL_CLAMP_TO_EDGE, GL_NEAREST,
res2, GL_RGBA16F, GL_RGBA, GL_FLOAT);
if (m_GaussianFrameBuffer_vert.GetHandle() == 0) {
m_GaussianFrameBuffer_vert.AddResource(std::shared_ptr<BufferResource>(new Texture2D(&m_DepthStencil_horiz, GL_DEPTH_STENCIL_ATTACHMENT)));
m_GaussianFrameBuffer_vert.AddResource(std::shared_ptr<BufferResource>(new Texture2D(&m_GaussianTexture_vert, GL_COLOR_ATTACHMENT0)));
}
m_GaussianFrameBuffer_vert.Generate();
CommonFunctions::GenerateTexture(&m_CombinedTexture, GL_CLAMP_TO_BORDER, GL_NEAREST,
res, GL_RGB16F, GL_RGB, GL_FLOAT);
if (m_CombinedTextureBuffer.GetHandle() == 0) {
m_CombinedTextureBuffer.AddResource(std::shared_ptr<BufferResource>(new Texture2D(&m_CombinedTexture, GL_COLOR_ATTACHMENT0)));
}
m_CombinedTextureBuffer.Generate();
}
void BlurHUD::ClearBuffer()
{
GLERROR("PRE");
m_GaussianFrameBuffer_horiz.Bind();
glClearColor(0.f, 0.f, 0.f, 0.f);
glClearStencil(0x00);
glStencilMask(~0);
glDisable(GL_SCISSOR_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
m_GaussianFrameBuffer_horiz.Unbind();
m_GaussianFrameBuffer_vert.Bind();
glClearColor(0.f, 0.f, 0.f, 0.f);
glClearStencil(0x00);
glStencilMask(~0);
glDisable(GL_SCISSOR_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
m_GaussianFrameBuffer_vert.Unbind();
m_CombinedTextureBuffer.Bind();
glClearColor(0.f, 0.f, 0.f, 0.f);
glClear(GL_COLOR_BUFFER_BIT);
m_CombinedTextureBuffer.Unbind();
GLERROR("END");
}
//Returns the finished blurred texture
GLuint BlurHUD::Draw(GLuint texture, RenderScene& scene)
{
GLERROR("DrawBloomPass::Draw: Pre");
bool shouldRun = false;
for (auto& job : scene.Jobs.SpriteJob) {
auto spriteJob = std::dynamic_pointer_cast<SpriteJob>(job);
if (!spriteJob) {
continue;
}
if (!spriteJob->BlurBackground) {
continue;
}
shouldRun = true;
break;
}
if(!shouldRun) {
return m_BlackTexture->m_Texture;
}
FillStencil(scene);
RenderState state;
state.Disable(GL_BLEND);
state.Disable(GL_DEPTH_TEST);
state.Disable(GL_CULL_FACE);
state.Enable(GL_STENCIL_TEST);
state.StencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
state.StencilFunc(GL_EQUAL, 1, 0xFF);
state.StencilMask(0x00);
state.DepthMask(GL_FALSE);
state.Enable(GL_SCISSOR_TEST);
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();
glViewport(0, 0, m_Renderer->GetViewportSize().Width/m_BlurQuality, m_Renderer->GetViewportSize().Height/m_BlurQuality);
glScissor(0, 0, m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height);
m_GaussianProgram_vert->Bind();
glUniform1i(glGetUniformLocation(shaderHandle_vert, "Lod"), 0);
m_GaussianProgram_horiz->Bind();
glUniform1i(glGetUniformLocation(shaderHandle_horiz, "Lod"), 0);
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].material->EndIndex - m_ScreenQuad->MaterialGroups()[0].material->StartIndex +1
, GL_UNSIGNED_INT, 0, m_ScreenQuad->MaterialGroups()[0].material->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();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_GaussianTexture_horiz);
glDrawElementsBaseVertex(GL_TRIANGLES, m_ScreenQuad->MaterialGroups()[0].material->EndIndex - m_ScreenQuad->MaterialGroups()[0].material->StartIndex +1
, GL_UNSIGNED_INT, 0, m_ScreenQuad->MaterialGroups()[0].material->StartIndex);
//horizontal pass
m_GaussianFrameBuffer_vert.Unbind();
m_GaussianFrameBuffer_horiz.Bind();
m_GaussianProgram_horiz->Bind();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_GaussianTexture_vert);
glDrawElementsBaseVertex(GL_TRIANGLES, m_ScreenQuad->MaterialGroups()[0].material->EndIndex - m_ScreenQuad->MaterialGroups()[0].material->StartIndex +1
, GL_UNSIGNED_INT, 0, m_ScreenQuad->MaterialGroups()[0].material->StartIndex);
m_GaussianFrameBuffer_horiz.Unbind();
}
//final vertical gaussian after the iterations are done
m_GaussianFrameBuffer_vert.Bind();
m_GaussianProgram_vert->Bind();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_GaussianTexture_horiz);
glDrawElementsBaseVertex(GL_TRIANGLES, m_ScreenQuad->MaterialGroups()[0].material->EndIndex - m_ScreenQuad->MaterialGroups()[0].material->StartIndex +1
, GL_UNSIGNED_INT, 0, m_ScreenQuad->MaterialGroups()[0].material->StartIndex);
GLERROR("DrawBloomPass::Draw: END");
glViewport(0, 0, m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height);
glScissor(0, 0, m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height);
return m_GaussianTexture_vert;
}
void BlurHUD::OnWindowResize()
{
InitializeBuffers();
}
void BlurHUD::FillStencil(RenderScene& scene)
{
RenderState state;
state.BindFramebuffer(m_GaussianFrameBuffer_horiz.GetHandle());
state.Enable(GL_DEPTH_TEST);
state.Enable(GL_CULL_FACE);
state.Enable(GL_STENCIL_TEST);
state.StencilFunc(GL_ALWAYS, 1, 0xFF);
state.StencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
state.StencilMask(0xFF);
state.AlphaFunc(GL_GEQUAL, 0.95f);
state.Enable(GL_ALPHA_TEST);
glViewport(0, 0, m_Renderer->GetViewportSize().Width/m_BlurQuality, m_Renderer->GetViewportSize().Height/m_BlurQuality);
m_FillDepthStencilProgram->Bind();
GLuint shaderHandle = m_FillDepthStencilProgram->GetHandle();
glm::mat4 VP = scene.Camera->ProjectionMatrix() * scene.Camera->ViewMatrix();
for (auto& job : scene.Jobs.SpriteJob) {
auto spriteJob = std::dynamic_pointer_cast<SpriteJob>(job);
if (!spriteJob) {
continue;
}
if (!spriteJob->BlurBackground) {
continue;
}
glm::mat4 MVP = VP * spriteJob->Matrix;
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "PVM"), 1, GL_FALSE, glm::value_ptr(MVP));
glBindVertexArray(spriteJob->Model->VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, spriteJob->Model->ElementBuffer);
glDrawElements(GL_TRIANGLES, spriteJob->EndIndex - spriteJob->StartIndex + 1, GL_UNSIGNED_INT, (void*)(spriteJob->StartIndex*sizeof(unsigned int)));
}
//state.BindFramebuffer(m_GaussianFrameBuffer_vert.GetHandle());
//for (auto& job : scene.Jobs.SpriteJob) {
// auto spriteJob = std::dynamic_pointer_cast<SpriteJob>(job);
// if (!spriteJob) {
// continue;
// }
// if(!spriteJob->BlurBackground) {
// continue;
// }
// glm::mat4 MVP = VP * spriteJob->Matrix;
// glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "PVM"), 1, GL_FALSE, glm::value_ptr(MVP));
// glBindVertexArray(spriteJob->Model->VAO);
// glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, spriteJob->Model->ElementBuffer);
// glDrawElements(GL_TRIANGLES, spriteJob->EndIndex - spriteJob->StartIndex + 1, GL_UNSIGNED_INT, (void*)(spriteJob->StartIndex*sizeof(unsigned int)));
//}
glViewport(0, 0, m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height);
}
//Texture 1 will be used if texture 2 is black at that texel, else texture 2 is used.
GLuint BlurHUD::CombineTextures(GLuint texture1, GLuint texture2)
{
//RenderState state;
//state.BindFramebuffer(m_CombinedTextureBuffer.GetHandle());
//state.Disable(GL_DEPTH_TEST);
//state.Disable(GL_STENCIL_TEST);
m_CombineTexturesProgram->Bind();
glActiveTexture(GL_TEXTURE0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture1);
glBindTexture(GL_TEXTURE_2D, texture2);
glBindVertexArray(m_ScreenQuad->VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ScreenQuad->ElementBuffer);
glDrawElementsBaseVertex(GL_TRIANGLES, m_ScreenQuad->MaterialGroups()[0].material->EndIndex - m_ScreenQuad->MaterialGroups()[0].material->StartIndex +1
, GL_UNSIGNED_INT, 0, m_ScreenQuad->MaterialGroups()[0].material->StartIndex);
return m_CombinedTexture;
}
+25 -57
View File
@@ -8,10 +8,13 @@ void BoneAttachmentSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapp
return;
}
auto parent = entity.FirstParentWithComponent("Animation");
if (!parent.HasComponent("Model")) {
auto parent = entity.FirstParentWithComponent("Model");
if(!parent.Valid()) {
return;
}
Model* model;
try {
model = ResourceManager::Load<::Model, true>(parent["Model"]["Resource"]);
@@ -35,66 +38,31 @@ void BoneAttachmentSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapp
return;
}
std::vector<::Skeleton::AnimationData> Animations;
::Skeleton::AnimationOffset AnimationOffset;
glm::mat4 boneTransform;
if (skeleton->BlendTrees.find(parent) != skeleton->BlendTrees.end()) {
if (parent.HasComponent("Animation")) {
for (int i = 1; i <= 3; i++) {
::Skeleton::AnimationData animationData;
animationData.animation = model->m_RawModel->m_Skeleton->GetAnimation(parent["Animation"]["AnimationName" + std::to_string(i)]);
if (animationData.animation == nullptr) {
continue;
}
animationData.time = (double)parent["Animation"]["Time" + std::to_string(i)];
animationData.weight = (double)parent["Animation"]["Weight" + std::to_string(i)];
Animations.push_back(animationData);
}
}
glm::mat4 boneTransform = skeleton->BlendTrees.at(parent)->GetBoneTransform(id);
if (parent.HasComponent("AnimationOffset")) {
AnimationOffset.animation = model->m_RawModel->m_Skeleton->GetAnimation(parent["AnimationOffset"]["AnimationName"]);
AnimationOffset.time = (double)parent["AnimationOffset"]["Time"];
glm::vec3 scale;
glm::quat rotation;
glm::vec3 translation;
glm::vec3 skew;
glm::vec4 perspective;
glm::decompose(boneTransform, scale, rotation, translation, skew, perspective);
if(AnimationOffset.animation != nullptr) {
boneTransform = skeleton->GetBoneTransform(false, skeleton->Bones.at(id), Animations, AnimationOffset, glm::mat4(1));
} else {
boneTransform = skeleton->GetBoneTransform(false, skeleton->Bones.at(id), Animations, glm::mat4(1));
}
rotation = glm::quat((glm::vec3)entity["BoneAttachment"]["OrientationOffset"]) * rotation;
rotation = glm::inverse(rotation);
glm::vec3 angles = glm::eulerAngles(rotation);
} else {
boneTransform = skeleton->GetBoneTransform(false, skeleton->Bones.at(id), Animations, glm::mat4(1));
if ((bool)entity["BoneAttachment"]["InheritPosition"]) {
entity["Transform"]["Position"] = translation + (glm::vec3)entity["BoneAttachment"]["PositionOffset"];
}
if ((bool)entity["BoneAttachment"]["InheritOrientation"]) {
entity["Transform"]["Orientation"] = angles;
}
if ((bool)entity["BoneAttachment"]["InheritScale"]) {
entity["Transform"]["Scale"] = scale * (glm::vec3)entity["BoneAttachment"]["ScaleOffset"];
}
}
glm::vec3 scale;
glm::quat rotation;
glm::vec3 translation;
glm::vec3 skew;
glm::vec4 perspective;
glm::decompose(boneTransform, scale, rotation, translation, skew, perspective);
glm::vec3 angles = glm::vec3(-glm::pitch(rotation), -glm::yaw(rotation), -glm::roll(rotation));
/*
angles.y = asin(-boneTransform[0][2]);
if (cos(angles.y) != 0) {
angles.x = atan2(boneTransform[1][2], boneTransform[2][2]);
angles.z = atan2(boneTransform[0][1], boneTransform[0][0]);
} else {
angles.x = atan2(-boneTransform[2][0], boneTransform[1][1]);
angles.z = 0;
}*/
if ((bool)entity["BoneAttachment"]["InheritPosition"]) {
(glm::vec3&)entity["Transform"]["Position"] = translation + (glm::vec3)entity["BoneAttachment"]["PositionOffset"];
}
if ((bool)entity["BoneAttachment"]["InheritOrientation"]) {
(glm::vec3&)entity["Transform"]["Orientation"] = angles + (glm::vec3)entity["BoneAttachment"]["OrientationOffset"];
}
if ((bool)entity["BoneAttachment"]["InheritScale"]) {
(glm::vec3&)entity["Transform"]["Scale"] = scale * (glm::vec3)entity["BoneAttachment"]["ScaleOffset"];
}
}
+8 -8
View File
@@ -6,18 +6,16 @@ CubeMapPass::CubeMapPass(IRenderer* renderer)
LoadTextures("Nevada");
}
void CubeMapPass::LoadTextures(std::string input)
void CubeMapPass::LoadTextures(std::string cubemapName)
{
if (m_PreviusCubeMapTexture != input) {
if (m_PreviusCubeMapTexture != cubemapName) {
m_CubeMapTextures.clear();
for (int i = 0; i < 6; i++) {
std::string str;
str = "Textures/Test/CubeMap/" + input + "/CubeMapTest0" + std::to_string(i) + ".png";
Texture* img = ResourceManager::Load<Texture>(str);
m_CubeMapTextures.push_back(img);
std::string path = "Textures/Test/CubeMap/" + cubemapName + "/CubeMapTest0" + std::to_string(i) + ".png";
m_CubeMapTextures.push_back(path);
}
GenerateCubeMapTexture();
m_PreviusCubeMapTexture = input;
m_PreviusCubeMapTexture = cubemapName;
}
}
@@ -29,7 +27,9 @@ void CubeMapPass::GenerateCubeMapTexture()
glBindTexture(GL_TEXTURE_CUBE_MAP, m_CubeMapTexture);
for (int i = 0; i < 6; i++) {
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGBA32F, m_CubeMapTextures[0]->Width, m_CubeMapTextures[0]->Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_CubeMapTextures[i]->Data);
PNG* img = ResourceManager::Load<PNG>(m_CubeMapTextures[i]);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGBA32F, img->Width, img->Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img->Data);
ResourceManager::Release("PNG", m_CubeMapTextures[i]);
}
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+113 -46
View File
@@ -9,9 +9,15 @@ DrawBloomPass::DrawBloomPass(IRenderer* renderer, ConfigFile* config)
ChangeQuality(m_Config->Get<int>("GLOW.Quality", 2));
}
DrawBloomPass::~DrawBloomPass() {
CommonFunctions::DeleteTexture(&m_GaussianTexture_horiz);
CommonFunctions::DeleteTexture(&m_GaussianTexture_vert);
CommonFunctions::DeleteTexture(&m_FinalGaussianTexture);
}
void DrawBloomPass::InitializeTextures()
{
m_BlackTexture = CommonFunctions::LoadTexture("Textures/Core/Black.png", false);
m_BlackTexture = CommonFunctions::TryLoadResource<Texture, false>("Textures/Core/Black.png");
}
void DrawBloomPass::ChangeQuality(int quality)
@@ -25,9 +31,8 @@ void DrawBloomPass::ChangeQuality(int quality)
if (m_Quality == 0) {
CommonFunctions::DeleteTexture(&m_GaussianTexture_horiz);
CommonFunctions::DeleteTexture(&m_GaussianTexture_vert);
m_GaussianTexture_horiz = 0;
m_GaussianTexture_vert = 0;
CommonFunctions::DeleteTexture(&m_GaussianTexture_vert);
CommonFunctions::DeleteTexture(&m_FinalGaussianTexture);
return;
}
InitializeTextures();
@@ -45,6 +50,7 @@ void DrawBloomPass::InitializeShaderPrograms()
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->BindFragDataLocation(0, "fragmentColor");
m_GaussianProgram_horiz->Link();
}
@@ -53,24 +59,53 @@ void DrawBloomPass::InitializeShaderPrograms()
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->BindFragDataLocation(0, "fragmentColor");
m_GaussianProgram_vert->Link();
}
m_GaussianCombineProgram = ResourceManager::Load<ShaderProgram>("#GaussianCombineProgram");
if (m_GaussianCombineProgram->GetHandle() == 0) {
m_GaussianCombineProgram->AddShader(std::shared_ptr<Shader>(new VertexShader("Shaders/CombineGaussianTexture.vert.glsl")));
m_GaussianCombineProgram->AddShader(std::shared_ptr<Shader>(new FragmentShader("Shaders/CombineGaussianTexture.frag.glsl")));
m_GaussianCombineProgram->Compile();
m_GaussianCombineProgram->BindFragDataLocation(0, "fragmentColor");
m_GaussianCombineProgram->Link();
}
}
void DrawBloomPass::InitializeBuffers()
{
CommonFunctions::GenerateTexture(&m_GaussianTexture_horiz, GL_CLAMP_TO_EDGE, GL_LINEAR, glm::vec2(m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height), GL_RGB16F, GL_RGB, GL_FLOAT);
CommonFunctions::GenerateMipMapTexture(
&m_GaussianTexture_horiz, GL_CLAMP_TO_BORDER, glm::vec2(m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height),
GL_RGB16F, GL_RGB, GL_FLOAT, m_BloomLod, GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST);
CommonFunctions::GenerateMipMapTexture(
&m_GaussianTexture_vert, GL_CLAMP_TO_BORDER, glm::vec2(m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height),
GL_RGB16F, GL_RGB, GL_FLOAT, m_BloomLod, GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST);
CommonFunctions::GenerateTexture(&m_FinalGaussianTexture, GL_CLAMP_TO_BORDER, GL_NEAREST, glm::vec2(m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height), GL_RGB16F, GL_RGB, GL_FLOAT);
if (m_GaussianFrameBuffer_horiz.GetHandle() == 0) {
m_GaussianFrameBuffer_horiz.AddResource(std::shared_ptr<BufferResource>(new Texture2D(&m_GaussianTexture_horiz, GL_COLOR_ATTACHMENT0)));
}
m_GaussianFrameBuffer_horiz.Generate();
if (m_GaussianCombineBuffer.GetHandle() == 0) {
m_GaussianCombineBuffer.AddResource(std::shared_ptr<BufferResource>(new Texture2D(&m_FinalGaussianTexture, GL_COLOR_ATTACHMENT0)));
}
m_GaussianCombineBuffer.Generate();
CommonFunctions::GenerateTexture(&m_GaussianTexture_vert, GL_CLAMP_TO_EDGE, GL_LINEAR, glm::vec2(m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height), GL_RGB16F, GL_RGB, GL_FLOAT);
if (m_GaussianFrameBuffer_vert.GetHandle() == 0) {
m_GaussianFrameBuffer_vert.AddResource(std::shared_ptr<BufferResource>(new Texture2D(&m_GaussianTexture_vert, GL_COLOR_ATTACHMENT0)));
}
m_GaussianFrameBuffer_vert.Generate();
if(m_GaussianFrameBuffer_horiz == nullptr) {
m_GaussianFrameBuffer_horiz = new FrameBuffer[m_BloomLod];
}
if (m_GaussianFrameBuffer_vert == nullptr) {
m_GaussianFrameBuffer_vert = new FrameBuffer[m_BloomLod];
}
for (int i = 0; i < m_BloomLod; i++) {
if(m_GaussianFrameBuffer_horiz[i].GetHandle() == 0) {
m_GaussianFrameBuffer_horiz[i].AddResource(std::shared_ptr<BufferResource>(new Texture2D(&m_GaussianTexture_horiz, GL_COLOR_ATTACHMENT0, i)));
}
m_GaussianFrameBuffer_horiz[i].Generate();
if (m_GaussianFrameBuffer_vert[i].GetHandle() == 0) {
m_GaussianFrameBuffer_vert[i].AddResource(std::shared_ptr<BufferResource>(new Texture2D(&m_GaussianTexture_vert, GL_COLOR_ATTACHMENT0, i)));
}
m_GaussianFrameBuffer_vert[i].Generate();
}
}
@@ -80,33 +115,64 @@ void DrawBloomPass::ClearBuffer()
return;
}
GLERROR("PRE");
m_GaussianFrameBuffer_horiz.Bind();
for (int i = 0; i < m_BloomLod; i++) {
m_GaussianFrameBuffer_horiz[i].Bind();
glClearColor(0.f, 0.f, 0.f, 0.f);
glClear(GL_COLOR_BUFFER_BIT);
m_GaussianFrameBuffer_horiz[i].Unbind();
m_GaussianFrameBuffer_vert[i].Bind();
glClearColor(0.f, 0.f, 0.f, 0.f);
glClear(GL_COLOR_BUFFER_BIT);
m_GaussianFrameBuffer_vert[i].Unbind();
}
m_GaussianCombineBuffer.Bind();
glClearColor(0.f, 0.f, 0.f, 0.f);
glClear(GL_COLOR_BUFFER_BIT);
m_GaussianFrameBuffer_horiz.Unbind();
m_GaussianFrameBuffer_vert.Bind();
glClearColor(0.f, 0.f, 0.f, 0.f);
glClear(GL_COLOR_BUFFER_BIT);
m_GaussianFrameBuffer_vert.Unbind();
m_GaussianCombineBuffer.Unbind();
GLERROR("END");
}
void DrawBloomPass::Draw(GLuint texture)
{
if (m_Quality == 0) {
return;
}
for (int i = 0; i < m_BloomLod; i++) {
GaussianLodPass(i, texture);
}
CombineGaussianBlur();
}
void DrawBloomPass::OnWindowResize()
{
if (m_Quality == 0) {
return;
}
GLERROR("DrawBloomPass::Draw: Pre");
InitializeBuffers();
}
void DrawBloomPass::GaussianLodPass(GLuint mipMap, GLuint texture)
{
GLERROR("DrawBloomPass::Draw: Pre");
glViewport(0, 0, m_Renderer->GetViewportSize().Width/(glm::pow(2, mipMap)), m_Renderer->GetViewportSize().Height/(glm::pow(2, mipMap)));
DrawBloomPassState state;
GLuint shaderHandle_horiz = m_GaussianProgram_horiz->GetHandle();
GLuint shaderHandle_vert = m_GaussianProgram_vert->GetHandle();
m_GaussianProgram_vert->Bind();
glUniform1i(glGetUniformLocation(shaderHandle_vert, "Lod"), mipMap);
m_GaussianProgram_horiz->Bind();
glUniform1i(glGetUniformLocation(shaderHandle_horiz, "Lod"), mipMap);
//Horizontal pass, first use the given texture then save it to the horizontal framebuffer.
m_GaussianFrameBuffer_horiz.Bind();
m_GaussianProgram_horiz->Bind();
m_GaussianFrameBuffer_horiz[mipMap].Bind();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glBindVertexArray(m_ScreenQuad->VAO);
@@ -116,55 +182,56 @@ void DrawBloomPass::Draw(GLuint texture)
//Iterate some times to make it more gaussian.
for (int i = 1; i < m_Iterations; i++) {
//Vertical pass
m_GaussianFrameBuffer_vert.Bind();
m_GaussianFrameBuffer_vert[mipMap].Bind();
m_GaussianProgram_vert->Bind();
glActiveTexture(GL_TEXTURE0);
glActiveTexture(GL_TEXTURE0);
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].material->EndIndex - m_ScreenQuad->MaterialGroups()[0].material->StartIndex +1
, GL_UNSIGNED_INT, 0, m_ScreenQuad->MaterialGroups()[0].material->StartIndex);
//horizontal pass
m_GaussianFrameBuffer_vert.Unbind();
m_GaussianFrameBuffer_vert[mipMap].Unbind();
m_GaussianFrameBuffer_horiz.Bind();
m_GaussianFrameBuffer_horiz[mipMap].Bind();
m_GaussianProgram_horiz->Bind();
glActiveTexture(GL_TEXTURE0);
glActiveTexture(GL_TEXTURE0);
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].material->EndIndex - m_ScreenQuad->MaterialGroups()[0].material->StartIndex +1
, GL_UNSIGNED_INT, 0, m_ScreenQuad->MaterialGroups()[0].material->StartIndex);
m_GaussianFrameBuffer_horiz.Unbind();
m_GaussianFrameBuffer_horiz[mipMap].Unbind();
}
//final vertical gaussian after the iterations are done
m_GaussianFrameBuffer_vert.Bind();
m_GaussianFrameBuffer_vert[mipMap].Bind();
m_GaussianProgram_vert->Bind();
glActiveTexture(GL_TEXTURE0);
glActiveTexture(GL_TEXTURE0);
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].material->EndIndex - m_ScreenQuad->MaterialGroups()[0].material->StartIndex +1
, GL_UNSIGNED_INT, 0, m_ScreenQuad->MaterialGroups()[0].material->StartIndex);
GLERROR("DrawBloomPass::Draw: END");
glViewport(0, 0, m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height);
m_GaussianFrameBuffer_vert[mipMap].Unbind();
}
void DrawBloomPass::OnWindowResize()
void DrawBloomPass::CombineGaussianBlur()
{
if (m_Quality == 0) {
return;
}
CommonFunctions::GenerateTexture(&m_GaussianTexture_vert, GL_CLAMP_TO_EDGE, GL_LINEAR, glm::vec2(m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height), GL_RGB16F, GL_RGB, GL_FLOAT);
m_GaussianFrameBuffer_vert.Generate();
CommonFunctions::GenerateTexture(&m_GaussianTexture_horiz, GL_CLAMP_TO_EDGE, GL_LINEAR, glm::vec2(m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height), GL_RGB16F, GL_RGB, GL_FLOAT);
m_GaussianFrameBuffer_horiz.Generate();
m_GaussianCombineBuffer.Bind();
m_GaussianCombineProgram->Bind();
glUniform1i(glGetUniformLocation(m_GaussianCombineProgram->GetHandle(), "MaxMipMap"), m_BloomLod);
glActiveTexture(GL_TEXTURE0);
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].material->EndIndex - m_ScreenQuad->MaterialGroups()[0].material->StartIndex +1
, GL_UNSIGNED_INT, 0, m_ScreenQuad->MaterialGroups()[0].material->StartIndex);
}
File diff suppressed because it is too large Load Diff
@@ -10,6 +10,8 @@ DrawFinalPassState::DrawFinalPassState(GLuint frameBuffer)
Enable(GL_DEPTH_TEST);
DepthMask(GL_TRUE);
Enable(GL_CULL_FACE);
Enable(GL_ALPHA_TEST);
AlphaFunc(GL_GEQUAL, 0.05f);
// Enable(GL_STENCIL_TEST);
// StencilFunc(GL_NOTEQUAL, 1, 0xFF);
// StencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
+50 -9
View File
@@ -2,11 +2,13 @@
#include "Rendering/FrameBuffer.h"
BufferResource::BufferResource(GLuint* resourceHandle, GLenum resourceType, GLenum attachment)
BufferResource::BufferResource(GLuint* resourceHandle, GLenum resourceType, GLenum attachment, GLuint mipMapLod, bool multiSampling)
{
m_ResourceHandle = resourceHandle;
m_ResourceType = resourceType;
m_Attachment = attachment;
m_MipMapLod = mipMapLod;
m_MultiSampling = multiSampling;
}
Texture2D::~Texture2D()
@@ -14,14 +16,31 @@ Texture2D::~Texture2D()
if (m_ResourceHandle != 0) {
glDeleteTextures(1, m_ResourceHandle);
}
*m_ResourceHandle = 0;
}
Texture2DMultiSample::~Texture2DMultiSample()
{
if (m_ResourceHandle != 0) {
glDeleteTextures(1, m_ResourceHandle);
}
*m_ResourceHandle = 0;
}
RenderBuffer::~RenderBuffer()
{
if (m_ResourceHandle != 0) {
glDeleteRenderbuffers(1, m_ResourceHandle);
}
*m_ResourceHandle = 0;
}
Texture2DArray::~Texture2DArray()
{
if (m_ResourceHandle != 0) {
glDeleteTextures(1, m_ResourceHandle);
}
*m_ResourceHandle = 0;
}
@@ -34,6 +53,14 @@ FrameBuffer::~FrameBuffer()
void FrameBuffer::AddResource(std::shared_ptr<BufferResource> resource)
{
//m_MultiSampling is true when initialized
if (m_MultiSampling != resource->m_MultiSampling) {
if (m_MultiSampling == false) {
GLERROR("All renderbuffers is/is not using multisampling");
} else {
m_MultiSampling = false;
}
}
m_Resources.push_back(resource);
}
@@ -47,17 +74,23 @@ void FrameBuffer::Generate()
}
glBindFramebuffer(GL_FRAMEBUFFER, m_BufferHandle);
GLERROR("1");
for (auto it = m_Resources.begin(); it != m_Resources.end(); it++) {
switch ((*it)->m_ResourceType) {
case GL_TEXTURE_2D_MULTISAMPLE:
glFramebufferTexture2D(GL_FRAMEBUFFER, (*it)->m_Attachment, GL_TEXTURE_2D_MULTISAMPLE, 0, 0);
GLERROR("FrameBuffer generate: GL_TEXTURE_2D_MULTISAMPLE");
break;
case GL_TEXTURE_2D:
glFramebufferTexture2D(GL_FRAMEBUFFER, (*it)->m_Attachment, (*it)->m_ResourceType, *(*it)->m_ResourceHandle, 0);
GLERROR("FrameBuffer generate: glFramebufferTexture2D");
glFramebufferTexture(GL_FRAMEBUFFER, (*it)->m_Attachment, *(*it)->m_ResourceHandle, (*it)->m_MipMapLod);
GLERROR("FrameBuffer generate: GL_TEXTURE_2D");
break;
case GL_RENDERBUFFER:
glFramebufferRenderbuffer(GL_FRAMEBUFFER, (*it)->m_Attachment, (*it)->m_ResourceType, *(*it)->m_ResourceHandle);
GLERROR("FrameBuffer generate: glFramebufferRenderbuffer");
GLERROR("FrameBuffer generate: GL_RENDERBUFFER");
break;
case GL_TEXTURE_2D_ARRAY:
glFramebufferTexture(GL_FRAMEBUFFER, (*it)->m_Attachment, *(*it)->m_ResourceHandle, 0);
GLERROR("FrameBuffer generate: GL_TEXTURE_2D_ARRAY");
break;
}
GLERROR("2");
@@ -66,11 +99,11 @@ void FrameBuffer::Generate()
attachments.push_back((*it)->m_Attachment);
}
GLERROR("Attachment");
}
GLERROR("3");
GLenum* bufferTextures = &attachments[0];
GLenum* bufferTextures = attachments.data();
glDrawBuffers(attachments.size(), bufferTextures);
if (GLERROR("GLBufferAttachement error")) {
printf(": AttachmentSize %i", attachments.size());
@@ -78,7 +111,7 @@ void FrameBuffer::Generate()
if (GLenum frameBufferStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
GLERROR("Framebuffer incomplete");
//LOG_ERROR("FrameBuffer incomplete: 0x%x\n", frameBufferStatus);
LOG_ERROR("FrameBuffer incomplete: 0x%x\n", glCheckFramebufferStatus(GL_FRAMEBUFFER));
exit(EXIT_FAILURE);
}
GLERROR("END");
@@ -99,3 +132,11 @@ GLuint FrameBuffer::GetHandle()
{
return m_BufferHandle;
}
void FrameBuffer::Read() {
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_BufferHandle);
}
void FrameBuffer::Draw() {
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_BufferHandle);
}
@@ -42,6 +42,15 @@ void LightCullingPass::SetSSBOSizes()
{
m_NumberOfTiles = (int)(m_Renderer->GetViewportSize().Width/TILE_SIZE) * (int)(m_Renderer->GetViewportSize().Height/TILE_SIZE);
if (m_Frustums != nullptr) {
delete[] m_Frustums;
}
if (m_LightGrid != nullptr) {
delete[] m_LightGrid;
}
if (m_LightIndex != nullptr) {
delete[] m_LightIndex;
}
m_Frustums = new Frustum[m_NumberOfTiles];
m_LightGrid = new LightGrid[m_NumberOfTiles];
m_LightIndex = new float[m_NumberOfTiles*MAX_LIGHTS_PER_TILE];
+9 -9
View File
@@ -10,31 +10,31 @@ Model::Model(std::string fileName)
case RawModel::MaterialType::SingleTextures:
{
RawModel::MaterialSingleTextures* materialSingleTexture = static_cast<RawModel::MaterialSingleTextures*>(materialProperty.material);
materialSingleTexture->ColorMap.Texture = CommonFunctions::LoadTexture(materialSingleTexture->ColorMap.TexturePath, false);
materialSingleTexture->NormalMap.Texture = CommonFunctions::LoadTexture(materialSingleTexture->NormalMap.TexturePath, false);
materialSingleTexture->SpecularMap.Texture = CommonFunctions::LoadTexture(materialSingleTexture->SpecularMap.TexturePath, false);
materialSingleTexture->IncandescenceMap.Texture = CommonFunctions::LoadTexture(materialSingleTexture->IncandescenceMap.TexturePath, false);
materialSingleTexture->ColorMap.Texture = CommonFunctions::TryLoadResource<Texture, false>(materialSingleTexture->ColorMap.TexturePath);
materialSingleTexture->NormalMap.Texture = CommonFunctions::TryLoadResource<Texture, false>(materialSingleTexture->NormalMap.TexturePath);
materialSingleTexture->SpecularMap.Texture = CommonFunctions::TryLoadResource<Texture, false>(materialSingleTexture->SpecularMap.TexturePath);
materialSingleTexture->IncandescenceMap.Texture = CommonFunctions::TryLoadResource<Texture, false>(materialSingleTexture->IncandescenceMap.TexturePath);
}
break;
case RawModel::MaterialType::SplatMapping:
{
RawModel::MaterialSplatMapping* materialSplatMapping = static_cast<RawModel::MaterialSplatMapping*>(materialProperty.material);
materialSplatMapping->SplatMap.Texture = CommonFunctions::LoadTexture(materialSplatMapping->SplatMap.TexturePath, false);
materialSplatMapping->SplatMap.Texture = CommonFunctions::TryLoadResource<Texture, false>(materialSplatMapping->SplatMap.TexturePath);
for (auto& texture : materialSplatMapping->ColorMaps)
{
texture.Texture = CommonFunctions::LoadTexture(texture.TexturePath, false);
texture.Texture = CommonFunctions::TryLoadResource<Texture, false>(texture.TexturePath);
}
for (auto& texture : materialSplatMapping->NormalMaps)
{
texture.Texture = CommonFunctions::LoadTexture(texture.TexturePath, false);
texture.Texture = CommonFunctions::TryLoadResource<Texture, false>(texture.TexturePath);
}
for (auto& texture : materialSplatMapping->SpecularMaps)
{
texture.Texture = CommonFunctions::LoadTexture(texture.TexturePath, false);
texture.Texture = CommonFunctions::TryLoadResource<Texture, false>(texture.TexturePath);
}
for (auto& texture : materialSplatMapping->IncandescenceMaps)
{
texture.Texture = CommonFunctions::LoadTexture(texture.TexturePath, false);
texture.Texture = CommonFunctions::TryLoadResource<Texture, false>(texture.TexturePath);
}
}
break;
+62 -55
View File
@@ -12,7 +12,8 @@ PickingPass::PickingPass(IRenderer* renderer, EventBroker* eb)
PickingPass::~PickingPass()
{
CommonFunctions::DeleteTexture(&m_PickingTexture);
CommonFunctions::DeleteTexture(&m_DepthBuffer);
}
@@ -23,7 +24,7 @@ void PickingPass::InitializeTextures()
glm::vec2(m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height), GL_RG8, GL_RG, GL_UNSIGNED_BYTE);
CommonFunctions::GenerateTexture(&m_DepthBuffer, GL_CLAMP_TO_BORDER, GL_NEAREST,
glm::vec2(m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height), GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT);
glm::vec2(m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height), GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT);
}
void PickingPass::InitializeFrameBuffers()
@@ -61,8 +62,9 @@ void PickingPass::Draw(RenderScene& scene)
//TODO: Render: Add code for more jobs than modeljobs.
GLuint shaderHandle = m_PickingProgram->GetHandle();
GLuint shaderSkinnedHandle = m_PickingSkinnedProgram->GetHandle();
GLuint lastShader = 0;
unsigned int lastModel = 0;
m_PickingProgram->Bind();
if (scene.ClearDepth) {
//glClear(GL_DEPTH_BUFFER_BIT);
state->Disable(GL_DEPTH_TEST);
@@ -74,6 +76,11 @@ void PickingPass::Draw(RenderScene& scene)
auto modelJob = std::dynamic_pointer_cast<ModelJob>(job);
if (modelJob) {
if(modelJob->NotPickable) {
continue;
}
int pickColor[2] = { m_ColorCounter[0], m_ColorCounter[1] };
PickingInfo pickInfo;
@@ -98,32 +105,36 @@ void PickingPass::Draw(RenderScene& scene)
m_PickingColorsToEntity[glm::ivec2(pickColor[0], pickColor[1])] = pickInfo;
if (modelJob->Model->IsSkinned()) {
m_PickingSkinnedProgram->Bind();
glUniformMatrix4fv(glGetUniformLocation(shaderSkinnedHandle, "M"), 1, GL_FALSE, glm::value_ptr(modelJob->Matrix));
glUniformMatrix4fv(glGetUniformLocation(shaderSkinnedHandle, "V"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ViewMatrix()));
glUniformMatrix4fv(glGetUniformLocation(shaderSkinnedHandle, "P"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ProjectionMatrix()));
if (lastShader != m_PickingSkinnedProgram->GetHandle()) {
m_PickingSkinnedProgram->Bind();
lastShader = m_PickingSkinnedProgram->GetHandle();
}
glUniformMatrix4fv(glGetUniformLocation(shaderSkinnedHandle, "PVM"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ProjectionMatrix() * scene.Camera->ViewMatrix() * modelJob->Matrix));
glUniform2fv(glGetUniformLocation(shaderSkinnedHandle, "PickingColor"), 1, glm::value_ptr(glm::vec2(pickColor[0], pickColor[1])));
if (modelJob->Model->m_RawModel->m_Skeleton != nullptr) {
std::vector<glm::mat4> frameBones;
if (modelJob->AnimationOffset.animation != nullptr) {
frameBones = modelJob->Skeleton->GetFrameBones(modelJob->Animations, modelJob->AnimationOffset);
} else {
frameBones = modelJob->Skeleton->GetFrameBones(modelJob->Animations);
}
glUniformMatrix4fv(glGetUniformLocation(shaderSkinnedHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0]));
std::vector<glm::mat4> frameBones;
if (modelJob->BlendTree != nullptr) {
frameBones = modelJob->BlendTree->GetFinalPose();
} else {
frameBones = modelJob->Skeleton->GetTPose();
}
glUniformMatrix4fv(glGetUniformLocation(shaderSkinnedHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0]));
} else {
m_PickingProgram->Bind();
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()));
if (lastShader != m_PickingProgram->GetHandle()) {
m_PickingProgram->Bind();
lastShader = m_PickingProgram->GetHandle();
}
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "PVM"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ProjectionMatrix() * scene.Camera->ViewMatrix() * modelJob->Matrix));
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);
if (lastModel != modelJob->ModelID) {
glBindVertexArray(modelJob->Model->VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, modelJob->Model->ElementBuffer);
lastModel = modelJob->ModelID;
}
glDrawElements(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, (void*)(modelJob->StartIndex * sizeof(unsigned int)));
}
}
@@ -162,13 +173,11 @@ void PickingPass::Draw(RenderScene& scene)
glUniformMatrix4fv(glGetUniformLocation(shaderSkinnedHandle, "P"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ProjectionMatrix()));
glUniform2fv(glGetUniformLocation(shaderSkinnedHandle, "PickingColor"), 1, glm::value_ptr(glm::vec2(pickColor[0], pickColor[1])));
std::vector<glm::mat4> frameBones;
if (modelJob->AnimationOffset.animation != nullptr) {
frameBones = modelJob->Skeleton->GetFrameBones(modelJob->Animations, modelJob->AnimationOffset);
} else {
frameBones = modelJob->Skeleton->GetFrameBones(modelJob->Animations);
if (modelJob->BlendTree != nullptr) {
std::vector<glm::mat4> frameBones;
frameBones = modelJob->BlendTree->GetFinalPose();
glUniformMatrix4fv(glGetUniformLocation(shaderSkinnedHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0]));
}
glUniformMatrix4fv(glGetUniformLocation(shaderSkinnedHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0]));
} else {
m_PickingProgram->Bind();
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "M"), 1, GL_FALSE, glm::value_ptr(modelJob->Matrix));
@@ -211,34 +220,41 @@ void PickingPass::Draw(RenderScene& scene)
m_PickingColorsToEntity[glm::ivec2(pickColor[0], pickColor[1])] = pickInfo;
if (modelJob->Model->IsSkinned()) {
m_PickingSkinnedProgram->Bind();
glUniformMatrix4fv(glGetUniformLocation(shaderSkinnedHandle, "M"), 1, GL_FALSE, glm::value_ptr(modelJob->Matrix));
glUniformMatrix4fv(glGetUniformLocation(shaderSkinnedHandle, "V"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ViewMatrix()));
glUniformMatrix4fv(glGetUniformLocation(shaderSkinnedHandle, "P"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ProjectionMatrix()));
if (lastShader != m_PickingSkinnedProgram->GetHandle()) {
m_PickingSkinnedProgram->Bind();
lastShader = m_PickingSkinnedProgram->GetHandle();
}
glUniformMatrix4fv(glGetUniformLocation(shaderSkinnedHandle, "PVM"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ProjectionMatrix() * scene.Camera->ViewMatrix() * modelJob->Matrix));
glUniform2fv(glGetUniformLocation(shaderSkinnedHandle, "PickingColor"), 1, glm::value_ptr(glm::vec2(pickColor[0], pickColor[1])));
std::vector<glm::mat4> frameBones;
if (modelJob->AnimationOffset.animation != nullptr) {
frameBones = modelJob->Skeleton->GetFrameBones(modelJob->Animations, modelJob->AnimationOffset);
if (modelJob->BlendTree != nullptr) {
frameBones = modelJob->BlendTree->GetFinalPose();
} else {
frameBones = modelJob->Skeleton->GetFrameBones(modelJob->Animations);
frameBones = modelJob->Skeleton->GetTPose();
}
glUniformMatrix4fv(glGetUniformLocation(shaderSkinnedHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0]));
} else {
m_PickingProgram->Bind();
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()));
if (lastShader != m_PickingProgram->GetHandle()) {
m_PickingProgram->Bind();
lastShader = m_PickingProgram->GetHandle();
}
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "PVM"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ProjectionMatrix() * scene.Camera->ViewMatrix() * modelJob->Matrix));
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);
if (lastModel != modelJob->ModelID) {
glBindVertexArray(modelJob->Model->VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, modelJob->Model->ElementBuffer);
lastModel = modelJob->ModelID;
}
glDrawElements(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, (void*)(modelJob->StartIndex * sizeof(unsigned int)));
}
}
m_PickingProgram->Bind();
for (auto& job : scene.Jobs.SpriteJob) {
auto spriteJob = std::dynamic_pointer_cast<SpriteJob>(job);
if (!spriteJob->Pickable) {
@@ -273,14 +289,11 @@ void PickingPass::Draw(RenderScene& scene)
m_PickingColorsToEntity[glm::ivec2(pickColor[0], pickColor[1])] = pickInfo;
m_PickingProgram->Bind();
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "M"), 1, GL_FALSE, glm::value_ptr(spriteJob->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()));
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "PVM"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ProjectionMatrix() * scene.Camera->ViewMatrix() * spriteJob->Matrix));
glUniform2fv(glGetUniformLocation(shaderHandle, "PickingColor"), 1, glm::value_ptr(glm::vec2(pickColor[0], pickColor[1])));
glBindVertexArray(spriteJob->Model->VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, spriteJob->Model->ElementBuffer);
glBindVertexArray(spriteJob->Model->VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, spriteJob->Model->ElementBuffer);
glDrawElements(GL_TRIANGLES, spriteJob->EndIndex - spriteJob->StartIndex + 1, GL_UNSIGNED_INT, (void*)(spriteJob->StartIndex * sizeof(unsigned int)));
}
}
@@ -322,16 +335,10 @@ void PickingPass::Draw(RenderScene& scene)
glUniformMatrix4fv(glGetUniformLocation(shaderSkinnedHandle, "P"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ProjectionMatrix()));
glUniform2fv(glGetUniformLocation(shaderSkinnedHandle, "PickingColor"), 1, glm::value_ptr(glm::vec2(pickColor[0], pickColor[1])));
if (modelJob->Model->m_RawModel->m_Skeleton != nullptr) {
if (modelJob->BlendTree != nullptr) {
std::vector<glm::mat4> frameBones;
if (modelJob->AnimationOffset.animation != nullptr) {
frameBones = modelJob->Skeleton->GetFrameBones(modelJob->Animations, modelJob->AnimationOffset);
} else {
frameBones = modelJob->Skeleton->GetFrameBones(modelJob->Animations);
}
frameBones = modelJob->BlendTree->GetFinalPose();
glUniformMatrix4fv(glGetUniformLocation(shaderSkinnedHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0]));
}
} else {
m_PickingProgram->Bind();
+15
View File
@@ -149,14 +149,29 @@ void RawModelCustom::ReadMaterialSingle(std::size_t& offset, char* fileData, con
case MaterialType::Basic:
newMaterialProperty.material = new MaterialBasic();
ReadMaterialBasic(newMaterialProperty.material, offset, fileData, fileByteSize);
if(hasSkin){
newMaterialProperty.ShaderID = ResourceManager::Load<ShaderProgram>("#ForwardPlusSkinnedProgram")->ResourceID;
} else {
newMaterialProperty.ShaderID = ResourceManager::Load<ShaderProgram>("#ForwardPlusProgram")->ResourceID;
}
break;
case MaterialType::SplatMapping:
newMaterialProperty.material = new MaterialSplatMapping();
ReadMaterialSplatMapping(static_cast<MaterialSplatMapping*>(newMaterialProperty.material), offset, fileData, fileByteSize);
if (hasSkin){
newMaterialProperty.ShaderID = ResourceManager::Load<ShaderProgram>("#ForwardPlusSplatMapSkinnedProgram")->ResourceID;
} else {
newMaterialProperty.ShaderID = ResourceManager::Load<ShaderProgram>("#ForwardPlusSplatMapProgram")->ResourceID;
}
break;
case MaterialType::SingleTextures:
newMaterialProperty.material = new MaterialSingleTextures();
ReadMaterialSingleTexture(static_cast<MaterialSingleTextures*>(newMaterialProperty.material), offset, fileData, fileByteSize);
if (hasSkin){
newMaterialProperty.ShaderID = ResourceManager::Load<ShaderProgram>("#ForwardPlusSkinnedProgram")->ResourceID;
} else {
newMaterialProperty.ShaderID = ResourceManager::Load<ShaderProgram>("#ForwardPlusProgram")->ResourceID;
}
break;
default:
throw Resource::FailedLoadingException("Material contains an unknown MaterialType");
+29 -13
View File
@@ -9,10 +9,11 @@ RenderSystem::RenderSystem(SystemParams params, const IRenderer* renderer, Rende
, m_Octree(frustumCullOctree)
{
EVENT_SUBSCRIBE_MEMBER(m_ESetCamera, &RenderSystem::OnSetCamera);
EVENT_SUBSCRIBE_MEMBER(m_EResolutionChanged, &RenderSystem::OnResolutionChanged);
EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &RenderSystem::OnInputCommand);
EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &RenderSystem::OnPlayerSpawned);
m_Camera = new Camera((float)m_Renderer->Resolution().Width / m_Renderer->Resolution().Height, glm::radians(45.f), 0.01f, 5000.f);
m_Camera = new Camera((float)m_Renderer->GetViewportSize().Width / m_Renderer->GetViewportSize().Height, glm::radians(45.f), 0.01f, 5000.f);
}
RenderSystem::~RenderSystem()
@@ -20,11 +21,18 @@ RenderSystem::~RenderSystem()
delete m_Camera;
}
bool RenderSystem::OnResolutionChanged(Events::ResolutionChanged& e)
{
// Update camera aspect ration on resolution change
m_Camera->SetAspectRatio((float)e.NewResolution.Width / e.NewResolution.Height);
return true;
}
bool RenderSystem::OnSetCamera(Events::SetCamera& e)
{
ComponentWrapper cTransform = e.CameraEntity["Transform"];
ComponentWrapper cCamera = e.CameraEntity["Camera"];
m_Camera->SetFOV((double)cCamera["FOV"]);
m_Camera->SetFOV(glm::radians((double)cCamera["FOV"]));
m_Camera->SetNearClip((double)cCamera["NearClip"]);
m_Camera->SetFarClip((double)cCamera["FarClip"]);
m_Camera->SetPosition(cTransform["Position"]);
@@ -63,7 +71,7 @@ void RenderSystem::fillSprites(std::list<std::shared_ptr<RenderJob>>& jobs, Worl
float minScale = (float)(double)indicator["MinScale"];
bool hasTeam = indicator["VisibleForSingleTeamOnly"];
isIndicator = true;
glm::vec3 pos = Transform::AbsolutePosition(entity);
glm::vec3 pos = TransformSystem::AbsolutePosition(entity);
EntityWrapper entityTeam;
@@ -130,7 +138,7 @@ void RenderSystem::fillSprites(std::list<std::shared_ptr<RenderJob>>& jobs, Worl
modelMatrix[3][2] = pos.z;
modelMatrix[3][3] = 1.0f;
glm::mat4 tranformationMatrix = modelMatrix * glm::scale(Transform::AbsoluteScale(entity));
glm::mat4 tranformationMatrix = modelMatrix * glm::scale(TransformSystem::AbsoluteScale(entity));
glm::vec4 tmp = tranformationMatrix * glm::vec4(glm::vec3(0.5, 0.5, 0), 1.0f);
glm::vec2 projectedTopRight = m_Camera->WorldToScreen(glm::vec3(tmp), m_Renderer->GetViewportSize());
tmp = tranformationMatrix * glm::vec4(glm::vec3(-0.5, -0.5, 0), 1.0f);
@@ -143,7 +151,7 @@ void RenderSystem::fillSprites(std::list<std::shared_ptr<RenderJob>>& jobs, Worl
modelMatrix = tranformationMatrix;
}
else {
modelMatrix = Transform::ModelMatrix(entity.ID, world);
modelMatrix = TransformSystem::ModelMatrix(entity.ID, world);
}
@@ -176,7 +184,7 @@ bool RenderSystem::isEntityVisible(EntityWrapper& entity)
}
// Hide things parented to local player if they have the HiddenFromLocalPlayer component
bool outOfBodyExperience = ResourceManager::Load<ConfigFile>("Config.ini")->Get<bool>("Debug.OutOfBodyExperience", false);
bool outOfBodyExperience = false; // ResourceManager::Load<ConfigFile>("Config.ini")->Get<bool>("Debug.OutOfBodyExperience", false);
if (
(entity.HasComponent("HiddenForLocalPlayer") || entity.FirstParentWithComponent("HiddenForLocalPlayer").Valid())
&& (entity == m_LocalPlayer || entity.IsChildOf(m_LocalPlayer))
@@ -242,7 +250,7 @@ void RenderSystem::fillModels(RenderScene::Queues &Jobs)
bool isShielded = m_World->HasComponent(cModel.EntityID, "Shielded") || m_World->HasComponent(cModel.EntityID, "Player");
glm::mat4 modelMatrix = Transform::ModelMatrix(cModel.EntityID, m_World);
glm::mat4 modelMatrix = TransformSystem::ModelMatrix(cModel.EntityID, m_World);
//Loop through all materialgroups of a model
for (auto matGroup : model->MaterialGroups()) {
//If the model has an explosioneffect component, we will add an explosioneffectjob
@@ -258,7 +266,8 @@ void RenderSystem::fillModels(RenderScene::Queues &Jobs)
m_World,
fillColor,
fillPercentage,
isShielded
isShielded,
false
));
if (m_World->HasComponent(cModel.EntityID, "Shield")){
explosionEffectJob->CalculateHash();
@@ -296,7 +305,8 @@ void RenderSystem::fillModels(RenderScene::Queues &Jobs)
m_World,
fillColor,
fillPercentage,
isShielded
isShielded,
(bool)cModel["Shadow"]
));
if (m_World->HasComponent(cModel.EntityID, "Shield")) {
modelJob->CalculateHash();
@@ -352,6 +362,11 @@ void RenderSystem::fillPointLights(std::list<std::shared_ptr<RenderJob>>& jobs,
continue;
}
EntityWrapper entity(world, pointlightC.EntityID);
if (!isEntityVisible(entity)) {
continue;
}
std::shared_ptr<PointLightJob> pointLightJob = std::shared_ptr<PointLightJob>(new PointLightJob(transformC, pointlightC, m_World));
jobs.push_back(pointLightJob);
}
@@ -412,7 +427,7 @@ void RenderSystem::fillText(std::list<std::shared_ptr<RenderJob>>& jobs, World*
}
}
glm::mat4 modelMatrix = Transform::ModelMatrix(textComponent.EntityID, world);
glm::mat4 modelMatrix = TransformSystem::ModelMatrix(textComponent.EntityID, world);
std::shared_ptr<TextJob> textJob = std::shared_ptr<TextJob>(new TextJob(modelMatrix, font, textComponent));
jobs.push_back(textJob);
@@ -430,11 +445,12 @@ void RenderSystem::Update(double dt)
// Update the current camera used for rendering
if (m_CurrentCamera.Valid()) {
m_Camera->SetPosition(Transform::AbsolutePosition(m_CurrentCamera));
m_Camera->SetOrientation(Transform::AbsoluteOrientation(m_CurrentCamera));
m_Camera->SetPosition(TransformSystem::AbsolutePosition(m_CurrentCamera));
m_Camera->SetOrientation(TransformSystem::AbsoluteOrientation(m_CurrentCamera));
}
RenderScene scene;
scene.ShouldBlur = true;
scene.Camera = m_Camera;
scene.Viewport = Rectangle(1280, 720);
@@ -448,7 +464,7 @@ void RenderSystem::Update(double dt)
fillModels(scene.Jobs);
fillPointLights(scene.Jobs.PointLight, m_World);
//TODO: Make sure all objects needed are also sorted.
scene.Jobs.OpaqueObjects.sort();
scene.Jobs.OpaqueObjects.sort([](auto& a, auto& b) {return *a < *b; });
fillSprites(scene.Jobs.SpriteJob, m_World);
fillDirectionalLights(scene.Jobs.DirectionalLight, m_World);
fillText(scene.Jobs.Text, m_World);
+94 -19
View File
@@ -2,6 +2,19 @@
std::unordered_map<GLFWwindow*, Renderer*> Renderer::m_WindowToRenderer;
Renderer::~Renderer() {
delete m_PickingPass;
delete m_LightCullingPass;
delete m_ImGuiRenderPass;
delete m_DrawFinalPass;
delete m_DrawScreenQuadPass;
delete m_DrawBloomPass;
delete m_DrawColorCorrectionPass;
delete m_SSAOPass;
delete m_CubeMapPass;
delete m_TextPass;
}
void Renderer::Initialize()
{
m_SSAO_Quality = m_Config->Get<int>("SSAO.Quality", 0);
@@ -17,22 +30,30 @@ void Renderer::Initialize()
m_TextPass->Initialize();
/* m_ScreenQuad = ResourceManager::Load<Model>("Models/Core/ScreenQuad.obj");
m_UnitQuad = ResourceManager::Load<Model>("Models/Core/UnitQuad.obj");
m_UnitQuad = ResourceManager::Load<Model>(sModels/Core/UnitQuad.obj");
m_UnitSphere = ResourceManager::Load<Model>("Models/Core/UnitSphere.obj");*/
m_ImGuiRenderPass = new ImGuiRenderPass(this, m_EventBroker);
}
void Renderer::glfwWindowSizeCallback(GLFWwindow* window, int width, int height)
{
m_WindowToRenderer[window]->setWindowSize(Rectangle(width, height));
}
void Renderer::glfwFrameBufferCallback(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
Renderer* currentRenderer = m_WindowToRenderer[window];
currentRenderer->m_ViewportSize = Rectangle(width, height);
currentRenderer->m_PickingPass->OnWindowResize();
currentRenderer->m_DrawFinalPass->OnWindowResize();
currentRenderer->m_LightCullingPass->OnWindowResize();
currentRenderer->m_DrawBloomPass->OnWindowResize();
currentRenderer->m_SSAOPass->OnWindowResize();
m_WindowToRenderer[window]->updateFramebufferSize();
}
void Renderer::SetResolution(const Rectangle& resolution)
{
m_Resolution = resolution;
if (m_Window != nullptr) {
setWindowSize(resolution);
updateFramebufferSize();
}
}
void Renderer::InitializeWindow()
@@ -46,14 +67,24 @@ void Renderer::InitializeWindow()
// Create a window
GLFWmonitor* monitor = nullptr;
if (m_Fullscreen) {
monitor = glfwGetPrimaryMonitor();
//monitor = glfwGetPrimaryMonitor();
//const GLFWvidmode* mode = glfwGetVideoMode(monitor);
//glfwWindowHint(GLFW_RED_BITS, mode->redBits);
//glfwWindowHint(GLFW_GREEN_BITS, mode->greenBits);
//glfwWindowHint(GLFW_BLUE_BITS, mode->blueBits);
//glfwWindowHint(GLFW_REFRESH_RATE, mode->refreshRate);
glfwWindowHint(GLFW_DECORATED, false);
glfwWindowHint(GLFW_AUTO_ICONIFY, false);
}
//glfwWindowHint(GLFW_SAMPLES, 8);
m_Window = glfwCreateWindow(m_Resolution.Width, m_Resolution.Height, "daydream", monitor, nullptr);
//glfwWindowHint(GLFW_SAMPLES, 8);
m_Window = glfwCreateWindow(m_Resolution.Width, m_Resolution.Height + 1, "daydream", monitor, nullptr);
if (!m_Window) {
LOG_ERROR("GLFW: Failed to create window");
exit(EXIT_FAILURE);
}
glfwSetWindowSizeCallback(m_Window, &glfwWindowSizeCallback);
glfwSetFramebufferSizeCallback(m_Window, &glfwFrameBufferCallback);
glfwMakeContextCurrent(m_Window);
@@ -98,6 +129,32 @@ void Renderer::InputUpdate(double dt)
}
void Renderer::setWindowSize(Rectangle size)
{
m_Resolution = size;
glfwSetWindowSize(m_Window, size.Width, size.Height);
}
void Renderer::updateFramebufferSize()
{
Events::ResolutionChanged e;
e.OldResolution = m_ViewportSize;
int width, height;
glfwGetFramebufferSize(m_Window, &width, &height);
glViewport(0, 0, width, height);
m_ViewportSize = Rectangle(width, height);
m_PickingPass->OnWindowResize();
m_DrawFinalPass->OnWindowResize();
m_LightCullingPass->OnWindowResize();
m_DrawBloomPass->OnWindowResize();
m_SSAOPass->OnWindowResize();
m_BlurHUDPass->OnWindowResize();
e.NewResolution = m_ViewportSize;
m_EventBroker->Publish(e);
}
void Renderer::Update(double dt)
{
m_EventBroker->Process<Renderer>();
@@ -110,7 +167,7 @@ void Renderer::Draw(RenderFrame& frame)
{
GLERROR("PRE");
glBindFramebuffer(GL_FRAMEBUFFER, 0);
ImGui::Combo("Draw textures", &m_DebugTextureToDraw, "Final\0Scene\0Bloom\0Gaussian\0Picking\0Ambient Occlusion");
ImGui::Combo("Draw textures", &m_DebugTextureToDraw, "Final\0Scene\0Bloom\0Gaussian\0Picking\0Ambient Occlusion\0Combined Scene Texture\0Full Blurred Texture");
ImGui::Combo("CubeMap", &m_CubeMapTexture, "Nevada(512)\0Sky(1024)");
if(m_CubeMapTexture == 0) {
m_CubeMapPass->LoadTextures("Nevada");
@@ -120,8 +177,10 @@ void Renderer::Draw(RenderFrame& frame)
ImGui::SliderInt("SSAO Quality", &m_SSAO_Quality, 0, 3);
ImGui::SliderInt("Glow Quality", &m_GLOW_Quality, 0, 3);
ImGui::SliderInt("MSAA Level", (int*)&m_MSAA_Level, 0, 16);
m_SSAOPass->ChangeQuality(m_SSAO_Quality);
m_DrawBloomPass->ChangeQuality(m_GLOW_Quality);
m_DrawFinalPass->setMSAA(m_MSAA_Level);
GLERROR("SSAO Settings");
//clear buffer 0
glClearColor(0.f, 0.f, 0.f, 0.f);
@@ -133,6 +192,9 @@ void Renderer::Draw(RenderFrame& frame)
m_DrawFinalPass->ClearBuffer();
m_DrawBloomPass->ClearBuffer();
m_SSAOPass->ClearBuffer();
m_ShadowPass->ClearBuffer();
m_BlurHUDPass->ClearBuffer();
m_ShadowPass->DebugGUI();
PerformanceTimer::StopTimer("Renderer-ClearBuffers");
GLERROR("ClearBuffers");
for (auto scene : frame.RenderScenes) {
@@ -148,6 +210,9 @@ void Renderer::Draw(RenderFrame& frame)
PerformanceTimer::StartTimer("Renderer-Depth");
SortRenderJobsByDepth(*scene);
GLERROR("SortByDepth");
PerformanceTimer::StartTimerAndStopPrevious("Draw shadow maps");
m_ShadowPass->Draw(*scene);
GLERROR("Draw shadow maps");
PerformanceTimer::StartTimerAndStopPrevious("Renderer-Generate Frustrums");
m_LightCullingPass->GenerateNewFrustum(*scene);
GLERROR("Generate frustums");
@@ -158,7 +223,7 @@ void Renderer::Draw(RenderFrame& frame)
m_LightCullingPass->CullLights(*scene);
GLERROR("LightCulling");
PerformanceTimer::StartTimerAndStopPrevious("Renderer-Draw Geometry+Light");
m_DrawFinalPass->Draw(*scene);
m_DrawFinalPass->Draw(*scene, m_BlurHUDPass);
GLERROR("Draw Geometry+Light");
//m_DrawScenePass->Draw(*scene);
@@ -174,7 +239,8 @@ void Renderer::Draw(RenderFrame& frame)
if (m_DebugTextureToDraw == 0) {
PerformanceTimer::StartTimer("Renderer-Color Correction Pass");
m_DrawColorCorrectionPass->Draw(m_DrawFinalPass->SceneTexture(), m_DrawBloomPass->GaussianTexture(), frame.Gamma, frame.Exposure);
GLuint test = m_DrawFinalPass->SceneTexture();
m_DrawColorCorrectionPass->Draw(test, m_DrawBloomPass->GaussianTexture(), frame.Gamma, frame.Exposure);
PerformanceTimer::StopTimer("Renderer-Color Correction Pass");
}
@@ -194,6 +260,12 @@ void Renderer::Draw(RenderFrame& frame)
if (m_DebugTextureToDraw == 5) {
m_DrawScreenQuadPass->Draw(m_SSAOPass->SSAOTexture());
}
if (m_DebugTextureToDraw == 6) {
m_DrawScreenQuadPass->Draw(m_DrawFinalPass->CombinedSceneTexture());
}
if (m_DebugTextureToDraw == 7) {
m_DrawScreenQuadPass->Draw(m_DrawFinalPass->FullBlurredTexture());
}
PerformanceTimer::StopTimer("Renderer-Misc Debug Draws");
PerformanceTimer::StartTimer("Renderer-ImGuiRenderPass");
@@ -213,8 +285,8 @@ PickData Renderer::Pick(glm::vec2 screenCoord)
void Renderer::InitializeTextures()
{
m_ErrorTexture = CommonFunctions::LoadTexture("Textures/Core/ErrorTexture.png", false);
m_WhiteTexture = CommonFunctions::LoadTexture("Textures/Core/White.png", false);
m_ErrorTexture = CommonFunctions::TryLoadResource<Texture, false>("Textures/Core/ErrorTexture.png");
m_WhiteTexture = CommonFunctions::TryLoadResource<Texture, false>("Textures/Core/White.png");
}
@@ -238,15 +310,18 @@ void Renderer::GenerateTexture(GLuint* texture, GLenum wrapping, GLenum filterin
GLERROR("Texture initialization failed");
}
void Renderer::InitializeRenderPasses()
{
m_PickingPass = new PickingPass(this, m_EventBroker);
m_LightCullingPass = new LightCullingPass(this);
m_CubeMapPass = new CubeMapPass(this);
m_SSAOPass = new SSAOPass(this, m_Config);
m_DrawFinalPass = new DrawFinalPass(this, m_LightCullingPass, m_CubeMapPass, m_SSAOPass);
m_ShadowPass = new ShadowPass(this);
m_BlurHUDPass = new BlurHUD(this);
m_DrawFinalPass = new DrawFinalPass(this, m_LightCullingPass, m_CubeMapPass, m_SSAOPass, m_ShadowPass, m_Config);
m_DrawScreenQuadPass = new DrawScreenQuadPass(this);
m_DrawBloomPass = new DrawBloomPass(this, m_Config);
m_DrawColorCorrectionPass = new DrawColorCorrectionPass(this);
}
+18 -7
View File
@@ -4,12 +4,19 @@ SSAOPass::SSAOPass(IRenderer* renderer, ConfigFile* config)
: m_Renderer(renderer)
, m_Config(config)
{
m_WhiteTexture = CommonFunctions::LoadTexture("Textures/Core/White.png", false);
m_WhiteTexture = CommonFunctions::TryLoadResource<Texture, false>("Textures/Core/White.png");
ChangeQuality(m_Config->Get<int>("SSAO.Quality", 0));
}
SSAOPass::~SSAOPass() {
CommonFunctions::DeleteTexture(&m_SSAOTexture);
CommonFunctions::DeleteTexture(&m_SSAOViewSpaceZTexture);
CommonFunctions::DeleteTexture(&m_Gaussian_horiz);
CommonFunctions::DeleteTexture(&m_Gaussian_vert);
}
void SSAOPass::ChangeQuality(int quality)
{
if (m_Quality == quality) {
@@ -56,6 +63,7 @@ void SSAOPass::InitializeShaderProgram()
m_SSAOProgram->AddShader(std::shared_ptr<Shader>(new VertexShader("Shaders/SSAO.vert.glsl")));
m_SSAOProgram->AddShader(std::shared_ptr<Shader>(new FragmentShader("Shaders/SSAO.frag.glsl")));
m_SSAOProgram->Compile();
m_SSAOProgram->BindFragDataLocation(0, "AO");
m_SSAOProgram->Link();
}
@@ -64,6 +72,7 @@ void SSAOPass::InitializeShaderProgram()
m_SSAOViewSpaceZProgram->AddShader(std::shared_ptr<Shader>(new VertexShader("Shaders/SSAO.vert.glsl")));
m_SSAOViewSpaceZProgram->AddShader(std::shared_ptr<Shader>(new FragmentShader("Shaders/SSAOViewSpaceZ.frag.glsl")));
m_SSAOViewSpaceZProgram->Compile();
m_SSAOViewSpaceZProgram->BindFragDataLocation(0, "depthLinear");
m_SSAOViewSpaceZProgram->Link();
}
@@ -72,6 +81,7 @@ void SSAOPass::InitializeShaderProgram()
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->BindFragDataLocation(0, "fragmentColor");
m_GaussianProgram_horiz->Link();
}
@@ -80,6 +90,7 @@ void SSAOPass::InitializeShaderProgram()
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->BindFragDataLocation(0, "fragmentColor");
m_GaussianProgram_vert->Link();
}
}
@@ -222,6 +233,11 @@ void SSAOPass::Draw(GLuint depthBuffer, Camera* camera)
GLuint shaderHandle_horiz = m_GaussianProgram_horiz->GetHandle();
GLuint shaderHandle_vert = m_GaussianProgram_vert->GetHandle();
m_GaussianProgram_vert->Bind();
glUniform1i(glGetUniformLocation(shaderHandle_vert, "Lod"), 0);
m_GaussianProgram_horiz->Bind();
glUniform1i(glGetUniformLocation(shaderHandle_horiz, "Lod"), 0);
m_GaussianFrameBuffer_horiz.Bind();
m_GaussianProgram_horiz->Bind();
@@ -241,8 +257,6 @@ void SSAOPass::Draw(GLuint depthBuffer, Camera* camera)
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_Gaussian_horiz);
glBindVertexArray(m_ScreenQuad->VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ScreenQuad->ElementBuffer);
glDrawElementsBaseVertex(GL_TRIANGLES, m_ScreenQuad->MaterialGroups()[0].material->EndIndex - m_ScreenQuad->MaterialGroups()[0].material->StartIndex + 1
, GL_UNSIGNED_INT, 0, m_ScreenQuad->MaterialGroups()[0].material->StartIndex);
//horizontal pass
@@ -254,8 +268,6 @@ void SSAOPass::Draw(GLuint depthBuffer, Camera* camera)
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_Gaussian_vert);
glBindVertexArray(m_ScreenQuad->VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ScreenQuad->ElementBuffer);
glDrawElementsBaseVertex(GL_TRIANGLES, m_ScreenQuad->MaterialGroups()[0].material->EndIndex - m_ScreenQuad->MaterialGroups()[0].material->StartIndex + 1
, GL_UNSIGNED_INT, 0, m_ScreenQuad->MaterialGroups()[0].material->StartIndex);
m_GaussianFrameBuffer_horiz.Unbind();
@@ -268,8 +280,7 @@ void SSAOPass::Draw(GLuint depthBuffer, Camera* camera)
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_Gaussian_horiz);
glBindVertexArray(m_ScreenQuad->VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ScreenQuad->ElementBuffer);
glDrawElementsBaseVertex(GL_TRIANGLES, m_ScreenQuad->MaterialGroups()[0].material->EndIndex - m_ScreenQuad->MaterialGroups()[0].material->StartIndex + 1
, GL_UNSIGNED_INT, 0, m_ScreenQuad->MaterialGroups()[0].material->StartIndex);
+39 -11
View File
@@ -4,22 +4,32 @@ GLuint Shader::CompileShader(GLenum shaderType, std::string fileName)
{
LOG_INFO("Compiling shader \"%s\"", fileName.c_str());
std::string shaderFile;
std::ifstream in(fileName, std::ios::in);
if (!in) {
LOG_ERROR("Error: Failed to open shader file \"%s\"", fileName.c_str());
return 0;
}
in.seekg(0, std::ios::end);
shaderFile.resize((int)in.tellg());
in.seekg(0, std::ios::beg);
in.read(&shaderFile[0], shaderFile.size());
in.close();
std::string shaderFile = ReadFile(fileName);
GLuint shader = glCreateShader(shaderType);
if (GLERROR("glCreateShader"))
return 0;
std::size_t startPos = 0;
std::size_t SEofNewFile[2];
std::string key = "#include";
while((startPos = shaderFile.find(key, startPos)) != std::string::npos)
{
SEofNewFile[0] = shaderFile.find('"', startPos+key.length())+1;
SEofNewFile[1] = shaderFile.find('"', SEofNewFile[0]);
if (SEofNewFile[0] == std::string::npos || SEofNewFile[1] == std::string::npos)
return 0;
std::string replacementFileName = shaderFile.substr(SEofNewFile[0], SEofNewFile[1] - SEofNewFile[0]);
std::string replacementString = ReadFile(replacementFileName);
size_t firstof = replacementString.find_first_of((char)0);
replacementString.erase(firstof, replacementString.size() - firstof);
if (replacementString.length() <= 0)
return 0;
shaderFile.replace(startPos, SEofNewFile[1]+2 - startPos, replacementString + "\n");
startPos += replacementString.length(); //This might not be wanted.
}
const GLchar* shaderFiles = shaderFile.c_str();
const GLint length = static_cast<GLint>(shaderFile.length());
glShaderSource(shader, 1, &shaderFiles, &length);
@@ -46,6 +56,24 @@ GLuint Shader::CompileShader(GLenum shaderType, std::string fileName)
return shader;
}
std::string Shader::ReadFile(std::string fileName)
{
std::string shaderFile;
std::ifstream in(fileName, std::ios::in);
if (!in) {
LOG_ERROR("Error: Failed to open shader file \"%s\"", fileName.c_str());
return "";
}
in.seekg(0, std::ios::end);
shaderFile.resize((int)in.tellg());
in.seekg(0, std::ios::beg);
in.read(&shaderFile[0], shaderFile.size());
in.close();
return shaderFile;
}
Shader::Shader(GLenum shaderType, std::string fileName) : m_ShaderType(shaderType), m_FileName(fileName)
{
m_ShaderHandle = 0;
+363
View File
@@ -0,0 +1,363 @@
#include "Rendering/ShadowPass.h"
ShadowPass::ShadowPass(IRenderer * renderer, int shadow_res_x, int shadow_res_y)
{
m_Renderer = renderer;
m_ResolutionSizeWidth = shadow_res_x;
m_ResolutionSizeHeight = shadow_res_y;
InitializeFrameBuffers();
InitializeShaderPrograms();
}
ShadowPass::ShadowPass(IRenderer * renderer)
{
m_Renderer = renderer;
InitializeFrameBuffers();
InitializeShaderPrograms();
}
ShadowPass::~ShadowPass()
{
}
void ShadowPass::DebugGUI()
{
ImGui::Checkbox("EnableShadows", &m_EnableShadows);
ImGui::DragFloat2("ShadowMapNearFar", m_NearFarPlane, 1.f, -1000.f, 1000.f);
ImGui::DragFloat("ShadowClippingWeight", &m_SplitWeight, 0.001f, 0.f, 1.f);
ImGui::Checkbox("ShadowTransparentObjects", &m_TransparentObjects);
ImGui::Checkbox("ShadowOnTextureAlphas", &m_TexturedShadows);
}
void ShadowPass::InitializeCameras(RenderScene & scene)
{
for (int i = 0; i < m_CurrentNrOfSplits; i++) {
m_shadowFrusta[i].AspectRatio = scene.Camera->AspectRatio();
m_shadowFrusta[i].FOV = scene.Camera->FOV();
}
}
// UpdateSplitDist computes the near and far distances for every frustum slice
// in camera eye space - that is, at what distance does a slice start and end
void ShadowPass::UpdateSplitDist(std::array<ShadowFrustum, MAX_SPLITS>& frusta, float near_distance, float far_distance)
{
float lambda = m_SplitWeight;
float ratio = far_distance / near_distance;
frusta[0].NearClip = near_distance;
for (int i = 1; i < m_CurrentNrOfSplits; i++) {
float si = i / static_cast<float>(m_CurrentNrOfSplits);
frusta[i].NearClip = lambda * (near_distance * powf(ratio, si)) + (1 - lambda) * (near_distance + (far_distance - near_distance) * si);
frusta[i - 1].FarClip = frusta[i].NearClip * 1.005f;
}
frusta[m_CurrentNrOfSplits - 1].FarClip = far_distance;
}
void ShadowPass::UpdateFrustumPoints(ShadowFrustum& frustum, glm::mat4 p, glm::mat4 v)
{
std::array<glm::vec4, 8> CornerPoint = {
glm::vec4(-1.f, -1.f, -1.f, 1.f),
glm::vec4(-1.f, 1.f, -1.f, 1.f),
glm::vec4(1.f, 1.f, -1.f, 1.f),
glm::vec4(1.f, -1.f, -1.f, 1.f),
glm::vec4(-1.f, -1.f, 1.f, 1.f),
glm::vec4(-1.f, 1.f, 1.f, 1.f),
glm::vec4(1.f, 1.f, 1.f, 1.f),
glm::vec4(1.f, -1.f, 1.f, 1.f)
};
for (int i = 0; i < 8; i++) {
glm::vec4 NDC = glm::inverse(p) * CornerPoint[i];
NDC = NDC / NDC.w;
frustum.CornerPoint[i] = glm::vec3(glm::inverse(v) * NDC);
}
}
// Compute the 8 corner points of the current view frustum in world space
void ShadowPass::UpdateFrustumPoints(ShadowFrustum& frustum, glm::vec3 camera_position, glm::vec3 view_dir)
{
glm::vec3 up = glm::vec3(0.f, 1.f, 0.f);
glm::vec3 right = glm::normalize(glm::cross(view_dir, up));
glm::vec3 far_center = camera_position + glm::normalize(view_dir) * frustum.FarClip;
glm::vec3 near_center = camera_position + glm::normalize(view_dir) * frustum.NearClip;
frustum.MiddlePoint = near_center + (far_center - near_center) * 0.5f;
up = glm::normalize(glm::cross(right, view_dir));
// these heights and widths are half the heights and widths of the near and far plane rectangles.
float near_height = tan(frustum.FOV / 2.f) * frustum.NearClip;
float near_width = near_height * frustum.AspectRatio;
float far_height = tan(frustum.FOV / 2.f) * frustum.FarClip;
float far_width = far_height * frustum.AspectRatio;
frustum.CornerPoint[0] = near_center - up * near_height - right * near_width;
frustum.CornerPoint[1] = near_center + up * near_height - right * near_width;
frustum.CornerPoint[2] = near_center + up * near_height + right * near_width;
frustum.CornerPoint[3] = near_center - up * near_height + right * near_width;
frustum.CornerPoint[4] = far_center - up * far_height - right * far_width;
frustum.CornerPoint[5] = far_center + up * far_height - right * far_width;
frustum.CornerPoint[6] = far_center + up * far_height + right * far_width;
frustum.CornerPoint[7] = far_center - up * far_height + right * far_width;
}
float ShadowPass::FindRadius(ShadowFrustum& frustum)
{
float radius = 0.f;
for (int i = 0; i < 8; i++) {
float distance = glm::distance(frustum.MiddlePoint, frustum.CornerPoint[i]);
if (distance > radius) {
radius = distance;
}
}
frustum.Radius = radius;
return radius;
}
void ShadowPass::InitializeFrameBuffers()
{
// Depth texture
glGenTextures(1, &m_DepthMap);
glBindTexture(GL_TEXTURE_2D_ARRAY, m_DepthMap);
glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_DEPTH_COMPONENT16, m_ResolutionSizeWidth, m_ResolutionSizeHeight, m_CurrentNrOfSplits);
//glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, m_ResolutionSizeWidth, m_ResolutionSizeHeight, m_CurrentNrOfSplits, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
glTexParameterfv(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BORDER_COLOR, glm::vec4(1.f).data);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
m_DepthBuffer.AddResource(std::shared_ptr<BufferResource>(new Texture2DArray(&m_DepthMap, GL_DEPTH_ATTACHMENT)));
m_DepthBuffer.Generate();
GLERROR("depthMap failed END");
}
void ShadowPass::InitializeShaderPrograms()
{
m_ShadowProgram = ResourceManager::Load<ShaderProgram>("#ShadowProgram");
m_ShadowProgram->AddShader(std::shared_ptr<Shader>(new VertexShader("Shaders/Shadow.vert.glsl")));
m_ShadowProgram->AddShader(std::shared_ptr<Shader>(new FragmentShader("Shaders/Shadow.frag.glsl")));
m_ShadowProgram->Compile();
m_ShadowProgram->BindFragDataLocation(0, "ShadowMap");
m_ShadowProgram->Link();
m_ShadowProgramSkinned = ResourceManager::Load<ShaderProgram>("#ShadowProgramSkinned");
m_ShadowProgramSkinned->AddShader(std::shared_ptr<Shader>(new VertexShader("Shaders/ShadowSkinned.vert.glsl")));
m_ShadowProgramSkinned->AddShader(std::shared_ptr<Shader>(new FragmentShader("Shaders/Shadow.frag.glsl")));
m_ShadowProgramSkinned->Compile();
m_ShadowProgramSkinned->BindFragDataLocation(0, "ShadowMap");
m_ShadowProgramSkinned->Link();
}
void ShadowPass::ClearBuffer()
{
m_DepthBuffer.Bind();
for (int i = 0; i < m_CurrentNrOfSplits; i++) {
glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_DepthMap, 0, i);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
m_DepthBuffer.Unbind();
}
void ShadowPass::PointsToLightspace(ShadowFrustum& frustum, glm::mat4 v)
{
float left = INFINITY;
float right = -INFINITY;
float bottom = INFINITY;
float top = -INFINITY;
for (int i = 0; i < 8; i++)
{
glm::vec3 tempPoint = glm::vec3(v * glm::vec4(frustum.CornerPoint[i], 1.f));
if (tempPoint.x < left) { left = tempPoint.x; }
if (tempPoint.x > right) { right = tempPoint.x; }
if (tempPoint.y < bottom) { bottom = tempPoint.y; }
if (tempPoint.y > top) { top = tempPoint.y; }
}
frustum.LRBT = { left, right, bottom, top };
}
void ShadowPass::RadiusToLightspace(ShadowFrustum& frustum)
{
float quantizationStep = 1.0f / m_ResolutionSizeHeight;
float left = -frustum.Radius;
float right = frustum.Radius;
float bottom = -frustum.Radius;
float top = frustum.Radius;
frustum.LRBT = { left, right, bottom, top };
}
void ShadowPass::Draw(RenderScene & scene)
{
if (m_EnableShadows) {
InitializeCameras(scene);
UpdateSplitDist(m_shadowFrusta, scene.Camera->NearClip(), scene.Camera->FarClip());
ShadowPassState* state = new ShadowPassState(m_DepthBuffer.GetHandle());
glViewport(0, 0, m_ResolutionSizeWidth, m_ResolutionSizeHeight);
for (int i = 0; i < m_CurrentNrOfSplits; i++) {
UpdateFrustumPoints(m_shadowFrusta[i], scene.Camera->Position(), scene.Camera->Forward());
glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_DepthMap, 0, i);
GLuint shaderHandle = 0;
GLuint lastModel = 0;
for (auto &job : scene.Jobs.DirectionalLight) {
auto directionalLightJob = std::dynamic_pointer_cast<DirectionalLightJob>(job);
if (directionalLightJob) {
m_LightView[i] = glm::lookAt(glm::vec3(-directionalLightJob->Direction) + m_shadowFrusta[i].MiddlePoint, m_shadowFrusta[i].MiddlePoint, glm::vec3(0.f, 1.f, 0.f));
PointsToLightspace(m_shadowFrusta[i], m_LightView[i]);
//FindRadius(m_shadowFrusta[i]);
//RadiusToLightspace(m_shadowFrusta[i]);
m_LightProjection[i] = glm::ortho(m_shadowFrusta[i].LRBT[LEFT], m_shadowFrusta[i].LRBT[RIGHT], m_shadowFrusta[i].LRBT[BOTTOM], m_shadowFrusta[i].LRBT[TOP], m_NearFarPlane[NEAR], m_NearFarPlane[FAR]);
GLERROR("ShadowLight ERROR");
for (auto &objectJob : scene.Jobs.OpaqueObjects) {
if (!std::dynamic_pointer_cast<ExplosionEffectJob>(objectJob)) {
auto modelJob = std::dynamic_pointer_cast<ModelJob>(objectJob);
if (!modelJob->Shadow) {
continue;
}
if(modelJob->Model->IsSkinned()) {
if (shaderHandle != m_ShadowProgramSkinned->GetHandle()) {
m_ShadowProgramSkinned->Bind();
shaderHandle = m_ShadowProgramSkinned->GetHandle();
}
std::vector<glm::mat4> frameBones;
if (modelJob->BlendTree != nullptr) {
frameBones = modelJob->BlendTree->GetFinalPose();
} else {
frameBones = modelJob->Skeleton->GetTPose();
}
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0]));
} else {
if (shaderHandle != m_ShadowProgram->GetHandle()) {
m_ShadowProgram->Bind();
shaderHandle = m_ShadowProgram->GetHandle();
}
}
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "PVM"), 1, GL_FALSE, glm::value_ptr(m_LightProjection[i] * m_LightView[i] * modelJob->Matrix));
glUniform1f(glGetUniformLocation(shaderHandle, "Alpha"), 1.f);
if (lastModel != modelJob->ModelID) {
glBindVertexArray(modelJob->Model->VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, modelJob->Model->ElementBuffer);
}
glDrawElements(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, (void*)(modelJob->StartIndex * sizeof(unsigned int)));
GLERROR("Shadow Draw ERROR");
}
}
if (m_TransparentObjects) {
state->CullFace(GL_BACK);
for (auto &objectJob : scene.Jobs.TransparentObjects) {
if (!std::dynamic_pointer_cast<ExplosionEffectJob>(objectJob)) {
auto modelJob = std::dynamic_pointer_cast<ModelJob>(objectJob);
if (!modelJob->Shadow) {
continue;
}
if (modelJob->Model->IsSkinned()) {
if (shaderHandle != m_ShadowProgramSkinned->GetHandle()) {
m_ShadowProgramSkinned->Bind();
shaderHandle = m_ShadowProgramSkinned->GetHandle();
}
std::vector<glm::mat4> frameBones;
if (modelJob->BlendTree != nullptr) {
frameBones = modelJob->BlendTree->GetFinalPose();
} else {
frameBones = modelJob->Skeleton->GetTPose();
}
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0]));
} else {
if (shaderHandle != m_ShadowProgram->GetHandle()) {
m_ShadowProgram->Bind();
shaderHandle = m_ShadowProgram->GetHandle();
}
}
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "PVM"), 1, GL_FALSE, glm::value_ptr(m_LightProjection[i] * m_LightView[i] * modelJob->Matrix));
glUniform1f(glGetUniformLocation(shaderHandle, "Alpha"), modelJob->Color.a);
if (m_TexturedShadows) {
switch (modelJob->Type) {
case RawModel::MaterialType::SingleTextures:
case RawModel::MaterialType::Basic:
{
glActiveTexture(GL_TEXTURE24);
if (modelJob->DiffuseTexture.size() > 0 && modelJob->DiffuseTexture[0]->Texture != nullptr) {
glBindTexture(GL_TEXTURE_2D, modelJob->DiffuseTexture[0]->Texture->m_Texture);
glUniform2fv(glGetUniformLocation(shaderHandle, "DiffuseUVRepeat"), 1, glm::value_ptr(modelJob->DiffuseTexture[0]->UVRepeat));
}
else {
glBindTexture(GL_TEXTURE_2D, m_WhiteTexture->m_Texture);
glUniform2fv(glGetUniformLocation(shaderHandle, "DiffuseUVRepeat"), 1, glm::value_ptr(glm::vec2(1.0f, 1.0f)));
}
break;
}
case RawModel::MaterialType::SplatMapping:
{
glActiveTexture(GL_TEXTURE24);
glBindTexture(GL_TEXTURE_2D, m_WhiteTexture->m_Texture);
glUniform2fv(glGetUniformLocation(shaderHandle, "DiffuseUVRepeat"), 1, glm::value_ptr(glm::vec2(1.0f, 1.0f)));
break;
}
}
}
if (lastModel != modelJob->ModelID) {
glBindVertexArray(modelJob->Model->VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, modelJob->Model->ElementBuffer);
}
glDrawElements(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, (void*)(modelJob->StartIndex * sizeof(unsigned int)));
GLERROR("Shadow Draw ERROR");
}
}
state->CullFace(GL_FRONT);
}
}
}
}
glViewport(0, 0, m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height);
m_DepthBuffer.Unbind();
delete state;
}
}
+19
View File
@@ -0,0 +1,19 @@
#include "Rendering/ShadowPassState.h"
ShadowPassState::ShadowPassState(GLuint frameBuffer)
{
BindFramebuffer(frameBuffer);
Enable(GL_DEPTH_TEST);
Enable(GL_CULL_FACE);
Disable(GL_BLEND);
Disable(GL_TEXTURE_2D);
CullFace(GL_FRONT);
ClearColor(glm::vec4(0.f, 0.f, 0.f, 0.f));
//Enable(GL_ALPHA_TEST);
//glAlphaFunc(GL_GREATER, 0.9f);
}
ShadowPassState::~ShadowPassState()
{
}
+255 -659
View File
@@ -1,372 +1,149 @@
#include "Rendering/Skeleton.h"
int Skeleton::CreateBone(int ID, int parentID, std::string name, glm::mat4 offsetMatrix)
std::map<int, Skeleton::PoseData> Skeleton::GetFrameBones(const Animation* animation, double time, bool additive, bool noRootMotion /*= false*/)
{
if (m_BonesByName.find(name) != m_BonesByName.end()) {
return m_BonesByName.at(name)->ID;
} else {
Bone* bone;
if (parentID == -1) {
bone = new Bone(ID, nullptr, name, offsetMatrix);
RootBone = bone;
} else {
Bone* parent = Bones[parentID];
bone = new Bone(ID, parent, name, offsetMatrix);
parent->Children.push_back(bone);
}
Bones[ID] = bone;
m_BonesByName[name] = bone;
return ID;
}
}
Skeleton::~Skeleton()
{
for (auto &kv : Bones) {
delete kv.second;
}
}
const Skeleton::Animation* Skeleton::GetAnimation(std::string name)
{
auto it = Animations.find(name);
if (it != Animations.end()) {
return const_cast<const Animation*>(&it->second);
} else {
return nullptr;
}
}
std::vector<glm::mat4> Skeleton::GetFrameBones(std::vector<AnimationData> animations, bool noRootMotion /*= false*/)
{
if (animations.size() <= 0) {
std::vector<glm::mat4> finalMatrices;
if (animation == nullptr) {
std::map<int, PoseData> finalMatrices;
for (auto& b : Bones) {
finalMatrices.push_back(glm::mat4(1));//b.second->OffsetMatrix);
PoseData poseData;
poseData.Translation = glm::vec3(0);
poseData.Orientation = glm::quat();
poseData.Scale = glm::vec3(1);
finalMatrices[b.second->ID] = poseData;
}
return finalMatrices;
}
std::map<int, glm::mat4> frameBones;
AccumulateBoneTransforms(true, animations, frameBones, RootBone, glm::mat4(1));
std::vector<glm::mat4> finalMatrices;
for (auto &kv : frameBones) {
finalMatrices.push_back(kv.second);
std::map<int, PoseData> frameBones;
if(!additive) {
AccumulateBoneTransforms(true, animation, time, frameBones, RootBone);
} else {
AdditiveBoneTransforms(animation, time, frameBones, RootBone);
}
return finalMatrices;
return frameBones;
}
std::vector<glm::mat4> Skeleton::GetFrameBones(std::vector<AnimationData> animations, AnimationOffset animationOffset, bool noRootMotion /*= false*/)
void Skeleton::AccumulateBoneTransforms(bool noRootMotion, const Animation* animation, double time, std::map<int, PoseData>& boneMatrices, const Bone* bone)
{
if (animations.size() <= 0 || animationOffset.animation == nullptr) {
std::vector<glm::mat4> finalMatrices;
for (auto& b : Bones) {
finalMatrices.push_back(glm::mat4(1));//b.second->OffsetMatrix);
}
return finalMatrices;
}
PoseData poseData;
std::map<int, glm::mat4> frameBones;
AccumulateBoneTransforms(true, animations, animationOffset, frameBones, RootBone, glm::mat4(1));
std::vector<glm::mat4> finalMatrices;
for (auto &kv : frameBones) {
finalMatrices.push_back(kv.second);
}
return finalMatrices;
}
void Skeleton::AccumulateBoneTransforms(bool noRootMotion, std::vector<AnimationData> animations, std::map<int, glm::mat4>& boneMatrices, const Bone* bone, glm::mat4 parentMatrix)
{
glm::mat4 boneMatrix;
std::vector<JointFrameTransform> JointTransforms;
for (const AnimationData animationData : animations) {
const Animation* animation = animationData.animation;
const float time = animationData.time;
JointFrameTransform jointTransform;
jointTransform.Weight = animationData.weight;;
if (animation->JointAnimations.find(bone->ID) != animation->JointAnimations.end()) {
std::vector<Animation::Keyframe> boneKeyFrames = animation->JointAnimations.at(bone->ID);
Animation::Keyframe currentFrame;
Animation::Keyframe nextFrame;
if (boneKeyFrames.size() > 1) { // 2+ keyframes for the current bone
for (int index = boneKeyFrames.size()-1; index >= 0; index--) { // find the bone keyframes that surrounds the current frame
if (time >= boneKeyFrames.at(index).Time) {
currentFrame = boneKeyFrames.at(index);
nextFrame = boneKeyFrames.at((index + 1) % boneKeyFrames.size());
break;
}
}
float progress;
if (nextFrame.Index == 0) {
nextFrame = currentFrame;
progress = (time - currentFrame.Time) / (animation->Duration - currentFrame.Time);
} else {
progress = (time - currentFrame.Time) / (nextFrame.Time - currentFrame.Time);
}
if (progress > 1.0f || progress < 0.0f) {
progress = glm::clamp(progress, 0.0f, 1.0f);
}
Animation::Keyframe::BoneProperty currentBoneProperty = currentFrame.BoneProperties;
Animation::Keyframe::BoneProperty nextBoneProperty = nextFrame.BoneProperties;
jointTransform.PositionInterp = currentBoneProperty.Position * (1.f - progress) + nextBoneProperty.Position * progress;
jointTransform.RotationInterp = glm::slerp(currentBoneProperty.Rotation, nextBoneProperty.Rotation, progress);
jointTransform.ScaleInterp = currentBoneProperty.Scale * (1.f - progress) + nextBoneProperty.Scale * progress;
// Flag for no root motion
if (bone == RootBone && noRootMotion) {
jointTransform.PositionInterp.x = 0;
jointTransform.PositionInterp.z = 0;
}
JointTransforms.push_back(jointTransform);
} else { // 1 keyframes for the current bone
currentFrame = boneKeyFrames.at(0);
jointTransform.PositionInterp = currentFrame.BoneProperties.Position;
jointTransform.RotationInterp = currentFrame.BoneProperties.Rotation;
jointTransform.ScaleInterp = currentFrame.BoneProperties.Scale;
JointTransforms.push_back(jointTransform);
}
} else { // 0 keyframes for the current bone
}
}
if (JointTransforms.size() <= 0) {
if (bone->Parent) {
boneMatrix = parentMatrix * glm::inverse(bone->OffsetMatrix) * bone->Parent->OffsetMatrix;
boneMatrices[bone->ID] = boneMatrix * bone->OffsetMatrix;
} else {
boneMatrix = glm::inverse(bone->OffsetMatrix);
boneMatrices[bone->ID] = parentMatrix;
}
} else if (JointTransforms.size() == 1) {
boneMatrix = parentMatrix *(glm::translate(JointTransforms.at(0).PositionInterp) * glm::toMat4(JointTransforms.at(0).RotationInterp) * glm::scale(JointTransforms.at(0).ScaleInterp));
boneMatrices[bone->ID] = boneMatrix * bone->OffsetMatrix;
} else {
glm::vec3 finalPosInterp;
glm::quat finalRotInterp;
glm::vec3 finalScaleInterp;
float totalWeight = 0;
for (JointFrameTransform jointTransform : JointTransforms) {
totalWeight += jointTransform.Weight;
}
for (JointFrameTransform jointTransform : JointTransforms) {
if (jointTransform.Weight == 1.0f) {
finalPosInterp = jointTransform.PositionInterp;
finalRotInterp = jointTransform.RotationInterp;
finalScaleInterp = jointTransform.ScaleInterp;
break;
} else {
finalPosInterp += jointTransform.PositionInterp * (jointTransform.Weight/totalWeight);
finalRotInterp *= glm::slerp(glm::quat(), jointTransform.RotationInterp, (jointTransform.Weight/totalWeight));
finalScaleInterp += jointTransform.ScaleInterp * (jointTransform.Weight/totalWeight);
}
}
boneMatrix = parentMatrix *(glm::translate(finalPosInterp) * glm::toMat4(finalRotInterp) * glm::scale(finalScaleInterp));
boneMatrices[bone->ID] = boneMatrix * bone->OffsetMatrix;
}
for (auto &child : bone->Children) {
AccumulateBoneTransforms(noRootMotion, animations, boneMatrices, child, boneMatrix);
}
}
void Skeleton::AccumulateBoneTransforms(bool noRootMotion, std::vector<AnimationData> animations, AnimationOffset animationOffset, std::map<int, glm::mat4>& boneMatrices, const Bone* bone, glm::mat4 parentMatrix)
{
glm::mat4 boneMatrix;
std::vector<JointFrameTransform> JointTransforms;
for (const AnimationData animationData : animations) {
const Animation* animation = animationData.animation;
const float time = animationData.time;
JointFrameTransform jointTransform;
jointTransform.Weight = animationData.weight;;
if (animation->JointAnimations.find(bone->ID) != animation->JointAnimations.end()) {
std::vector<Animation::Keyframe> boneKeyFrames = animation->JointAnimations.at(bone->ID);
Animation::Keyframe currentFrame;
Animation::Keyframe nextFrame;
if (boneKeyFrames.size() > 1) { // 2+ keyframes for the current bone
for (int index = boneKeyFrames.size()-1; index >= 0; index--) { // find the bone keyframes that surrounds the current frame
if (time >= boneKeyFrames.at(index).Time) {
currentFrame = boneKeyFrames.at(index);
nextFrame = boneKeyFrames.at((index + 1) % boneKeyFrames.size());
break;
}
}
float progress;
if (nextFrame.Index == 0) {
nextFrame = currentFrame;
progress = (time - currentFrame.Time) / (animation->Duration - currentFrame.Time);
} else {
progress = (time - currentFrame.Time) / (nextFrame.Time - currentFrame.Time);
}
if (progress > 1.0f || progress < 0.0f) {
progress = glm::clamp(progress, 0.0f, 1.0f);
}
Animation::Keyframe::BoneProperty currentBoneProperty = currentFrame.BoneProperties;
Animation::Keyframe::BoneProperty nextBoneProperty = nextFrame.BoneProperties;
jointTransform.PositionInterp = currentBoneProperty.Position * (1.f - progress) + nextBoneProperty.Position * progress;
jointTransform.RotationInterp = glm::slerp(currentBoneProperty.Rotation, nextBoneProperty.Rotation, progress);
jointTransform.ScaleInterp = currentBoneProperty.Scale * (1.f - progress) + nextBoneProperty.Scale * progress;
// Flag for no root motion
if (bone == RootBone && noRootMotion) {
jointTransform.PositionInterp.x = 0;
jointTransform.PositionInterp.z = 0;
}
JointTransforms.push_back(jointTransform);
} else { // 1 keyframes for the current bone
currentFrame = boneKeyFrames.at(0);
jointTransform.PositionInterp = currentFrame.BoneProperties.Position;
jointTransform.RotationInterp = currentFrame.BoneProperties.Rotation;
jointTransform.ScaleInterp = currentFrame.BoneProperties.Scale;
JointTransforms.push_back(jointTransform);
}
} else { // 0 keyframes for the current bone
}
}
glm::mat4 offset = GetOffsetTransform(bone, animationOffset);
if (JointTransforms.size() == 0) {
if (bone->Parent) {
if (offset != glm::mat4(1)) {
boneMatrix = parentMatrix * offset;// *((glm::inverse(bone->OffsetMatrix) * bone->Parent->OffsetMatrix));
} else {
boneMatrix = parentMatrix *((glm::inverse(bone->OffsetMatrix) * bone->Parent->OffsetMatrix));
}
boneMatrices[bone->ID] = boneMatrix * bone->OffsetMatrix;
} else {
boneMatrix = offset * glm::inverse(bone->OffsetMatrix);
boneMatrices[bone->ID] = parentMatrix;
}
} else {
glm::vec3 finalPosInterp;
glm::quat finalRotInterp;
glm::vec3 finalScaleInterp;
float totalWeight = 0;
for (JointFrameTransform jointTransform : JointTransforms) {
totalWeight += jointTransform.Weight;
}
for (JointFrameTransform jointTransform : JointTransforms) {
if (jointTransform.Weight == 1.0f) {
finalPosInterp = jointTransform.PositionInterp;
finalRotInterp = jointTransform.RotationInterp;
finalScaleInterp = jointTransform.ScaleInterp;
break;
} else {
finalPosInterp += jointTransform.PositionInterp * (jointTransform.Weight/totalWeight);
finalRotInterp *= glm::slerp(glm::quat(), jointTransform.RotationInterp, (jointTransform.Weight/totalWeight));
finalScaleInterp += jointTransform.ScaleInterp * (jointTransform.Weight/totalWeight);
}
}
if (offset != glm::mat4(1)) {
boneMatrix = parentMatrix * ((glm::translate(finalPosInterp) * glm::toMat4(finalRotInterp) * glm::scale(finalScaleInterp)) + offset);
} else {
boneMatrix = parentMatrix * (glm::translate(finalPosInterp) * glm::toMat4(finalRotInterp) * glm::scale(finalScaleInterp));
}
boneMatrices[bone->ID] = boneMatrix * bone->OffsetMatrix;
}
for (auto &child : bone->Children) {
AccumulateBoneTransforms(noRootMotion, animations, animationOffset, boneMatrices, child, boneMatrix);
}
}
glm::mat4 Skeleton::GetOffsetTransform(const Bone* bone, AnimationOffset animationOffset)
{
const Animation* animation = animationOffset.animation;
float time = animationOffset.time;
glm::vec3 position = glm::vec3(0);
glm::quat rotation = glm::quat();
glm::vec3 scale = glm::vec3(1);
if (animation->JointAnimations.find(bone->ID) != animation->JointAnimations.end()) {
std::vector<Animation::Keyframe> boneKeyFrames = animation->JointAnimations.at(bone->ID);
const std::vector<Animation::Keyframe>& boneKeyFrames = animation->JointAnimations.at(bone->ID);
Animation::Keyframe currentFrame;
Animation::Keyframe nextFrame;
const Animation::Keyframe* currentFrame;
const Animation::Keyframe* nextFrame;
if (boneKeyFrames.size() > 1) { // 2+ keyframes for the current bone
for (int index = boneKeyFrames.size()-1; index >= 0; index--) { // find the bone keyframes that surrounds the current frame
if (time >= boneKeyFrames.at(index).Time) {
currentFrame = boneKeyFrames.at(index);
nextFrame = boneKeyFrames.at((index + 1) % boneKeyFrames.size());
currentFrame = &boneKeyFrames.at(index);
nextFrame = &boneKeyFrames.at((index + 1) % boneKeyFrames.size());
break;
}
}
float progress;
if (nextFrame.Index == 0) {
if (nextFrame->Index == 0) {
nextFrame = currentFrame;
progress = (time - currentFrame.Time) / (animation->Duration - currentFrame.Time);
progress = (time - currentFrame->Time) / (animation->Duration - currentFrame->Time);
} else {
progress = (time - currentFrame.Time) / (nextFrame.Time - currentFrame.Time);
progress = (time - currentFrame->Time) / (nextFrame->Time - currentFrame->Time);
}
progress = glm::clamp(progress, 0.0f, 1.0f);
const Animation::Keyframe::BoneProperty& currentBoneProperty = currentFrame->BoneProperties;
const Animation::Keyframe::BoneProperty& nextBoneProperty = nextFrame->BoneProperties;
glm::vec3 position = currentBoneProperty.Position * (1.f - progress) + nextBoneProperty.Position * progress;
glm::quat rotation = glm::normalize(glm::slerp(currentBoneProperty.Rotation, nextBoneProperty.Rotation, progress));
glm::vec3 scale = currentBoneProperty.Scale * (1.f - progress) + nextBoneProperty.Scale * progress;
// Flag for no root motion
if (bone == RootBone && noRootMotion) {
position.x = 0;
position.z = 0;
}
poseData.Translation = position;
poseData.Orientation = rotation;
poseData.Scale = scale;
boneMatrices[bone->ID] = poseData;
} else { // 1 keyframes for the current bone
currentFrame = &boneKeyFrames.at(0);
poseData.Translation = currentFrame->BoneProperties.Position;
poseData.Orientation = currentFrame->BoneProperties.Rotation;
poseData.Scale = currentFrame->BoneProperties.Scale;
boneMatrices[bone->ID] = poseData;
}
}
for (auto &child : bone->Children) {
AccumulateBoneTransforms(noRootMotion, animation, time, boneMatrices, child);
}
}
void Skeleton::AdditiveBoneTransforms(const Animation* animation, double time, std::map<int, PoseData>& boneMatrices, const Bone* bone)
{
if (animation->JointAnimations.find(bone->ID) != animation->JointAnimations.end()) {
PoseData refPose = GetAdditiveBonePose(bone, animation, 0.0);
PoseData srcPose = GetAdditiveBonePose(bone, animation, time + 1.0/60.0);
PoseData finalPose;
finalPose.Translation = srcPose.Translation - refPose.Translation;
finalPose.Orientation = srcPose.Orientation * glm::inverse(refPose.Orientation);
finalPose.Scale = srcPose.Scale - refPose.Scale;
boneMatrices[bone->ID] = finalPose;
}
for (auto &child : bone->Children) {
AdditiveBoneTransforms(animation, time, boneMatrices, child);
}
}
Skeleton::PoseData Skeleton::GetAdditiveBonePose(const Bone* bone, const Animation* animation, double time)
{
glm::vec3 position = glm::vec3(0);
glm::quat rotation = glm::quat();
glm::vec3 scale = glm::vec3(1);
if (animation->JointAnimations.find(bone->ID) != animation->JointAnimations.end()) {
const std::vector<Animation::Keyframe>& boneKeyFrames = animation->JointAnimations.at(bone->ID);
const Animation::Keyframe* currentFrame;
const Animation::Keyframe* nextFrame;
if (boneKeyFrames.size() > 1) { // 2+ keyframes for the current bone
for (int index = boneKeyFrames.size()-1; index >= 0; index--) { // find the bone keyframes that surrounds the current frame
if (time >= boneKeyFrames.at(index).Time) {
currentFrame = &boneKeyFrames.at(index);
nextFrame = &boneKeyFrames.at((index + 1) % boneKeyFrames.size());
break;
}
}
float progress;
if (nextFrame->Index == 0) {
nextFrame = currentFrame;
progress = (time - currentFrame->Time) / (animation->Duration - currentFrame->Time);
} else {
progress = (time - currentFrame->Time) / (nextFrame->Time - currentFrame->Time);
}
progress = glm::clamp(progress, 0.0f, 1.0f);
Animation::Keyframe::BoneProperty currentBoneProperty = currentFrame.BoneProperties;
Animation::Keyframe::BoneProperty nextBoneProperty = nextFrame.BoneProperties;
const Animation::Keyframe::BoneProperty& currentBoneProperty = currentFrame->BoneProperties;
const Animation::Keyframe::BoneProperty& nextBoneProperty = nextFrame->BoneProperties;
position = currentBoneProperty.Position * (1.f - progress) + nextBoneProperty.Position * progress;
rotation = glm::slerp(currentBoneProperty.Rotation, nextBoneProperty.Rotation, progress);
@@ -374,315 +151,137 @@ glm::mat4 Skeleton::GetOffsetTransform(const Bone* bone, AnimationOffset animati
} else { // 1 keyframes for the current bone
currentFrame = boneKeyFrames.at(0);
position = currentFrame.BoneProperties.Position;
rotation = currentFrame.BoneProperties.Rotation;
scale = currentFrame.BoneProperties.Scale;
currentFrame = &boneKeyFrames.at(0);
position = currentFrame->BoneProperties.Position;
rotation = currentFrame->BoneProperties.Rotation;
scale = currentFrame->BoneProperties.Scale;
}
}
return (glm::translate(position) * glm::toMat4(rotation) * glm::scale(scale));
PoseData finalPose;
finalPose.Translation = position;
finalPose.Orientation = rotation;
finalPose.Scale = scale;
return finalPose;
}
std::map<int, Skeleton::PoseData> Skeleton::BlendPoses(const std::map<int, PoseData>& pose1, const std::map<int, PoseData>& pose2, double weight)
{
std::map<int, PoseData> finalPose;
float weight1 = (float)(1.0 - weight);
float weight2 = (float)(weight);
for (auto& b : Bones) {
int boneID = b.second->ID;
PoseData blendedPose;
blendedPose.Translation = glm::vec3(0);
blendedPose.Orientation = glm::quat();
blendedPose.Scale = glm::vec3(1);
if(pose1.find(boneID) != pose1.end() && pose2.find(boneID) != pose2.end()) {
blendedPose.Translation = pose1.at(boneID).Translation * weight1 + pose2.at(boneID).Translation * weight2;
blendedPose.Orientation = glm::slerp(pose1.at(boneID).Orientation, pose2.at(boneID).Orientation, weight2);
blendedPose.Scale = pose1.at(boneID).Scale * weight1 + pose2.at(boneID).Scale * weight2;
finalPose[boneID] = blendedPose;
} else if(pose1.find(boneID) != pose1.end()) {
finalPose[boneID] = pose1.at(boneID);
} else if (pose2.find(boneID) != pose2.end()) {
finalPose[boneID] = pose2.at(boneID);
}
}
return finalPose;
}
std::map<int, Skeleton::PoseData> Skeleton::OverridePose(const std::map<int, PoseData>& overridePose, const std::map<int, PoseData>& targetPose)
{
std::map<int, PoseData> finalPose;
for (auto& b : Bones) {
int boneID = b.second->ID;
if (overridePose.find(boneID) != overridePose.end()) {
finalPose[boneID] = overridePose.at(boneID);
} else if (targetPose.find(boneID) != targetPose.end()) {
finalPose[boneID] = targetPose.at(boneID);
}
}
return finalPose;
}
std::map<int, Skeleton::PoseData> Skeleton::BlendPoseAdditive(const std::map<int, PoseData>& additivePose, const std::map<int, PoseData>& targetPose)
{
std::map<int, PoseData> finalPose;
for (auto& b : Bones) {
int boneID = b.second->ID;
PoseData blendedPose;
blendedPose.Translation = glm::vec3(0);
blendedPose.Orientation = glm::quat();
blendedPose.Scale = glm::vec3(1);
if (additivePose.find(boneID) != additivePose.end() && targetPose.find(boneID) != targetPose.end()) {
blendedPose.Translation = additivePose.at(boneID).Translation + targetPose.at(boneID).Translation;
blendedPose.Orientation = additivePose.at(boneID).Orientation * targetPose.at(boneID).Orientation;
blendedPose.Scale = additivePose.at(boneID).Scale + targetPose.at(boneID).Scale;
finalPose[boneID] = blendedPose;
} else if (additivePose.find(boneID) != additivePose.end()) {
finalPose[boneID] = additivePose.at(boneID);
} else if (targetPose.find(boneID) != targetPose.end()) {
finalPose[boneID] = targetPose.at(boneID);
}
}
return finalPose;
}
void Skeleton::GetFinalPose(std::map<int, Skeleton::PoseData>& poseDatas, std::vector<glm::mat4>& finalPose, std::map<int, glm::mat4>& boneTransforms)
{
std::map<int, glm::mat4> boneMatrices;
AccumulateFinalPose(boneMatrices, poseDatas, boneTransforms, RootBone, glm::mat4(1));
for(auto& b : boneMatrices) {
finalPose.push_back(b.second);
}
}
glm::mat4 Skeleton::GetBoneTransform(const Bone* bone, const Animation* animation, float time, glm::mat4 childMatrix)
std::vector<glm::mat4> Skeleton::GetTPose()
{
glm::mat4 boneMatrix;
std::vector<glm::mat4> finalMatrices;
Animation::Keyframe currentFrame;
Animation::Keyframe nextFrame;
if (animation->JointAnimations.find(bone->ID) != animation->JointAnimations.end()) {
std::vector<Animation::Keyframe> boneKeyFrames = animation->JointAnimations.at(bone->ID);
if (boneKeyFrames.size() > 1) { // 2+ keyframes for the current bone
for (int index = boneKeyFrames.size()-1; index >= 0; index--) { // find the bone keyframes that surrounds the current frame
if (time >= boneKeyFrames.at(index).Time) {
currentFrame = boneKeyFrames.at(index);
nextFrame = boneKeyFrames.at((index + 1) % boneKeyFrames.size());
break;
}
}
float progress;
if (nextFrame.Index == 0) {
nextFrame = currentFrame;
progress = (time - currentFrame.Time) / (animation->Duration - currentFrame.Time);
} else {
progress = (time - currentFrame.Time) / (nextFrame.Time - currentFrame.Time);
}
if (progress > 1.0f || progress < 0.0f) {
LOG_INFO("Progress %f", progress);
progress = glm::clamp(progress, 0.0f, 1.0f);
}
Animation::Keyframe::BoneProperty currentBoneProperty = currentFrame.BoneProperties;
Animation::Keyframe::BoneProperty nextBoneProperty = nextFrame.BoneProperties;
glm::vec3 positionInterp = currentBoneProperty.Position * (1.f - progress) + nextBoneProperty.Position * progress;
glm::quat rotationInterp = glm::slerp(currentBoneProperty.Rotation, nextBoneProperty.Rotation, progress);
glm::vec3 scaleInterp = currentBoneProperty.Scale * (1.f - progress) + nextBoneProperty.Scale * progress;
boneMatrix = (glm::translate(positionInterp) * glm::toMat4(rotationInterp) * glm::scale(scaleInterp)) * childMatrix;
} else { // 1 keyframes for the current bone
currentFrame = boneKeyFrames.at(0);
boneMatrix = (glm::translate(currentFrame.BoneProperties.Position) * glm::toMat4(currentFrame.BoneProperties.Rotation) * glm::scale(currentFrame.BoneProperties.Scale)) * childMatrix;
}
} else { // 0 keyframes for the current bone
if (bone->Parent) {
boneMatrix = bone->Parent->OffsetMatrix * glm::inverse(bone->OffsetMatrix) * childMatrix;
} else {
boneMatrix = glm::inverse(bone->OffsetMatrix) * childMatrix;
}
for (auto b : Bones) {
finalMatrices.push_back(glm::mat4(1));
}
if (bone->Parent) {
return GetBoneTransform(bone->Parent, animation, time, boneMatrix);
} else {
return boneMatrix;
}
return finalMatrices;
}
glm::mat4 Skeleton::GetBoneTransform(bool noRootMotion, const Bone* bone, std::vector<AnimationData> animations, AnimationOffset animationOffset, glm::mat4 childMatrix)
void Skeleton::AccumulateFinalPose(std::map<int, glm::mat4>& boneMatrices, std::map<int, Skeleton::PoseData>& poseDatas, std::map<int, glm::mat4>& boneTransforms, const Bone* bone, glm::mat4 parentMatrix)
{
glm::mat4 boneMatrix;
std::vector<JointFrameTransform> JointTransforms;
for (const AnimationData animationData : animations) {
const Animation* animation = animationData.animation;
const float time = animationData.time;
JointFrameTransform jointTransform;
jointTransform.Weight = animationData.weight;;
if (animation->JointAnimations.find(bone->ID) != animation->JointAnimations.end()) {
std::vector<Animation::Keyframe> boneKeyFrames = animation->JointAnimations.at(bone->ID);
Animation::Keyframe currentFrame;
Animation::Keyframe nextFrame;
if (boneKeyFrames.size() > 1) { // 2+ keyframes for the current bone
for (int index = boneKeyFrames.size()-1; index >= 0; index--) { // find the bone keyframes that surrounds the current frame
if (time >= boneKeyFrames.at(index).Time) {
currentFrame = boneKeyFrames.at(index);
nextFrame = boneKeyFrames.at((index + 1) % boneKeyFrames.size());
break;
}
}
float progress;
if (nextFrame.Index == 0) {
nextFrame = currentFrame;
progress = (time - currentFrame.Time) / (animation->Duration - currentFrame.Time);
} else {
progress = (time - currentFrame.Time) / (nextFrame.Time - currentFrame.Time);
}
if (progress > 1.0f || progress < 0.0f) {
progress = glm::clamp(progress, 0.0f, 1.0f);
}
Animation::Keyframe::BoneProperty currentBoneProperty = currentFrame.BoneProperties;
Animation::Keyframe::BoneProperty nextBoneProperty = nextFrame.BoneProperties;
jointTransform.PositionInterp = currentBoneProperty.Position * (1.f - progress) + nextBoneProperty.Position * progress;
jointTransform.RotationInterp = glm::slerp(currentBoneProperty.Rotation, nextBoneProperty.Rotation, progress);
jointTransform.ScaleInterp = currentBoneProperty.Scale * (1.f - progress) + nextBoneProperty.Scale * progress;
// Flag for no root motion
if (bone == RootBone && noRootMotion) {
jointTransform.PositionInterp.x = 0;
jointTransform.PositionInterp.z = 0;
}
JointTransforms.push_back(jointTransform);
} else { // 1 keyframes for the current bone
currentFrame = boneKeyFrames.at(0);
jointTransform.PositionInterp = currentFrame.BoneProperties.Position;
jointTransform.RotationInterp = currentFrame.BoneProperties.Rotation;
jointTransform.ScaleInterp = currentFrame.BoneProperties.Scale;
JointTransforms.push_back(jointTransform);
}
} else { // 0 keyframes for the current bone
}
}
glm::mat4 offset = GetOffsetTransform(bone, animationOffset);
if (JointTransforms.size() == 0) {
if (poseDatas.find(bone->ID) != poseDatas.end()) {
boneMatrix = parentMatrix * (glm::translate(poseDatas.at(bone->ID).Translation) * glm::mat4(poseDatas.at(bone->ID).Orientation) * glm::scale(poseDatas.at(bone->ID).Scale));
boneMatrices[bone->ID] = boneMatrix * bone->OffsetMatrix;
} else {
if (bone->Parent) {
if (offset != glm::mat4(1)) {
boneMatrix = offset * childMatrix;// *((glm::inverse(bone->OffsetMatrix) * bone->Parent->OffsetMatrix));
} else {
boneMatrix = ((glm::inverse(bone->OffsetMatrix) * bone->Parent->OffsetMatrix)) * childMatrix;
}
boneMatrix = parentMatrix * bone->BindTransformMatrix * bone->Parent->OffsetMatrix;
boneMatrices[bone->ID] = boneMatrix * bone->OffsetMatrix;
} else {
boneMatrix = offset * glm::inverse(bone->OffsetMatrix);
}
} else {
glm::vec3 finalPosInterp;
glm::quat finalRotInterp;
glm::vec3 finalScaleInterp;
float totalWeight = 0;
for (JointFrameTransform jointTransform : JointTransforms) {
totalWeight += jointTransform.Weight;
}
for (JointFrameTransform jointTransform : JointTransforms) {
if (jointTransform.Weight == 1.0f) {
finalPosInterp = jointTransform.PositionInterp;
finalRotInterp = jointTransform.RotationInterp;
finalScaleInterp = jointTransform.ScaleInterp;
break;
} else {
finalPosInterp += jointTransform.PositionInterp * (jointTransform.Weight/totalWeight);
finalRotInterp *= glm::slerp(glm::quat(), jointTransform.RotationInterp, (jointTransform.Weight/totalWeight));
finalScaleInterp += jointTransform.ScaleInterp * (jointTransform.Weight/totalWeight);
}
}
if (offset != glm::mat4(1)) {
boneMatrix = ((glm::translate(finalPosInterp) * glm::toMat4(finalRotInterp) * glm::scale(finalScaleInterp)) + offset) * childMatrix;
} else {
boneMatrix = (glm::translate(finalPosInterp) * glm::toMat4(finalRotInterp) * glm::scale(finalScaleInterp)) * childMatrix;
boneMatrix = bone->BindTransformMatrix;
boneMatrices[bone->ID] = parentMatrix;
}
}
if (bone->Parent != nullptr) {
return GetBoneTransform(noRootMotion, bone->Parent, animations, animationOffset, boneMatrix);
} else {
return boneMatrix;
}
}
boneTransforms[bone->ID] = boneMatrix;
glm::mat4 Skeleton::GetBoneTransform(bool noRootMotion, const Bone* bone, std::vector<AnimationData> animations, glm::mat4 childMatrix)
{
glm::mat4 boneMatrix;
std::vector<JointFrameTransform> JointTransforms;
for (const AnimationData animationData : animations) {
const Animation* animation = animationData.animation;
const float time = animationData.time;
JointFrameTransform jointTransform;
jointTransform.Weight = animationData.weight;;
if (animation->JointAnimations.find(bone->ID) != animation->JointAnimations.end()) {
std::vector<Animation::Keyframe> boneKeyFrames = animation->JointAnimations.at(bone->ID);
Animation::Keyframe currentFrame;
Animation::Keyframe nextFrame;
if (boneKeyFrames.size() > 1) { // 2+ keyframes for the current bone
for (int index = boneKeyFrames.size()-1; index >= 0; index--) { // find the bone keyframes that surrounds the current frame
if (time >= boneKeyFrames.at(index).Time) {
currentFrame = boneKeyFrames.at(index);
nextFrame = boneKeyFrames.at((index + 1) % boneKeyFrames.size());
break;
}
}
float progress;
if (nextFrame.Index == 0) {
nextFrame = currentFrame;
progress = (time - currentFrame.Time) / (animation->Duration - currentFrame.Time);
} else {
progress = (time - currentFrame.Time) / (nextFrame.Time - currentFrame.Time);
}
if (progress > 1.0f || progress < 0.0f) {
progress = glm::clamp(progress, 0.0f, 1.0f);
}
Animation::Keyframe::BoneProperty currentBoneProperty = currentFrame.BoneProperties;
Animation::Keyframe::BoneProperty nextBoneProperty = nextFrame.BoneProperties;
jointTransform.PositionInterp = currentBoneProperty.Position * (1.f - progress) + nextBoneProperty.Position * progress;
jointTransform.RotationInterp = glm::slerp(currentBoneProperty.Rotation, nextBoneProperty.Rotation, progress);
jointTransform.ScaleInterp = currentBoneProperty.Scale * (1.f - progress) + nextBoneProperty.Scale * progress;
// Flag for no root motion
if (bone == RootBone && noRootMotion) {
jointTransform.PositionInterp.x = 0;
jointTransform.PositionInterp.z = 0;
}
JointTransforms.push_back(jointTransform);
} else { // 1 keyframes for the current bone
currentFrame = boneKeyFrames.at(0);
jointTransform.PositionInterp = currentFrame.BoneProperties.Position;
jointTransform.RotationInterp = currentFrame.BoneProperties.Rotation;
jointTransform.ScaleInterp = currentFrame.BoneProperties.Scale;
JointTransforms.push_back(jointTransform);
}
} else { // 0 keyframes for the current bone
}
}
if (JointTransforms.size() <= 0) {
if (bone->Parent) {
boneMatrix = glm::inverse(bone->OffsetMatrix) * bone->Parent->OffsetMatrix * childMatrix;
} else {
boneMatrix = glm::inverse(bone->OffsetMatrix) * childMatrix;
}
} else if (JointTransforms.size() == 1) {
boneMatrix = (glm::translate(JointTransforms.at(0).PositionInterp) * glm::toMat4(JointTransforms.at(0).RotationInterp) * glm::scale(JointTransforms.at(0).ScaleInterp)) * childMatrix;
} else {
glm::vec3 finalPosInterp;
glm::quat finalRotInterp;
glm::vec3 finalScaleInterp;
float totalWeight = 0;
for (JointFrameTransform jointTransform : JointTransforms) {
totalWeight += jointTransform.Weight;
}
for (JointFrameTransform jointTransform : JointTransforms) {
if (jointTransform.Weight == 1.0f) {
finalPosInterp = jointTransform.PositionInterp;
finalRotInterp = jointTransform.RotationInterp;
finalScaleInterp = jointTransform.ScaleInterp;
break;
} else {
finalPosInterp += jointTransform.PositionInterp * (jointTransform.Weight/totalWeight);
finalRotInterp *= glm::slerp(glm::quat(), jointTransform.RotationInterp, (jointTransform.Weight/totalWeight));
finalScaleInterp += jointTransform.ScaleInterp * (jointTransform.Weight/totalWeight);
}
}
boneMatrix = (glm::translate(finalPosInterp) * glm::toMat4(finalRotInterp) * glm::scale(finalScaleInterp)) * childMatrix;
}
if (bone->Parent != nullptr) {
return GetBoneTransform(noRootMotion, bone->Parent, animations, boneMatrix);
} else {
return boneMatrix;
for (auto &child : bone->Children) {
AccumulateFinalPose(boneMatrices, poseDatas, boneTransforms, child, boneMatrix);
}
}
@@ -695,46 +294,43 @@ int Skeleton::GetBoneID(std::string name)
}
}
void Skeleton::PrintSkeleton()
int Skeleton::CreateBone(int ID, int parentID, std::string name, glm::mat4 offsetMatrix)
{
if (LOG_LEVEL < LOG_LEVEL_DEBUG) {
return;
}
PrintSkeleton(RootBone, 0);
if (m_BonesByName.find(name) != m_BonesByName.end()) {
return m_BonesByName.at(name)->ID;
} else {
Bone* bone;
if (parentID == -1) {
bone = new Bone(ID, nullptr, name, offsetMatrix);
RootBone = bone;
} else {
Bone* parent = Bones[parentID];
bone = new Bone(ID, parent, name, offsetMatrix);
parent->Children.push_back(bone);
}
Bones[ID] = bone;
m_BonesByName[name] = bone;
return ID;
}
}
void Skeleton::PrintSkeleton(const Bone* bone, int depthCount)
Skeleton::~Skeleton()
{
std::stringstream ss;
ss << std::string(depthCount, ' ');
ss << bone->ID << ": " << bone->Name;
std::cout << ss.str() << std::endl;
depthCount++;
for (auto &kv : Bones) {
delete kv.second;
}
for (auto &child : bone->Children) {
PrintSkeleton(child, depthCount);
}
BlendTrees.clear();
}
int Skeleton::GetKeyframe(const Animation& animation, double time)
const Skeleton::Animation* Skeleton::GetAnimation(std::string name)
{
/*
if (time < 0) {
time = 0;
}
if (time >= animation.Duration) {
return animation..size() - 1;
}
for (int keyframe = 0; keyframe < animation.Keyframes.size(); ++keyframe) {
if (animation.Keyframes[keyframe].Time > time) {
return (keyframe - 1) % animation.Keyframes.size();
}
}
*/
return 0;
}
auto it = Animations.find(name);
if (it != Animations.end()) {
return const_cast<const Animation*>(&it->second);
} else {
return nullptr;
}
}
+173 -74
View File
@@ -7,23 +7,23 @@ 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);
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();
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()
@@ -33,81 +33,180 @@ void TextPass::Update()
void TextPass::Draw(RenderScene& scene, FrameBuffer& frameBuffer)
{
GLERROR("Derp1");
TextPassState* state = new TextPassState(frameBuffer.GetHandle());
for (auto &job : scene.Jobs.Text) {
auto textJob = std::dynamic_pointer_cast<TextJob>(job);
if (textJob) {
GLERROR("Derp1");
TextPassState* state = new TextPassState(frameBuffer.GetHandle());
for (auto &job : scene.Jobs.Text) {
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;
renderText(textJob->Content, textJob->Resource, textJob->Alignment, textJob->Color, textJob->Matrix, scene.Camera->ProjectionMatrix(), scene.Camera->ViewMatrix());
}
}
GLERROR("Derp2");
delete state;
}
std::string TextPass::parseColors(std::string text, std::map<int, glm::vec4>& colorChanges, glm::vec4 originalColor)
{
std::string parsedString = text;
glm::vec4 newColor = originalColor;
bool colorChange = false;
for (std::string::const_iterator c = parsedString.begin(); c != parsedString.end(); c++) {
if (*c == char(92)) { // Backlash
if ((c + 1) != parsedString.end()) {
if (*(c + 1) == char('C')) { // C for Color
if ((c + 7) != parsedString.end()) {
bool hasCorrectFormat = true;
for (std::string::const_iterator colorC = c + 2; colorC != c + 8; colorC++) {
if (*colorC < '0' || *colorC > 'F') {
hasCorrectFormat = false;
break;
}
}
if (hasCorrectFormat == true) {
colorChange = true;
std::array<int, 3> hexToInt = {
std::stoi(std::string(c + 2, c + 4), 0, 16),
std::stoi(std::string(c + 4, c + 6), 0, 16),
std::stoi(std::string(c + 6, c + 8), 0, 16)
};
newColor = glm::vec4(
float(hexToInt[0]) / 255.f,
float(hexToInt[1]) / 255.f,
float(hexToInt[2]) / 255.f,
newColor.a);
parsedString.erase(c, (c + 8));
}
}
}
if (*(c + 1) == char('A')) { // A for Alpha
if ((c + 3) != parsedString.end()) {
bool hasCorrectFormat = true;
for (std::string::const_iterator colorC = c + 2; colorC != c + 4; colorC++) {
if (*colorC < '0' || *colorC > 'F') {
hasCorrectFormat = false;
break;
}
}
if (hasCorrectFormat == true) {
colorChange = true;
int hexToInt = std::stoi(std::string(c + 2, c + 4), 0, 16);
newColor = glm::vec4(
newColor.r,
newColor.g,
newColor.b,
float(hexToInt) / 255.f);
parsedString.erase(c, (c + 4));
}
}
}
if ((*(c + 1) >= '1' && *(c + 1) <= '9') || *(c + 1) == 'B' || *(c + 1) == 'E' || *(c + 1) == 'F') { // Icons
if (*(c + 1) >= '1' && *(c + 1) <= '9') {
parsedString.replace(c, (c + 2), 1, (*(c + 1) - 48));
}
else {
parsedString.replace(c, (c + 2), 1, (*(c + 1) - 55));
}
}
if (colorChange) {
colorChanges[c - parsedString.begin()] = newColor;
}
}
}
}
return parsedString;
}
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 penX = 0;
GLfloat penY = 0;
GLfloat scale = 1.0 / font->FontSize;
GLfloat stringWidth = 0.f;
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;
}
std::map<int, glm::vec4> colorChanges;
std::string parsedText = parseColors(text, colorChanges, color);
if(alignment == TextJob::AlignmentEnum::Center) {
penX = -stringWidth/2.f;
} else if (alignment == TextJob::AlignmentEnum::Right) {
penX = -stringWidth;
} else {
penX = 0;
}
for (std::string::const_iterator c = parsedText.begin(); c != parsedText.end(); c++) {
Font::Character ch = font->m_Characters[*c];
stringWidth += (ch.Advance >> 6) * scale;
}
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);
if (alignment == TextJob::AlignmentEnum::Center) {
penX = -stringWidth / 2.f;
}
else if (alignment == TextJob::AlignmentEnum::Right) {
penX = -stringWidth;
}
else {
penX = 0;
}
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;
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);
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 },
for (std::string::const_iterator c = parsedText.begin(); c != parsedText.end(); c++) {
{ xpos, ypos + h, 0.0, 0.0 },
{ xpos + w, ypos, 1.0, 1.0 },
{ xpos + w, ypos + h, 1.0, 0.0 }
};
auto it = colorChanges.find(c - parsedText.begin());
if (it != colorChanges.end()) {
glUniform4fv(glGetUniformLocation(m_TextProgram->GetHandle(), "textColor"), 1, glm::value_ptr(it->second));
}
glBindTexture(GL_TEXTURE_2D, ch.TextureID);
Font::Character ch = font->m_Characters[*c];
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);
GLfloat xpos = penX + ch.Bearing.x * scale;
GLfloat ypos = penY - (ch.Size.y - ch.Bearing.y) * scale;
GLERROR("Text rendering Error");
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");
}
+3 -14
View File
@@ -4,18 +4,6 @@ Texture::Texture(std::string path)
{
PNG* img = ResourceManager::Load<PNG, true>(path); //TODO: Make this threaded. Catch exeptions in all other load places.
//PNG image(path);
//if (img->Width == 0 && img->Height == 0 || img->Format == Image::ImageFormat::Unknown) {
// //image = PNG("Textures/Core/ErrorTexture.png");
// //return; // Temporary fix to remove crash
// if (img->Width == 0 && img->Height == 0 || img->Format == Image::ImageFormat::Unknown) {
// LOG_ERROR("Couldn't even load the error texture. This is a dark day indeed.");
// return;
// }
//}
this->Width = img->Width;
this->Height = img->Height;
this->Data = img->Data;
@@ -29,8 +17,7 @@ Texture::Texture(std::string path)
format = GL_RGBA;
break;
}
// Construct the OpenGL texture
glGenTextures(1, &m_Texture);
glBindTexture(GL_TEXTURE_2D, m_Texture);
@@ -42,6 +29,8 @@ Texture::Texture(std::string path)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
GLERROR("Texture load");
ResourceManager::Release("PNG", path);
}
Texture::~Texture()
+11
View File
@@ -0,0 +1,11 @@
#include "Rendering/TextureSprite.h"
TextureSprite::TextureSprite(std::string path)
:Texture(path)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
GLERROR("Texture load");
}
+10 -25
View File
@@ -1,23 +1,5 @@
#include "Rendering/Util/CommonFunctions.h"
Texture* CommonFunctions::LoadTexture(std::string path, bool threaded)
{
Texture* img;
try {
if(threaded) {
img = ResourceManager::Load<Texture, true>(path);
} else {
img = ResourceManager::Load<Texture, false>(path);
}
} catch (const Resource::StillLoadingException&) {
img = ResourceManager::Load<Texture>("Textures/Core/ErrorTexture.png");
} catch (const std::exception&) {
img = nullptr;
}
return img;
}
void CommonFunctions::GenerateTexture(GLuint* texture, GLenum wrapping, GLenum filtering, glm::vec2 dimensions, GLint internalFormat, GLint format, GLenum type)
{
glDeleteTextures(1, texture);
@@ -35,23 +17,26 @@ void CommonFunctions::GenerateMultiSampleTexture(GLuint* texture, int numSamples
{
glDeleteTextures(1, texture);
glGenTextures(1, texture);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, *texture);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, numSamples, internalFormat, dimensions.x, dimensions.y, false);
glBindTexture(GL_TEXTURE_2D, *texture);
GLERROR("Texture initialization failed 1");
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, numSamples, internalFormat, dimensions.x, dimensions.y, GL_FALSE);
GLERROR("Texture initialization failed");
}
void CommonFunctions::GenerateMipMapTexture(GLuint* texture, GLenum wrapping, glm::vec2 dimensions, GLint format, GLenum type, GLint numMipMaps)
void CommonFunctions::GenerateMipMapTexture(GLuint* texture, GLenum wrapping, glm::vec2 dimensions, GLint internalFormat, GLint format, GLenum type, GLint numMipMaps, GLint MAGFilter, GLint MINFilter)
{
glDeleteTextures(1, texture);
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);
glTexStorage2D(GL_TEXTURE_2D, numMipMaps, internalFormat, dimensions.x, dimensions.y);
//glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, dimensions.x, dimensions.y, format, type, NULL);
GLERROR("MipMap Texture glTexSubImage2D failed");
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);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, MAGFilter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, MINFilter);
GLERROR("MipMap Texture initialization failed");
}
@@ -36,10 +36,6 @@ ScreenCoords::PixelData ScreenCoords::ToPixelData(float x, float y, FrameBuffer*
unsigned char pdata[3];
glReadPixels(x, y, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, &pdata);
GLERROR("glReadPixels(pdata) Error");
PickDataBuffer->Unbind();
glBindFramebuffer(GL_FRAMEBUFFER, DepthBuffer);
GLERROR("glBindFramebuffer(DepthBuffer) Error");
float depthData;
glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depthData);
GLERROR("glReadPixels(depthData) Error");
+159 -26
View File
@@ -7,6 +7,7 @@ SoundManager::SoundManager(World* world, EventBroker* eventBroker)
m_World = world;
m_BGMVolumeChannel = config->Get<float>("Sound.BGMVolume", 1.f);
m_SFXVolumeChannel = config->Get<float>("Sound.SFXVolume", 1.f);
m_AnnouncerVolumeChannel = config->Get<float>("Sound.AnnouncerVolume", 1.f);
initOpenAL();
alSpeedOfSound(340.29f);
@@ -16,16 +17,20 @@ SoundManager::SoundManager(World* world, EventBroker* eventBroker)
EVENT_SUBSCRIBE_MEMBER(m_EPlaySoundOnEntity, &SoundManager::OnPlaySoundOnEntity);
EVENT_SUBSCRIBE_MEMBER(m_EPlaySoundOnPosition, &SoundManager::OnPlaySoundOnPosition);
EVENT_SUBSCRIBE_MEMBER(m_EPlayBackgroundMusic, &SoundManager::OnPlayBackgroundMusic);
EVENT_SUBSCRIBE_MEMBER(m_EPlayAnnouncerVoice, &SoundManager::OnPlayAnnouncerVoice);
EVENT_SUBSCRIBE_MEMBER(m_EStopSound, &SoundManager::OnStopSound);
EVENT_SUBSCRIBE_MEMBER(m_EPauseSound, &SoundManager::OnPauseSound);
EVENT_SUBSCRIBE_MEMBER(m_EContinueSound, &SoundManager::OnContinueSound);
EVENT_SUBSCRIBE_MEMBER(m_ESetBGMGain, &SoundManager::OnSetBGMGain);
EVENT_SUBSCRIBE_MEMBER(m_ESetSFXGain, &SoundManager::OnSetSFXGain);
EVENT_SUBSCRIBE_MEMBER(m_ESetAnnouncerGain, &SoundManager::OnSetAnnouncerGain);
EVENT_SUBSCRIBE_MEMBER(m_EPause, &SoundManager::OnPause);
EVENT_SUBSCRIBE_MEMBER(m_EResume, &SoundManager::OnResume);
EVENT_SUBSCRIBE_MEMBER(m_EComponentAttached, &SoundManager::OnComponentAttached);
EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &SoundManager::OnPlayerSpawned);
EVENT_SUBSCRIBE_MEMBER(m_EPlayQueueOnEntity, &SoundManager::OnPlayQueueOnEntity);
EVENT_SUBSCRIBE_MEMBER(m_EChangeBGM, &SoundManager::OnChangeBGM);
EVENT_SUBSCRIBE_MEMBER(m_ESetCamera, &SoundManager::OnSetCamera);
}
SoundManager::~SoundManager()
@@ -56,13 +61,10 @@ void SoundManager::stopEmitters()
void SoundManager::Update(double dt)
{
m_EventBroker->Process<SoundManager>();
deleteInactiveEmitters(); // can be optimized with "EEntityDeleted"
deleteInactiveEmitters();
updateEmitters(dt);
updateListener(dt);
// Editor debug info
ImGui::SliderFloat("BGM", &m_BGMVolumeChannel, 0.0f, 1.0f, "%.3f", 1.0f);
ImGui::SliderFloat("SFX", &m_SFXVolumeChannel, 0.0f, 1.0f, "%.3f", 1.0f);
matchBGMLoop();
}
void SoundManager::deleteInactiveEmitters()
@@ -113,18 +115,18 @@ void SoundManager::updateEmitters(double dt)
if (!m_World->ValidEntity(m_World->GetParent(it->first))) {
return;
}
glm::vec3 nextPos = Transform::AbsolutePosition(m_World, it->first);
glm::vec3 nextPos = TransformSystem::AbsolutePosition(m_World, it->first);
// Calculate velocity
glm::vec3 velocity = glm::vec3(nextPos - previousPos) / (float)dt;
setSourcePos(it->second->ALsource, nextPos);
setSourceVel(it->second->ALsource, velocity);
//setSourceVel(it->second->ALsource, glm::vec3(0));
auto emitter = m_World->GetComponent(it->first, "SoundEmitter");
setSoundProperties(it->second, &emitter);
// Path changed
if (it->second->SoundResource->Path() != (std::string)emitter["FilePath"]) {
it->second->SoundResource = ResourceManager::Load<Sound>((std::string)emitter["FilePath"]);
if (it->second->SoundResource->Path() != (const std::string&)emitter["FilePath"]) {
it->second->SoundResource = ResourceManager::Load<Sound>((const std::string&)emitter["FilePath"]);
if (it->second->SoundResource->Buffer() != 0) {
playSound(it->second);
}
@@ -147,11 +149,11 @@ void SoundManager::updateListener(double dt)
if (listener.IsChildOf(m_LocalPlayer) || listener == m_LocalPlayer) {
glm::vec3 previousPos;
alGetListener3f(AL_POSITION, &previousPos.x, &previousPos.y, &previousPos.z); // Get previous pos
glm::vec3 nextPos = Transform::AbsolutePosition(listener); // Get next (current) pos
glm::vec3 nextPos = TransformSystem::AbsolutePosition(listener); // Get next (current) pos
glm::vec3 velocity = glm::vec3(nextPos - previousPos) / (float)dt; // Calculate velocity
setListenerPos(nextPos);
setListenerVel(velocity);
setListenerOri(glm::eulerAngles(Transform::AbsoluteOrientation(listener)));
setListenerOri(glm::eulerAngles(TransformSystem::AbsoluteOrientation(listener)));
break;
}
}
@@ -166,9 +168,34 @@ Source* SoundManager::createSource(std::string filePath)
Source* source = new Source();
source->ALsource = alSource;
source->SoundResource = ResourceManager::Load<Sound>(filePath);
source->Duration = getDurationSeconds(source);
return source;
}
void SoundManager::matchBGMLoop()
{
if (m_CurrentBGMCombo == nullptr)
return;
auto cCapturePoints = m_World->GetComponents("CapturePoint");
for (auto it = cCapturePoints->begin(); it != cCapturePoints->end(); it++) {
float timeCaptured = (float)(double)(*it)["CaptureTimer"];
float maxTimer = (float)(double)(*it)["CapturePointMaxTimer"];
int capturePointIndex = (int)(*it)["CapturePointNumber"];
if (capturePointIndex == 0) { // Home for red team
if (timeCaptured < 0 && glm::abs(timeCaptured) < maxTimer) {
float gain = glm::abs(timeCaptured) / maxTimer;
setGain(m_CurrentBGMCombo, gain);
}
} else if (capturePointIndex == 4) { // Home for blue team
if (timeCaptured > 0 && timeCaptured < maxTimer) {
float gain = timeCaptured / maxTimer;
setGain(m_CurrentBGMCombo, gain);
}
}
}
}
void SoundManager::playSound(Source* source)
{
alSourcei(source->ALsource, AL_BUFFER, source->SoundResource->Buffer());
@@ -192,10 +219,12 @@ bool SoundManager::OnPlaySoundOnEntity(const Events::PlaySoundOnEntity & e)
{
Source* source = createSource(e.FilePath);
source->Type = SoundType::SFX;
EntityID child = m_World->CreateEntity(e.EmitterID);
EntityID child = m_World->CreateEntity(e.Emitter.ID);
m_World->AttachComponent(child, "Transform");
m_World->AttachComponent(child, "SoundEmitter");
auto cEmitter = m_World->AttachComponent(child, "SoundEmitter");
(double&)(float)cEmitter["Gain"] = e.Gain;
m_Sources[child] = source;
setGain(source, cEmitter["Gain"]);
playSound(source);
return false;
}
@@ -205,14 +234,14 @@ bool SoundManager::OnPlaySoundOnPosition(const Events::PlaySoundOnPosition & e)
Source* source = createSource(e.FilePath);
auto emitterID = m_World->CreateEntity();
auto transform = m_World->AttachComponent(emitterID, "Transform");
(glm::vec3&)transform["Position"] = e.Position;
transform["Position"] = e.Position;
auto emitter = m_World->AttachComponent(emitterID, "SoundEmitter");
(float&)(double)emitter["Gain"] = e.Gain;
(float&)(double)emitter["Pitch"] = e.Pitch;
(bool&)emitter["Loop"] = e.Loop;
(float&)(double)emitter["MaxDistance"] = e.MaxDistance;
(float&)(double)emitter["RollOffFactor"] = e.RollOffFactor;
(float&)(double)emitter["ReferenceDistance"] = e.ReferenceDistance;
emitter["Gain"] = e.Gain;
emitter["Pitch"] = e.Pitch;
emitter["Loop"] = e.Loop;
emitter["MaxDistance"] = e.MaxDistance;
emitter["RollOffFactor"] = e.RollOffFactor;
emitter["ReferenceDistance"] = e.ReferenceDistance;
source->Type = SoundType::SFX;
m_Sources[emitterID] = source;
playSound(source);
@@ -242,12 +271,12 @@ bool SoundManager::OnPlayBackgroundMusic(const Events::PlayBackgroundMusic & e)
auto listenerComponents = m_World->GetComponents("Listener");
for (auto it = listenerComponents->begin(); it != listenerComponents->end(); it++) {
if ((*it).EntityID != m_LocalPlayer.ID) {
break;
continue;
}
auto emitterChild = m_World->CreateEntity((*it).EntityID);
auto emitter = m_World->AttachComponent(emitterChild, "SoundEmitter");
(bool&)emitter["Loop"] = true;
(std::string&)emitter["FilePath"] = e.FilePath;
emitter["Loop"] = true;
emitter["FilePath"] = e.FilePath;
m_World->AttachComponent(emitterChild, "Transform");
Source* source = createSource(e.FilePath);
source->Type = SoundType::BGM;
@@ -258,6 +287,28 @@ bool SoundManager::OnPlayBackgroundMusic(const Events::PlayBackgroundMusic & e)
return true;
}
bool SoundManager::OnPlayAnnouncerVoice(const Events::PlayAnonuncerVoice& e)
{
auto listenerComponents = m_World->GetComponents("Listener");
for (auto it = listenerComponents->begin(); it != listenerComponents->end(); it++) {
if ((*it).EntityID != m_LocalPlayer.ID) {
continue;
}
auto emitterChild = m_World->CreateEntity((*it).EntityID);
auto emitter = m_World->AttachComponent(emitterChild, "SoundEmitter");
emitter["Loop"] = false;
emitter["FilePath"] = e.FilePath;
m_World->AttachComponent(emitterChild, "Transform");
Source* source = createSource(e.FilePath);
source->Type = SoundType::Announcer;
setSoundProperties(source, &emitter);
m_Sources[emitterChild] = source;
playSound(source);
}
return true;
}
bool SoundManager::OnSetBGMGain(const Events::SetBGMGain & e)
{
m_BGMVolumeChannel = e.Gain;
@@ -270,6 +321,13 @@ bool SoundManager::OnSetSFXGain(const Events::SetSFXGain & e)
return true;
}
bool SoundManager::OnSetAnnouncerGain(const Events::SetAnnouncerGain& e)
{
m_AnnouncerVolumeChannel = e.Gain;
return true;
}
bool SoundManager::OnComponentAttached(const Events::ComponentAttached & e)
{
if (e.Component.Info.Name == "SoundEmitter") {
@@ -306,7 +364,6 @@ bool SoundManager::OnPlayerSpawned(const Events::PlayerSpawned &e)
return false;
}
bool SoundManager::OnPlayQueueOnEntity(const Events::PlayQueueOnEntity &e)
{
Source* source = createSource(*e.FilePaths.begin());
@@ -321,6 +378,48 @@ bool SoundManager::OnPlayQueueOnEntity(const Events::PlayQueueOnEntity &e)
return true;
}
bool SoundManager::OnChangeBGM(const Events::ChangeBGM &e)
{
if (m_CurrentBGM != nullptr) {
if (getSourceState(m_CurrentBGM->ALsource) == AL_PLAYING) {
stopSound(m_CurrentBGM);
}
}
m_CurrentBGM = createSource(e.FilePath);
m_CurrentBGM->Type = SoundType::BGM;
alSourcei(m_CurrentBGM->ALsource, AL_LOOPING, 1);
playSound(m_CurrentBGM);
return true;
}
bool SoundManager::OnSetCamera(const Events::SetCamera& e)
{
if (e.CameraEntity.Name() == "Overview_Camera_Start_Menu") {
if (m_CurrentBGMCombo != nullptr) {
if (getSourceState(m_CurrentBGMCombo->ALsource) == AL_PLAYING) {
stopSound(m_CurrentBGMCombo);
}
}
Events::ChangeBGM changeBGM;
changeBGM.FilePath = "Audio/BGM/MenuMusic.wav";
m_EventBroker->Publish(changeBGM);
} else if (e.CameraEntity.Name() == "PickTeamCamera") {
Events::ChangeBGM changeBGM;
changeBGM.FilePath = "Audio/BGM/Layer1.wav";
m_EventBroker->Publish(changeBGM);
if (m_CurrentBGMCombo != nullptr) {
if (getSourceState(m_CurrentBGMCombo->ALsource) == AL_PLAYING) {
stopSound(m_CurrentBGMCombo);
}
}
m_CurrentBGMCombo = createSource("Audio/BGM/Layer2.wav");
m_CurrentBGMCombo->Type = SoundType::BGM;
alSourcei(m_CurrentBGMCombo->ALsource, AL_LOOPING, 1);
setGain(m_CurrentBGMCombo, 0);
playSound(m_CurrentBGMCombo);
}
}
ALenum SoundManager::getSourceState(ALuint source)
{
ALenum state;
@@ -335,15 +434,49 @@ void SoundManager::setGain(Source * source, float gain)
void SoundManager::setSoundProperties(Source* source, ComponentWrapper* soundComponent)
{
float gain = (source->Type == SoundType::SFX) ? m_SFXVolumeChannel : m_BGMVolumeChannel;
float gain;
switch (source->Type) {
case SoundType::SFX:
gain = m_SFXVolumeChannel;
break;
case SoundType::BGM:
gain = m_BGMVolumeChannel;
break;
case SoundType::Announcer:
gain = m_AnnouncerVolumeChannel;
break;
default:
gain = 1.f;
break;
}
alSourcef(source->ALsource, AL_GAIN, (float)(double)(*soundComponent)["Gain"] * gain);
alSourcef(source->ALsource, AL_PITCH, (float)(double)(*soundComponent)["Pitch"]);
alSourcei(source->ALsource, AL_LOOPING, (int)(bool)(*soundComponent)["Loop"]); // YOLO
alSourcei(source->ALsource, AL_LOOPING, (int)(bool)(*soundComponent)["Loop"]);
alSourcef(source->ALsource, AL_MAX_DISTANCE, (float)(double)(*soundComponent)["MaxDistance"]);
alSourcef(source->ALsource, AL_ROLLOFF_FACTOR, (float)(double)(*soundComponent)["RollOffFactor"]);
alSourcef(source->ALsource, AL_REFERENCE_DISTANCE, (float)(double)(*soundComponent)["ReferenceDistance"]);
}
float SoundManager::getDurationSeconds(Source* source)
{
ALuint buffer = source->SoundResource->Buffer();
ALint sizeBytes, channels, bits, frequenzy;
alGetBufferi(buffer, AL_SIZE, &sizeBytes);
alGetBufferi(buffer, AL_CHANNELS, &channels);
alGetBufferi(buffer, AL_BITS, &bits);
alGetBufferi(buffer, AL_FREQUENCY, &frequenzy);
float sampleLength = (float)sizeBytes * 8 / (channels * bits);
return (sampleLength / frequenzy);
}
float SoundManager::getTimeOffsetSeconds(Source* source)
{
float time;
alGetSourcef(source->ALsource, AL_SEC_OFFSET, &time);
return time;
}
void SoundManager::initOpenAL()
{
// Initialize OpenAL