diff --git a/.gitignore b/.gitignore index 0df2db42..23056510 100755 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,6 @@ tools/MayaExporter/x64/Debug/ tools/MayaExporter/MayaExporter/Debug/ tools/MayaExporter/MayaExporter/GeneratedFiles/ + +tools/MayaExporter/MayaExporter/x64/* +tools/MayaExporter/x64/* diff --git a/assets b/assets index 091ad5c0..dfa0fc61 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 091ad5c01bf7b6ef5501fc907fc610576a4a45ea +Subproject commit dfa0fc61ab88456f3461779bd7c6ac97d15f6493 diff --git a/deps b/deps index bf83f099..ed45883a 160000 --- a/deps +++ b/deps @@ -1 +1 @@ -Subproject commit bf83f099ba16f0a87f9bebe8cfc5fd4e59fee805 +Subproject commit ed45883a444c6de548b6211a83a079ff2ecfce15 diff --git a/include/Engine/Collision/Collision.h b/include/Engine/Collision/Collision.h index cd10dbb2..5b4150d8 100644 --- a/include/Engine/Collision/Collision.h +++ b/include/Engine/Collision/Collision.h @@ -20,6 +20,9 @@ class World; struct ComponentWrapper; +template +class Octree; + namespace Collision { //Return true if the ray hits the box. @@ -28,30 +31,51 @@ bool RayVsAABB(const Ray& ray, const AABB& box); //Return true if the ray hits the box, also outputs distance from ray origin to intersection point in [outDistance]. bool RayVsAABB(const Ray& ray, const AABB& box, float& outDistance); +//Return true if the ray hits the triangle. +bool RayVsTriangle(const Ray& ray, + const glm::vec3& v0, + const glm::vec3& v1, + const glm::vec3& v2, + bool trueOnNegativeDistance = false); +//Return true if the ray hits the triangle, and the distance is less than outDistance. +bool RayVsTriangle(const Ray& ray, + const glm::vec3& v0, + const glm::vec3& v1, + const glm::vec3& v2, + float& outDistance, + float& outUCoord, + float& outVCoord, + bool trueOnNegativeDistance = false); //Return true if the ray hits any of the triangles in the model. Stops checking when a hit is detected. -bool RayVsModel(const Ray& ray, - const std::vector& modelVertices, - const std::vector& modelIndices); +bool RayVsModel(const Ray& ray, + const RawModel::Vertex* modelVertices, + const std::vector& modelIndices, + const glm::mat4& modelMatrix); //Return true if the ray hits any of the triangles in the model. //Also returns the position of the intersection point. Will loop through all the whole model indices. bool RayVsModel(const Ray& ray, - const std::vector& modelVertices, + const RawModel::Vertex* modelVertices, const std::vector& modelIndices, + const glm::mat4& modelMatrix, glm::vec3& outHitPosition); //Return true if the ray hits any of the triangles in the model. //Also returns the distance from the ray origin to the closest //intersection point, and the barycentric u,v-coordinates. Will loop through all the whole model indices. bool RayVsModel(const Ray& ray, - const std::vector& modelVertices, + const RawModel::Vertex* modelVertices, const std::vector& modelIndices, + const glm::mat4& modelMatrix, float& outDistance, float& outUCoord, float& outVCoord); bool AABBvsTriangles(const AABB& box, - const std::vector& modelVertices, + const RawModel::Vertex* modelVertices, const std::vector& modelIndices, const glm::mat4& modelMatrix, + glm::vec3& boxVelocity, + float verticalStepHeight, + bool& isOnGround, glm::vec3& outResolutionVector); //Return true if the boxes are intersecting. @@ -61,7 +85,15 @@ bool AABBVsAABB(const AABB& a, const AABB& b); bool AABBVsAABB(const AABB& a, const AABB& b, glm::vec3& minimumTranslation); // Calculates an absolute AABB from an entity AABB component -boost::optional EntityAbsoluteAABB(EntityWrapper& entity); +boost::optional EntityAbsoluteAABB(EntityWrapper& entity, bool takeModelBox = false); +boost::optional AbsoluteAABBExplosionEffect(EntityWrapper& entity); +//Returns the first entity hit by the input ray. entitiesPotentiallyHitSorted needs to be sorted +//by their distance to the ray, e.g. result from Octree::ObjectsPossiblyHitByRay. +//Returns boost::none if none was hit. outDistance will be the distance to the intersection point if the ray intersects. +boost::optional EntityFirstHitByRay(const Ray& ray, std::vector entitiesPotentiallyHitSorted, float outDistance, glm::vec3& outIntersectPos); +//Returns the first entity hit by the input ray that exists in the octree. +//outDistance will be the distance to the intersection point if the ray intersects. +boost::optional EntityFirstHitByRay(const Ray& ray, Octree* octree, float outDistance, glm::vec3& outIntersectPos); } diff --git a/include/Engine/Collision/CollisionSystem.h b/include/Engine/Collision/CollisionSystem.h index f3a7e4fe..c963e6b8 100644 --- a/include/Engine/Collision/CollisionSystem.h +++ b/include/Engine/Collision/CollisionSystem.h @@ -13,8 +13,8 @@ class CollisionSystem : public PureSystem { public: - CollisionSystem(World* world, EventBroker* eventBroker, Octree* octree) - : System(world, eventBroker) + CollisionSystem(SystemParams params, Octree* octree) + : System(params) , PureSystem("Collidable") , m_Octree(octree) { } diff --git a/include/Engine/Collision/CollidableOctreeSystem.h b/include/Engine/Collision/FillFrustumOctreeSystem.h similarity index 51% rename from include/Engine/Collision/CollidableOctreeSystem.h rename to include/Engine/Collision/FillFrustumOctreeSystem.h index 0aa01d2e..430b4037 100644 --- a/include/Engine/Collision/CollidableOctreeSystem.h +++ b/include/Engine/Collision/FillFrustumOctreeSystem.h @@ -1,17 +1,17 @@ -#ifndef CollidableOctreeSystem_h__ -#define CollidableOctreeSystem_h__ +#ifndef FillFrustumOctreeSystem_h__ +#define FillFrustumOctreeSystem_h__ #include "../Core/System.h" #include "../Core/Octree.h" #include "Collision.h" #include "EntityAABB.h" -class CollidableOctreeSystem : public ImpureSystem, public PureSystem +class FillFrustumOctreeSystem : public ImpureSystem, public PureSystem { public: - CollidableOctreeSystem(World* world, EventBroker* eventBroker, Octree* octree, const std::string& componentType) - : System(world, eventBroker) - , PureSystem(componentType) + FillFrustumOctreeSystem(SystemParams params, Octree* octree) + : System(params) + , PureSystem("Model") , m_Octree(octree) { } diff --git a/include/Engine/Collision/FillOctreeSystem.h b/include/Engine/Collision/FillOctreeSystem.h new file mode 100644 index 00000000..9c75878b --- /dev/null +++ b/include/Engine/Collision/FillOctreeSystem.h @@ -0,0 +1,25 @@ +#ifndef FillOctreeSystem_h__ +#define FillOctreeSystem_h__ + +#include "../Core/System.h" +#include "../Core/Octree.h" +#include "Collision.h" +#include "EntityAABB.h" + +class FillOctreeSystem : public ImpureSystem, public PureSystem +{ +public: + FillOctreeSystem(SystemParams params, Octree* octree, const std::string& fillComponentType) + : System(params) + , PureSystem(fillComponentType) + , m_Octree(octree) + { } + + virtual void Update(double dt) override; + virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) override; + +private: + Octree* m_Octree; +}; + +#endif \ No newline at end of file diff --git a/include/Engine/Collision/TriggerSystem.h b/include/Engine/Collision/TriggerSystem.h index fa322ddd..d71fad08 100644 --- a/include/Engine/Collision/TriggerSystem.h +++ b/include/Engine/Collision/TriggerSystem.h @@ -15,8 +15,8 @@ class AABB; class TriggerSystem : public PureSystem { public: - TriggerSystem(World* world, EventBroker* eventBroker, Octree* octree) - : System(world, eventBroker) + TriggerSystem(SystemParams params, Octree* octree) + : System(params) , PureSystem("Trigger") , m_Octree(octree) { diff --git a/include/Engine/Core/ComponentInfo.h b/include/Engine/Core/ComponentInfo.h index 49ed2a3f..d9799059 100644 --- a/include/Engine/Core/ComponentInfo.h +++ b/include/Engine/Core/ComponentInfo.h @@ -13,6 +13,7 @@ struct ComponentInfo unsigned int Allocation = 0; std::map FieldAnnotations; std::map> FieldEnumDefinitions; + bool NetworkReplicated = true; }; struct Field_t diff --git a/include/Engine/Core/ComponentWrapper.h b/include/Engine/Core/ComponentWrapper.h index 1dc131d2..0b9f7357 100644 --- a/include/Engine/Core/ComponentWrapper.h +++ b/include/Engine/Core/ComponentWrapper.h @@ -1,6 +1,7 @@ #ifndef ComponentWrapper_h__ #define ComponentWrapper_h__ +#include #include "../Common.h" #include "Entity.h" #include "ComponentInfo.h" @@ -43,6 +44,11 @@ struct ComponentWrapper // Specialization for string literals template void SetField(std::string name, const char(&value)[N]) { Field(name) = std::string(value); } + + void Copy(ComponentWrapper& destination) + { + memcpy(destination.Data, this->Data, Info.Stride); + } struct SubscriptProxy { @@ -76,6 +82,18 @@ struct ComponentWrapper SubscriptProxy operator[](std::string propertyName) { return SubscriptProxy(this, propertyName); } }; +// A component wrapper that "owns" its data through a shared pointer +struct SharedComponentWrapper : ComponentWrapper +{ + SharedComponentWrapper(const ComponentInfo& componentInfo, boost::shared_array data) + : ComponentWrapper(componentInfo, data.get()) + , m_DataReference(data) + { } + +private: + boost::shared_array m_DataReference; +}; + // TODO: Move this to Tests once entity importing is finished class ComponentWrapperFactory { diff --git a/include/Engine/Core/EPickupSpawned.h b/include/Engine/Core/EPickupSpawned.h new file mode 100644 index 00000000..9f85913a --- /dev/null +++ b/include/Engine/Core/EPickupSpawned.h @@ -0,0 +1,17 @@ +#ifndef EPickupSpawned_h__ +#define EPickupSpawned_h__ + +#include "Core/Event.h" +#include "Core/EntityWrapper.h" + +namespace Events +{ + +struct PickupSpawned : Event +{ + EntityWrapper Pickup; +}; + +} + +#endif \ No newline at end of file diff --git a/include/Engine/Core/EPlayerDamage.h b/include/Engine/Core/EPlayerDamage.h index a7e135ce..c11b121f 100644 --- a/include/Engine/Core/EPlayerDamage.h +++ b/include/Engine/Core/EPlayerDamage.h @@ -9,7 +9,9 @@ namespace Events struct PlayerDamage : Event { + //NOTE: this struct is missing information on what the damageSource is EntityWrapper Player; + EntityWrapper PlayerShooter; double Damage; }; diff --git a/include/Engine/Core/EPlayerDeath.h b/include/Engine/Core/EPlayerDeath.h index 00ede5ed..363745a6 100644 --- a/include/Engine/Core/EPlayerDeath.h +++ b/include/Engine/Core/EPlayerDeath.h @@ -2,7 +2,7 @@ #define EPlayerDeath_h__ #include "EventBroker.h" -#include "../Core/Entity.h" +#include "../Core/EntityWrapper.h" namespace Events { @@ -10,8 +10,7 @@ namespace Events struct PlayerDeath : Event { //KilledBy,KilledByWhat is optional for now. It might be used later in the playerlog-system - EntityID KilledBy; - EntityID PlayerID; + EntityWrapper Player; std::string KilledByWhat; }; diff --git a/include/Engine/Core/EPlayerHealthPickup.h b/include/Engine/Core/EPlayerHealthPickup.h index f3158f92..7d44e544 100644 --- a/include/Engine/Core/EPlayerHealthPickup.h +++ b/include/Engine/Core/EPlayerHealthPickup.h @@ -2,16 +2,16 @@ #define EPlayerHealthPickup_h__ #include "EventBroker.h" -#include "../Core/Entity.h" +#include "../Core/EntityWrapper.h" namespace Events { -struct PlayerHealthPickup : Event -{ - double HealthAmount; - EntityID PlayerHealedID; -}; + struct PlayerHealthPickup : Event + { + EntityWrapper Player; + double HealthAmount; + }; } diff --git a/include/Engine/Core/EntityFilePreprocessor.h b/include/Engine/Core/EntityFilePreprocessor.h index 3139169f..b46bd383 100644 --- a/include/Engine/Core/EntityFilePreprocessor.h +++ b/include/Engine/Core/EntityFilePreprocessor.h @@ -3,6 +3,8 @@ #include #include +#include +#include #include #include #include diff --git a/include/Engine/Core/EntityWrapper.h b/include/Engine/Core/EntityWrapper.h index bf34b9be..b0e65d9e 100644 --- a/include/Engine/Core/EntityWrapper.h +++ b/include/Engine/Core/EntityWrapper.h @@ -25,11 +25,12 @@ struct EntityWrapper const std::string Name(); bool HasComponent(const std::string& componentType); + void AttachComponent(const char* componentName); EntityWrapper Parent(); EntityWrapper FirstChildByName(const std::string& name); EntityWrapper FirstParentWithComponent(const std::string& componentType); bool IsChildOf(EntityWrapper potentialParent); - bool Valid(); + bool Valid() const; ComponentWrapper operator[](const char* componentName); bool operator==(const EntityWrapper& e) const; diff --git a/include/Engine/Core/EventBroker.h b/include/Engine/Core/EventBroker.h index dc1babc0..20d3b60c 100644 --- a/include/Engine/Core/EventBroker.h +++ b/include/Engine/Core/EventBroker.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "../Common.h" #include "Event.h" @@ -107,7 +108,7 @@ private: typedef std::unordered_map ContextRelays_t; ContextRelays_t m_ContextRelays; std::vector m_RelaysToSubscribe; - std::vector> m_RelaysToUnsubscribe; + std::unordered_map> m_RelaysToUnsubscribe; typedef std::list>> EventQueue_t; std::shared_ptr m_EventQueueRead; diff --git a/include/Engine/Core/Frustum.h b/include/Engine/Core/Frustum.h new file mode 100644 index 00000000..c2d83b23 --- /dev/null +++ b/include/Engine/Core/Frustum.h @@ -0,0 +1,77 @@ +#ifndef Frustum_h__ +#define Frustum_h__ + +#include "../GLM.h" +#include "AABB.h" +#include + +//A frustum defined by 6 planes. +struct Frustum +{ + //Contains points P in: dot(normal, P) + d = 0 + struct Plane + { + glm::vec3 Normal; + float Distance; + }; + + enum class Output + { + Inside, + Outside, + Intersects + }; + Plane Planes[6]; + + Frustum() = default; + Frustum(glm::mat4x4 viewProjMatrix) + { + //Order: Right, left, top, bottom, far, near. + int sign = 1; + for (int i = 0; i < 6; ++i) { + sign = -sign; + int index = i / 2; + Plane& plane = Planes[i]; + plane.Normal.x = viewProjMatrix[0].w + sign * viewProjMatrix[0][index]; + plane.Normal.y = viewProjMatrix[1].w + sign * viewProjMatrix[1][index]; + plane.Normal.z = viewProjMatrix[2].w + sign * viewProjMatrix[2][index]; + plane.Distance = viewProjMatrix[3].w + sign * viewProjMatrix[3][index]; + float divByNormalLength = 1.0f / glm::length(plane.Normal); + plane.Normal *= divByNormalLength; + plane.Distance *= divByNormalLength; + } + } + + Output VsAABB(const AABB& box) const + { + const glm::vec3& maxCorner = box.MaxCorner(); + const glm::vec3& minCorner = box.MinCorner(); + bool completelyInside = true; + for (const Plane& p : Planes) { + bool anyWasInside = false; + bool anyWasOutside = false; + //If points are on both sides of the plane, we can stop. + for (int i = 0; i < 8 && (!anyWasInside || !anyWasOutside); ++i) { + std::bitset<3> bits(i); + glm::vec3 corner; + 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; + if (glm::dot(p.Normal, corner) > -p.Distance) { + anyWasInside = true; + } else { + anyWasOutside = true; + } + } + if (!anyWasInside) { + return Output::Outside; + } + if (anyWasOutside) { + completelyInside = false; + } + } + return completelyInside ? Output::Inside : Output::Intersects; + } +}; + +#endif \ No newline at end of file diff --git a/include/Engine/Core/MemoryPool.h b/include/Engine/Core/MemoryPool.h index 3a1cc069..f4073294 100644 --- a/include/Engine/Core/MemoryPool.h +++ b/include/Engine/Core/MemoryPool.h @@ -102,7 +102,7 @@ public: m_ExtraMemory.push_back((char*)malloc(m_Stride)); //We should preferably not enter here to avoid performance issues. Set more numMaxElements in constructor instead. if (!DisableMemoryPool::Value) { - LOG_WARNING("Allocated slots exceed Pool size, extra memory allocated dynamically. Pool size: %u, dynamic size: %u.", m_NumSlots, m_ExtraMemory.size()); + LOG_DEBUG("Allocated slots exceed Pool size, extra memory allocated dynamically. Pool size: %u, dynamic size: %u.", m_NumSlots, m_ExtraMemory.size()); } return m_ExtraMemory.back(); } diff --git a/include/Engine/Core/Octree.h b/include/Engine/Core/Octree.h index 8bac5503..3f03a77c 100644 --- a/include/Engine/Core/Octree.h +++ b/include/Engine/Core/Octree.h @@ -5,9 +5,8 @@ #include "../Common.h" #include "AABB.h" - -//Fwd declarations. -class Ray; +#include "Frustum.h" +#include "Ray.h" namespace OctSpace { @@ -40,6 +39,10 @@ public: //The type Box must be AABB, or inherit from AABB. template void ObjectsInSameRegion(const Box& box, std::vector& outObjects); + //Get the objects that are inside the frustum, the objects are put in outObjects. + void ObjectsInFrustum(const Frustum& frustum, std::vector& outObjects); + //Get objects, which AABB the input ray intersects, the objects are put in outObjects. + void ObjectsPossiblyHitByRay(const Ray& ray, std::vector& outObjects); //Empty the tree of all objects, static and dynamic. void ClearObjects(); //Empty the tree of all dynamic objects. Static objects remain in the tree. @@ -97,6 +100,10 @@ struct Child void AddStaticObject(const AABB& box); template void ObjectsInSameRegion(const Box& box, std::vector& outObjects) const; + template + void ObjectsInFrustum(const Frustum& frustum, std::vector& outObjects, bool takeAllDontTest) const; + template + void ObjectsPossiblyHitByRay(const Ray& ray, std::vector& outObjects) const; void ClearObjects(); void ClearDynamicObjects(); bool RayCollides(const Ray& ray, Output& data) const; @@ -111,11 +118,20 @@ struct Child std::vector& m_StaticObjectsRef; std::vector& m_DynamicObjectsRef; - bool hasChildren() const; + inline bool hasChildren() const { return m_Children[0] != nullptr; } int childIndexContainingPoint(const glm::vec3& point) const; std::vector childIndicesContainingBox(const AABB& box) const; }; +//To be able to sort child nodes and contained objects based on distance to ray origin. +struct RaySorterInfo +{ + int Index; + float Distance; +}; + +bool isFirstLower(const RaySorterInfo& first, const RaySorterInfo& second); + } template @@ -154,6 +170,20 @@ void Octree::ObjectsInSameRegion(const Box& box, std::vector& outObjects) m_Root->ObjectsInSameRegion(box, outObjects); } +template +void Octree::ObjectsInFrustum(const Frustum& frustum, std::vector& outObjects) +{ + falsifyObjectChecks(); + m_Root->ObjectsInFrustum(frustum, outObjects, false); +} + +template +void Octree::ObjectsPossiblyHitByRay(const Ray& ray, std::vector& outObjects) +{ + falsifyObjectChecks(); + m_Root->ObjectsPossiblyHitByRay(ray, outObjects); +} + template void Octree::ClearObjects() { @@ -230,4 +260,101 @@ void OctSpace::Child::ObjectsInSameRegion(const Box& box, std::vector& outObj } } +template +void OctSpace::Child::ObjectsInFrustum(const Frustum& frustum, std::vector& outObjects, bool takeAllDontTest) const +{ + if (hasChildren()) { + for (const Child* c : m_Children) { + Frustum::Output out = Frustum::Output::Inside; + if (!takeAllDontTest) { + out = frustum.VsAABB(c->m_Box); + if (out == Frustum::Output::Outside) { + continue; + } + } + c->ObjectsInFrustum(frustum, outObjects, out == Frustum::Output::Inside); + } + } else { + size_t startIndex = outObjects.size(); + int numDuplicates = 0; + outObjects.resize(outObjects.size() + m_StaticObjIndices.size() + m_DynamicObjIndices.size()); + for (size_t i = 0; i < m_StaticObjIndices.size(); ++i) { + ContainedObject& obj = m_StaticObjectsRef[m_StaticObjIndices[i]]; + if (obj.Checked || frustum.VsAABB(*obj.Box) == Frustum::Output::Outside) { + ++numDuplicates; + } else { + obj.Checked = true; + outObjects[startIndex + i - numDuplicates] = *static_cast(obj.Box.get()); + } + } + for (size_t i = 0; i < m_DynamicObjIndices.size(); ++i) { + ContainedObject& obj = m_DynamicObjectsRef[m_DynamicObjIndices[i]]; + if (obj.Checked || frustum.VsAABB(*obj.Box) == Frustum::Output::Outside) { + ++numDuplicates; + } else { + obj.Checked = true; + outObjects[startIndex + i - numDuplicates] = *static_cast(obj.Box.get()); + } + } + for (size_t i = 0; i < numDuplicates; ++i) { + outObjects.pop_back(); + } + } +} + +template +void OctSpace::Child::ObjectsPossiblyHitByRay(const Ray& ray, std::vector& outObjects) const +{ + //If the node AABB is missed, everything it contains is missed. + if (Collision::RayAABBIntr(ray, m_Box)) { + //If the ray shoots the tree, and it is a parent. + if (hasChildren()) { + //Sort children according to their distance from the ray origin. + std::vector childInfos; + childInfos.resize(8); + for (int i = 0; i < 8; ++i) { + childInfos[i] = { i, glm::distance(ray.Origin(), m_Children[i]->m_Box.Origin()) }; + } + std::sort(childInfos.begin(), childInfos.end(), isFirstLower); + //Loop through the children, starting with the one closest to the ray origin. I.e the first to be hit. + for (const RaySorterInfo& info : childInfos) { + m_Children[info.Index]->ObjectsPossiblyHitByRay(ray, outObjects); + } + } else { + //Check against boxes in the node. + bool intersected = false; + float dist; + //Sort all contained objects according to the distance from the ray origin to + //the intersection, if they are intersecting. + std::vector objectHitInfos; + objectHitInfos.reserve(m_StaticObjIndices.size() + m_DynamicObjIndices.size()); + for (int i : m_StaticObjIndices) { + //If we haven't tested against this object before, and the ray hits. + if (!m_StaticObjectsRef[i].Checked && + Collision::RayVsAABB(ray, *m_StaticObjectsRef[i].Box, dist)) { + objectHitInfos.push_back({ i, dist }); + } + m_StaticObjectsRef[i].Checked = true; + } + for (int i : m_DynamicObjIndices) { + //If we haven't tested against this object before, and the ray hits. + if (!m_DynamicObjectsRef[i].Checked && + Collision::RayVsAABB(ray, *m_DynamicObjectsRef[i].Box, dist)) { + objectHitInfos.push_back({ i + (int)m_StaticObjIndices.size(), dist }); + } + m_DynamicObjectsRef[i].Checked = true; + } + std::sort(objectHitInfos.begin(), objectHitInfos.end(), isFirstLower); + int startSize = (int)outObjects.size(); + outObjects.resize(startSize + objectHitInfos.size()); + for (int i = 0; i < objectHitInfos.size(); ++i) { + outObjects[startSize + i] = (objectHitInfos[i].Index < m_StaticObjIndices.size()) ? + *static_cast(m_StaticObjectsRef[objectHitInfos[i].Index].Box.get()) : + *static_cast(m_DynamicObjectsRef[objectHitInfos[i].Index - m_StaticObjIndices.size()].Box.get()); + } + } + } +} + + #endif \ No newline at end of file diff --git a/include/Engine/Core/Ray.h b/include/Engine/Core/Ray.h index a234a488..03bfa391 100644 --- a/include/Engine/Core/Ray.h +++ b/include/Engine/Core/Ray.h @@ -7,6 +7,10 @@ class Ray { public: + Ray() + : m_Origin(glm::vec3(0.f)) + , m_Direction(glm::vec3(0, 0, 1)) + {} Ray(const glm::vec3& origin, const glm::vec3& dir) : m_Origin(origin) , m_Direction(glm::normalize(dir)) diff --git a/include/Engine/Core/ResourceManager.h b/include/Engine/Core/ResourceManager.h index 10529819..b994b5cf 100644 --- a/include/Engine/Core/ResourceManager.h +++ b/include/Engine/Core/ResourceManager.h @@ -200,13 +200,16 @@ static T* ResourceManager::Load(const std::string& resourceName, Resource* paren } //If resource has already been cached and completely loaded. - it = m_ResourceCache.find(cacheKey); - if (it != m_ResourceCache.end()) { - if (it->second != nullptr) { - return static_cast(it->second); - } else { - //Don't return null on failure, exception instead. - throw Resource::FailedLoadingException(); + { + boost::lock_guard guard(m_Mutex); + it = m_ResourceCache.find(cacheKey); + if (it != m_ResourceCache.end()) { + if (it->second != nullptr) { + return static_cast(it->second); + } else { + //Don't return null on failure, exception instead. + throw Resource::FailedLoadingException(); + } } } diff --git a/include/Engine/Core/System.h b/include/Engine/Core/System.h index ec57f5fc..1a387855 100644 --- a/include/Engine/Core/System.h +++ b/include/Engine/Core/System.h @@ -5,21 +5,55 @@ #include "World.h" #include "EntityWrapper.h" #include "ComponentWrapper.h" +#include "EPlayerSpawned.h" + +struct SystemParams +{ + SystemParams(::World* World, ::EventBroker* EventBroker, bool IsClient, bool IsServer) + : World(World) + , EventBroker(EventBroker) + , IsClient(IsClient) + , IsServer(IsServer) + { } + + ::World* World; + ::EventBroker* EventBroker; + bool IsClient = false; + bool IsServer = false; +}; class System { friend class SystemPipeline; protected: - System(World* world, EventBroker) { } - System(World* world, EventBroker* eventBroker) - : m_World(world) - , m_EventBroker(eventBroker) - { } + System(SystemParams params) + : m_World(params.World) + , m_EventBroker(params.EventBroker) + , IsClient(params.IsClient) + , IsServer(params.IsServer) + { + if (IsClient) { + EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &System::setLocalPlayer); + } + } virtual ~System() = default; World* m_World; EventBroker* m_EventBroker; + bool IsClient = false; + bool IsServer = false; + EntityWrapper LocalPlayer = EntityWrapper::Invalid; + +private: + EventRelay m_EPlayerSpawned; + virtual bool setLocalPlayer(Events::PlayerSpawned& e) + { + if (e.PlayerID == -1) { + LocalPlayer = e.Player; + } + return true; + } }; class PureSystem : public virtual System @@ -34,7 +68,7 @@ protected: const std::string m_ComponentType; - virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cComponent, double dt) = 0; + virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cPlayer, double dt) = 0; }; class ImpureSystem : public virtual System diff --git a/include/Engine/Core/SystemPipeline.h b/include/Engine/Core/SystemPipeline.h index 90303f12..5f7aee0b 100644 --- a/include/Engine/Core/SystemPipeline.h +++ b/include/Engine/Core/SystemPipeline.h @@ -10,9 +10,11 @@ class SystemPipeline { public: - SystemPipeline(World* world, EventBroker* eventBroker) + SystemPipeline(World* world, EventBroker* eventBroker, bool isClient, bool isServer) : m_World(world) , m_EventBroker(eventBroker) + , m_IsClient(isClient) + , m_IsServer(isServer) { EVENT_SUBSCRIBE_MEMBER(m_EPause, &SystemPipeline::OnPause); EVENT_SUBSCRIBE_MEMBER(m_EResume, &SystemPipeline::OnResume); @@ -35,7 +37,7 @@ public: m_OrderedSystemGroups.resize(updateOrderLevel + 1); } UnorderedSystems& group = m_OrderedSystemGroups[updateOrderLevel]; - System* system = new T(m_World, m_EventBroker, args...); + System* system = new T(SystemParams(m_World, m_EventBroker, m_IsClient, m_IsServer), args...); group.Systems[typeid(T).name()] = system; PureSystem* pureSystem = dynamic_cast(system); @@ -59,6 +61,9 @@ public: dt = 0.0; } + // Process utility events for the System base class + m_EventBroker->Process(); + for (UnorderedSystems& group : m_OrderedSystemGroups) { // Process events for (auto& pair : group.Systems) { @@ -88,6 +93,8 @@ public: private: World* m_World; EventBroker* m_EventBroker; + bool m_IsClient = false; + bool m_IsServer = false; bool m_Paused = false; struct UnorderedSystems diff --git a/include/Engine/Core/Transform.h b/include/Engine/Core/Transform.h index 2f549140..bd381e8b 100644 --- a/include/Engine/Core/Transform.h +++ b/include/Engine/Core/Transform.h @@ -18,6 +18,7 @@ glm::vec3 AbsoluteScale(EntityWrapper entity); glm::vec3 AbsoluteScale(World* world, EntityID entity); glm::mat4 ModelMatrix(EntityWrapper entity); glm::mat4 ModelMatrix(EntityID entity, World* world); +glm::vec3 TransformPoint(const glm::vec3& point, const glm::mat4& matrix); } diff --git a/include/Engine/Core/UniformScaleSystem.h b/include/Engine/Core/UniformScaleSystem.h index 0ebc0672..cd679fed 100644 --- a/include/Engine/Core/UniformScaleSystem.h +++ b/include/Engine/Core/UniformScaleSystem.h @@ -8,7 +8,7 @@ class UniformScaleSystem : public PureSystem { public: - UniformScaleSystem(World* world, EventBroker* eventBroker); + UniformScaleSystem(SystemParams params); virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cUniformScale, double dt) override; diff --git a/include/Engine/Core/Util/IfDebug.h b/include/Engine/Core/Util/IfDebug.h index 79cb3a4c..85b64c8d 100644 --- a/include/Engine/Core/Util/IfDebug.h +++ b/include/Engine/Core/Util/IfDebug.h @@ -4,7 +4,7 @@ // } // NOTE: condition statement is not executed at all in release mode. #ifndef DEBUG_IF -#ifndef DEBUG +#ifdef DEBUG #define DEBUG_IF(c) if(c) #else #define DEBUG_IF(c) if(false) diff --git a/include/Engine/Editor/EditorRenderSystem.h b/include/Engine/Editor/EditorRenderSystem.h index 361669ba..a42ad779 100644 --- a/include/Engine/Editor/EditorRenderSystem.h +++ b/include/Engine/Editor/EditorRenderSystem.h @@ -10,7 +10,7 @@ class EditorRenderSystem : public ImpureSystem { public: - EditorRenderSystem(World* world, EventBroker* eventBroker, IRenderer* renderer, RenderFrame* renderFrame); + EditorRenderSystem(SystemParams params, IRenderer* renderer, RenderFrame* renderFrame); virtual void Update(double dt) override; diff --git a/include/Engine/Editor/EditorSystem.h b/include/Engine/Editor/EditorSystem.h index accf66e4..fcaa2e47 100644 --- a/include/Engine/Editor/EditorSystem.h +++ b/include/Engine/Editor/EditorSystem.h @@ -17,7 +17,7 @@ class EditorSystem : public ImpureSystem { public: - EditorSystem(World* world, EventBroker* eventBroker, IRenderer* renderer, RenderFrame* renderFrame); + EditorSystem(SystemParams params, IRenderer* renderer, RenderFrame* renderFrame); ~EditorSystem(); void Update(double dt); diff --git a/include/Engine/Editor/EditorWidgetSystem.h b/include/Engine/Editor/EditorWidgetSystem.h index a060bdd5..57e653d6 100644 --- a/include/Engine/Editor/EditorWidgetSystem.h +++ b/include/Engine/Editor/EditorWidgetSystem.h @@ -25,7 +25,7 @@ struct WidgetDelta : Event class EditorWidgetSystem : public ImpureSystem, PureSystem { public: - EditorWidgetSystem(World* world, EventBroker* eventBroker, IRenderer* renderer); + EditorWidgetSystem(SystemParams params, IRenderer* renderer); virtual void Update(double dt) override; virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cEditorWidget, double dt) override; diff --git a/include/Engine/GUI/TextureFrame.h b/include/Engine/GUI/TextureFrame.h index 2c6d34dd..77967b4d 100644 --- a/include/Engine/GUI/TextureFrame.h +++ b/include/Engine/GUI/TextureFrame.h @@ -3,6 +3,7 @@ #include "Frame.h" #include "../Rendering/Texture.h" +#include "../Rendering/Util/CommonFunctions.h" namespace GUI { @@ -55,10 +56,10 @@ public: return; } - m_Texture = ResourceManager::Load(resourceName); + m_Texture = CommonFunctions::LoadTexture(resourceName, false); m_TextureName = resourceName; if (m_Texture == nullptr) { - m_Texture = ResourceManager::Load("Textures/Core/ErrorTexture.png"); + m_Texture = CommonFunctions::LoadTexture("Textures/Core/ErrorTexture.png", false); } SizeToTexture(); diff --git a/include/Engine/Input/FirstPersonInputController.h b/include/Engine/Input/FirstPersonInputController.h index 2bbd768d..5529185a 100644 --- a/include/Engine/Input/FirstPersonInputController.h +++ b/include/Engine/Input/FirstPersonInputController.h @@ -4,6 +4,7 @@ #include "../GLM.h" #include "../Core/InputController.h" #include "../Core/ELockMouse.h" +#include "../Game/Events/EDashAbility.h" #include "InputHandler.h" template @@ -54,6 +55,7 @@ protected: //specialabilitys bool m_MovementKeyDown = false; bool m_SpecialAbilityKeyDown = false; + int m_NumberOfMovementKeysDown = 0; EventRelay m_ELockMouse; bool OnLockMouse(const Events::LockMouse& e); @@ -131,6 +133,7 @@ bool FirstPersonInputController::OnCommand(const Events::InputComm } //if value = 0 then you have just released this key if (e.Value != 0) { + m_NumberOfMovementKeysDown++; m_MovementKeyDown = true; //if you pressed the same key within m_AssaultDashDoubleTapSensitivityTimer then you have doubletapped it if (m_AssaultDashDoubleTapDeltaTime < m_AssaultDashDoubleTapSensitivityTimer && m_AssaultDashTapDirection == m_CurrentDirectionVector) { @@ -138,10 +141,14 @@ bool FirstPersonInputController::OnCommand(const Events::InputComm } } else { //== 0 - m_MovementKeyDown = false; - //you have just released the key, store what key it was and reset the doubletap-sensitivity-timer - m_AssaultDashTapDirection = m_CurrentDirectionVector; - m_AssaultDashDoubleTapDeltaTime = 0.f; + m_NumberOfMovementKeysDown--; + if (m_NumberOfMovementKeysDown == 0) { + m_MovementKeyDown = false; + } + //you have just released the key, store what key it was and reset the doubletap-sensitivity-timer + m_AssaultDashTapDirection = m_CurrentDirectionVector; + m_AssaultDashDoubleTapDeltaTime = 0.f; + } } @@ -201,12 +208,6 @@ void FirstPersonInputController::AssaultDashCheck(double dt, bool m_AssaultDashCoolDownTimer = assaultDashCoolDownMaxTimer; m_AssaultDashDoubleTapped = true; m_AssaultDashDoubleTapDeltaTime = 0.f; - //moving to the side has priority - return; - } - - //dashing with doubletap - check if doubletap to dash enabled - if (ResourceManager::Load("Input.ini")->Get("Keyboard.DoubleTapToDash", false)) { return; } @@ -215,6 +216,11 @@ void FirstPersonInputController::AssaultDashCheck(double dt, bool m_AssaultDashDoubleTapped = false; } + //dashing with doubletap - check if doubletap to dash enabled + if (!ResourceManager::Load("Input.ini")->Get("Keyboard.DoubleTapToDash", false)) { + return; + } + //check if we have received a valid doubletap if (!m_ValidDoubleTap) { return; @@ -230,6 +236,9 @@ void FirstPersonInputController::AssaultDashCheck(double dt, bool m_AssaultDashDoubleTapped = true; m_AssaultDashDoubleTapDeltaTime = 0.f; m_AssaultDashCoolDownTimer = assaultDashCoolDownMaxTimer; + + Events::DashAbility e; + m_EventBroker->Publish(e); } #endif \ No newline at end of file diff --git a/include/Engine/Network/Client.h b/include/Engine/Network/Client.h index 7d1d5bba..fb367874 100644 --- a/include/Engine/Network/Client.h +++ b/include/Engine/Network/Client.h @@ -20,16 +20,22 @@ #include "Input/EInputCommand.h" #include "Core/EPlayerDamage.h" #include "Network/EInterpolate.h" +#include "Network/SnapshotFilter.h" #include "Core/EPlayerSpawned.h" class Client : public Network { public: - Client(ConfigFile* config); + Client(World* world, EventBroker* eventBroker); + Client(World* world, EventBroker* eventBroker, std::unique_ptr snapshotFilter); ~Client(); - void Start(World* world, EventBroker* eventBroker) override; + + void Connect(std::string address, int port); void Update() override; + private: + std::unique_ptr m_SnapshotFilter = nullptr; + // Assio UDP logic boost::asio::ip::udp::endpoint m_ReceiverEndpoint; boost::asio::io_service m_IOService; @@ -45,10 +51,8 @@ private: PacketID m_SendPacketID = 0; // Game logic - World* m_World; std::string m_PlayerName; PlayerID m_PlayerID = -1; - EntityID m_ServerEntityID = std::numeric_limits::max(); bool m_IsConnected = false; EntityWrapper m_LocalPlayer = EntityWrapper::Invalid; // Server Client Lookup map @@ -74,7 +78,9 @@ private: void connect(); void disconnect(); void parseMessageType(Packet& packet); - void updateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID, const std::string& componentType); + void updateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID); + SharedComponentWrapper createSharedComponent(Packet& packet, EntityID entityID, const ComponentInfo& componentInfo); + void ignoreFields(Packet& packet, const ComponentInfo& componentInfo); void parseConnect(Packet& packet); void parsePlayerConnected(Packet& packet); void parsePing(); @@ -99,7 +105,6 @@ private: void deleteFromServerClientMaps(EntityID serverEntityID, EntityID clientEntityID); // Events - EventBroker* m_EventBroker; EventRelay m_EInputCommand; bool OnInputCommand(const Events::InputCommand& e); EventRelay m_EPlayerDamage; diff --git a/include/Engine/Network/EInterpolate.h b/include/Engine/Network/EInterpolate.h index 93bf1a5c..79af840d 100644 --- a/include/Engine/Network/EInterpolate.h +++ b/include/Engine/Network/EInterpolate.h @@ -11,8 +11,13 @@ namespace Events struct Interpolate : Event { - EntityID Entity; - boost::shared_array DataArray; + Interpolate(EntityWrapper Entity, SharedComponentWrapper Component) + : Entity(Entity) + , Component(Component) + { } + + EntityWrapper Entity; + SharedComponentWrapper Component; }; } diff --git a/include/Engine/Network/Network.h b/include/Engine/Network/Network.h index 874e3377..0dbc4915 100644 --- a/include/Engine/Network/Network.h +++ b/include/Engine/Network/Network.h @@ -19,10 +19,15 @@ typedef unsigned int PacketID; class Network { public: + Network(World* world, EventBroker* eventBroker); virtual ~Network() { }; - virtual void Start(World* m_world, EventBroker *eventBroker) = 0; + virtual void Update() = 0; + protected: + World* m_World; + EventBroker* m_EventBroker; + // For Debug bool isReadingData = false; NetworkData m_NetworkData; @@ -32,7 +37,6 @@ protected: double m_TimeoutMs; void saveToFile(); void updateNetworkData(); - void initialize(); }; #endif \ No newline at end of file diff --git a/include/Engine/Network/Server.h b/include/Engine/Network/Server.h index 90b9e922..f16c6c16 100644 --- a/include/Engine/Network/Server.h +++ b/include/Engine/Network/Server.h @@ -22,15 +22,17 @@ class Server : public Network { public: - Server(); + Server(World* world, EventBroker* eventBroker, int port); ~Server(); - void Start(World* m_world, EventBroker *eventBroker) override; + void Update() override; + private: + int m_Port = 27666; // UDP logic boost::asio::ip::udp::endpoint m_ReceiverEndpoint; boost::asio::io_service m_IOService; - boost::asio::ip::udp::socket m_Socket; + std::unique_ptr m_Socket; // Sending messages to client logic std::map m_ConnectedPlayers; @@ -46,13 +48,10 @@ private: float snapshotInterval; int checkTimeOutInterval = 100; int m_NextPlayerID = 0; + std::vector m_InputCommandsToBroadcast; //Timers std::clock_t m_StartPingTime; - - // Game logic - World* m_World; - EventBroker* m_EventBroker; // Packet loss logic PacketID m_PacketID = 0; @@ -66,6 +65,7 @@ private: void broadcast(Packet& packet); void sendSnapshot(); void addChildrenToPacket(Packet& packet, EntityID entityID); + void addInputCommandsToPacket(Packet& packet); void sendPing(); void checkForTimeOuts(); void disconnect(PlayerID playerID); diff --git a/include/Engine/Network/SnapshotFilter.h b/include/Engine/Network/SnapshotFilter.h new file mode 100644 index 00000000..4e63c4b1 --- /dev/null +++ b/include/Engine/Network/SnapshotFilter.h @@ -0,0 +1,19 @@ +#ifndef SnapshotFilter_h__ +#define SnapshotFilter_h__ + +#include "../Core/EntityWrapper.h" +#include "../Core/ComponentWrapper.h" + +class SnapshotFilter +{ +public: + // Filters an incoming snapshot. + // Modify the component and return true if the component snapshot should be applied. + // Otherwise return false and it will be ignored. + virtual bool FilterComponent(EntityWrapper entity, SharedComponentWrapper& component) + { + return true; + } +}; + +#endif \ No newline at end of file diff --git a/include/Engine/Rendering/AnimationSystem.h b/include/Engine/Rendering/AnimationSystem.h index fcdcbc92..dbe4b3fc 100644 --- a/include/Engine/Rendering/AnimationSystem.h +++ b/include/Engine/Rendering/AnimationSystem.h @@ -9,12 +9,13 @@ #include "Rendering/Model.h" #include "Rendering/EAnimationComplete.h" #include "Rendering/Skeleton.h" +#include class AnimationSystem : public PureSystem { public: - AnimationSystem(World* world, EventBroker* eventBroker) - : System(world, eventBroker) + AnimationSystem(SystemParams params) + : System(params) , PureSystem("Animation") { @@ -23,7 +24,6 @@ public: virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& animationComponent, double dt) override; private: - }; #endif \ No newline at end of file diff --git a/include/Engine/Rendering/BoneAttachmentSystem.h b/include/Engine/Rendering/BoneAttachmentSystem.h new file mode 100644 index 00000000..55c2a1c8 --- /dev/null +++ b/include/Engine/Rendering/BoneAttachmentSystem.h @@ -0,0 +1,29 @@ +#ifndef BoneAttachmentSystem_h__ +#define BoneAttachmentSystem_h__ + +#include "GLM.h" + +#include "Common.h" +#include "Core/System.h" +#include "Core/ResourceManager.h" +#include "Rendering/Model.h" +#include "Rendering/Skeleton.h" + +//Needs to be a higher orderlevel than AnimationSystem +class BoneAttachmentSystem : public PureSystem +{ +public: + BoneAttachmentSystem(SystemParams params) + : System(params) + , PureSystem("BoneAttachment") + { + + } + ~BoneAttachmentSystem() { } + virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& BoneAttachmentComponent, double dt) override; +private: + + +}; + +#endif \ No newline at end of file diff --git a/include/Engine/Rendering/Camera.h b/include/Engine/Rendering/Camera.h index 29dd4626..6130fd01 100644 --- a/include/Engine/Rendering/Camera.h +++ b/include/Engine/Rendering/Camera.h @@ -33,6 +33,8 @@ public: glm::mat4 ViewMatrix() const { return m_ViewMatrix; } void SetViewMatrix(glm::mat4 val); + glm::mat4 BillboardMatrix(); + float AspectRatio() const { return m_AspectRatio; } void SetAspectRatio(float val); diff --git a/include/Engine/Rendering/DrawColorCorrectionPass.h b/include/Engine/Rendering/DrawColorCorrectionPass.h index e9a7e281..231e2d33 100644 --- a/include/Engine/Rendering/DrawColorCorrectionPass.h +++ b/include/Engine/Rendering/DrawColorCorrectionPass.h @@ -7,6 +7,7 @@ #include "ShaderProgram.h" //#include "Util/UnorderedMapVec2.h" #include "Texture.h" +#include "imgui/imgui.h" class DrawColorCorrectionPass { @@ -16,14 +17,13 @@ public: void InitializeFrameBuffers(); void InitializeShaderPrograms(); - void Draw(GLuint sceneTexture, GLuint bloomTexture); + void Draw(GLuint sceneTexture, GLuint bloomTexture, GLuint sceneTextureLowRes, GLuint bloomTextureLowRes, GLfloat gamma, GLfloat exposure); private: const IRenderer* m_Renderer; ShaderProgram* m_ColorCorrectionProgram; Model* m_ScreenQuad; - GLfloat m_Exposure; }; #endif \ No newline at end of file diff --git a/include/Engine/Rendering/DrawFinalPass.h b/include/Engine/Rendering/DrawFinalPass.h index 74f505fe..bf8d4d76 100644 --- a/include/Engine/Rendering/DrawFinalPass.h +++ b/include/Engine/Rendering/DrawFinalPass.h @@ -7,6 +7,7 @@ #include "FrameBuffer.h" #include "ShaderProgram.h" #include "Util/UnorderedMapVec2.h" +#include "Util/CommonFunctions.h" #include "Texture.h" class DrawFinalPass @@ -22,37 +23,67 @@ public: //Return the texture that is used in later stages to apply the bloom effect GLuint BloomTexture() const { return m_BloomTexture; } + GLuint BloomTextureLowRes() const { return m_BloomTextureLowRes; } //Return the texture with diffuse and lighting of the scene. GLuint SceneTexture() const { return m_SceneTexture; } + GLuint SceneTextureLowRes() const { return m_SceneTextureLowRes; } + //Return the framebuffer used in the scene rendering stage. FrameBuffer* FinalPassFrameBuffer() { return &m_FinalPassFrameBuffer; } + FrameBuffer* FinalPassFrameBufferLowRes() { return &m_FinalPassFrameBufferLowRes; } private: void GenerateTexture(GLuint* texture, GLenum wrapping, GLenum filtering, glm::vec2 dimensions, GLint internalFormat, GLint format, GLenum type) const; void GenerateMipMapTexture(GLuint* texture, GLenum wrapping, glm::vec2 dimensions, GLint format, GLenum type, GLint numMipMaps) const; - void DrawModelRenderQueues(std::list>& job, RenderScene& scene); + + void DrawSprites(std::list>&jobs, RenderScene& scene); + void DrawModelRenderQueues(std::list>& jobs, RenderScene& scene); + void DrawShieldToStencilBuffer(std::list>& jobs, RenderScene& scene); + void DrawShieldedModelRenderQueue(std::list>& jobs, RenderScene& scene); + void DrawToDepthBuffer(std::list>& jobs, RenderScene& scene); void BindExplosionUniforms(GLuint shaderHandle, std::shared_ptr& job, RenderScene& scene); void BindModelUniforms(GLuint shaderHandle, std::shared_ptr& job, RenderScene& scene); - void BindExplosionTextures(std::shared_ptr& job); - void BindModelTextures(std::shared_ptr& job); + void BindExplosionTextures(GLuint shaderHandle, std::shared_ptr& job); + void BindModelTextures(GLuint shaderHandle, std::shared_ptr& job); Texture* m_WhiteTexture; Texture* m_BlackTexture; Texture* m_NeutralNormalTexture; Texture* m_GreyTexture; + Texture* m_ErrorTexture; FrameBuffer m_FinalPassFrameBuffer; + FrameBuffer m_FinalPassFrameBufferLowRes; GLuint m_BloomTexture; GLuint m_SceneTexture; + GLuint m_BloomTextureLowRes; + GLuint m_SceneTextureLowRes; GLuint m_DepthBuffer; + GLuint m_DepthBufferLowRes; + + //maqke this component based i guess? + GLuint m_ShieldPixelRate = 16; const IRenderer* m_Renderer; const LightCullingPass* m_LightCullingPass; ShaderProgram* m_ForwardPlusProgram; ShaderProgram* m_ExplosionEffectProgram; + ShaderProgram* m_ExplosionEffectSplatMapProgram; + ShaderProgram* m_SpriteProgram; + ShaderProgram* m_ForwardPlusSplatMapProgram; + ShaderProgram* m_ShieldToStencilProgram; + ShaderProgram* m_FillDepthBufferProgram; + + + ShaderProgram* m_ForwardPlusSkinnedProgram; + ShaderProgram* m_ExplosionEffectSkinnedProgram; + ShaderProgram* m_ExplosionEffectSplatMapSkinnedProgram; + ShaderProgram* m_ForwardPlusSplatMapSkinnedProgram; + ShaderProgram* m_ShieldToStencilSkinnedProgram; + ShaderProgram* m_FillDepthBufferSkinnedProgram; }; #endif \ No newline at end of file diff --git a/include/Engine/Rendering/DrawFinalPassState.h b/include/Engine/Rendering/DrawFinalPassState.h index 10b840e9..91fc4cf4 100644 --- a/include/Engine/Rendering/DrawFinalPassState.h +++ b/include/Engine/Rendering/DrawFinalPassState.h @@ -12,4 +12,11 @@ private: }; +class DrawStencilState : public RenderState +{ +public: + DrawStencilState(GLuint frameBuffer); + ~DrawStencilState(); +}; + #endif \ No newline at end of file diff --git a/include/Engine/Rendering/ExplosionEffectJob.h b/include/Engine/Rendering/ExplosionEffectJob.h index 89b1342b..8f339526 100644 --- a/include/Engine/Rendering/ExplosionEffectJob.h +++ b/include/Engine/Rendering/ExplosionEffectJob.h @@ -15,7 +15,7 @@ struct ExplosionEffectJob : ModelJob { - ExplosionEffectJob(ComponentWrapper explosionEffectComponent, ::Model* model, Camera* camera, glm::mat4 matrix, ::RawModel::MaterialGroup matGroup, ComponentWrapper modelComponent, ::World* world, glm::vec4 fillColor, float fillPercentage) + ExplosionEffectJob(ComponentWrapper explosionEffectComponent, ::Model* model, Camera* camera, glm::mat4 matrix, ::RawModel::MaterialProperties matGroup, ComponentWrapper modelComponent, ::World* world, glm::vec4 fillColor, float fillPercentage) : ModelJob(model, camera, matrix, matGroup, modelComponent, world, fillColor, fillPercentage) { ExplosionOrigin = (glm::vec3)explosionEffectComponent["ExplosionOrigin"]; diff --git a/include/Engine/Rendering/IRenderer.h b/include/Engine/Rendering/IRenderer.h index b399aefa..4441bb7d 100644 --- a/include/Engine/Rendering/IRenderer.h +++ b/include/Engine/Rendering/IRenderer.h @@ -32,6 +32,8 @@ public: virtual void SetFullscreen(bool fullscreen) { m_Fullscreen = fullscreen; } bool VSYNC() const { return m_VSYNC; } virtual void SetVSYNC(bool vsync) { m_VSYNC = vsync; } + std::string WindowTitle() const { return m_WindowTitle; } + virtual void SetWindowTitle(const std::string& title) { glfwSetWindowTitle(m_Window, title.c_str()); m_WindowTitle = title; } //Returns screen size excluding window border and header Rectangle GetViewportSize() const { return m_ViewportSize; } virtual void Initialize() = 0; @@ -47,6 +49,7 @@ protected: int m_GLVersion[2]; std::string m_GLVendor; GLFWwindow* m_Window = nullptr; + std::string m_WindowTitle; }; #endif // Renderer_h__ diff --git a/include/Engine/Rendering/Model.h b/include/Engine/Rendering/Model.h index f751a8cc..4c63b922 100644 --- a/include/Engine/Rendering/Model.h +++ b/include/Engine/Rendering/Model.h @@ -2,8 +2,10 @@ #define Model_h__ #include "Rendering/RawModelCustom.h" +#include "Util/CommonFunctions.h" //#include "Rendering/RawModelAssimp.h" #include "../OpenGL.h" +#include "Core/AABB.h" class Model : public ThreadUnsafeResource { @@ -14,16 +16,19 @@ private: public: ~Model(); - const std::vector& MaterialGroups() const { return m_RawModel->MaterialGroups; } + const std::vector& MaterialGroups() const { return m_RawModel->m_Materials; } const glm::mat4& Matrix() const { return m_RawModel->m_Matrix; } - const std::vector& Vertices() const { return m_RawModel->m_Vertices; } - + const RawModel::Vertex* Vertices() const { return m_RawModel->Vertices(); } + unsigned int NumberOfVertices() const { return m_RawModel->NumVertices(); } + const AABB& Box() const { return m_Box; } + bool IsSkinned() const { return m_RawModel->IsSkinned(); } GLuint VAO; GLuint ElementBuffer; RawModel* m_RawModel; private: - + AABB m_Box; + GLuint VertexBuffer; GLuint NormalBuffer; GLuint TangentNormalsBuffer; diff --git a/include/Engine/Rendering/ModelJob.h b/include/Engine/Rendering/ModelJob.h index 2cb2169c..4bb1b51f 100644 --- a/include/Engine/Rendering/ModelJob.h +++ b/include/Engine/Rendering/ModelJob.h @@ -14,39 +14,98 @@ #include "../Core/World.h" #include "../Core/Transform.h" #include "Skeleton.h" +#include "ShaderProgram.h" struct ModelJob : RenderJob { - ModelJob(Model* model, Camera* camera, glm::mat4 matrix, ::RawModel::MaterialGroup matGroup, ComponentWrapper modelComponent, World* world, glm::vec4 fillColor, float fillPercentage) + ModelJob(Model* model, Camera* camera, glm::mat4 matrix, ::RawModel::MaterialProperties matProp, ComponentWrapper modelComponent, World* world, glm::vec4 fillColor, float fillPercentage) : RenderJob() { Model = model; - TextureID = (matGroup.Texture) ? matGroup.Texture->ResourceID : 0; - if (modelComponent["DiffuseTexture"]) { - DiffuseTexture = matGroup.Texture.get(); - } else { - DiffuseTexture = nullptr; - } - if (modelComponent["NormalMap"]) { - NormalTexture = matGroup.NormalMap.get(); - } else { - NormalTexture = nullptr; - } - if (modelComponent["SpecularMap"]) { - SpecularTexture = matGroup.SpecularMap.get(); - } else { - SpecularTexture = nullptr; - } - if (modelComponent["GlowMap"]) { - IncandescenceTexture = matGroup.IncandescenceMap.get(); - } else { - IncandescenceTexture = nullptr; - } - DiffuseColor = matGroup.DiffuseColor; - SpecularColor = matGroup.SpecularColor; - IncandescenceColor = matGroup.IncandescenceColor; - StartIndex = matGroup.StartIndex; - EndIndex = matGroup.EndIndex; + ModelID = model->ResourceID; + Type = matProp.type; + ::RawModel::MaterialBasic* matGroup = matProp.material; + switch(matProp.type){ + case ::RawModel::MaterialType::Basic: + if (Model->IsSkinned()) { + ShaderID = ResourceManager::Load("#ForwardPlusSkinnedProgram")->ResourceID; + } + else { + ShaderID = ResourceManager::Load("#ForwardPlusProgram")->ResourceID; + } + TextureID = 0; + break; + case ::RawModel::MaterialType::SingleTextures: + { + if (Model->IsSkinned()) { + ShaderID = ResourceManager::Load("#ForwardPlusSkinnedProgram")->ResourceID; + } + else { + ShaderID = ResourceManager::Load("#ForwardPlusProgram")->ResourceID; + } + ::RawModel::MaterialSingleTextures* singleTextures = static_cast<::RawModel::MaterialSingleTextures*>(matProp.material); + TextureID = (singleTextures->ColorMap.Texture) ? singleTextures->ColorMap.Texture->ResourceID : 0; + if (modelComponent["DiffuseTexture"]) { + DiffuseTexture.push_back(&singleTextures->ColorMap); + } + + if (modelComponent["NormalMap"]) { + NormalTexture.push_back(&singleTextures->NormalMap); + } + + if (modelComponent["SpecularMap"]) { + SpecularTexture.push_back(&singleTextures->SpecularMap); + } + + if (modelComponent["GlowMap"]) { + IncandescenceTexture.push_back(&singleTextures->IncandescenceMap); + } + } + break; + case ::RawModel::MaterialType::SplatMapping: + { + if (Model->IsSkinned()) { + ShaderID = ResourceManager::Load("#ForwardPlusSplatMapSkinnedProgram")->ResourceID; + } + else { + ShaderID = ResourceManager::Load("#ForwardPlusSplatMapProgram")->ResourceID; + } + ::RawModel::MaterialSplatMapping* SplatTextures = static_cast<::RawModel::MaterialSplatMapping*>(matProp.material); + + SplatMap = &SplatTextures->SplatMap; + + TextureID = (SplatTextures->ColorMaps[0].Texture) ? SplatTextures->ColorMaps[0].Texture->ResourceID : 0; + if (modelComponent["DiffuseTexture"]) { + for (auto& texture : SplatTextures->ColorMaps) { + DiffuseTexture.push_back(&texture); + } + } + + if (modelComponent["NormalMap"]) { + for (auto& texture : SplatTextures->NormalMaps) { + NormalTexture.push_back(&texture); + } + } + + if (modelComponent["SpecularMap"]) { + for (auto& texture : SplatTextures->SpecularMaps) { + SpecularTexture.push_back(&texture); + } + } + + if (modelComponent["GlowMap"]) { + for (auto& texture : SplatTextures->IncandescenceMaps) { + IncandescenceTexture.push_back(&texture); + } + } + } + break; + } + DiffuseColor = matGroup->DiffuseColor; + SpecularColor = matGroup->SpecularColor; + IncandescenceColor = matGroup->IncandescenceColor; + StartIndex = matGroup->StartIndex; + EndIndex = matGroup->EndIndex; Matrix = matrix; Color = modelComponent["Color"]; Entity = modelComponent.EntityID; @@ -57,31 +116,34 @@ struct ModelJob : RenderJob FillColor = fillColor; FillPercentage = fillPercentage; - Skeleton = Model->m_RawModel->m_Skeleton; - if (world->HasComponent(Entity, "Animation") && Skeleton != nullptr) { - auto animationComponent = world->GetComponent(Entity, "Animation"); - Animation = model->m_RawModel->m_Skeleton->GetAnimation(animationComponent["Name"]); - AnimationTime = (double)animationComponent["Time"]; + + if (model->IsSkinned()) { + Skeleton = Model->m_RawModel->m_Skeleton; } + }; unsigned int TextureID; unsigned int ShaderID; + unsigned int ModelID; + ::RawModel::MaterialType Type; EntityID Entity; glm::mat4 Matrix; - const Texture* DiffuseTexture; - const Texture* NormalTexture; - const Texture* SpecularTexture; - const Texture* IncandescenceTexture; + const ::RawModel::TextureProperties* SplatMap; + std::vector DiffuseTexture; + std::vector NormalTexture; + std::vector SpecularTexture; + std::vector IncandescenceTexture; float Shininess = 0.f; glm::vec4 Color; const ::Model* Model = nullptr; ::Skeleton* Skeleton = nullptr; - const ::Skeleton::Animation* Animation = nullptr; + // const ::Skeleton::Animation* Animation = nullptr; + + - float AnimationTime = 0.f; glm::vec4 DiffuseColor; glm::vec4 SpecularColor; @@ -95,7 +157,7 @@ struct ModelJob : RenderJob void CalculateHash() override { - Hash = TextureID; + Hash = TextureID + ModelID << 10 + ShaderID << 20; } }; diff --git a/include/Engine/Rendering/PNG.h b/include/Engine/Rendering/PNG.h index f2cbf157..a45e9e7c 100644 --- a/include/Engine/Rendering/PNG.h +++ b/include/Engine/Rendering/PNG.h @@ -6,9 +6,10 @@ #include #include "../Common.h" +#include "../Core/ResourceManager.h" #include "Image.h" -class PNG : public Image +class PNG : public Image, public Resource { public: PNG(std::string path); diff --git a/include/Engine/Rendering/PickingPass.h b/include/Engine/Rendering/PickingPass.h index da3ed31b..2ce2e78d 100644 --- a/include/Engine/Rendering/PickingPass.h +++ b/include/Engine/Rendering/PickingPass.h @@ -40,6 +40,7 @@ private: const IRenderer* m_Renderer; ShaderProgram* m_PickingProgram; + ShaderProgram* m_PickingSkinnedProgram; Camera* m_Camera; struct PickingInfo diff --git a/include/Engine/Rendering/RawModelCustom.h b/include/Engine/Rendering/RawModelCustom.h index e903f49f..ebf8da2b 100644 --- a/include/Engine/Rendering/RawModelCustom.h +++ b/include/Engine/Rendering/RawModelCustom.h @@ -33,18 +33,27 @@ protected: public: ~RawModelCustom(); - struct Vertex - { - glm::vec3 Position; - glm::vec3 Normal; - glm::vec3 Tangent; - glm::vec3 BiNormal; - glm::vec2 TextureCoords; + struct Vertex + { + glm::vec3 Position; + glm::vec3 Normal; + glm::vec3 Tangent; + glm::vec3 BiNormal; + glm::vec2 TextureCoords; + }; + + struct SkinedVertex : public Vertex { glm::vec4 BoneIndices; glm::vec4 BoneWeights; }; - struct MaterialGroup + struct TextureProperties { + std::string TexturePath; + glm::vec2 UVRepeat; + Texture* Texture; + }; + + struct MaterialBasic { float SpecularExponent; float ReflectionFactor; @@ -54,25 +63,69 @@ public: unsigned int StartIndex; unsigned int EndIndex; //float Transparency; - std::string TexturePath; - std::shared_ptr<::Texture> Texture; - std::string NormalMapPath; - std::shared_ptr<::Texture> NormalMap; - std::string SpecularMapPath; - std::shared_ptr<::Texture> SpecularMap; - std::string IncandescenceMapPath; - std::shared_ptr<::Texture> IncandescenceMap; }; - std::vector MaterialGroups; + struct MaterialSplatMapping : public MaterialBasic + { + TextureProperties SplatMap; + std::vector ColorMaps; + std::vector NormalMaps; + std::vector SpecularMaps; + std::vector IncandescenceMaps; + }; + + struct MaterialSingleTextures : public MaterialBasic + { + TextureProperties ColorMap; + TextureProperties NormalMap; + TextureProperties SpecularMap; + TextureProperties IncandescenceMap; + }; + + enum class MaterialType { Basic = 1, SplatMapping, SingleTextures }; + + struct MaterialProperties { + MaterialType type; + MaterialBasic* material; + }; + + const Vertex* Vertices() const { + if (hasSkin) { + return m_SkinedVertices.data(); + } else { + return m_Vertices.data(); + } + }; + + unsigned int VertexSize() const { + if (hasSkin) { + return sizeof(SkinedVertex); + } + else { + return sizeof(Vertex); + } + }; + + unsigned int NumVertices() const { + if (hasSkin) { + return m_SkinedVertices.size(); + } else { + return m_Vertices.size(); + } + }; + + bool IsSkinned() const { return hasSkin; }; + + std::vector m_Materials; - std::vector m_Vertices; std::vector m_Indices; Skeleton* m_Skeleton = nullptr; glm::mat4 m_Matrix; private: - + bool hasSkin; + std::vector m_Vertices; + std::vector m_SkinedVertices; void ReadMeshFile(std::string filePath); void ReadMeshFileHeader(std::size_t& offset, char* fileData); @@ -83,13 +136,17 @@ private: void ReadMaterialFile(std::string filePath); void ReadMaterials(std::size_t& offset, char* fileData, const unsigned int& fileByteSize); void ReadMaterialSingle(std::size_t& offset, char* fileData, const unsigned int& fileByteSize); + void ReadMaterialBasic(MaterialBasic* Material, std::size_t& offset, char* fileData, const unsigned int& fileByteSize); + void ReadMaterialSingleTexture(MaterialSingleTextures* Material, std::size_t& offset, char* fileData, const unsigned int& fileByteSize); + void ReadMaterialSplatMapping(MaterialSplatMapping* Material, std::size_t& offset, char* fileData, const unsigned int& fileByteSize); + void ReadMaterialTextureProperties(TextureProperties& texture, std::size_t& offset, char* fileData, const unsigned int& fileByteSize); void ReadAnimationFile(std::string filePath); void ReadAnimationBindPoses(std::size_t& offset, char* fileData, const unsigned int& fileByteSize); void ReadAnimationJoint(std::size_t& offset, char* fileData, const unsigned int& fileByteSize); void ReadAnimationClips(std::size_t& offset, char* fileData, const unsigned int& fileByteSize, unsigned int numberOfClips); void ReadAnimationClipSingle(std::size_t& offset, char* fileData, const unsigned int& fileByteSize, unsigned int clipIndex); - void ReadAnimationKeyFrame(std::size_t& offset, char* fileData, const unsigned int& fileByteSize, unsigned int numberOfJoints, Skeleton::Animation& animation); + void ReadAnimationKeyFrame(std::size_t& offset, char* fileData, const unsigned int& fileByteSize, std::vector& animation); //void CreateSkeleton(std::vector> &boneInfo, std::map &boneNameMapping, aiNode* node, int parentID); }; diff --git a/include/Engine/Rendering/RenderQueue.h b/include/Engine/Rendering/RenderQueue.h index 57371146..647adab8 100644 --- a/include/Engine/Rendering/RenderQueue.h +++ b/include/Engine/Rendering/RenderQueue.h @@ -15,31 +15,45 @@ #include "PointLightJob.h" #include "DirectionalLightJob.h" #include "ExplosionEffectJob.h" +#include "SpriteJob.h" struct RenderScene { ::Camera* Camera = nullptr; - std::list> OpaqueObjects; - std::list> TransparentObjects; - std::list> PointLightJobs; - std::list> TextJobs; - std::list> DirectionalLightJobs; + struct Queues { + std::list> OpaqueObjects; + std::list> TransparentObjects; + std::list> OpaqueShieldedObjects; + std::list> TransparentShieldedObjects; + std::list> ShieldObjects; + std::list> SpriteJob; + std::list> PointLight; + std::list> Text; + std::list> DirectionalLight; + } Jobs; + Rectangle Viewport; bool ClearDepth = false; + glm::vec4 AmbientColor; void Clear() { - OpaqueObjects.clear(); - TransparentObjects.clear(); - PointLightJobs.clear(); - TextJobs.clear(); - DirectionalLightJobs.clear(); + Jobs.OpaqueObjects.clear(); + Jobs.TransparentObjects.clear(); + Jobs.OpaqueShieldedObjects.clear(); + Jobs.TransparentShieldedObjects.clear(); + Jobs.ShieldObjects.clear(); + Jobs.SpriteJob.clear(); + Jobs.DirectionalLight.clear(); } }; struct RenderFrame { public: + //TODO: Getters + GLfloat Gamma = 2.2f; + GLfloat Exposure = 1.f; void Add(RenderScene &scene) { diff --git a/include/Engine/Rendering/RenderState.h b/include/Engine/Rendering/RenderState.h index 688ef520..c1886247 100644 --- a/include/Engine/Rendering/RenderState.h +++ b/include/Engine/Rendering/RenderState.h @@ -2,6 +2,7 @@ #define RenderState_h__ #include +#include #include "../Common.h" #include "../OpenGL.h" #include "../GLM.h" @@ -19,6 +20,9 @@ public: bool BindFramebuffer(GLint framebuffer); bool BlendEquation(GLenum mode); bool BlendFunc(GLenum sfactor, GLenum dfactor); + bool StencilOp(GLenum sfail, GLenum dpfail, GLenum dppass); + bool StencilFunc(GLenum func, GLint ref, GLuint mask); + bool StencilMask(GLuint mask); bool DepthMask(GLboolean flag); private: diff --git a/include/Engine/Rendering/RenderSystem.h b/include/Engine/Rendering/RenderSystem.h index d64147b9..d73d8680 100644 --- a/include/Engine/Rendering/RenderSystem.h +++ b/include/Engine/Rendering/RenderSystem.h @@ -16,11 +16,13 @@ #include "PointLightJob.h" #include "../Core/Transform.h" #include "../Core/EPlayerSpawned.h" +#include "../Core/Octree.h" +#include "../Collision/EntityAABB.h" class RenderSystem : public ImpureSystem { public: - RenderSystem(World* world, EventBroker* eventBrokerer, const IRenderer* renderer, RenderFrame* renderFrame); + RenderSystem(SystemParams params, const IRenderer* renderer, RenderFrame* renderFrame, Octree* frustumCullOctree); ~RenderSystem(); virtual void Update(double dt) override; @@ -29,9 +31,9 @@ private: const IRenderer* m_Renderer; RenderFrame* m_RenderFrame; Camera* m_Camera; - World* m_World; EntityWrapper m_CurrentCamera = EntityWrapper::Invalid; EntityWrapper m_LocalPlayer = EntityWrapper::Invalid; + Octree* m_Octree; EventRelay m_ESetCamera; bool OnSetCamera(Events::SetCamera &event); @@ -40,14 +42,14 @@ private: EventRelay m_EPlayerSpawned; bool OnPlayerSpawned(Events::PlayerSpawned& e); - void fillModels(std::list>& opaqueJobs, std::list>& transparentJobs); + void fillModels(RenderScene::Queues &jobs); void fillText(std::list>& jobs, World* world); void fillPointLights(std::list>& jobs, World* world); void fillDirectionalLights(std::list>& jobs, World* world); void fillLight(std::list>& jobs); + void fillSprites(std::list>& jobs, World* world); bool isChildOfACamera(EntityWrapper entity); bool isChildOfCurrentCamera(EntityWrapper entity); - }; #endif \ No newline at end of file diff --git a/include/Engine/Rendering/Renderer.h b/include/Engine/Rendering/Renderer.h index 33a61edf..04754514 100644 --- a/include/Engine/Rendering/Renderer.h +++ b/include/Engine/Rendering/Renderer.h @@ -22,6 +22,7 @@ #include "../Core/Transform.h" #include "imgui/imgui.h" #include "TextPass.h" +#include "Util/CommonFunctions.h" class Renderer : public IRenderer { diff --git a/include/Engine/Rendering/Skeleton.h b/include/Engine/Rendering/Skeleton.h index 3b89b89b..a8dd982d 100644 --- a/include/Engine/Rendering/Skeleton.h +++ b/include/Engine/Rendering/Skeleton.h @@ -5,6 +5,7 @@ #include "Common.h" #include "../GLM.h" #include +#include //struct Bone //{ @@ -53,22 +54,39 @@ public: { struct BoneProperty { - int ID; - glm::vec3 Position; - glm::quat Rotation; + glm::vec3 Position; + glm::quat Rotation; glm::vec3 Scale = glm::vec3(1); }; - int Index = 0; - double Time = 0.0; - std::map BoneProperties; + int Index = 0; + double Time = 0.0; + BoneProperty BoneProperties; }; - - std::string Name; - double Duration; - std::vector Keyframes; + std::string Name; + double Duration; + std::map> JointAnimations; }; + struct AnimationData + { + const Animation* animation; + float time; + float weight; + }; + + struct JointFrameTransform { + glm::vec3 PositionInterp = glm::vec3(0); + glm::quat RotationInterp = glm::quat(); + glm::vec3 ScaleInterp = glm::vec3(0); + float Weight; + }; + + struct AnimationOffset { + const Animation* animation; + float time; + }; + Skeleton() { } ~Skeleton(); @@ -82,17 +100,50 @@ public: int GetBoneID(std::string name); - const Animation* GetAnimation(std::string name); - std::vector GetFrameBones(const Animation& animation, double time, bool noRootMotion = false); - void AccumulateBoneTransforms(bool noRootMotion, const Animation::Keyframe& currentFrame, const Animation::Keyframe& nextFrame, float progress, std::map& boneMatrices, const Bone* bone, glm::mat4 parentMatrix); - void PrintSkeleton(); + void CalculateFrameBones(std::vector animations, AnimationOffset animationOffset, bool noRootMotion = false); + void CalculateFrameBones(std::vector animations, bool noRootMotion = false); + + const Animation* GetAnimation(std::string name); + + void AccumulateBoneTransforms(bool noRootMotion, std::vector animations, const Bone* bone, glm::mat4 parentMatrix); + void AccumulateBoneTransforms(bool noRootMotion, std::vector animations, AnimationOffset animationOffset, const Bone* bone, glm::mat4 parentMatrix); + + void PrintSkeleton(); void PrintSkeleton(const Bone* parent, int depthCount); std::map Animations; -private: - std::map m_BonesByName; + glm::mat4 GetBoneTransform(const Bone* bone, const Animation* animation, float time, glm::mat4 childMatrix); + int GetKeyframe(const Animation& animation, double time); - int GetKeyframe(const Animation& animation, double time); + + std::vector GetBones() + { + std::vector finalMatrices; + for (auto &kv : m_BoneLocalTransforms) { + finalMatrices.push_back(kv.second); + } + return finalMatrices;; + } + + glm::mat4 GetBoneTransformSuper(int boneID) + { + if(m_BoneTransforms.find(boneID) != m_BoneTransforms.end()) { + return m_BoneTransforms.at(boneID); + } else { + return glm::mat4(1); + } + } + +private: + + glm::mat4 GetOffsetTransform(const Bone* bone, AnimationOffset animationOffset); + + std::map m_BonesByName; + float aim = 0.f; + + + std::map m_BoneLocalTransforms; + std::map m_BoneTransforms; }; #endif diff --git a/include/Engine/Rendering/SpriteJob.h b/include/Engine/Rendering/SpriteJob.h new file mode 100644 index 00000000..3bb43a1c --- /dev/null +++ b/include/Engine/Rendering/SpriteJob.h @@ -0,0 +1,73 @@ +#ifndef SpriteJob_h__ +#define SpriteJob_h__ + +#include + +#include "../Common.h" +#include "../GLM.h" +#include "../Core/ComponentWrapper.h" +#include "Texture.h" +#include "Model.h" +#include "RenderJob.h" +#include "../Core/ResourceManager.h" +#include "Camera.h" +#include "../Core/World.h" +#include "../Core/Transform.h" +#include "Skeleton.h" + +struct SpriteJob : RenderJob +{ + SpriteJob(ComponentWrapper cSprite, Camera* camera, glm::mat4 matrix, World* world, glm::vec4 fillColor, float fillPercentage, bool depthSorted) + : RenderJob() + { + Model = ResourceManager::Load<::Model>("Models/Core/UnitQuad.mesh"); + ::RawModel::MaterialProperties matProp = Model->MaterialGroups().front(); + TextureID = 0; + + DiffuseTexture = CommonFunctions::LoadTexture(cSprite["DiffuseTexture"], true); + + IncandescenceTexture = CommonFunctions::LoadTexture(cSprite["GlowMap"], true); + + StartIndex = matProp.material->StartIndex; + EndIndex = matProp.material->EndIndex; + Matrix = matrix; + Color = cSprite["Color"]; + Entity = cSprite.EntityID; + Position = Transform::AbsolutePosition(world, cSprite.EntityID); + Depth = 0; + if (depthSorted) { + glm::vec3 viewpos = glm::vec3(camera->ViewMatrix() * glm::vec4(Position, 1)); + Depth = viewpos.z; + } + World = world; + + FillColor = fillColor; + FillPercentage = fillPercentage; + }; + + unsigned int TextureID; + + EntityID Entity; + glm::mat4 Matrix; + const Texture* DiffuseTexture; + const Texture* NormalTexture; + const Texture* SpecularTexture; + const Texture* IncandescenceTexture; + float Shininess = 0.f; + glm::vec4 Color; + glm::vec3 Position; + const ::Model* Model = nullptr; + unsigned int StartIndex = 0; + unsigned int EndIndex = 0; + World* World; + + glm::vec4 FillColor = glm::vec4(0); + float FillPercentage = 0.0; + + void CalculateHash() override + { + Hash = TextureID; + } +}; + +#endif \ No newline at end of file diff --git a/include/Engine/Rendering/Util/CommonFunctions.h b/include/Engine/Rendering/Util/CommonFunctions.h index b262568c..e178f52d 100644 --- a/include/Engine/Rendering/Util/CommonFunctions.h +++ b/include/Engine/Rendering/Util/CommonFunctions.h @@ -4,14 +4,11 @@ #include "../../Common.h" #include "../../OpenGL.h" #include "../../GLM.h" +#include "../Texture.h" -class CommonFuntions -{ -public: - CommonFuntions() = delete; - -private: - +namespace CommonFunctions +{ +Texture* LoadTexture(std::string path, bool threaded); }; #endif \ No newline at end of file diff --git a/include/Engine/Rendering/Util/GLError.h b/include/Engine/Rendering/Util/GLError.h index 754623d1..2b244e1c 100644 --- a/include/Engine/Rendering/Util/GLError.h +++ b/include/Engine/Rendering/Util/GLError.h @@ -9,7 +9,7 @@ inline bool _GLERROR(const char* info, const char* file, const char* func, unsig GLenum error = glGetError(); if (error != GL_NO_ERROR) { - _LOG(LOG_LEVEL_ERROR, file, func, line, "GL Error: %s, %i, %s", info, error, gluErrorString(error)); + _LOG(LOG_LEVEL_ERROR, file, func, line, "GL Error: %s\nError code: %i, %s\n", info, error, gluErrorString(error)); return true; } diff --git a/include/Engine/Sound/EPlayQueueOnEntity.h b/include/Engine/Sound/EPlayQueueOnEntity.h new file mode 100644 index 00000000..e880819a --- /dev/null +++ b/include/Engine/Sound/EPlayQueueOnEntity.h @@ -0,0 +1,18 @@ +#ifndef Events_PlayQueueOnEntity_h__ +#define Events_PlayQueueOnEntity_h__ + +#include "../Core/Event.h" +#include "../Core/EntityWrapper.h" + +namespace Events +{ + +struct PlayQueueOnEntity : public Event +{ + EntityWrapper Emitter; + std::vector FilePaths; +}; + +} + +#endif diff --git a/include/Engine/Sound/Sound.h b/include/Engine/Sound/Sound.h index 6b2aac04..cccbdf07 100644 --- a/include/Engine/Sound/Sound.h +++ b/include/Engine/Sound/Sound.h @@ -1,6 +1,9 @@ #ifndef Sound_h__ #define Sound_h__ +#include +#include + #include "Core/ResourceManager.h" class Sound : public Resource diff --git a/include/Engine/Sound/SoundSystem.h b/include/Engine/Sound/SoundManager.h similarity index 57% rename from include/Engine/Sound/SoundSystem.h rename to include/Engine/Sound/SoundManager.h index b9cc2589..5b027c62 100644 --- a/include/Engine/Sound/SoundSystem.h +++ b/include/Engine/Sound/SoundManager.h @@ -1,17 +1,23 @@ -#ifndef SoundSystem_h__ -#define SoundSystem_h__ +#ifndef SoundManager_h__ +#define SoundManager_h__ #include +#include #include "glm/common.hpp" #include "glm/gtx/rotate_vector.hpp" // Calculate Up vector #include "OpenAL/al.h" #include "OpenAL/alc.h" +#include "imgui/imgui.h" + #include "Core/World.h" #include "Core/EventBroker.h" +#include "../Engine/Core/ResourceManager.h" +#include "../Engine/Core/ConfigFile.h" #include "Core/Transform.h" // Absolute transform #include "Sound/Sound.h" +#include "../Engine/Sound/EPlayQueueOnEntity.h" #include "Sound/EPlaySoundOnEntity.h" #include "Sound/EPlaySoundOnPosition.h" #include "Sound/EPlayBackgroundMusic.h" @@ -20,6 +26,11 @@ #include "Sound/EStopSound.h" #include "Sound/ESetBGMGain.h" #include "Sound/ESetSFXGain.h" +#include "Core/EPause.h" +#include "Core/EComponentAttached.h" +#include "../Core/EPlayerSpawned.h" + +typedef std::pair> QueuedBuffers; enum class SoundType { SFX, @@ -34,14 +45,15 @@ struct Source SoundType Type; }; -class SoundSystem +class SoundManager { public: - SoundSystem() { } - SoundSystem(World* world, EventBroker* eventBroker, bool editorMode); - ~SoundSystem(); + SoundManager() { } + SoundManager(World* world, EventBroker* eventBroker); + ~SoundManager(); // Update emitters / listener void Update(double dt); + private: // Help functions for working with OpenaAL void setListenerPos(glm::vec3 pos) { alListener3f(AL_POSITION, pos.x, pos.y, pos.z); }; @@ -56,46 +68,62 @@ private: // Logic void initOpenAL(); void updateEmitters(double dt); - void updateListener(double dt); void deleteInactiveEmitters(); - void addNewEmitters(double dt); - Source* createSource(std::string filePath); - void playSound(Source* source); - void stopSound(Source* source); void stopEmitters(); + void updateListener(double dt); ALenum getSourceState(ALuint source); void setGain(Source* source, float gain); - void setSoundProperties(ALuint source, ComponentWrapper* soundComponent); + void setSoundProperties(Source* source, ComponentWrapper* soundComponent); + + // Specific logic + void playSound(Source* source); + // Need to be the same format (sample rate etc) + void playQueue(QueuedBuffers qb); + void stopSound(Source* source); + Source* createSource(std::string filePath); + std::unordered_map m_Sources; + + // Logic + World* m_World = nullptr; + EventBroker* m_EventBroker = nullptr; // OpenAL system variables ALCdevice* m_ALCdevice = nullptr; ALCcontext* m_ALCcontext = nullptr; - // Logic - World* m_World = nullptr; - EventBroker* m_EventBroker = nullptr; - std::unordered_map m_Sources; float m_BGMVolumeChannel = 1.0f; - float m_SFXVolumeChannel = 1.f; - bool m_EditorEnabled = false; - + float m_SFXVolumeChannel = 1.0f; + EntityWrapper m_LocalPlayer = EntityWrapper(); + // Events - EventRelay m_EPlaySoundOnEntity; + EventRelay m_EPlaySoundOnEntity; bool OnPlaySoundOnEntity(const Events::PlaySoundOnEntity &e); - EventRelay m_EPlaySoundOnPosition; + EventRelay m_EPlaySoundOnPosition; bool OnPlaySoundOnPosition(const Events::PlaySoundOnPosition &e); - EventRelay m_EPlayBackgroundMusic; + EventRelay m_EPlayBackgroundMusic; bool OnPlayBackgroundMusic(const Events::PlayBackgroundMusic &e); - EventRelay m_EPauseSound; + EventRelay m_EPauseSound; bool OnPauseSound(const Events::PauseSound &e); - EventRelay m_EStopSound; + EventRelay m_EStopSound; bool OnStopSound(const Events::StopSound &e); - EventRelay m_EContinueSound; + EventRelay m_EContinueSound; bool OnContinueSound(const Events::ContinueSound &e); - EventRelay m_ESetBGMGain; - bool OnSetBGMGain(const Events::SetBGMGain &e); // Not tested - EventRelay m_ESetSFXGain; - bool OnSetSFXGain(const Events::SetSFXGain &e); // Not tested + EventRelay m_ESetBGMGain; + bool OnSetBGMGain(const Events::SetBGMGain &e); + EventRelay m_ESetSFXGain; + bool OnSetSFXGain(const Events::SetSFXGain &e); + EventRelay m_EComponentAttached; + bool OnComponentAttached(const Events::ComponentAttached &e); + EventRelay m_EPause; + bool OnPause(const Events::Pause &e); + EventRelay m_EResume; + bool OnResume(const Events::Resume &e); + EventRelay m_EPlayerSpawned; + bool OnPlayerSpawned(const Events::PlayerSpawned &e); + EventRelay m_EPlayQueueOnEntity; + bool OnPlayQueueOnEntity(const Events::PlayQueueOnEntity &e); + + }; #endif \ No newline at end of file diff --git a/include/Game/Events/EDashAbility.h b/include/Game/Events/EDashAbility.h new file mode 100644 index 00000000..62a2b935 --- /dev/null +++ b/include/Game/Events/EDashAbility.h @@ -0,0 +1,13 @@ +#ifndef Events_DashAbility_h__ +#define Events_DashAbility_h__ + +#include "Core/Event.h" + +namespace Events +{ + +struct DashAbility : public Event { }; + +} + +#endif \ No newline at end of file diff --git a/include/Game/Events/EDoubleJump.h b/include/Game/Events/EDoubleJump.h new file mode 100644 index 00000000..767d5b39 --- /dev/null +++ b/include/Game/Events/EDoubleJump.h @@ -0,0 +1,16 @@ +#ifndef Events_DoubleJump_h__ +#define Events_DoubleJump_h__ + +#include "Core/Event.h" + +namespace Events +{ + +struct DoubleJump : public Event +{ + +}; + +} + +#endif diff --git a/include/Game/ExplosionEffectSystem.h b/include/Game/ExplosionEffectSystem.h deleted file mode 100644 index 061ad221..00000000 --- a/include/Game/ExplosionEffectSystem.h +++ /dev/null @@ -1,24 +0,0 @@ -#include "Common.h" -#include "Core/System.h" - -class ExplosionEffectSystem : public PureSystem -{ -public: - ExplosionEffectSystem(World* world, EventBroker* eventBroker) - : System(world, eventBroker) - , PureSystem("ExplosionEffect") - { } - - virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) override - { - - if ((double)component["TimeSinceDeath"] > (double)component["ExplosionDuration"]) { - (double)component["TimeSinceDeath"] = 0.f; - } - (double&)component["TimeSinceDeath"] += dt; - - //if ((bool)Component["Gravity"] == true) { - // (bool)Component["ExponentialAccelaration"] = false; - //} - } -}; \ No newline at end of file diff --git a/include/Game/Game.h b/include/Game/Game.h index 37267a68..baf15656 100644 --- a/include/Game/Game.h +++ b/include/Game/Game.h @@ -1,6 +1,8 @@ #ifndef Game_h__ #define Game_h__ +#include + #include "Core/ResourceManager.h" #include "Core/ConfigFile.h" #include "Core/EventBroker.h" @@ -14,7 +16,7 @@ #include "Core/EKeyDown.h" #include "Core/EntityFilePreprocessor.h" #include "Core/SystemPipeline.h" -#include "ExplosionEffectSystem.h" +#include "Systems/ExplosionEffectSystem.h" #include "Editor/EditorSystem.h" #include "Core/EntityFile.h" #include "Rendering/RenderSystem.h" @@ -30,7 +32,8 @@ #include "Network/Client.h" // Sound -#include "Sound/SoundSystem.h" +#include "Sound/SoundManager.h" +#include "Systems/SoundSystem.h" class Game { @@ -42,7 +45,9 @@ public: void Tick(); private: - double m_LastTime; + std::string m_NetworkAddress; + int m_NetworkPort = 0; + ConfigFile* m_Config = nullptr; EventBroker* m_EventBroker; IRenderer* m_Renderer; @@ -55,24 +60,15 @@ private: Octree* m_OctreeFrustrumCulling; SystemPipeline* m_SystemPipeline; RenderFrame* m_RenderFrame; - // Network variables - boost::thread m_NetworkThread; + Client* m_NetworkClient = nullptr; + Server* m_NetworkServer = nullptr; + SoundManager* m_SoundManager; + double m_LastTime; - // Network methods - void networkFunction(); - Network* m_ClientOrServer; - bool m_IsClientOrServer = false; - - // Sound - SoundSystem* m_SoundSystem; - - //EventRelay m_EInputCommand; - //bool debugOnInputCommand(const Events::InputCommand& e); - - void debugInitialize(); - void debugTick(double dt); - EventRelay m_EKeyDown; + bool m_IsClient = false; + bool m_IsServer = false; + int parseArgs(int argc, char* argv[]); }; #endif diff --git a/include/Game/Network/MultiplayerSnapshotFilter.h b/include/Game/Network/MultiplayerSnapshotFilter.h new file mode 100644 index 00000000..32c82e01 --- /dev/null +++ b/include/Game/Network/MultiplayerSnapshotFilter.h @@ -0,0 +1,25 @@ +#ifndef MultiplayerSnapshotFilter_h__ +#define MultiplayerSnapshotFilter_h__ + +#include "Core/EventBroker.h" +#include "Core/EPlayerSpawned.h" +#include "Network/SnapshotFilter.h" +#include "Network/EInterpolate.h" + +class MultiplayerSnapshotFilter : public SnapshotFilter +{ +public: + MultiplayerSnapshotFilter(EventBroker* eventBroker); + + virtual bool FilterComponent(EntityWrapper entity, SharedComponentWrapper& component) override; + +private: + EventBroker* m_EventBroker; + + EntityWrapper m_LocalPlayer = EntityWrapper::Invalid; + + EventRelay m_EPlayerSpawned; + bool OnPlayerSpawned(Events::PlayerSpawned ePlayerSpawned); +}; + +#endif \ No newline at end of file diff --git a/include/Game/Systems/CapturePointHUDSystem.h b/include/Game/Systems/CapturePointHUDSystem.h new file mode 100644 index 00000000..41db0c12 --- /dev/null +++ b/include/Game/Systems/CapturePointHUDSystem.h @@ -0,0 +1,22 @@ +#ifndef CapturePointHUDSystem_h__ +#define CapturePointHUDSystem_h__ + +#include +#include +#include + +#include "Common.h" +#include "Core/System.h" +#include "Engine/Collision/ETrigger.h" + +class CapturePointHUDSystem : public ImpureSystem +{ +public: + CapturePointHUDSystem(SystemParams params); + + virtual void Update(double dt) override; + +private: +}; + +#endif \ No newline at end of file diff --git a/include/Game/Systems/CapturePointSystem.h b/include/Game/Systems/CapturePointSystem.h index 18c32c76..34a23e14 100644 --- a/include/Game/Systems/CapturePointSystem.h +++ b/include/Game/Systems/CapturePointSystem.h @@ -17,7 +17,7 @@ class CapturePointSystem : public PureSystem { public: //WARNING: on new map, destroy all info in the vectors, as well as reset all variables (just make new?) - CapturePointSystem(World* world, EventBroker* eventBroker); + CapturePointSystem(SystemParams params); //updatecomponent virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& capturePoint, double dt) override; @@ -44,7 +44,6 @@ private: //std::vector - const double m_CaptureTimeToTakeOver = 15.0; bool m_ResetTimers = false; //vectors which will keep track of enter/leave changes diff --git a/include/Game/Systems/DamageIndicatorSystem.h b/include/Game/Systems/DamageIndicatorSystem.h new file mode 100644 index 00000000..e70a69a9 --- /dev/null +++ b/include/Game/Systems/DamageIndicatorSystem.h @@ -0,0 +1,33 @@ +#ifndef DamageIndicatorSystem_h__ +#define DamageIndicatorSystem_h__ + +#include "Core/System.h" +#include "Core/Transform.h" +#include "Core/ResourceManager.h" +#include "Core/EntityFileParser.h" +#include "Core/EPlayerDamage.h" +#include "Common.h" +#include + +#include "Rendering/ESetCamera.h" +#include +#include + +#include "Rendering/Util/CommonFunctions.h" + +class DamageIndicatorSystem : public System +{ +public: + DamageIndicatorSystem(SystemParams params); + +private: + EventRelay m_DamageTakenFromPlayer; + bool OnPlayerDamageTaken(Events::PlayerDamage& e); + + EventRelay m_ESetCamera; + bool OnSetCamera(const Events::SetCamera& e); + + EntityID m_CurrentCamera = -1; + +}; +#endif diff --git a/include/Game/Systems/ExplosionEffectSystem.h b/include/Game/Systems/ExplosionEffectSystem.h new file mode 100644 index 00000000..24eee955 --- /dev/null +++ b/include/Game/Systems/ExplosionEffectSystem.h @@ -0,0 +1,18 @@ +#ifndef ExplosionEffectSystem_h__ +#define ExplosionEffectSystem_h__ + +#include "Common.h" +#include "Core/System.h" + +class ExplosionEffectSystem : public PureSystem +{ +public: + ExplosionEffectSystem(SystemParams params) + : System(params) + , PureSystem("ExplosionEffect") + { } + + virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) override; +}; + +#endif \ No newline at end of file diff --git a/include/Game/Systems/HealthSystem.h b/include/Game/Systems/HealthSystem.h index 3b069349..b66d8eb0 100644 --- a/include/Game/Systems/HealthSystem.h +++ b/include/Game/Systems/HealthSystem.h @@ -12,11 +12,12 @@ #include #include +#include class HealthSystem : public PureSystem { public: - HealthSystem(World* world, EventBroker* eventBroker); + HealthSystem(SystemParams params); //updatecomponent virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) override; @@ -26,7 +27,7 @@ private: EventRelay m_EPlayerDamage; bool HealthSystem::OnPlayerDamaged(Events::PlayerDamage& e); EventRelay m_EPlayerHealthPickup; - bool HealthSystem::OnPlayerHealthPickup(const Events::PlayerHealthPickup& e); + bool HealthSystem::OnPlayerHealthPickup(Events::PlayerHealthPickup& e); //vector which will keep track of health changes std::vector> m_DeltaHealthVector; diff --git a/include/Game/Systems/InterpolationSystem.h b/include/Game/Systems/InterpolationSystem.h index 96236f62..758609c8 100644 --- a/include/Game/Systems/InterpolationSystem.h +++ b/include/Game/Systems/InterpolationSystem.h @@ -16,38 +16,47 @@ #include "Network/EInterpolate.h" -class InterpolationSystem : public PureSystem +class InterpolationSystem : public ImpureSystem { - struct Transform - { - glm::vec3 Position; - glm::vec3 Scale; - glm::quat Orientation; - float interpolationTime; - }; public: - InterpolationSystem(World* world, EventBroker* eventBroker); + InterpolationSystem(SystemParams params); ~InterpolationSystem() { } - virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& transform, double dt) override; -private: - std::unordered_map m_NextTransform; - std::unordered_map m_LastReceivedTransform; - EntityWrapper m_LocalPlayer = EntityWrapper::Invalid; - //glm::vec3 vectorInterpolation(glm::vec3 prev, glm::vec3 next, double currentTime); + virtual void Update(double dt) override; + +private: + template + struct Interpolation + { + Interpolation(const ComponentWrapper& Component, const std::string& Field, const T& Start, const T& Goal) + : Component(Component) + , Field(Field) + , Start(Start) + , Goal(Goal) + { } + + ComponentWrapper Component; + std::string Field; + T Start; + T Goal; + double Alpha = 0.0; + }; + + float m_SnapshotInterval; + std::unordered_map> m_InterpolatePosition; + std::unordered_map> m_InterpolateOrientation; + std::unordered_map> m_InterpolateVelocity; + + EventRelay m_EInterpolate; + bool InterpolationSystem::OnInterpolate(Events::Interpolate& e); + template T vectorInterpolation(T prev, T next, double currentTime) { T difference = next - prev; - T vector = (difference / m_SnapshotInterval) * static_cast(currentTime); + T vector = difference * (static_cast(currentTime) / m_SnapshotInterval); return vector; } - float m_SnapshotInterval; - - EventRelay m_EInterpolate; - bool InterpolationSystem::OnInterpolate(const Events::Interpolate& e); - EventRelay m_EPlayerSpawned; - bool OnPlayerSpawned(Events::PlayerSpawned& e); }; #endif diff --git a/include/Game/Systems/LifetimeSystem.h b/include/Game/Systems/LifetimeSystem.h index da88cfa2..6dee644d 100644 --- a/include/Game/Systems/LifetimeSystem.h +++ b/include/Game/Systems/LifetimeSystem.h @@ -6,10 +6,12 @@ class LifetimeSystem : public ImpureSystem, PureSystem { public: - LifetimeSystem(World* world, EventBroker* eventBroker) - : System(world, eventBroker) + LifetimeSystem(SystemParams params) + : System(params) , PureSystem("Lifetime") - { } + { + LOG_INFO("ASDASDASSA"); + } virtual void Update(double dt) override; virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cLifetime, double dt) override; diff --git a/include/Game/Systems/PickupSpawnSystem.h b/include/Game/Systems/PickupSpawnSystem.h new file mode 100644 index 00000000..f912e8ff --- /dev/null +++ b/include/Game/Systems/PickupSpawnSystem.h @@ -0,0 +1,33 @@ +#ifndef PickupSpawnSystem_h__ +#define PickupSpawnSystem_h__ + +#include "Core/System.h" +#include "Core/Transform.h" +#include "Core/ResourceManager.h" +#include "Core/EntityFileParser.h" +#include "Core/EPickupSpawned.h" +#include "Core/EPlayerHealthPickup.h" +#include "Engine/Collision/ETrigger.h" +#include "Common.h" +#include + +class PickupSpawnSystem : public ImpureSystem +{ +public: + PickupSpawnSystem(SystemParams params); + + virtual void Update(double dt) override; + +private: + EventRelay m_ETriggerTouch; + bool OnTriggerTouch(Events::TriggerTouch& e); + + struct NewHealthPickup { + glm::vec3 Pos; + double HealthGain; + double RespawnTimer; + double DecreaseThisRespawnTimer; + }; + std::vector m_ETriggerTouchVector; +}; +#endif diff --git a/include/Game/Systems/PlayerDeathSystem.h b/include/Game/Systems/PlayerDeathSystem.h new file mode 100644 index 00000000..112c202e --- /dev/null +++ b/include/Game/Systems/PlayerDeathSystem.h @@ -0,0 +1,29 @@ +#ifndef PlayerDeathSystem_h__ +#define PlayerDeathSystem_h__ + +#include "Core/System.h" +#include "Input/EInputCommand.h" +#include "GLM.h" +#include "Rendering/ESetCamera.h" +#include "Core/ConfigFile.h" + +#include "Core/EntityFile.h" +#include "Core/EntityFileParser.h" + +#include "Core/EPlayerDeath.h" + +class PlayerDeathSystem : public ImpureSystem +{ +public: + PlayerDeathSystem(SystemParams params); + + virtual void Update(double dt) override; + +private: + EventRelay m_OnPlayerDeath; + bool OnPlayerDeath(Events::PlayerDeath& e); + + void createDeathEffect(EntityWrapper player); + +}; +#endif \ No newline at end of file diff --git a/include/Game/Systems/PlayerHUD.h b/include/Game/Systems/PlayerHUDSystem.h similarity index 58% rename from include/Game/Systems/PlayerHUD.h rename to include/Game/Systems/PlayerHUDSystem.h index 180f5a2a..50b6a258 100644 --- a/include/Game/Systems/PlayerHUD.h +++ b/include/Game/Systems/PlayerHUDSystem.h @@ -6,18 +6,14 @@ #include "../../Engine/Rendering/ESetCamera.h" #include -class PlayerHUD : public ImpureSystem +class PlayerHUDSystem : public ImpureSystem { public: - PlayerHUD(World* world, EventBroker* eventBrokerer); - ~PlayerHUD(); + PlayerHUDSystem(SystemParams params) + : System(params) + { } virtual void Update(double dt) override; - -private: - World* m_World; - EventBroker* m_EventBroker; - }; #endif \ No newline at end of file diff --git a/include/Game/Systems/PlayerMovementSystem.h b/include/Game/Systems/PlayerMovementSystem.h index 34862e90..2bcae866 100644 --- a/include/Game/Systems/PlayerMovementSystem.h +++ b/include/Game/Systems/PlayerMovementSystem.h @@ -4,21 +4,40 @@ #include "Core/EPlayerSpawned.h" #include "Input/FirstPersonInputController.h" #include +#include "Events/EDoubleJump.h" +#include "../Engine/Sound/EPlaySoundOnEntity.h" -class PlayerMovementSystem : public ImpureSystem, PureSystem +#include "Core/EntityFile.h" +#include "Core/EntityFileParser.h" + +class PlayerMovementSystem : public ImpureSystem { public: - PlayerMovementSystem(World* world, EventBroker* eventBroker); + PlayerMovementSystem(SystemParams params); ~PlayerMovementSystem(); virtual void Update(double dt) override; - virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt); private: // State std::unordered_map*> m_PlayerInputControllers; + EntityWrapper m_LocalPlayer = EntityWrapper::Invalid; + // Walking logic + // Keeps track of how far the player has walked within this "key press session". + float m_DistanceMoved = 0.0f; + // How far a step is (How often the step sound will be played). + const float m_PlayerStepLength = 1.75f; + // Determine what sound file to play. + bool m_LeftFoot = false; + // To get a difference when calculating the walking state. + glm::vec3 m_LastPosition = glm::vec3(); + // The logic for making the sound play when player is moving + void playerStep(double dt); + EventRelay m_EPlayerSpawned; bool OnPlayerSpawned(Events::PlayerSpawned& e); + void updateMovementControllers(double dt); + void updateVelocity(double dt); }; \ No newline at end of file diff --git a/include/Game/Systems/PlayerSpawnSystem.h b/include/Game/Systems/PlayerSpawnSystem.h index b0ff1d79..c68bb21f 100644 --- a/include/Game/Systems/PlayerSpawnSystem.h +++ b/include/Game/Systems/PlayerSpawnSystem.h @@ -3,13 +3,14 @@ #include "Systems/SpawnerSystem.h" #include "Events/ESpawnerSpawn.h" #include "Core/EPlayerSpawned.h" +#include "Core/EPlayerDeath.h" #include "Rendering/ESetCamera.h" #include "Core/ConfigFile.h" class PlayerSpawnSystem : public ImpureSystem { public: - PlayerSpawnSystem(World* world, EventBroker* eventBroker); + PlayerSpawnSystem(SystemParams params); virtual void Update(double dt) override; diff --git a/include/Game/Systems/RaptorCopterSystem.h b/include/Game/Systems/RaptorCopterSystem.h index 8bb18de6..b3589dcd 100644 --- a/include/Game/Systems/RaptorCopterSystem.h +++ b/include/Game/Systems/RaptorCopterSystem.h @@ -4,8 +4,8 @@ class RaptorCopterSystem : public PureSystem { public: - RaptorCopterSystem(World* world, EventBroker* eventBroker) - : System(world, eventBroker) + RaptorCopterSystem(SystemParams params) + : System(params) , PureSystem("RaptorCopter") { } diff --git a/include/Game/Systems/SoundSystem.h b/include/Game/Systems/SoundSystem.h new file mode 100644 index 00000000..962eb085 --- /dev/null +++ b/include/Game/Systems/SoundSystem.h @@ -0,0 +1,65 @@ +#ifndef Systems_SoundSystem_h__ +#define Systems_SoundSystem_h__ + +#include + +#include "../Engine/Core/System.h" +#include "../Engine/Core/ResourceManager.h" +#include "../Engine/Core/ConfigFile.h" +#include "../Engine/Sound/Sound.h" +#include "../Engine/Sound/EPlayQueueOnEntity.h" +#include "../Engine/Core/EPlayerSpawned.h" +#include "../Engine/Input/EInputCommand.h" +#include "../Engine/Core/EShoot.h" +#include "../Engine/Core/EPlayerSpawned.h" +#include "../Engine/Input/EInputCommand.h" +#include "../Engine/Core/ECaptured.h" +#include "../Engine/Core/EPlayerDamage.h" +#include "../Engine/Core/EPlayerDeath.h" +#include "../Engine/Core/EPlayerHealthPickup.h" +#include "../Engine/Collision/ETrigger.h" +#include "../Engine/Sound/EPlaySoundOnEntity.h" +#include "../Engine/Sound/EPlayBackgroundMusic.h" +#include "../Game/Events/EDoubleJump.h" +#include "../Game/Events/EDashAbility.h" + + +class SoundSystem : public PureSystem, ImpureSystem +{ +public: + SoundSystem(SystemParams params); + virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cComponent, double dt) override; + virtual void Update(double dt) override; +private: + std::string m_Announcer = ""; + // Logic for playing a sound when a player jumps + void playerJumps(); + + // Temporary solution for play test. + bool m_DrumsIsPlaying = false; + double m_DrumTimer = 0.0; + bool drumTimer(double dt); + + std::default_random_engine generator; + + EventRelay m_EPlayerSpawned; + bool OnPlayerSpawned(const Events::PlayerSpawned &e); + EventRelay m_InputCommand; + bool OnInputCommand(const Events::InputCommand &e); + EventRelay m_EDoubleJump; + bool OnDoubleJump(const Events::DoubleJump &e); + EventRelay m_EDashAbility; + bool OnDashAbility(const Events::DashAbility &e); + EventRelay m_ETriggerTouch; + bool OnTriggerTouch(const Events::TriggerTouch &e); + EventRelay m_ECaptured; + bool OnCaptured(const Events::Captured &e); + EventRelay m_EPlayerDamage; + bool OnPlayerDamage(const Events::PlayerDamage &e); + EventRelay m_EPlayerDeath; + bool OnPlayerDeath(const Events::PlayerDeath &e); + EventRelay m_EPlayerHealthPickup; + bool OnPlayerHealthPickup(const Events::PlayerHealthPickup &e); +}; + +#endif diff --git a/include/Game/Systems/SpawnerSystem.h b/include/Game/Systems/SpawnerSystem.h index 62f6b09a..9cb4bd06 100644 --- a/include/Game/Systems/SpawnerSystem.h +++ b/include/Game/Systems/SpawnerSystem.h @@ -13,7 +13,7 @@ class SpawnerSystem : public System { public: - SpawnerSystem(World* world, EventBroker* eventBroker); + SpawnerSystem(SystemParams params); static EntityWrapper Spawn(EntityWrapper spawner, EntityWrapper parent = EntityWrapper::Invalid); diff --git a/include/Game/Systems/WeaponSystem.h b/include/Game/Systems/WeaponSystem.h index 0dd5cc54..b118b8cd 100644 --- a/include/Game/Systems/WeaponSystem.h +++ b/include/Game/Systems/WeaponSystem.h @@ -13,31 +13,180 @@ #include "Input/EInputCommand.h" #include "Core/EntityFile.h" #include "Core/EntityFileParser.h" +#include "Core/Octree.h" +#include "Collision/EntityAABB.h" +#include "Systems/SpawnerSystem.h" +#include "Sound/EPlaySoundOnEntity.h" -#include -#include +class WeaponBehaviour; - -class WeaponSystem : public ImpureSystem +class WeaponSystem : public PureSystem, ImpureSystem { public: - WeaponSystem(World* world, EventBroker* eventBroker, IRenderer* renderer); + WeaponSystem(SystemParams params, IRenderer* renderer, Octree* collisionOctree); virtual void Update(double dt) override; + virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cPlayer, double dt) override; private: + SystemParams m_SystemParams; IRenderer* m_Renderer; + Octree* m_CollisionOctree; - // State - EntityWrapper m_LocalPlayer = EntityWrapper::Invalid; + std::unordered_map> m_ActiveWeapons; // Events EventRelay m_EPlayerSpawned; - bool WeaponSystem::OnPlayerSpawned(const Events::PlayerSpawned& e); + bool OnPlayerSpawned(Events::PlayerSpawned& e); EventRelay m_EShoot; - bool WeaponSystem::OnShoot(Events::Shoot& e); + bool OnShoot(Events::Shoot& e); EventRelay m_EInputCommand; - bool WeaponSystem::OnInputCommand(const Events::InputCommand& e); + bool OnInputCommand(Events::InputCommand& e); + + void selectWeapon(EntityWrapper player, ComponentInfo::EnumType slot); +}; + +class WeaponBehaviour : public System +{ +public: + WeaponBehaviour(SystemParams systemParams, Octree* collisionOctree, EntityWrapper weaponEntity) + : System(systemParams) + , m_CollisionOctree(collisionOctree) + , m_Entity(weaponEntity) + { } + virtual ~WeaponBehaviour() = default; + + WeaponBehaviour(const WeaponBehaviour&) = delete; + WeaponBehaviour& operator=(const WeaponBehaviour &) = delete; + + virtual void Fire() = 0; + virtual void CeaseFire() { } + virtual void Reload() { } + virtual void Update(double dt) { } + +protected: + Octree* m_CollisionOctree; + EntityWrapper m_Entity; +}; + +class AssaultWeaponBehaviour : public WeaponBehaviour +{ +public: + AssaultWeaponBehaviour(SystemParams systemParams, Octree* collisionOctree, EntityWrapper weaponEntity) + : WeaponBehaviour(systemParams, collisionOctree, weaponEntity) + { } + + virtual void Fire() override + { + m_TimeSinceLastFire = 0.0; + m_Firing = true; + fireRound(); + } + + virtual void CeaseFire() override + { + m_Firing = false; + } + + virtual void Reload() override + { + ComponentWrapper& cAssaultWeapon = m_Entity["AssaultWeapon"]; + + int& magAmmo = cAssaultWeapon["MagazineAmmo"]; + int magSize = cAssaultWeapon["MagazineSize"]; + int& ammo = cAssaultWeapon["Ammo"]; + + // Don't reload if we're already fully loaded + if (magAmmo == magSize) { + return; + } + + // Throw away rounds in magazine to incentivise ammo sharing + int toLoad = glm::min(magSize, ammo); + magAmmo = toLoad; + ammo -= toLoad; + } + + virtual void Update(double dt) override + { + if (!m_Firing) { + return; + } + + m_TimeSinceLastFire += dt; + + ComponentWrapper& cAssaultWeapon = m_Entity["AssaultWeapon"]; + if (m_TimeSinceLastFire >= 1.0 / ((double)cAssaultWeapon["RPM"] / 60.0)) { + fireRound(); + } + } + +private: + bool m_Firing = false; + double m_TimeSinceLastFire = 0.0; + EntityFile* m_RayRed = nullptr; + EntityFile* m_RayBlue = nullptr; + + void fireRound() + { + ComponentWrapper& cAssaultWeapon = m_Entity["AssaultWeapon"]; + + int& magAmmo = cAssaultWeapon["MagazineAmmo"]; + int ammo = cAssaultWeapon["Ammo"]; + + // Reload if our magazine is empty + if (magAmmo <= 0) { + Reload(); + return; + } + + // Fire + magAmmo -= 1; + spawnTracer(); + playSound(); + + m_TimeSinceLastFire = 0.0; + } + + void spawnTracer() + { + if (!IsClient) { + return; + } + + EntityWrapper spawner; + if (m_Entity == LocalPlayer) { + spawner = m_Entity.FirstChildByName("WeaponMuzzle"); + } else { + spawner = m_Entity.FirstChildByName("ThirdPersonWeaponMuzzle"); + } + + if (!spawner.Valid()) { + return; + } + + Events::SpawnerSpawn e; + e.Spawner = spawner; + m_EventBroker->Publish(e); + } + + float traceRayDistance(glm::vec3 origin, glm::vec3 direction) + { + // TODO: Cast a ray and size tracer appropriately + return 100.f; + } + + void playSound() + { + if (!IsClient) { + return; + } + + Events::PlaySoundOnEntity e; + e.EmitterID = m_Entity.ID; + e.FilePath = "Audio/laser/laser1.wav"; + m_EventBroker->Publish(e); + } }; #endif \ No newline at end of file diff --git a/resources/DefaultConfig.ini b/resources/DefaultConfig.ini index 86dc735c..12ec06c8 100644 --- a/resources/DefaultConfig.ini +++ b/resources/DefaultConfig.ini @@ -29,3 +29,8 @@ TimeoutMs=15000 [Multithreading] ResourceLoading=true + +[Sound] +BGMVolume=1.0 +SFXVolume=1.0 +Announcer=female \ No newline at end of file diff --git a/resources/DefaultInput.ini b/resources/DefaultInput.ini index a3f7d166..683d48e2 100644 --- a/resources/DefaultInput.ini +++ b/resources/DefaultInput.ini @@ -2,6 +2,9 @@ Sensitivity=0.5 InvertPitch=false +[Keyboard] +DoubleTapToDash=false + [Bindings] MouseLeft=PrimaryFire MouseX=Yaw @@ -13,7 +16,10 @@ A=Right,-1 R=Reload Space=Jump LeftControl=Crouch -LeftShift=Sprint +RightShift=Sprint +LeftShift=SpecialAbility +1=SelectWeapon,1 +2=SelectWeapon,2 F1=ToggleEditor C=ConnectToServer N=SwitchToServer diff --git a/resources/Schema/Components.xsd b/resources/Schema/Components.xsd index d872e057..f950e8c8 100644 --- a/resources/Schema/Components.xsd +++ b/resources/Schema/Components.xsd @@ -11,6 +11,7 @@ + @@ -27,7 +28,15 @@ + + + + + + + + \ No newline at end of file diff --git a/resources/Schema/Components/AABB.xsd b/resources/Schema/Components/AABB.xsd index daa633a6..7dec510f 100644 --- a/resources/Schema/Components/AABB.xsd +++ b/resources/Schema/Components/AABB.xsd @@ -7,10 +7,10 @@ - Middle point of the bounding box + Middle point of the bounding box, in model space - Size of the bounding box + Size of the bounding box, in model space diff --git a/resources/Schema/Components/Animation.xml b/resources/Schema/Components/Animation.xml index 66d2865d..ae42009d 100644 --- a/resources/Schema/Components/Animation.xml +++ b/resources/Schema/Components/Animation.xml @@ -1,7 +1,18 @@ - - - 0 - true + + 1.0 + 0 + 0 + true + + 1.0 + 0 + 0 + true + + 1.0 + 0 + 0 + true \ No newline at end of file diff --git a/resources/Schema/Components/Animation.xsd b/resources/Schema/Components/Animation.xsd index 0dd21f29..f39aac18 100644 --- a/resources/Schema/Components/Animation.xsd +++ b/resources/Schema/Components/Animation.xsd @@ -6,11 +6,23 @@ - - - - + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/Schema/Components/AnimationOffset.xml b/resources/Schema/Components/AnimationOffset.xml new file mode 100644 index 00000000..4aef8219 --- /dev/null +++ b/resources/Schema/Components/AnimationOffset.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/resources/Schema/Components/AnimationOffset.xsd b/resources/Schema/Components/AnimationOffset.xsd new file mode 100644 index 00000000..c3430cc2 --- /dev/null +++ b/resources/Schema/Components/AnimationOffset.xsd @@ -0,0 +1,17 @@ + + + + + + + + Aim animation offset for the skeleton + + + + + + + + + \ No newline at end of file diff --git a/resources/Schema/Components/AssaultWeapon.xml b/resources/Schema/Components/AssaultWeapon.xml new file mode 100755 index 00000000..902795c1 --- /dev/null +++ b/resources/Schema/Components/AssaultWeapon.xml @@ -0,0 +1,9 @@ + + + 32 + 32 + 360 + 360 + 5 + 120 + \ No newline at end of file diff --git a/resources/Schema/Components/AssaultWeapon.xsd b/resources/Schema/Components/AssaultWeapon.xsd new file mode 100755 index 00000000..1b2704ea --- /dev/null +++ b/resources/Schema/Components/AssaultWeapon.xsd @@ -0,0 +1,28 @@ + + + + + + + + + + Ammo currently loaded into the magazine + + + Max number of rounds in a magazine + + + Current ammo carried + + + Maximum ammo able to be carried + + + + Rate of fire in rounds per minute + + + + + diff --git a/resources/Schema/Components/BoneAttachment.xml b/resources/Schema/Components/BoneAttachment.xml new file mode 100644 index 00000000..47df9e40 --- /dev/null +++ b/resources/Schema/Components/BoneAttachment.xml @@ -0,0 +1,10 @@ + + + + + + + true + true + false + \ No newline at end of file diff --git a/resources/Schema/Components/BoneAttachment.xsd b/resources/Schema/Components/BoneAttachment.xsd new file mode 100644 index 00000000..aee1868f --- /dev/null +++ b/resources/Schema/Components/BoneAttachment.xsd @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/Schema/Components/CapturePoint.xml b/resources/Schema/Components/CapturePoint.xml index ba164fd9..638b16c3 100644 --- a/resources/Schema/Components/CapturePoint.xml +++ b/resources/Schema/Components/CapturePoint.xml @@ -2,5 +2,6 @@ 0 0 + 15 \ No newline at end of file diff --git a/resources/Schema/Components/CapturePoint.xsd b/resources/Schema/Components/CapturePoint.xsd index fbdb3568..3c91dfdd 100644 --- a/resources/Schema/Components/CapturePoint.xsd +++ b/resources/Schema/Components/CapturePoint.xsd @@ -20,7 +20,11 @@ CapturePointNumber specify an int number for this - + + + The time needed to take over a Capture Point + + Specify if this is a HomePoint for either team diff --git a/resources/Schema/Components/CapturePointHUD.xml b/resources/Schema/Components/CapturePointHUD.xml new file mode 100644 index 00000000..2943d57b --- /dev/null +++ b/resources/Schema/Components/CapturePointHUD.xml @@ -0,0 +1,5 @@ + + + 0 + + \ No newline at end of file diff --git a/resources/Schema/Components/CapturePointHUD.xsd b/resources/Schema/Components/CapturePointHUD.xsd new file mode 100644 index 00000000..7984fc50 --- /dev/null +++ b/resources/Schema/Components/CapturePointHUD.xsd @@ -0,0 +1,24 @@ + + + + + + + Hud element for tracking capture points. + + + + + + Corresponds to the number on the capture point it should track. + + + + + Specify the team that own this capturePoint. + + + + + + \ No newline at end of file diff --git a/resources/Schema/Components/Collidable.xsd b/resources/Schema/Components/Collidable.xsd index 84c66f11..93f7ac24 100644 --- a/resources/Schema/Components/Collidable.xsd +++ b/resources/Schema/Components/Collidable.xsd @@ -4,5 +4,8 @@ + + Needs a Model or AABB component to work, uses AABB if both are attached. + \ No newline at end of file diff --git a/resources/Schema/Components/DashAbility.xml b/resources/Schema/Components/DashAbility.xml index 25b9e19a..a313c447 100644 --- a/resources/Schema/Components/DashAbility.xml +++ b/resources/Schema/Components/DashAbility.xml @@ -1,4 +1,4 @@ - + 2.0 - \ No newline at end of file + \ No newline at end of file diff --git a/resources/Schema/Components/HealthPickup.xml b/resources/Schema/Components/HealthPickup.xml new file mode 100644 index 00000000..1c9ee0f4 --- /dev/null +++ b/resources/Schema/Components/HealthPickup.xml @@ -0,0 +1,5 @@ + + + 3 + 30 + \ No newline at end of file diff --git a/resources/Schema/Components/HealthPickup.xsd b/resources/Schema/Components/HealthPickup.xsd new file mode 100644 index 00000000..bf3b327c --- /dev/null +++ b/resources/Schema/Components/HealthPickup.xsd @@ -0,0 +1,21 @@ + + + + + + + + A Health Pickup + + + + + The respawn timer for a health pickup + + + How much percent max-health the player will get when he picks the healthPickup up + + + + + diff --git a/resources/Schema/Components/Physics.xml b/resources/Schema/Components/Physics.xml index 9d1638fb..6cb73c75 100644 --- a/resources/Schema/Components/Physics.xml +++ b/resources/Schema/Components/Physics.xml @@ -2,4 +2,6 @@ true + false + 0.33 diff --git a/resources/Schema/Components/Physics.xsd b/resources/Schema/Components/Physics.xsd index 72037f48..7fed1fb5 100644 --- a/resources/Schema/Components/Physics.xsd +++ b/resources/Schema/Components/Physics.xsd @@ -13,6 +13,10 @@ m/s^2 + + + The largest height of a "stair-step" that can be walked over + diff --git a/resources/Schema/Components/SceneLight.xml b/resources/Schema/Components/SceneLight.xml new file mode 100644 index 00000000..80b6b9f4 --- /dev/null +++ b/resources/Schema/Components/SceneLight.xml @@ -0,0 +1,7 @@ + + + + true + 2.2 + 1 + \ No newline at end of file diff --git a/resources/Schema/Components/SceneLight.xsd b/resources/Schema/Components/SceneLight.xsd new file mode 100644 index 00000000..9f8a9705 --- /dev/null +++ b/resources/Schema/Components/SceneLight.xsd @@ -0,0 +1,25 @@ + + + + + + Some settings for the scene lighting + + + + + Color of the ambient light + + + Wether the ambient light should be applied or not + + + Gamma correction for the scene + + + The exposure of the camera + + + + + \ No newline at end of file diff --git a/resources/Schema/Components/Shield.xml b/resources/Schema/Components/Shield.xml new file mode 100644 index 00000000..161f09bc --- /dev/null +++ b/resources/Schema/Components/Shield.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/resources/Schema/Components/Shield.xsd b/resources/Schema/Components/Shield.xsd new file mode 100644 index 00000000..9831cbfc --- /dev/null +++ b/resources/Schema/Components/Shield.xsd @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/resources/Schema/Components/Shielded.xml b/resources/Schema/Components/Shielded.xml new file mode 100644 index 00000000..0d95fb0a --- /dev/null +++ b/resources/Schema/Components/Shielded.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/resources/Schema/Components/Shielded.xsd b/resources/Schema/Components/Shielded.xsd new file mode 100644 index 00000000..b2348cf5 --- /dev/null +++ b/resources/Schema/Components/Shielded.xsd @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/resources/Schema/Components/Sprite.xml b/resources/Schema/Components/Sprite.xml new file mode 100644 index 00000000..ce4a6e1b --- /dev/null +++ b/resources/Schema/Components/Sprite.xml @@ -0,0 +1,8 @@ + + + + + + true + true + diff --git a/resources/Schema/Components/Sprite.xsd b/resources/Schema/Components/Sprite.xsd new file mode 100644 index 00000000..3c3d124a --- /dev/null +++ b/resources/Schema/Components/Sprite.xsd @@ -0,0 +1,30 @@ + + + + + + + + A sprite that will be facing the camera + + + + + Diffuse Texture file + + + GlowMap file + + + Color tint + + + Whether the model is visible or not + + + Whether the sprite should be sorted with depth or not. Only use false for textures that are on HUD + + + + + \ No newline at end of file diff --git a/resources/Schema/Components/Transform.xsd b/resources/Schema/Components/Transform.xsd index f0db2472..555b336c 100644 --- a/resources/Schema/Components/Transform.xsd +++ b/resources/Schema/Components/Transform.xsd @@ -4,9 +4,6 @@ - - It's a transform thingy! - @@ -15,6 +12,7 @@ + diff --git a/resources/Schema/Components/Trigger.xsd b/resources/Schema/Components/Trigger.xsd index a8bc8865..8119b966 100644 --- a/resources/Schema/Components/Trigger.xsd +++ b/resources/Schema/Components/Trigger.xsd @@ -4,5 +4,8 @@ + + Needs a Model or AABB component to work, uses AABB if both are attached. + \ No newline at end of file diff --git a/resources/Schema/Components/Weapon.xml b/resources/Schema/Components/Weapon.xml new file mode 100644 index 00000000..38c6fce9 --- /dev/null +++ b/resources/Schema/Components/Weapon.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/resources/Schema/Components/Weapon.xsd b/resources/Schema/Components/Weapon.xsd new file mode 100644 index 00000000..8bddd8a9 --- /dev/null +++ b/resources/Schema/Components/Weapon.xsd @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/Schema/Entities/AnimatedArmy.xml b/resources/Schema/Entities/AnimatedArmy.xml index b711a0fe..67accc40 100644 --- a/resources/Schema/Entities/AnimatedArmy.xml +++ b/resources/Schema/Entities/AnimatedArmy.xml @@ -20,7 +20,7 @@ - models/dummyscene.mesh + Models/Test/DummyScene.mesh @@ -31,7 +31,7 @@ - models/animtest. + Models/Test/AnimTest.mesh @@ -42,7 +42,7 @@ - models/animTest.mesh + Models/Test/AnimTest.mesh @@ -53,7 +53,7 @@ - models/animTest.mesh + Models/Test/AnimTest.mesh @@ -64,7 +64,7 @@ - models/animTest.mesh + Models/Test/AnimTest.mesh @@ -91,7 +91,7 @@ - + @@ -154,7 +154,7 @@ - + diff --git a/resources/Schema/Entities/AnimationTests.xml b/resources/Schema/Entities/AnimationTests.xml new file mode 100644 index 00000000..77c87e64 --- /dev/null +++ b/resources/Schema/Entities/AnimationTests.xml @@ -0,0 +1,377 @@ + + + + + + + + + + + + Models/Core/UnitPlane.mesh + + + + + + + + + + + + + Models/DirectionalLightWidget.mesh + + + + + + + + + + + + Crouch + + 1 + + + Models/Asstest.mesh + + + + + + + + + + R_Leg_Top + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + R_Leg_Bottom + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + R_Foot + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + L_Foot + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + L_Leg_Bottom + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + L_Leg_Top + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + Hip + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + Spine_1 + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + Spine_2 + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + Spine_3 + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + Neck + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + R_Shoulder + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + R_Arm + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + R_Elbow + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + R_Hand + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + Chin + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + L_Hand + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + L_Elbow + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + + diff --git a/resources/Schema/Entities/AnimationTests2.xml b/resources/Schema/Entities/AnimationTests2.xml new file mode 100644 index 00000000..6536a839 --- /dev/null +++ b/resources/Schema/Entities/AnimationTests2.xml @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + Models/Widgets/Lights/DirectionalLightWidget.mesh + + + + + + + + + + + + Run + 0.5 + 0.78014858943309839 + 1 + 1 + StrafeRight + 0.5 + 0.78620929522779459 + ShootFastRifle + 0.13809128482706701 + 1 + + + AimRifle + + + + Models/Characters/Assault/AssaultAnimations.mesh + + true + + + + + + + + + + R_Arm_Weapon_Joint + + + + Models/Weapons/Blue/AssaultWeapon.mesh + + true + + + + + + + + + + + + + + 10 + + + + + + + + + + + Models/Core/UnitPlane.mesh + + + + + + + + + + + + diff --git a/resources/Schema/Entities/AnimationTests3.xml b/resources/Schema/Entities/AnimationTests3.xml new file mode 100644 index 00000000..bd985b2d --- /dev/null +++ b/resources/Schema/Entities/AnimationTests3.xml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + Models/Widgets/Lights/DirectionalLightWidget.mesh + + + + + + + + + + + + Run + 0.5 + 0.97312056690160276 + 1 + 1 + ReloadSwitch + 0.91310356788604263 + LeftRight + 0 + 0.040207288496060478 + 1 + + + DownUp + + + + Models/Characters/Assault/FirstPerson.mesh + + true + + + + + + + + + + R_Arm_Weapon_Joint + + + Models/Weapons/Blue/AssaultWeapon.mesh + + + + + + + + + + + + + + + + + + + + + 10 + + + + + + + + + + + Models/Core/UnitPlane.mesh + + + + + + + + + + + + diff --git a/resources/Schema/Entities/AssetPedistal.xml b/resources/Schema/Entities/AssetPedistal.xml new file mode 100644 index 00000000..3c816149 --- /dev/null +++ b/resources/Schema/Entities/AssetPedistal.xml @@ -0,0 +1,51 @@ + + + + + + Models/Core/UnitCylinder.mesh + + + + + + + + + + + + + + + + + + + + + 0.5 + + + + + + + + + + + Models/Weapons/Blue/AssaultWeaponBlue.mesh + + + + + + + + + + + + + diff --git a/resources/Schema/Entities/BoneMarker b/resources/Schema/Entities/BoneMarker new file mode 100644 index 00000000..eda56d56 --- /dev/null +++ b/resources/Schema/Entities/BoneMarker @@ -0,0 +1,22 @@ + + + + + + R_Leg_Top + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + diff --git a/resources/Schema/Entities/CapturePoint.xml b/resources/Schema/Entities/CapturePoint.xml index 9b3c5036..9f33c4de 100644 --- a/resources/Schema/Entities/CapturePoint.xml +++ b/resources/Schema/Entities/CapturePoint.xml @@ -5,7 +5,7 @@ - C:\Users\123456\Workspace\TacticalZ\assets\Models\Core\UnitSphere.mesh + Models/Core/UnitSphere.mesh diff --git a/resources/Schema/Entities/CapturePointHUDGroup b/resources/Schema/Entities/CapturePointHUDGroup new file mode 100644 index 00000000..9dce0ffb --- /dev/null +++ b/resources/Schema/Entities/CapturePointHUDGroup @@ -0,0 +1,172 @@ + + + + + + + + + + + + + + Textures/Core/UnitHexagon.png + + + + + + + + + + + 2 + + + + + + Textures/Core/UnitHexagon_Rotated.png + + + + + + + + + + + + + + + Textures/Core/UnitHexagon.png + + + + + + + + + + + 3 + + + 0.80222018197612788 + + + + Textures/Core/UnitHexagon_Rotated.png + + + + + + + + + + + + + + + Textures/Core/UnitHexagon.png + + + + + + + + + + + 4 + + + + + + Textures/Core/UnitHexagon_Rotated.png + + + + + + + + + + + + + + + Textures/Core/UnitHexagon.png + + + + + + + + + + + 1 + + + + + + Textures/Core/UnitHexagon_Rotated.png + + + + + + + + + + + + + + + Textures/Core/UnitHexagon.png + + + + + + + + + + + + + + + Textures/Core/UnitHexagon_Rotated.png + + + + + + + + + + + + + + diff --git a/resources/Schema/Entities/CapturePointHUDHexagon.xml b/resources/Schema/Entities/CapturePointHUDHexagon.xml new file mode 100644 index 00000000..68cf42a7 --- /dev/null +++ b/resources/Schema/Entities/CapturePointHUDHexagon.xml @@ -0,0 +1,34 @@ + + + + + + Textures/Core/UnitHexagon.png + + + + + + + + + + + + + 0.5 + + + Textures/Core/UnitHexagon_Rotated.png + + + + + + + + + + + + diff --git a/resources/Schema/Entities/CaptureTest.xml b/resources/Schema/Entities/CaptureTest.xml index 5f657e51..3d678bd7 100644 --- a/resources/Schema/Entities/CaptureTest.xml +++ b/resources/Schema/Entities/CaptureTest.xml @@ -9,7 +9,7 @@ - ../assets/Models/DummyScene.mesh + Models/Test/DummyScene.mesh @@ -41,7 +41,7 @@ 3 - ../assets/Models/Core/UnitSphere.mesh + Models/Core/UnitSphere.mesh @@ -61,7 +61,7 @@ 1 - ../assets/Models/Core/UnitSphere.mesh + Models/Core/UnitSphere.mesh @@ -81,7 +81,7 @@ 2 - ../assets/Models/Core/UnitSphere.mesh + Models/Core/UnitSphere.mesh @@ -102,7 +102,7 @@ 3 - ../assets/Models/Core/UnitSphere.mesh + Models/Core/UnitSphere.mesh @@ -120,7 +120,7 @@ - ../assets/Models/Core/UnitCube.mesh + Models/Core/UnitCube.mesh @@ -138,7 +138,7 @@ - ../assets/Models/Core/UnitCube.mesh + Models/Core/UnitCube.mesh diff --git a/resources/Schema/Entities/CaptureTestState1.xml b/resources/Schema/Entities/CaptureTestState1.xml index ffabd5c2..64999074 100644 --- a/resources/Schema/Entities/CaptureTestState1.xml +++ b/resources/Schema/Entities/CaptureTestState1.xml @@ -9,7 +9,7 @@ - ../assets/Models/DummyScene.mesh + Models/Test/DummyScene.mesh @@ -42,7 +42,7 @@ 6.9158446328696002 - ../assets/Models/Core/UnitSphere.mesh + Models/Core/UnitSphere.mesh @@ -63,7 +63,7 @@ 1 - ../assets/Models/Core/UnitSphere.mesh + Models/Core/UnitSphere.mesh @@ -83,7 +83,7 @@ 2 - ../assets/Models/Core/UnitSphere.mesh + Models/Core/UnitSphere.mesh @@ -104,7 +104,7 @@ 3 - ../assets/Models/Core/UnitSphere.mesh + Models/Core/UnitSphere.mesh @@ -122,7 +122,7 @@ - ../assets/Models/Core/UnitCube.mesh + Models/Core/UnitCube.mesh @@ -140,7 +140,7 @@ - ../assets/Models/Core/UnitCube.mesh + Models/Core/UnitCube.mesh diff --git a/resources/Schema/Entities/CaptureTestState2.xml b/resources/Schema/Entities/CaptureTestState2.xml index 29abdfbd..6ddb306f 100644 --- a/resources/Schema/Entities/CaptureTestState2.xml +++ b/resources/Schema/Entities/CaptureTestState2.xml @@ -9,7 +9,7 @@ - ../assets/Models/DummyScene.mesh + Models/Test/DummyScene.mesh @@ -41,7 +41,7 @@ 3 - ../assets/Models/Core/UnitSphere.mesh + Models/Core/UnitSphere.mesh @@ -61,7 +61,7 @@ 1 - ../assets/Models/Core/UnitSphere.mesh + Models/Core/UnitSphere.mesh @@ -79,7 +79,7 @@ 2 - ../assets/Models/Core/UnitSphere.mesh + Models/Core/UnitSphere.mesh @@ -98,7 +98,7 @@ 3 - ../assets/Models/Core/UnitSphere.mesh + Models/Core/UnitSphere.mesh @@ -116,7 +116,7 @@ - ../assets/Models/Core/UnitCube.mesh + Models/Core/UnitCube.mesh @@ -134,7 +134,7 @@ - ../assets/Models/Core/UnitCube.mesh + Models/Core/UnitCube.mesh diff --git a/resources/Schema/Entities/CaptureTestState3.xml b/resources/Schema/Entities/CaptureTestState3.xml index ff875dc4..3bed3624 100644 --- a/resources/Schema/Entities/CaptureTestState3.xml +++ b/resources/Schema/Entities/CaptureTestState3.xml @@ -9,7 +9,7 @@ - ../assets/Models/DummyScene.mesh + Models/Test/DummyScene.mesh @@ -41,7 +41,7 @@ 3 - ../assets/Models/Core/UnitSphere.mesh + Models/Core/UnitSphere.mesh @@ -61,7 +61,7 @@ 1 - ../assets/Models/Core/UnitSphere.mesh + Models/Core/UnitSphere.mesh @@ -81,7 +81,7 @@ 2 - ../assets/Models/Core/UnitSphere.mesh + Models/Core/UnitSphere.mesh @@ -101,7 +101,7 @@ 3 - ../assets/Models/Core/UnitSphere.mesh + Models/Core/UnitSphere.mesh @@ -122,7 +122,7 @@ 4 - ../assets/Models/Core/UnitSphere.mesh + Models/Core/UnitSphere.mesh @@ -140,7 +140,7 @@ - ../assets/Models/Core/UnitCube.mesh + Models/Core/UnitCube.mesh @@ -158,7 +158,7 @@ - ../assets/Models/Core/UnitCube.mesh + Models/Core/UnitCube.mesh @@ -176,7 +176,7 @@ - ../assets/Models/Core/UnitCube.mesh + Models/Core/UnitCube.mesh @@ -194,7 +194,7 @@ - ../assets/Models/Core/UnitCube.mesh + Models/Core/UnitCube.mesh diff --git a/resources/Schema/Entities/CaptureTestState4.xml b/resources/Schema/Entities/CaptureTestState4.xml index 740d7e7b..30db23aa 100644 --- a/resources/Schema/Entities/CaptureTestState4.xml +++ b/resources/Schema/Entities/CaptureTestState4.xml @@ -9,7 +9,7 @@ - ../assets/Models/DummyScene.mesh + Models/Test/DummyScene.mesh @@ -41,7 +41,7 @@ 3 - ../assets/Models/Core/UnitSphere.mesh + Models/Core/UnitSphere.mesh @@ -61,7 +61,7 @@ 1 - ../assets/Models/Core/UnitSphere.mesh + Models/Core/UnitSphere.mesh @@ -79,7 +79,7 @@ 2 - ../assets/Models/Core/UnitSphere.mesh + Models/Core/UnitSphere.mesh @@ -96,7 +96,7 @@ 3 - ../assets/Models/Core/UnitSphere.mesh + Models/Core/UnitSphere.mesh @@ -115,7 +115,7 @@ 4 - ../assets/Models/Core/UnitSphere.mesh + Models/Core/UnitSphere.mesh @@ -133,7 +133,7 @@ - ../assets/Models/Core/UnitCube.mesh + Models/Core/UnitCube.mesh @@ -151,7 +151,7 @@ - ../assets/Models/Core/UnitCube.mesh + Models/Core/UnitCube.mesh @@ -169,7 +169,7 @@ - ../assets/Models/Core/UnitCube.mesh + Models/Core/UnitCube.mesh @@ -187,7 +187,7 @@ - ../assets/Models/Core/UnitCube.mesh + Models/Core/UnitCube.mesh diff --git a/resources/Schema/Entities/CaptureTestState5.xml b/resources/Schema/Entities/CaptureTestState5.xml index f1b07a7b..c733706c 100644 --- a/resources/Schema/Entities/CaptureTestState5.xml +++ b/resources/Schema/Entities/CaptureTestState5.xml @@ -2,12 +2,246 @@ - - - + + + + + + + + + Models/LevelBase/MapVersion1.mesh + + + + + + + + + 2 + + + Models/Widgets/Lights/DirectionalLightWidget.mesh + false + + + + + + + + + + + + + 8 + 2.7999999523162842 + + + + + + + + + + + 8 + 2.7999999523162842 + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + Models/Core/UnitCube.mesh + false + + + Schema/Entities/Player.xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Models/Core/UnitCube.mesh + false + + + Schema/Entities/Player.xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -15,10 +249,12 @@ + 15 - C:\Users\123456\Workspace\TacticalZ\assets\Models\Core\UnitSphere.mesh - + Models/Core/UnitSphere.mesh + + true @@ -26,7 +262,7 @@ - + @@ -39,12 +275,13 @@ 1 - C:\Users\123456\Workspace\TacticalZ\assets\Models\Core\UnitSphere.mesh - + Models/Core/UnitSphere.mesh + + true - + @@ -57,16 +294,13 @@ 2 - C:\Users\123456\Workspace\TacticalZ\assets\Models\Core\UnitSphere.mesh - + Models/Core/UnitSphere.mesh + + true - - - - - + - + @@ -76,11 +310,13 @@ + -15 3 - C:\Users\123456\Workspace\TacticalZ\assets\Models\Core\UnitSphere.mesh - + Models/Core/UnitSphere.mesh + + true @@ -88,7 +324,7 @@ - + @@ -101,11 +337,13 @@ + -15 4 - C:\Users\123456\Workspace\TacticalZ\assets\Models\Core\UnitSphere.mesh - + Models/Core/UnitSphere.mesh + + true @@ -113,61 +351,12 @@ - + - - - - - - C:\Users\123456\Workspace\TacticalZ\assets\Models\Core\UnitCube.mesh - - - - - - - - - - - - - - - - - - - C:\Users\123456\Workspace\TacticalZ\assets\Models\Core\UnitCube.mesh - - - - - - - - - - - - - - - - - C:\Users\123456\Workspace\TacticalZ\assets\Models\DummyScene.mesh - - - - - - - diff --git a/resources/Schema/Entities/CollisionSpawnTest.xml b/resources/Schema/Entities/CollisionSpawnTest.xml new file mode 100644 index 00000000..331beae6 --- /dev/null +++ b/resources/Schema/Entities/CollisionSpawnTest.xml @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + ../assets/Models/Test/ObstacleCourse.mesh + + + + + + + + + + + 0.46000027656555176 + + + + + + + + + + + + + ../assets/Models/Core/UnitCube.mesh + + + + + + + + + + + + + Models/Core/UnitCube.mesh + false + + + Schema/Entities/Player.xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Models/Core/UnitCube.mesh + false + + + Schema/Entities/Player.xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/Schema/Entities/CollisionTestLevel.xml b/resources/Schema/Entities/CollisionTestLevel.xml index e58ab6ce..66b1109f 100644 --- a/resources/Schema/Entities/CollisionTestLevel.xml +++ b/resources/Schema/Entities/CollisionTestLevel.xml @@ -1,122 +1,67 @@ - + + - - - - - - - Models/DummyScene.mesh - - - - - - - - - - - Models/Core/UnitSphere.mesh - - - - - - - - - - - Models/RotationWidgetX.mesh - - - - - - - - - - - - - - - Models/Core/UnitCube.mesh - - - - - - - - - - - - - - - - - - - - - - Models/Core/UnitRaptor.mesh - - - - - - - - - - - - 20 - - - - - - - - - - - - - Models/Core/UnitCube.mesh - - - - - - - - - - - - - Models/Core/UnitCube.mesh - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + ../assets/Models/Test/ObstacleCourse.mesh + + + + + + + + + + + 0.46000027656555176 + + + + + + + + + + + + + ../assets/Models/Core/UnitCube.mesh + + + false + + + + + + + + + + + + + + + ../assets/Models/Core/colorbox.mesh + + + + + + + + + + + diff --git a/resources/Schema/Entities/DamageIndicator.xml b/resources/Schema/Entities/DamageIndicator.xml new file mode 100644 index 00000000..3e9e4fef --- /dev/null +++ b/resources/Schema/Entities/DamageIndicator.xml @@ -0,0 +1,22 @@ + + + + + + Textures/DamageIndicator.png + + false + + + + + + + + 1.5 + + + + + + diff --git a/resources/Schema/Entities/DamageIndicatorTest.xml b/resources/Schema/Entities/DamageIndicatorTest.xml new file mode 100644 index 00000000..1155ddd5 --- /dev/null +++ b/resources/Schema/Entities/DamageIndicatorTest.xml @@ -0,0 +1,426 @@ + + + + + + + + + + + + + + + Models\MapVersion1.mesh + + + + + + + + + 2 + + + Models/DirectionalLightWidget.mesh + false + + + + + + + + + + + + + 8 + 2.7999999523162842 + + + + + + + + + + + 8 + 2.7999999523162842 + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + Models/Core/UnitCube.mesh + false + + + Schema/Entities/Player.xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Models/Core/UnitCube.mesh + false + + + Schema/Entities/Player.xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 99 + + + + + + 5 + + + + + + + + + + + + + + + + + + + + + + + Fonts/DroidSans.ttf,100 + + + + + + + + + + + + + + Models/Camera.mesh + false + + + + + + + + + + + + + + + + + + + 0.99000000953674316 + + + + + Models/Core/UnitHexagon.mesh + + + + + + + + + + + + + + Models/CrosshairQuad.mesh + + + + + + + + + + + + + Models/AssaultWeaponRed.mesh + + + + + + + + + + + + + + + + + + + + + + + + + Models/Camera.mesh + false + + + + + + + + + + + + + + Models/Characters/Assault/AssaultAnimations.mesh + + + + + + + + + + Models/Core/UnitCube.mesh + + false + + + + + + + + + + + + Models/Core/UnitCube.mesh + + false + + + + + + + + + + + + diff --git a/resources/Schema/Entities/DoubleJumpHexagon.xml b/resources/Schema/Entities/DoubleJumpHexagon.xml new file mode 100644 index 00000000..c1aaec34 --- /dev/null +++ b/resources/Schema/Entities/DoubleJumpHexagon.xml @@ -0,0 +1,30 @@ + + + + + + Models/Effects/JumpEffectHexagon.mesh + + true + + + + + + + 0.5 + + + true + + + true + 0.5 + + true + + + + + + diff --git a/resources/Schema/Entities/EditorTestWorld.xml b/resources/Schema/Entities/EditorTestWorld.xml index 9565e2d4..46e6d54d 100755 --- a/resources/Schema/Entities/EditorTestWorld.xml +++ b/resources/Schema/Entities/EditorTestWorld.xml @@ -2,7 +2,9 @@ - + + + @@ -18,7 +20,7 @@ - + @@ -35,23 +37,32 @@ 0.80000001192092896 - Models/DirectionalLightWidget.mesh + Models/Widgets/Lights/DirectionalLightWidget.mesh - 1.0499999523162842 + 1 - + + + true + + + 5.0498686575577523 + 5 + + 3 + - Models/Assault.mesh + Models/Characters/Assault/AssaultTPose.mesh @@ -62,11 +73,26 @@ - Models/SecondaryWeapon.mesh + Models/Weapons/Red/AssaultWeaponRed.mesh + true - - + + + + + + + + + + Models/Weapons/Red/DefenderGunRed.mesh + true + false + + + + @@ -85,11 +111,11 @@ Run - + 1 - models/AssaultAnimated.mesh + Models/Characters/Assault/AssaultAnimated.mesh @@ -101,11 +127,11 @@ Walk - + 1 - models/AssaultAnimated.mesh + Models/Characters/Assault/AssaultAnimated.mesh @@ -131,7 +157,7 @@ - Models/Log.mesh + Models/Props/TreeLog.mesh @@ -147,74 +173,10 @@ - - - - Models/NormalMapSphere.mesh - - - - - - - - - - - Models/SpecularMapSphere.mesh - - - - - - - - - - 1 - - - - - - - - - - - Models/Core/UnitSphere.mesh - - - - 3 - 1.1399998664855957 - - - - - - - - - - - - - - - - Models/IncandescenceMapSphere.mesh - - - - - - - - models/NormSpecIncdMapSphere.mesh + Models/Test/NormSpecIncdMapSphere.mesh @@ -227,7 +189,7 @@ - + @@ -284,8 +246,94 @@ + + + + 1 + + + + + + + + + + + Models/Test/NormalMapSphere.mesh + + + + + + + + + + + Models/Test/SpecularMapSphere.mesh + + + + + + + + + + 1 + + + + + + + + + + + Models/Core/UnitSphere.mesh + + + + 3 + 1.1399998664855957 + + + + + + + + + + + + + + + + Models/Test/IncandescenceMapSphere.mesh + + + + + + + + + + + + + 1.3999999761581421 + + + + + diff --git a/resources/Schema/Entities/EditorWidgetRotate.xml b/resources/Schema/Entities/EditorWidgetRotate.xml index 88452aac..1276f3e4 100644 --- a/resources/Schema/Entities/EditorWidgetRotate.xml +++ b/resources/Schema/Entities/EditorWidgetRotate.xml @@ -18,7 +18,7 @@ - Models/RotationWidgetX.mesh + Models/Widgets/Rotate/RotationWidgetX.mesh @@ -33,7 +33,7 @@ - Models/RotationWidgetY.mesh + Models/Widgets/Rotate/RotationWidgetY.mesh @@ -48,7 +48,7 @@ - Models/RotationWidgetZ.mesh + Models/Widgets/Rotate/RotationWidgetZ.mesh diff --git a/resources/Schema/Entities/EditorWidgetScale.xml b/resources/Schema/Entities/EditorWidgetScale.xml index 786b079e..65cb2b86 100644 --- a/resources/Schema/Entities/EditorWidgetScale.xml +++ b/resources/Schema/Entities/EditorWidgetScale.xml @@ -3,7 +3,7 @@ - Models/ScaleWidgetOrigin.mesh + Models/Widgets/Scale/ScalingWidgetOrigin.mesh @@ -20,7 +20,7 @@ - Models/ScaleWidgetX.mesh + Models/Widgets/Scale/ScalingWidgetX.mesh @@ -34,7 +34,7 @@ - Models/ScaleWidgetY.mesh + Models/Widgets/Scale/ScalingWidgetY.mesh @@ -48,7 +48,7 @@ - Models/ScaleWidgetZ.mesh + Models/Widgets/Scale/ScalingWidgetZ.mesh diff --git a/resources/Schema/Entities/EditorWidgetTranslate.xml b/resources/Schema/Entities/EditorWidgetTranslate.xml index d4ed5e76..e177b7e9 100644 --- a/resources/Schema/Entities/EditorWidgetTranslate.xml +++ b/resources/Schema/Entities/EditorWidgetTranslate.xml @@ -3,7 +3,7 @@ - Models/TranslationWidgetOrigin.mesh + Models/Widgets/Translate/TranslationWidgetOrigin.mesh @@ -18,7 +18,7 @@ - Models/TranslationWidgetX.mesh + Models/Widgets/Translate/TranslationWidgetX.mesh @@ -30,7 +30,7 @@ - Models/TranslationWidgetY.mesh + Models/Widgets/Translate/TranslationWidgetY.mesh @@ -42,7 +42,7 @@ - Models/TranslationWidgetZ.mesh + Models/Widgets/Translate/TranslationWidgetZ.mesh @@ -54,7 +54,7 @@ - Models/WidgetPlaneX.mesh + Models/Widgets/Translate/TranslationWidgetPlaneX.mesh @@ -66,7 +66,7 @@ - Models/WidgetPlaneY.mesh + Models/Widgets/Translate/TranslationWidgetPlaneY.mesh @@ -78,21 +78,12 @@ - Models/WidgetPlaneZ.mesh + Models/Widgets/Translate/TranslationWidgetPlaneZ.mesh - - - - - - - - - diff --git a/resources/Schema/Entities/FastWorld.xml b/resources/Schema/Entities/FastWorld.xml index 1289d9d1..94df077d 100644 --- a/resources/Schema/Entities/FastWorld.xml +++ b/resources/Schema/Entities/FastWorld.xml @@ -3,7 +3,7 @@ - + @@ -18,23 +18,17 @@ - + - Run - - 1 + Crouch Walk + + 8 - - - - 0.95625903442123672 - - Models/AssaultAnimated.mesh diff --git a/resources/Schema/Entities/FirstPersonArms b/resources/Schema/Entities/FirstPersonArms new file mode 100644 index 00000000..bf749a4e --- /dev/null +++ b/resources/Schema/Entities/FirstPersonArms @@ -0,0 +1,57 @@ + + + + + + Run + 0.5 + 0.97312056690160276 + 1 + 1 + ReloadSwitch + 0.91310356788604263 + LeftRight + 0 + 0.040207288496060478 + 1 + + + DownUp + + + + Models/Characters/Assault/FirstPerson.mesh + + true + + + + + + + + + + + R_Arm_Weapon_Joint + + + Models/Weapons/Blue/AssaultWeapon.mesh + + + + + + + + + + + + + + + + + + diff --git a/resources/Schema/Entities/GameMap.xml b/resources/Schema/Entities/GameMap.xml index 97fd3f4d..84a1e363 100644 --- a/resources/Schema/Entities/GameMap.xml +++ b/resources/Schema/Entities/GameMap.xml @@ -8,8 +8,13 @@ + + + + + - Models\MapVersion1.mesh + Models/LevelBase/MapVersion1.mesh @@ -21,7 +26,7 @@ 2 - Models/DirectionalLightWidget.mesh + Models/Widgets/Lights/DirectionalLightWidget.mesh false @@ -139,7 +144,7 @@ - + @@ -201,7 +206,7 @@ - + diff --git a/resources/Schema/Entities/HealthPickup.xml b/resources/Schema/Entities/HealthPickup.xml new file mode 100644 index 00000000..dfc6f938 --- /dev/null +++ b/resources/Schema/Entities/HealthPickup.xml @@ -0,0 +1,18 @@ + + + + + + + + Models/Core/UnitSphere.mesh + + + + + + + + + + diff --git a/resources/Schema/Entities/HealthPickupTest.xml b/resources/Schema/Entities/HealthPickupTest.xml new file mode 100644 index 00000000..2980fb51 --- /dev/null +++ b/resources/Schema/Entities/HealthPickupTest.xml @@ -0,0 +1,294 @@ + + + + + + + + + + + + Models\MapVersion1.mesh + + + + + + + + + 2 + + + Models/DirectionalLightWidget.mesh + false + + + + + + + + + + + + + 8 + 2.7999999523162842 + + + + + + + + + + + 8 + 2.7999999523162842 + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + Models/Core/UnitCube.mesh + false + + + Schema/Entities/Player.xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Models/Core/UnitCube.mesh + false + + + Schema/Entities/Player.xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + 22 + + + Models/Core/UnitSphere.mesh + + + + + + + + + + + + + 1 + 22 + + + Models/Core/UnitSphere.mesh + + + + + + + + + + + + + 4 + 44 + + + Models/Core/UnitSphere.mesh + + + + + + + + + + + diff --git a/resources/Schema/Entities/LevelCollisionTest.xml b/resources/Schema/Entities/LevelCollisionTest.xml new file mode 100644 index 00000000..3c3f3bab --- /dev/null +++ b/resources/Schema/Entities/LevelCollisionTest.xml @@ -0,0 +1,41 @@ + + + + + + + ../assets/Models/MapVersion1.mesh + + + + + + + + + + + ../assets/Models/Core/UnitCube.mesh + + + false + + + + + + + + + + + + + + + + + + + + diff --git a/resources/Schema/Entities/Model.xml b/resources/Schema/Entities/Model.xml index 57856cbd..bee6b7e1 100644 --- a/resources/Schema/Entities/Model.xml +++ b/resources/Schema/Entities/Model.xml @@ -19,7 +19,7 @@ - models/animTest.mesh + Models/Test/AnimTest.mesh diff --git a/resources/Schema/Entities/ModelCollisionTest.xml b/resources/Schema/Entities/ModelCollisionTest.xml new file mode 100644 index 00000000..c4a3f81b --- /dev/null +++ b/resources/Schema/Entities/ModelCollisionTest.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + ../assets/Models/Core/Tri.obj + + + + + + + + + + + + ../assets/Models/Core/Tri.obj + + + + + + + + + + + + + + + + ../assets/Models/Core/UnitCube.obj + + + + + + + + + + + diff --git a/resources/Schema/Entities/MovementTest.xml b/resources/Schema/Entities/MovementTest.xml index 1378f623..16a28684 100644 --- a/resources/Schema/Entities/MovementTest.xml +++ b/resources/Schema/Entities/MovementTest.xml @@ -6,22 +6,6 @@ - - - - - - Models/Core/UnitCube.mesh - - false - - - - - - - - @@ -42,7 +26,7 @@ - Models/Assault.mesh + Models/Characters/Assault/AssaultTPose.mesh @@ -55,7 +39,7 @@ - Models/Assault.mesh + Models/Characters/Assault/AssaultTPose.mesh @@ -68,9 +52,10 @@ + - Models/DirectionalLightWidget.mesh + sModels/Widgets/Lights/DirectionalLightWidget.mesh @@ -81,6 +66,7 @@ + Models/Test/ObstacleCourse.mesh @@ -88,51 +74,6 @@ - - - - - - Models/Core/UnitCube.mesh - false - - - - - - - - - - - - - - Models/Core/UnitCube.mesh - false - - - - - - - - - - - - - - Models/Core/UnitCube.mesh - false - - - - - - - - @@ -153,7 +94,7 @@ - Models/Assault.mesh + Models/Characters/Assault/AssaultTPose.mesh @@ -166,7 +107,7 @@ - Models/Assault.mesh + Models/Characters/Assault/AssaultTPose.mesh @@ -197,7 +138,7 @@ - + @@ -228,7 +169,7 @@ - Models/Camera.mesh + Models/Widgets/Camera.mesh @@ -243,7 +184,7 @@ - Models/Camera.mesh + Models/Widgets/Camera.mesh false @@ -256,7 +197,7 @@ - Models/AssaultHeadless.mesh + Models/Characters/Assault/AssaultHeadless.mesh diff --git a/resources/Schema/Entities/NewMap.xml b/resources/Schema/Entities/NewMap.xml new file mode 100644 index 00000000..a79fee7b --- /dev/null +++ b/resources/Schema/Entities/NewMap.xml @@ -0,0 +1,2396 @@ + + + + + + + + + + + + + + + + + + Models/Props/Ground.mesh + + + + + + + + + Models/Props/Highground1.mesh + + + + + + + + + + Models/Props/Highground2.mesh + + + + + + + + + + Models/Props/Highground1.mesh + + + + + + + + + + + + Models/Props/Highground2.mesh + + + + + + + + + + + + Models/Props/Highground3.mesh + + + + + + + + + + Models/Props/Highground4.mesh + + + + + + + + + + Models/Props/Highground5.mesh + + + + + + + + + + Models/Props/Highground6.mesh + + + + + + + + + + + + + + + + + + Models/Props/Pillars/SciFiPillar1.mesh + + + + + + + + + + + + + + Models/Props/Pillars/SciFiPillar1.mesh + + + + + + + + + + + + + + Models/Props/Pillars/StonePillar.mesh + + + + + + + + + + + + Models/Props/Pillars/StonePillar.mesh + + + + + + + + + + + + + Models/Props/Pillars/SciFiPillar2.mesh + + + + + + + + + + + + + Models/Props/Pillars/SciFiPillar3.mesh + + + + + + + + + + + + + + Models/Props/Pillars/SciFiPillar1.mesh + + + + + + + + + + + + + + Models/Props/Pillars/SciFiPillar1.mesh + + + + + + + + + + + + + + Models/Props/Pillars/SciFiPillar3.mesh + + + + + + + + + + + + + + Models/Props/Pillars/StonePillar.mesh + + + + + + + + + + + + Models/Props/Pillars/StonePillar.mesh + + + + + + + + + + + + + Models/Props/Pillars/StonePillar.mesh + + + + + + + + + + + + + Models/Props/Pillars/SciFiPillar2.mesh + + + + + + + + + + + + + Models/Props/Pillars/SciFiPillar2.mesh + + + + + + + + + + + + + Models/Props/Pillars/StonePillar.mesh + + + + + + + + + + + Models/Props/Pillars/StonePillar.mesh + + + + + + + + + + + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + + + + Models/Props/Walls/MediumWall3.mesh + + + + + + + + + + + + Models/Props/Walls/MediumWall3.mesh + + + + + + + + + + + + + + Models/Props/Walls/SmallWall3.mesh + + + + + + + + + + + + + Models/Props/Walls/SmallWall3.mesh + + + + + + + + + + + + Models/Props/Walls/SmallWall3.mesh + + + + + + + + + + + + + + Models/Props/Walls/SmallWall2.mesh + + + + + + + + + + + + + Models/Props/Walls/SmallWall4.mesh + + + + + + + + + + + + Models/Props/Walls/SmallWall3.mesh + + + + + + + + + + + + Models/Props/Walls/SmallWall2.mesh + + + + + + + + + + + + + Models/Props/Walls/SmallWall2.mesh + + + + + + + + + + + + + Models/Props/Walls/SmallWall2.mesh + + + + + + + + + + + + + Models/Props/Walls/MediumWall2.mesh + + + + + + + + + + + + Models/Props/Walls/MediumWall2.mesh + + + + + + + + + + + + + + Models/Props/Walls/MediumWall1.mesh + + + + + + + + + + + + Models/Props/Walls/MediumWall1.mesh + + + + + + + + + + + + + + Models/Props/Walls/MediumWall3.mesh + + + + + + + + + + + + Models/Props/Walls/MediumWall3.mesh + + + + + + + + + + + + Models/Props/Walls/MediumWall3.mesh + + + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + Models/Props/Walls/SmallWall3.mesh + + + + + + + + + + + + Models/Props/Walls/SmallWall3.mesh + + + + + + + + + + + + + Models/Props/Walls/SmallWall4.mesh + + + + + + + + + + + + + + Models/Props/Walls/SmallWall4.mesh + + + + + + + + + + + + Models/Props/Walls/SmallWall2.mesh + + + + + + + + + + + + + + Models/Props/Walls/SmallWall2.mesh + + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + + + Models/Props/Walls/SmallWall2.mesh + + + + + + + + + + + + + + Models/Props/Walls/SmallWall2.mesh + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + Models/Props/Walls/BigWall.mesh + + + + + + + + + + + + + + + Models/Props/Walls/MediumWall3.mesh + + + + + + + + + + + + + + + + + + + + Models/Props/Bridges/WoodenBridge.mesh + + + + + + + + + + + + + + Models/Props/Bridges/WoodenBridge.mesh + + + + + + + + + + + + + + Models/Props/Bridges/WoodenBridge.mesh + + + + + + + + + + + + + Models/Props/Bridges/SciFiBridge.mesh + + + + + + + + + + + + + + Models/Props/Bridges/SciFiBridge.mesh + + + + + + + + + + + + + + Models/Props/Flora/TreeLog.mesh + + + + + + + + + + + + + + + + + + + + + Models/Props/Pillars/SciFiBridgePillar1.mesh + + + + + + + + + + + + + + Models/Props/Pillars/SciFiBridgePillar1.mesh + + + + + + + + + + + + + + Models/Props/Walls/MediumWall2.mesh + + + + + + + + + + + Models/Props/Walls/MediumWall2.mesh + + + + + + + + + + + + + + + Models/Props/Walls/MediumWall3.mesh + + + + + + + + + + + Models/Props/Walls/MediumWall3.mesh + + + + + + + + + + + + + + Models/Props/Pillars/SciFiBridgePillar1.mesh + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + + Models/Props/Walls/MediumWall1.mesh + + + + + + + + + + + + Models/Props/Walls/MediumWall1.mesh + + + + + + + + + + + + Models/Props/Walls/MediumWall1.mesh + + + + + + + + + + + + + + Models/Props/Walls/MediumWall1.mesh + + + + + + + + + + + Models/Props/Walls/MediumWall1.mesh + + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + + + + + Models/Props/Flora/TreeLog.mesh + + + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + Models/Props/Stones/MediumStone1.mesh + + + + + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + + Models/Props/Stones/BigStone.mesh + + + + + + + + + + + + + + + + + + + + + + Models/Props/PickUps/PickUpHolder.mesh + + + + + + + + + + + + + + Models/Props/PickUps/PickUpHolder.mesh + + + + + + + + + + + + + + Models/Props/PickUps/PickUpHolder.mesh + + + + + + + + + + + + + + Models/Props/PickUps/PickUpHolder.mesh + + + + + + + + + + + + + Models/Props/PickUps/PickUpHolder.mesh + + + + + + + + + + + + + + Models/Props/PickUps/PickUpHolder.mesh + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Models/Props/CapturePoint.mesh + + + + + + + + + + + + + + + + + + + 1 + + + Models/Props/CapturePoint.mesh + + + + + + + + + + + + + + + 2 + + + Models/Props/CapturePoint.mesh + + + + + + + + + + + + + + 3 + + + Models/Props/CapturePoint.mesh + + + + + + + + + + + + + + + + + + 4 + + + Models/Props/CapturePoint.mesh + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + + + + + + 10 + + + + + + + + + + 10 + + + + + + + + + + + + + 10 + + + + + + + + + + + 10 + + + + + + + + + + + 10 + + + + + + + + + + + 1 + + + + + + + + + + + + + Models/Characters/Assault/AssaultTPose.mesh + + + + + + + + + + diff --git a/resources/Schema/Entities/Player.xml b/resources/Schema/Entities/Player.xml index d20de7b0..4ba23a0d 100644 --- a/resources/Schema/Entities/Player.xml +++ b/resources/Schema/Entities/Player.xml @@ -2,15 +2,16 @@ - - - 2.0 - + + 600 + + + @@ -19,12 +20,10 @@ - + - - - + @@ -32,7 +31,7 @@ - + @@ -53,7 +52,7 @@ - Models/Camera.mesh + Models/Widgets/Camera.mesh false @@ -92,7 +91,7 @@ - Models/CrosshairQuad.mesh + Models/Weapons/CrosshairQuad.mesh @@ -102,25 +101,48 @@ - + + + + + + Idle + 0.52743271827223559 + 1 + + + Models/Characters/Assault/FirstPerson.mesh + true + + + + + + + R_Arm_Weapon_Joint + - Models/AssaultWeapon.mesh + Models/Weapons/Blue/AssaultWeaponBlue.mesh - - + + - - - - - - - - - + + + + + Schema/Entities/RayBlue.xml + + + + + + + + @@ -130,7 +152,7 @@ - Models/Camera.mesh + Models/Widgets/Camera.mesh false @@ -143,18 +165,50 @@ - Hold Pos - - 1 + Idle + 0.69666320633760392 + 1 + + AimRifle + + - Models/AssaultAnimated.mesh - + Models/Characters/Assault/AssaultAnimations.mesh + - + + + + + R_Arm_Weapon_Joint + + + Models/Weapons/Blue/AssaultWeaponBlue.mesh + + + + + + + + + + + Schema/Entities/RayBlue.xml + + + + + + + + + + diff --git a/resources/Schema/Entities/PlayerDeathExplosionWithCamera.xml b/resources/Schema/Entities/PlayerDeathExplosionWithCamera.xml new file mode 100644 index 00000000..8a9f5e5b --- /dev/null +++ b/resources/Schema/Entities/PlayerDeathExplosionWithCamera.xml @@ -0,0 +1,43 @@ + + + + + + Hold Pos + + + 2.5 + + + true + + + true + 3 + + true + + + Models/AssaultAnimated.mesh + + true + + + + + + + + + + + + + + + + + + + + diff --git a/resources/Schema/Entities/QualityAssurance.xml b/resources/Schema/Entities/QualityAssurance.xml new file mode 100644 index 00000000..40951468 --- /dev/null +++ b/resources/Schema/Entities/QualityAssurance.xml @@ -0,0 +1,2150 @@ + + + + + + + + + + + + + + + + Models/Core/UnitPlane.mesh + + + + + + + + + + + 90 + + + + + + + + + + + + 1 + + + + + + + + + + + Audio/crosscounter.wav + true + + + + + + + + + + SoundEmitter + Fonts/DroidSans.ttf,64 + + + + + + + + + + + + + + + + + + + + + Sound Test + Fonts/DroidSans.ttf,64 + + + + + + + + + + + + + 0.80000001192092896 + + + Models/Widgets/Lights/DirectionalLightWidget.mesh + + + 1 + + + + + + + + + + + + + + + + + + + + + + Models/Characters/Assault/AssaultAnimated.mesh + + + + + + + + + + + + Models/Characters/Assault/AssaultAnimated.mesh + + + + + + + + + Animation test + Fonts/DroidSans.ttf,64 + + + + + + + + + + + + Models/Core/UnitCylinder.mesh + + + + + + + + + + + + + + + + + + + + 0.5 + + + + + + + + + + + + Models/Characters/Assault/AssaultAnimated.mesh + + + + + + + + + + + + + + + + + + + + + + + + Models/Test/NormSpecIncdMapSphere.mesh + + + + + + + + + 1 + + + + + + + + + + + Models/Core/UnitSphere.mesh + + + + 3 + 1.1399998664855957 + + + + + + + + + + + + Models/Core/UnitSphere.mesh + + + + 5.0100002288818359 + 0.69999998807907104 + + + + + + + + + + + + Models/Core/UnitSphere.mesh + + + + 4 + 0.80000001192092896 + + + + + + + + + + + + + + 1 + + + + + + + + + + + Models/Test/NormalMapSphere.mesh + + + + + + + + + + + Models/Test/SpecularMapSphere.mesh + + + + + + + + + + 1 + + + + + + + + + + + Models/Core/UnitSphere.mesh + + + + 3 + 1.1399998664855957 + + + + + + + + + + + + + + + + Models/Test/IncandescenceMapSphere.mesh + + + + + + + + + + + + + TextureMap's Test + Fonts/DroidSans.ttf,64 + + + + + + + + + + + + + + 1.3999999761581421 + + + + + + + + + + + + + + + + + Schema/Entities/Player.xml + + + + + + + + + + + + + + + + Models/Characters/Assault/AssaultTPose.mesh + + + + + + + + + + + + + Models/Characters/Assault/AssaultTPose.mesh + + + + + + + + + + + + + Models/Characters/Assault/AssaultTPose.mesh + + + + + + + + + + + + + Models/Characters/Assault/AssaultTPose.mesh + + + + + + + + + + + + + + + Schema/Entities/Player.xml + + + + + + + + + + + + + + + + + Models/Characters/Assault/AssaultTPose.mesh + + + + + + + + + + + + + Models/Characters/Assault/AssaultTPose.mesh + + + + + + + + + + + + + Models/Characters/Assault/AssaultTPose.mesh + + + + + + + + + + + + + Models/Characters/Assault/AssaultTPose.mesh + + + + + + + + + + + + + + Spawn Test + Fonts/DroidSans.ttf,64 + + + + + + + + + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + true + + + + + + + + + + + Models/Core/UnitCylinder.mesh + + true + + + + + + + + + + + + Models/Core/UnitRaptor.mesh + + true + + + + + + + + + + + Models/Characters/Assault/AssaultTPose.mesh + + true + + + + + + + + + + + + Models/Core/UnitCube.mesh + + true + + + + + + + + + + + + + Transparency Test + Fonts/DroidSans.ttf,64 + + + + + + + + + + + + + + + + + + + + + Models/Core/UnitCylinder.mesh + + + + + + + + + + + + + + + + + + + + 0.5 + + + + + + + + + + + Models/Weapons/Blue/AssaultWeaponBlue.mesh + + + + + + + + + + + + + + + + Models/Core/UnitCylinder.mesh + + + + + + + + + + + + + + + + + + + + 0.5 + + + + + + + + + + + Models/Weapons/Red/AssaultWeaponRed.mesh + + + + + + + + + + + + + + + + Asset Test + Fonts/DroidSans.ttf,64 + + + + + + + + + + + + Models/Core/UnitCylinder.mesh + + + + + + + + + + + + + + + + + + + + 0.5 + + + + + + + + + + + Models/Weapons/SecondaryWeapon.mesh + + + + + + + + + + + + + + + + Models/Core/UnitCylinder.mesh + + + + + + + + + + + + + + + + + + + + 0.5 + + + + + + + + + + + Models/Test/AssaultTPoseSoftEdge.mesh + + + + + + + + + + + + + + + Models/Core/UnitCylinder.mesh + + + + + + + + + + + + + + + + + + + + 0.5 + + + + + + + + + + + Models/Weapons/Blue/DefenderGunBlue.mesh + + + + + + + + + + + + + + + + Models/Core/UnitCylinder.mesh + + + + + + + + + + + + + + + + + + + + 0.5 + + + + + + + + + + + Models/Weapons/Red/DefenderGunRed.mesh + + + + + + + + + + + + + + + + Models/Core/UnitCylinder.mesh + + + + + + + + + + + + + + + + + + + + 0.5 + + + + + + + + + + + Models/Test/AssaultTPoseHardEdge.mesh + + + + + + + + + + + + + + + + + + + + + + + + CapturePoint Test + Fonts/DroidSans.ttf,64 + + + + + + + + + + + + Models/Props/CapturePoint.mesh + + + + + + + + + + + + + + 15 + + + Models/Core/UnitCube.mesh + + true + + + + + + + + + + + + + + + + + + Red team home point + Fonts/DroidSans.ttf,64 + + + + + + + + + + + + + + + Models/Props/CapturePoint.mesh + + + + + + + + + + + 1 + + + Models/Core/UnitCube.mesh + + true + + + + + + + + + + + + + + RedMiddle Point + Fonts/DroidSans.ttf + + + + + + + + + + + + + + + Models/Props/CapturePoint.mesh + + + + + + + + + 2 + + + Models/Core/UnitCube.mesh + + true + + + + + + + + + + + + + + Middle Point + Fonts/DroidSans.ttf,64 + + + + + + + + + + + + + + + Models/Props/CapturePoint.mesh + + + + + + + + + + + 3 + + + Models/Core/UnitCube.mesh + + true + + + + + + + + + + + + + + BlueMiddle Point + Fonts/DroidSans.ttf + + + + + + + + + + + + + + + Models/Props/CapturePoint.mesh + + + + + + + + + + + + + + -15 + 4 + + + Models/Core/UnitCube.mesh + + true + + + + + + + + + + + + + + + + + + Blue team home point + Fonts/DroidSans.ttf,64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Models/Test/ObstacleCourse.mesh + + + + + + + + + + + Collision Test + Fonts/DroidSans.ttf,64 + + + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + + + + + + + + ExplosionEffect Test + Fonts/DroidSans.ttf,64 + + + + + + + + + + + + Models/Core/UnitCylinder.mesh + + + + + + + + + + + + + + + + + + + + 0.5 + + + + + + + + + + + true + + 0.75205058136495551 + 3.7999999523162842 + + true + + + Models/Weapons/Blue/AssaultWeaponBlue.mesh + true + + + + + + + + + + + + + + + + Models/Core/UnitCylinder.mesh + + + + + + + + + + + + + + + + + + + + 0.5 + + + + + + + + + + + + + 1.2019563319790627 + + + Models/Characters/Assault/AssaultTPose.mesh + true + + + + + + + + + + + + + + + Models/Core/UnitCylinder.mesh + + + + + + + + + + + + + + + + + + + + 0.5 + + + + + + + + + + + + true + + + 0.68540211563899389 + + true + + + Models/Characters/Assault/AssaultAnimated.mesh + true + + + + + + + + + + + + + + + Models/Core/UnitCylinder.mesh + + + + + + + + + + + + + + + + + + + + 0.5 + + + + + + + + + + + true + + + 0.95150063648635763 + 10 + + 3 + true + + + Models/Core/UnitSphere.mesh + + true + + + + + + + + + + + + + + + Models/Core/UnitCylinder.mesh + + + + + + + + + + + + + + + + + + + + 0.5 + + + + + + + + + + + true + + + 1.3515288978624223 + true + 5 + true + + + Models/Assault.mesh + + true + + + + + + + + + + + + + + + + + + + + + + + + Remember to pick random entities. + Fonts/DroidSans.ttf,64 + + + + + + + + + + + + + + + + + + + + + + Models/Core/UnitHexagon.mesh + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + + + + + + false + + + 5 + + + + + + + + + + + + + + + + + + + + + + + Fonts/DroidSans.ttf,100 + + + + + + + + + + + + + + Models/Camera.mesh + false + + + + + + + + + + + + + + + + + + + 1 + + + + + Models/Core/UnitHexagon.mesh + + + + + + + + + + + + + + Models/CrosshairQuad.mesh + + + + + + + + + + + + + true + + 1.3682019578975679 + 3.7999999523162842 + + true + + + Models/AssaultWeaponRed.mesh + + + + + + + + + + + + + + + + + + + + + + + + + Models/Camera.mesh + false + + + + + + + + + + + + + + Models/AssaultAnimated.mesh + + + + + + + + + + + Models/Core/UnitCube.mesh + + false + + + + + + + + + + + + Models/Core/UnitCube.mesh + + false + + + + + + + + + + + + + + + + + + + + Models/Log.mesh + + + + + + + + + + + + Models/Props/Flora/AliveBush.mesh + true + + + + + + + + + + + + + + + Defender Shield Test + Fonts/DroidSans.ttf,64 + + + + + + + + + + + + + + + + + + + + + + Textures/Props/FoliageDiff.png + + + + + + + + + Textures/Props/FoliageDiff.png + + + + + + + + + + + + + + + + + + + + Textures/Core/UnitHexagon.png + + + + + + + + + + + 2 + + + + + + Textures/Core/UnitHexagon_Rotated.png + + + + + + + + + + + + + + + Textures/Core/UnitHexagon.png + + + + + + + + + + + 3 + + + + + + Textures/Core/UnitHexagon_Rotated.png + + + + + + + + + + + + + + + Textures/Core/UnitHexagon.png + + + + + + + + + + + 4 + + + 1 + + + + Textures/Core/UnitHexagon_Rotated.png + + + + + + + + + + + + + + + Textures/Core/UnitHexagon.png + + + + + + + + + + + 1 + + + + + + Textures/Core/UnitHexagon_Rotated.png + + + + + + + + + + + + + + + Textures/Core/UnitHexagon.png + + + + + + + + + + + + 1 + + + + Textures/Core/UnitHexagon_Rotated.png + + + + + + + + + + + + + + + + + + + + + + + + + Models/Widgets/Camera.mesh + + + + + + + + + + + + diff --git a/resources/Schema/Entities/RayBlue.xml b/resources/Schema/Entities/RayBlue.xml index 3b985a7e..022d7769 100644 --- a/resources/Schema/Entities/RayBlue.xml +++ b/resources/Schema/Entities/RayBlue.xml @@ -6,11 +6,12 @@ 0.25 - Models/CylinderBullet.mesh - + Models/Effects/CylinderShot.mesh + + true - + diff --git a/resources/Schema/Entities/RayRed.xml b/resources/Schema/Entities/RayRed.xml index df563476..11a9b077 100644 --- a/resources/Schema/Entities/RayRed.xml +++ b/resources/Schema/Entities/RayRed.xml @@ -6,8 +6,9 @@ 0.25 - Models/CylinderBullet.mesh - + Models/Weapons/CylinderBullet.mesh + + true diff --git a/resources/Schema/Entities/RenderingWorld.xml b/resources/Schema/Entities/RenderingWorld.xml index 20301d5f..8bbc39f8 100644 --- a/resources/Schema/Entities/RenderingWorld.xml +++ b/resources/Schema/Entities/RenderingWorld.xml @@ -20,7 +20,7 @@ - Models/Assault.obj + Models/Characters/Assault/AssaultTPose.mesh @@ -35,7 +35,7 @@ 80 - Models/Camera.mesh + Models/Widgets/Camera.mesh @@ -52,14 +52,15 @@ - 0.65990006923675537 + Models/Core/UnitHexagon.mesh + true @@ -132,7 +133,7 @@ - Models/Assault.mesh + Models/Characters/Assault/AssaultTPose.mesh @@ -161,7 +162,7 @@ - + @@ -308,7 +309,7 @@ - Models/Assault.mesh + Models/Characters/Assault/AssaultTPose.mesh @@ -324,7 +325,7 @@ 0.10000000149011612 - Models/DirectionalLightWidget.mesh + Models/Widgets/Lights/DirectionalLightWidget.mesh @@ -346,6 +347,32 @@ + + + + Textures/HexmapDiff.png + Textures/GlowFrame.png + + + + + + + + + + + Run + + 0.004999999888241291 + + + Models/SuperTest.mesh + + + + + diff --git a/resources/Schema/Entities/ShootEventTest.xml b/resources/Schema/Entities/ShootEventTest.xml index 9e9adf50..80dd2f35 100644 --- a/resources/Schema/Entities/ShootEventTest.xml +++ b/resources/Schema/Entities/ShootEventTest.xml @@ -9,7 +9,7 @@ - ../assets/Models/DummyScene.mesh + Models/Test/DummyScene.mesh @@ -41,7 +41,7 @@ 3 - ../assets/Models/Core/UnitSphere.mesh + Models/Core/UnitSphere.mesh @@ -61,7 +61,7 @@ 1 - ../assets/Models/Core/UnitSphere.mesh + Models/Core/UnitSphere.mesh @@ -79,7 +79,7 @@ 2 - ../assets/Models/Core/UnitSphere.mesh + Models/Core/UnitSphere.mesh @@ -96,7 +96,7 @@ 3 - ../assets/Models/Core/UnitSphere.mesh + Models/Core/UnitSphere.mesh @@ -115,7 +115,7 @@ 4 - ../assets/Models/Core/UnitSphere.mesh + Models/Core/UnitSphere.mesh @@ -133,7 +133,7 @@ - ../assets/Models/Core/UnitCube.mesh + Models/Core/UnitCube.mesh @@ -151,7 +151,7 @@ - ../assets/Models/Core/UnitCube.mesh + Models/Core/UnitCube.mesh @@ -171,7 +171,7 @@ - ../assets/Models/Core/UnitCube.mesh + Models/Core/UnitCube.mesh @@ -191,7 +191,7 @@ - ../assets/Models/Core/UnitCube.mesh + Models/Core/UnitCube.mesh diff --git a/resources/Schema/Entities/Skeleton.xml b/resources/Schema/Entities/Skeleton.xml new file mode 100644 index 00000000..b8deb2eb --- /dev/null +++ b/resources/Schema/Entities/Skeleton.xml @@ -0,0 +1,497 @@ + + + + + + + + + + + + R_Arm_Weapon_Joint + + + + Models/Core/UnitCube.mesh + + true + + + + + + + + + + + + + R_Hand + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + R_Arm + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + R_Shoulder + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + Neck + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + Spine_3 + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + Spine_2 + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + Spine_1 + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + Hip + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + L_Leg_Top + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + L_Leg_Bottom + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + L_Foot + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + L_Toe + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + L_Shoulder + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + L_Arm + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + L_Hand + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + L_Shoulder_Armor_Joint + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + Chin + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + Head + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + Perietal + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + L_Elbow + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + R_Leg_Bottom + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + R_Elbow + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + R_Leg_Top + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + R_Foot + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + R_Toe + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + R_Shoulder_Armor_Joint + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + diff --git a/resources/Schema/Entities/SoundEmitter.xml b/resources/Schema/Entities/SoundEmitter.xml new file mode 100644 index 00000000..39b4c750 --- /dev/null +++ b/resources/Schema/Entities/SoundEmitter.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + SoundEmitter + Fonts/DroidSans.ttf,64 + + + + + + + + + + diff --git a/resources/Schema/Entities/SpawnPointClusterWithModels.xml b/resources/Schema/Entities/SpawnPointClusterWithModels.xml new file mode 100644 index 00000000..ea8e09d4 --- /dev/null +++ b/resources/Schema/Entities/SpawnPointClusterWithModels.xml @@ -0,0 +1,68 @@ + + + + + + + Schema/Entities/Player.xml + + + + + + + + + + + + + + + Models/Characters/Assault/AssaultTPose.mesh + + + + + + + + + + + + Models/Characters/Assault/AssaultTPose.mesh + + + + + + + + + + + + Models/Characters/Assault/AssaultTPose.mesh + + + + + + + + + + + + Models/Characters/Assault/AssaultTPose.mesh + + + + + + + + + + diff --git a/resources/Schema/Entities/SpawnerWithPlayerModel.xml b/resources/Schema/Entities/SpawnerWithPlayerModel.xml new file mode 100644 index 00000000..dbd93ed4 --- /dev/null +++ b/resources/Schema/Entities/SpawnerWithPlayerModel.xml @@ -0,0 +1,16 @@ + + + + + + + Models/Characters/Assault/AssaultTPose.mesh + + + + + + + + + diff --git a/resources/Schema/Entities/SplatMapTesWorld.xml b/resources/Schema/Entities/SplatMapTesWorld.xml new file mode 100644 index 00000000..fe5718eb --- /dev/null +++ b/resources/Schema/Entities/SplatMapTesWorld.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + Models/Ground.mesh + + + + + + + + diff --git a/resources/Schema/Entities/Test.xml b/resources/Schema/Entities/Test.xml index 2cdf4e17..7f40e6de 100644 --- a/resources/Schema/Entities/Test.xml +++ b/resources/Schema/Entities/Test.xml @@ -6,7 +6,7 @@ - Models/DummyScene.mesh + Models/Test/DummyScene.mesh @@ -36,7 +36,7 @@ 0 - Models/Camera.mesh + Models/Widgets/Camera.mesh diff --git a/resources/Schema/Entities/Testingu b/resources/Schema/Entities/Testingu new file mode 100644 index 00000000..145550f4 --- /dev/null +++ b/resources/Schema/Entities/Testingu @@ -0,0 +1,45 @@ + + + + + + + + + + + + Models/Core/UnitPlane.mesh + + + + + + + + + + + + Schema/Entities/Player.xml + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/Schema/Entities/aaaatestremoveme.xml b/resources/Schema/Entities/aaaatestremoveme.xml new file mode 100644 index 00000000..8da40b58 --- /dev/null +++ b/resources/Schema/Entities/aaaatestremoveme.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + Models/Core/Unithexagon.mesh + + + + + + + + + + + + + + + + + + + 2.2000000476837158 + + + + + + + + diff --git a/resources/Schema/Entities/aim_rays.xml b/resources/Schema/Entities/aim_rays.xml new file mode 100644 index 00000000..c8dac9a3 --- /dev/null +++ b/resources/Schema/Entities/aim_rays.xml @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + models/core/unitcube.mesh + + + + + + + + + + + + + + + models/core/unitcube.mesh + + + + + + + + + + + + + + + + + + + + + + + + models/core/unitcube.mesh + + + + + + + + + + + + + + + models/core/unitcube.mesh + + + + + + + + + + + + + + + models/core/unitcube.mesh + + + + + + + + + + + + + + Schema/Entities/Player.xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Schema/Entities/Player.xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + models/core/unitcube.mesh + + + + + + + + + + + + + + + + + + Models\Core\UnitCube.mesh + + + + + + + + + + + + + + + + + + + + + + + 1 + + + Models\Core\UnitCube.mesh + + + + + + + + + + + + + + + + + + diff --git a/resources/Schema/Entities/awdawd b/resources/Schema/Entities/awdawd new file mode 100644 index 00000000..d8dacb54 --- /dev/null +++ b/resources/Schema/Entities/awdawd @@ -0,0 +1,23 @@ + + + + + + + L_Foot + true + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + diff --git a/resources/Schema/Entities/joint.xml b/resources/Schema/Entities/joint.xml new file mode 100644 index 00000000..912693f3 --- /dev/null +++ b/resources/Schema/Entities/joint.xml @@ -0,0 +1,22 @@ + + + + + + L_Elbow + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + diff --git a/resources/Schema/Types/Entity.xsd b/resources/Schema/Types/Entity.xsd index 99b90caa..ffe3421a 100644 --- a/resources/Schema/Types/Entity.xsd +++ b/resources/Schema/Types/Entity.xsd @@ -31,12 +31,18 @@ + + + + + + diff --git a/resources/Shaders/DrawColorCorrection.frag.glsl b/resources/Shaders/DrawColorCorrection.frag.glsl index 8d13992a..76db3e82 100644 --- a/resources/Shaders/DrawColorCorrection.frag.glsl +++ b/resources/Shaders/DrawColorCorrection.frag.glsl @@ -2,7 +2,10 @@ layout (binding = 0) uniform sampler2D SceneTexture; layout (binding = 1) uniform sampler2D BloomTexture; +layout (binding = 2) uniform sampler2D SceneTextureLowRes; +layout (binding = 3) uniform sampler2D BloomTextureLowRes; uniform float Exposure; +uniform float Gamma; in VertexData{ vec2 TextureCoordinate; @@ -12,16 +15,24 @@ out vec4 fragmentColor; void main() { - const float gamma = 2.2; vec4 hdrColor = texture(SceneTexture, Input.TextureCoordinate); vec4 bloomColor = texture(BloomTexture, Input.TextureCoordinate); + vec4 hdrColorLowRes = texture(SceneTextureLowRes, Input.TextureCoordinate); + vec4 bloomColorLowRes = texture(BloomTextureLowRes, Input.TextureCoordinate); hdrColor += bloomColor; + hdrColorLowRes; + float hdrColorsum = hdrColorLowRes.r + hdrColorLowRes.g + hdrColorLowRes.b; //Toon mapping thingy - vec3 result = vec3(1.0) - exp(-hdrColor.rgb * Exposure); + vec3 result; + if(hdrColorsum > 0.0) { + result = vec3(1.0) - exp(-hdrColorLowRes.rgb * Exposure); + } else { + result = vec3(1.0) - exp(-hdrColor.rgb * Exposure); + } //gamme correction - result = pow(result, vec3(1.0 / gamma)); + result = pow(result, vec3(1.0 / Gamma)); fragmentColor = vec4(result, 1.0); //fragmentColor = hdrColor; diff --git a/resources/Shaders/ExplosionEffect.geom.glsl b/resources/Shaders/ExplosionEffect.geom.glsl index cb91b545..44b44aa6 100644 --- a/resources/Shaders/ExplosionEffect.geom.glsl +++ b/resources/Shaders/ExplosionEffect.geom.glsl @@ -17,15 +17,21 @@ uniform bool ExponentialAccelaration; in VertexData{ vec3 Position; vec3 Normal; + vec3 Tangent; + vec3 BiTangent; vec2 TextureCoordinate; vec4 ExplosionColor; + float ExplosionPercentageElapsed; }Input[]; out VertexData{ vec3 Position; vec3 Normal; + vec3 Tangent; + vec3 BiTangent; vec2 TextureCoordinate; vec4 ExplosionColor; + float ExplosionPercentageElapsed; }Output; layout(triangles) in; @@ -114,12 +120,17 @@ void main() { // calculate the max distance (s) the triangle will move float s = (randomVelocity.x * ExplosionDuration) + (0.5 * a * pow(ExplosionDuration, 2)); + float te = (length(triangleCenter2ExplosionRadius) / s); - Output.ExplosionColor = EndColor * (length(triangleCenter2ExplosionRadius) / s); + Output.ExplosionColor = EndColor; + Output.ExplosionPercentageElapsed = te; + } else { - Output.ExplosionColor = EndColor * timePercetage; + Output.ExplosionColor = EndColor; + Output.ExplosionPercentageElapsed = timePercetage; + } // for every vertex on the triangle... @@ -132,6 +143,8 @@ void main() Output.Normal = Input[i].Normal; Output.Position = Input[i].Position; Output.TextureCoordinate = Input[i].TextureCoordinate; + Output.Tangent = Input[i].Tangent; + Output.BiTangent = Input[i].BiTangent; // convert to model space for the gravity to always be in -y vec4 ExplodedPositionInModelSpace = M * vec4(ExplodedPosition, 1.0); @@ -154,11 +167,14 @@ void main() // if explosion color should be affected by distance instead of time... if (ColorByDistance == true) { - Output.ExplosionColor = vec4(0.0); + Output.ExplosionColor = EndColor; + Output.ExplosionPercentageElapsed = 0.0; } else { - Output.ExplosionColor = EndColor * timePercetage; + Output.ExplosionColor = EndColor; + Output.ExplosionPercentageElapsed = timePercetage; + } // for every vertex on the triangle... @@ -168,7 +184,9 @@ void main() Output.Normal = Input[i].Normal; Output.Position = Input[i].Position; Output.TextureCoordinate = Input[i].TextureCoordinate; - + Output.Tangent = Input[i].Tangent; + Output.BiTangent = Input[i].BiTangent; + // no change in position, pass through vertex gl_Position = gl_in[i].gl_Position; EmitVertex(); diff --git a/resources/Shaders/FillDepthBuffer.frag.glsl b/resources/Shaders/FillDepthBuffer.frag.glsl new file mode 100644 index 00000000..a125fc25 --- /dev/null +++ b/resources/Shaders/FillDepthBuffer.frag.glsl @@ -0,0 +1,11 @@ +#version 430 + +in VertexData{ + vec3 Position; +}Input; + +void main() +{ +} + + diff --git a/resources/Shaders/FillDepthBuffer.vert.glsl b/resources/Shaders/FillDepthBuffer.vert.glsl new file mode 100644 index 00000000..ff849790 --- /dev/null +++ b/resources/Shaders/FillDepthBuffer.vert.glsl @@ -0,0 +1,21 @@ +#version 430 + +uniform mat4 M; +uniform mat4 V; +uniform mat4 P; + +layout(location = 0) in vec3 Position; +layout(location = 5) in vec4 BoneIndices; +layout(location = 6) in vec4 BoneWeights; + + +out VertexData{ + vec3 Position; +}Output; + +void main() +{ + gl_Position = P * V * M * vec4(Position, 1.0); + + Output.Position = Position; +} \ No newline at end of file diff --git a/resources/Shaders/FillDepthBufferSkinned.vert.glsl b/resources/Shaders/FillDepthBufferSkinned.vert.glsl new file mode 100644 index 00000000..ce2a142d --- /dev/null +++ b/resources/Shaders/FillDepthBufferSkinned.vert.glsl @@ -0,0 +1,33 @@ +#version 430 + +uniform mat4 M; +uniform mat4 V; +uniform mat4 P; +uniform mat4 Bones[100]; + + +layout(location = 0) in vec3 Position; +layout(location = 5) in vec4 BoneIndices; +layout(location = 6) in vec4 BoneWeights; + + + +out VertexData{ + vec3 Position; +}Output; + +void main() +{ + mat4 boneTransform = mat4(1); + + if(BoneWeights[0] > 0.0f){ + boneTransform = BoneWeights[0] * Bones[int(BoneIndices[0])] + + BoneWeights[1] * Bones[int(BoneIndices[1])] + + BoneWeights[2] * Bones[int(BoneIndices[2])] + + BoneWeights[3] * Bones[int(BoneIndices[3])]; + } + + gl_Position = P*V*M*boneTransform * vec4(Position, 1.0); + + Output.Position = vec3(0.0); +} \ No newline at end of file diff --git a/resources/Shaders/ForwardPlus.frag.glsl b/resources/Shaders/ForwardPlus.frag.glsl index de672dd1..471ee20b 100644 --- a/resources/Shaders/ForwardPlus.frag.glsl +++ b/resources/Shaders/ForwardPlus.frag.glsl @@ -7,13 +7,18 @@ uniform vec4 Color; uniform vec4 DiffuseColor; uniform vec2 ScreenDimensions; uniform vec4 FillColor; +uniform vec4 AmbientColor; uniform float FillPercentage; + +uniform vec2 DiffuseUVRepeat; +uniform vec2 NormalUVRepeat; +uniform vec2 SpecularUVRepeat; +uniform vec2 GlowUVRepeat; layout (binding = 0) uniform sampler2D DiffuseTexture; layout (binding = 1) uniform sampler2D NormalMapTexture; layout (binding = 2) uniform sampler2D SpecularMapTexture; layout (binding = 3) uniform sampler2D GlowMapTexture; - #define TILE_SIZE 16 struct LightSource { @@ -55,13 +60,12 @@ in VertexData{ vec3 BiTangent; vec2 TextureCoordinate; vec4 ExplosionColor; + float ExplosionPercentageElapsed; }Input; out vec4 sceneColor; out vec4 bloomColor; -vec4 scene_ambient = vec4(0.3,0.3,0.3,1); - struct LightResult { vec4 Diffuse; vec4 Specular; @@ -115,11 +119,12 @@ vec4 CalcNormalMappedValue(vec3 normal, vec3 tangent, vec3 bitangent, vec2 textu void main() { - vec4 diffuseTexel = texture2D(DiffuseTexture, Input.TextureCoordinate); - vec4 glowTexel = texture2D(GlowMapTexture, Input.TextureCoordinate); - vec4 specularTexel = texture2D(SpecularMapTexture, Input.TextureCoordinate); + vec4 diffuseTexel = texture2D(DiffuseTexture, Input.TextureCoordinate * DiffuseUVRepeat); + vec4 glowTexel = texture2D(GlowMapTexture, Input.TextureCoordinate * GlowUVRepeat); + vec4 specularTexel = texture2D(SpecularMapTexture, Input.TextureCoordinate * SpecularUVRepeat); vec4 position = V * M * vec4(Input.Position, 1.0); - vec4 normal = V * CalcNormalMappedValue(Input.Normal, Input.Tangent, Input.BiTangent, Input.TextureCoordinate, NormalMapTexture); + vec4 normal = V * CalcNormalMappedValue(Input.Normal, Input.Tangent, Input.BiTangent, Input.TextureCoordinate * NormalUVRepeat, NormalMapTexture); + normal = normalize(normal); //vec4 normal = normalize(V * vec4(Input.Normal, 0.0)); vec4 viewVec = normalize(-position); @@ -128,7 +133,7 @@ void main() tilePos.y = int(gl_FragCoord.y/TILE_SIZE); LightResult totalLighting; - totalLighting.Diffuse = scene_ambient; + totalLighting.Diffuse = vec4(AmbientColor.rgb, 1.0); int currentTile = int(floor(gl_FragCoord.x/TILE_SIZE) + (floor(gl_FragCoord.y/TILE_SIZE) * int(ScreenDimensions.x/TILE_SIZE))); int start = int(LightGrids.Data[currentTile].Start); @@ -150,8 +155,9 @@ void main() totalLighting.Specular += light_result.Specular; } - - vec4 color_result = (DiffuseColor + Input.ExplosionColor) * (totalLighting.Diffuse + (totalLighting.Specular * specularTexel)) * diffuseTexel * Color; + vec4 color_result = mix((Color * diffuseTexel * DiffuseColor), Input.ExplosionColor, Input.ExplosionPercentageElapsed); + color_result = color_result * (totalLighting.Diffuse + (totalLighting.Specular * specularTexel)); + //vec4 color_result = (DiffuseColor + Input.ExplosionColor) * (totalLighting.Diffuse + (totalLighting.Specular * specularTexel)) * diffuseTexel * Color; float pos = ((P * vec4(Input.Position, 1)).y + 1.0)/2.0; @@ -160,7 +166,7 @@ void main() color_result += FillColor; } sceneColor = vec4(color_result.xyz, clamp(color_result.a, 0, 1)); - color_result += glowTexel; + color_result += glowTexel*3; bloomColor = vec4(clamp(color_result.xyz - 1.0, 0, 100), 1.0); diff --git a/resources/Shaders/ForwardPlus.vert.glsl b/resources/Shaders/ForwardPlus.vert.glsl index 1a7cca12..d475d825 100644 --- a/resources/Shaders/ForwardPlus.vert.glsl +++ b/resources/Shaders/ForwardPlus.vert.glsl @@ -3,15 +3,12 @@ uniform mat4 M; uniform mat4 V; uniform mat4 P; -uniform mat4 Bones[100]; layout(location = 0) in vec3 Position; layout(location = 1) in vec3 Normal; layout(location = 2) in vec3 Tangent; layout(location = 3) in vec3 BiTangent; layout(location = 4) in vec2 TextureCoords; -layout(location = 5) in vec4 BoneIndices; -layout(location = 6) in vec4 BoneWeights; out VertexData{ vec3 Position; @@ -20,26 +17,18 @@ out VertexData{ vec3 BiTangent; vec2 TextureCoordinate; vec4 ExplosionColor; + float ExplosionPercentageElapsed; }Output; void main() { - - - mat4 boneTransform = mat4(1); - if(BoneWeights[0] > 0.0f){ - boneTransform = BoneWeights[0] * Bones[int(BoneIndices[0])] - + BoneWeights[1] * Bones[int(BoneIndices[1])] - + BoneWeights[2] * Bones[int(BoneIndices[2])] - + BoneWeights[3] * Bones[int(BoneIndices[3])]; - } - - gl_Position = P*V*M*boneTransform * vec4(Position, 1.0); + gl_Position = P*V*M * vec4(Position, 1.0); - Output.Position = (boneTransform * vec4(Position, 1.0)).xyz; + Output.Position = Position; Output.TextureCoordinate = TextureCoords; Output.Normal = vec3(M * vec4(Normal, 0.0)); Output.Tangent = vec3(M * vec4(Tangent, 0.0)); Output.BiTangent = vec3(M * vec4(BiTangent, 0.0)); - Output.ExplosionColor = vec4(0.0); + Output.ExplosionColor = vec4(1.0); + Output.ExplosionPercentageElapsed = 0.0; } \ No newline at end of file diff --git a/resources/Shaders/ForwardPlusSkinned.vert.glsl b/resources/Shaders/ForwardPlusSkinned.vert.glsl new file mode 100644 index 00000000..5fd55a8c --- /dev/null +++ b/resources/Shaders/ForwardPlusSkinned.vert.glsl @@ -0,0 +1,46 @@ +#version 430 + +uniform mat4 M; +uniform mat4 V; +uniform mat4 P; +uniform mat4 Bones[100]; + +layout(location = 0) in vec3 Position; +layout(location = 1) in vec3 Normal; +layout(location = 2) in vec3 Tangent; +layout(location = 3) in vec3 BiTangent; +layout(location = 4) in vec2 TextureCoords; +layout(location = 5) in vec4 BoneIndices; +layout(location = 6) in vec4 BoneWeights; + +out VertexData{ + vec3 Position; + vec3 Normal; + vec3 Tangent; + vec3 BiTangent; + vec2 TextureCoordinate; + vec4 ExplosionColor; + float ExplosionPercentageElapsed; +}Output; + +void main() +{ + mat4 boneTransform = mat4(1); + + if(BoneWeights[0] > 0.0f){ + boneTransform = BoneWeights[0] * Bones[int(BoneIndices[0])] + + BoneWeights[1] * Bones[int(BoneIndices[1])] + + BoneWeights[2] * Bones[int(BoneIndices[2])] + + BoneWeights[3] * Bones[int(BoneIndices[3])]; + } + + gl_Position = P*V*M*boneTransform * vec4(Position, 1.0); + + Output.Position = (boneTransform * vec4(Position, 1.0)).xyz; + Output.TextureCoordinate = TextureCoords; + Output.Normal = vec3(M * boneTransform * vec4(Normal, 0.0)); + Output.Tangent = vec3(M * vec4(Tangent, 0.0)); + Output.BiTangent = vec3(M * vec4(BiTangent, 0.0)); + Output.ExplosionColor = vec4(1.0); + Output.ExplosionPercentageElapsed = 0.0; +} \ No newline at end of file diff --git a/resources/Shaders/ForwardPlusSplatMap.frag.glsl b/resources/Shaders/ForwardPlusSplatMap.frag.glsl new file mode 100644 index 00000000..239c51b5 --- /dev/null +++ b/resources/Shaders/ForwardPlusSplatMap.frag.glsl @@ -0,0 +1,277 @@ +#version 430 + +uniform mat4 M; +uniform mat4 V; +uniform mat4 P; +uniform vec2 ScreenDimensions; +uniform float FillPercentage; +uniform vec4 DiffuseColor; +uniform vec4 FillColor; +uniform vec4 Color; +uniform vec4 AmbientColor; + +//Get bineded at the same time as the textures +uniform vec2 DiffuseUVRepeat1; +uniform vec2 DiffuseUVRepeat2; +uniform vec2 DiffuseUVRepeat3; +uniform vec2 DiffuseUVRepeat4; +uniform vec2 DiffuseUVRepeat5; +uniform vec2 NormalUVRepeat1; +uniform vec2 NormalUVRepeat2; +uniform vec2 NormalUVRepeat3; +uniform vec2 NormalUVRepeat4; +uniform vec2 NormalUVRepeat5; +uniform vec2 SpecularUVRepeat1; +uniform vec2 SpecularUVRepeat2; +uniform vec2 SpecularUVRepeat3; +uniform vec2 SpecularUVRepeat4; +uniform vec2 SpecularUVRepeat5; +uniform vec2 GlowUVRepeat1; +uniform vec2 GlowUVRepeat2; +uniform vec2 GlowUVRepeat3; +uniform vec2 GlowUVRepeat4; +uniform vec2 GlowUVRepeat5; +layout (binding = 0) uniform sampler2D SplatMapTexture; +layout (binding = 1) uniform sampler2D DiffuseTexture1; +layout (binding = 2) uniform sampler2D DiffuseTexture2; +layout (binding = 3) uniform sampler2D DiffuseTexture3; +layout (binding = 4) uniform sampler2D DiffuseTexture4; +layout (binding = 5) uniform sampler2D DiffuseTexture5; +layout (binding = 6) uniform sampler2D NormalMapTexture1; +layout (binding = 7) uniform sampler2D NormalMapTexture2; +layout (binding = 8) uniform sampler2D NormalMapTexture3; +layout (binding = 9) uniform sampler2D NormalMapTexture4; +layout (binding = 10) uniform sampler2D NormalMapTexture5; +layout (binding = 11) uniform sampler2D SpecularMapTexture1; +layout (binding = 12) uniform sampler2D SpecularMapTexture2; +layout (binding = 13) uniform sampler2D SpecularMapTexture3; +layout (binding = 14) uniform sampler2D SpecularMapTexture4; +layout (binding = 15) uniform sampler2D SpecularMapTexture5; +layout (binding = 16) uniform sampler2D GlowMapTexture1; +layout (binding = 17) uniform sampler2D GlowMapTexture2; +layout (binding = 18) uniform sampler2D GlowMapTexture3; +layout (binding = 19) uniform sampler2D GlowMapTexture4; +layout (binding = 20) uniform sampler2D GlowMapTexture5; + +#define TILE_SIZE 16 + +struct LightSource { + vec4 Position; + vec4 Direction; + vec4 Color; + float Radius; + float Intensity; + float Falloff; + int Type; +}; + +layout (std430, binding = 1) buffer LightBuffer +{ + LightSource List[]; +} LightSources; + +struct LightGrid { + float Start; + float Amount; + vec2 Padding; +}; + +layout (std430, binding = 2) buffer LightGridBuffer +{ + LightGrid Data[]; +} LightGrids; + +layout (std430, binding = 4) buffer LightIndexBuffer +{ + float LightIndex[]; +}; + + +in VertexData{ + vec3 Position; + vec3 Normal; + vec3 Tangent; + vec3 BiTangent; + vec2 TextureCoordinate; + vec4 ExplosionColor; + float ExplosionPercentageElapsed; +}Input; + +out vec4 sceneColor; +out vec4 bloomColor; + +struct LightResult { + vec4 Diffuse; + vec4 Specular; +}; + +float CalcAttenuation(float radius, float dist, float falloff) { + return 1.0 - smoothstep(radius * 0.3, radius, dist); +} + +vec4 CalcSpecular(vec4 lightColor, vec4 viewVec, vec4 lightVec, vec4 normal) { + vec4 R = normalize( reflect(-lightVec, normal)); + float RdotV = max( dot(R, viewVec), 0.0); + return lightColor * pow(RdotV, 90.0); +} + +vec4 CalcDiffuse(vec4 lightColor, vec4 lightVec, vec4 normal) { + float power = max( dot(normal, lightVec), 0.0); + return lightColor * power; +} + +LightResult CalcPointLightSource(vec4 lightPos, float lightRadius, vec4 lightColor, float intensity, vec4 viewVec, vec4 position, vec4 normal, float falloff) +{ + vec4 L = lightPos - position; + float dist = length(L); + L = normalize(L); + + float attenuation = CalcAttenuation(lightRadius, dist, falloff); + + LightResult result; + result.Diffuse = CalcDiffuse(lightColor, L, normal) * attenuation * intensity; + result.Specular = CalcSpecular(lightColor, viewVec, L, normal) * attenuation * intensity; + return result; +} + +LightResult CalcDirectionalLightSource(vec4 direction, vec4 color, float intensity, vec4 viewVec, vec4 vertNormal) +{ + vec4 L = normalize( -vec4(direction.xyz, 0) ); + + LightResult result; + result.Diffuse = CalcDiffuse(color, L, vertNormal) * intensity; + result.Specular = CalcSpecular(color, viewVec, L, vertNormal) * intensity; + return result; +} + +vec4 CalcNormalMappedValue(vec3 normal, vec3 tangent, vec3 bitangent, vec2 textureCoordinate, sampler2D normalMap) +{ + mat3 TBN = mat3(tangent, bitangent, normal); + vec3 NormalMap = texture(normalMap, textureCoordinate).xyz * 2.0 - vec3(1.0); + return vec4(TBN * normalize(NormalMap), 0.0); +} + +vec4 CalcBlendedTexel(vec4 blendValue, sampler2D R, sampler2D G, sampler2D B, sampler2D A, sampler2D D, + vec2 R_TileValues, vec2 G_TileValues, vec2 B_TileValues, vec2 A_TileValues, vec2 D_TileValues){ + vec4 R_Channel = texture2D(R, Input.TextureCoordinate * R_TileValues); + vec4 G_Channel = texture2D(G, Input.TextureCoordinate * G_TileValues); + vec4 B_Channel = texture2D(B, Input.TextureCoordinate * B_TileValues); + vec4 A_Channel = texture2D(A, Input.TextureCoordinate * A_TileValues); + vec4 D_Channel = texture2D(D, Input.TextureCoordinate * D_TileValues); + + float total = blendValue.r + blendValue.g + blendValue.b + blendValue.a; + if(total > 1.0f){ + float totalDiv = 1.0f / total; + blendValue.r = blendValue.r * totalDiv; + blendValue.g = blendValue.g * totalDiv; + blendValue.b = blendValue.b * totalDiv; + blendValue.a = blendValue.a * totalDiv; + } + float D_percent = clamp( 1.0f - total, 0.0f, 1.0f); + + return blendValue.r * R_Channel + + blendValue.g * G_Channel + + blendValue.b * B_Channel + + blendValue.a * A_Channel + + D_percent * D_Channel; +} + +vec4 CalcBlendedNormal(vec4 blendValue, sampler2D R, sampler2D G, sampler2D B, sampler2D A, sampler2D D, + vec2 R_TileValues, vec2 G_TileValues, vec2 B_TileValues, vec2 A_TileValues, vec2 D_TileValues){ + mat3 TBN = mat3(Input.Tangent, Input.BiTangent, Input.Normal); + vec3 R_Channel = texture(R, Input.TextureCoordinate * R_TileValues).xyz * 2.0 - vec3(1.0); + vec3 G_Channel = texture(G, Input.TextureCoordinate * G_TileValues).xyz * 2.0 - vec3(1.0); + vec3 B_Channel = texture(B, Input.TextureCoordinate * B_TileValues).xyz * 2.0 - vec3(1.0); + vec3 A_Channel = texture(A, Input.TextureCoordinate * A_TileValues).xyz * 2.0 - vec3(1.0); + vec3 D_Channel = texture(D, Input.TextureCoordinate * D_TileValues).xyz * 2.0 - vec3(1.0); + + float total = blendValue.r + blendValue.g + blendValue.b + blendValue.a; + if(total > 1.0f){ + float totalDiv = 1 / total; + blendValue.r = blendValue.r * totalDiv; + blendValue.g = blendValue.g * totalDiv; + blendValue.b = blendValue.b * totalDiv; + blendValue.a = blendValue.a * totalDiv; + } + float D_percent = clamp( 1.0f - total, 0.0f, 1.0f); + + vec3 Normal_result = blendValue.r * R_Channel + + blendValue.g * G_Channel + + blendValue.b * B_Channel + + blendValue.a * A_Channel + + D_percent * D_Channel; + + return vec4(TBN * normalize(Normal_result), 0.0); +} + +void main() +{ + vec4 splatTexel = texture2D(SplatMapTexture, Input.TextureCoordinate); + + vec4 diffuseTexel = CalcBlendedTexel(splatTexel, DiffuseTexture1, DiffuseTexture2, DiffuseTexture3, DiffuseTexture4, DiffuseTexture5, + DiffuseUVRepeat1, DiffuseUVRepeat2, DiffuseUVRepeat3, DiffuseUVRepeat4, DiffuseUVRepeat5); + vec4 glowTexel = CalcBlendedTexel(splatTexel, GlowMapTexture1, GlowMapTexture2, GlowMapTexture3, GlowMapTexture4, GlowMapTexture5, + GlowUVRepeat1, GlowUVRepeat2, GlowUVRepeat3, GlowUVRepeat4, GlowUVRepeat5); + vec4 specularTexel = CalcBlendedTexel(splatTexel, SpecularMapTexture1, SpecularMapTexture2, SpecularMapTexture3, SpecularMapTexture4, SpecularMapTexture5, + SpecularUVRepeat1, SpecularUVRepeat2, SpecularUVRepeat3, SpecularUVRepeat4, SpecularUVRepeat5); + vec4 position = V * M * vec4(Input.Position, 1.0); + //vec4 normal = V * CalcNormalMappedValue(Input.Normal, Input.Tangent, Input.BiTangent, Input.TextureCoordinate, SplatMapTexture); + vec4 normal = V * CalcBlendedNormal(splatTexel, NormalMapTexture1, NormalMapTexture2, NormalMapTexture3, NormalMapTexture4, NormalMapTexture5, + NormalUVRepeat1, NormalUVRepeat2, NormalUVRepeat3, NormalUVRepeat4, NormalUVRepeat5); + normal = normalize(normal); + //vec4 normal = normalize(V * vec4(Input.Normal, 0.0)); + vec4 viewVec = normalize(-position); + + vec2 tilePos; + tilePos.x = int(gl_FragCoord.x/TILE_SIZE); + tilePos.y = int(gl_FragCoord.y/TILE_SIZE); + + LightResult totalLighting; + totalLighting.Diffuse = vec4(AmbientColor.rgb, 1.0); + int currentTile = int(floor(gl_FragCoord.x/TILE_SIZE) + (floor(gl_FragCoord.y/TILE_SIZE) * int(ScreenDimensions.x/TILE_SIZE))); + + int start = int(LightGrids.Data[currentTile].Start); + int amount = int(LightGrids.Data[currentTile].Amount); + + for(int i = start; i < start + amount; i++) { + + int l = int(LightIndex[i]); + LightSource light = LightSources.List[l]; + + LightResult light_result; + //These if statements should be removed. + if(light.Type == 1) { // point + light_result = CalcPointLightSource(V * light.Position, light.Radius, light.Color, light.Intensity, viewVec, position, normal, light.Falloff); + } else if (light.Type == 2) { //Directional + light_result = CalcDirectionalLightSource(V * light.Direction, light.Color, light.Intensity, viewVec, normal); + } + totalLighting.Diffuse += light_result.Diffuse; + totalLighting.Specular += light_result.Specular; + } + + vec4 color_result = mix((Color * diffuseTexel * DiffuseColor), Input.ExplosionColor, Input.ExplosionPercentageElapsed); + color_result = color_result * (totalLighting.Diffuse + (totalLighting.Specular * specularTexel)); + //vec4 color_result = (DiffuseColor + Input.ExplosionColor) * (totalLighting.Diffuse + (totalLighting.Specular * specularTexel)) * diffuseTexel * Color; + + + float pos = ((P * vec4(Input.Position, 1)).y + 1.0)/2.0; + + if(pos <= FillPercentage) { + color_result += FillColor; + } + sceneColor = vec4(color_result.xyz, clamp(color_result.a, 0, 1)); + color_result += glowTexel*3; + + bloomColor = vec4(clamp(color_result.xyz - 1.0, 0, 100), 1.0); + + //Tiled Debug Code + /* + if(int(gl_FragCoord.x)%16 == 0 || int(gl_FragCoord.y)%16 == 0 ) { + sceneColor += vec4(0.5, 0, 0, 0); + } else { + sceneColor += vec4(LightGrids.Data[int(tilePos.x + tilePos.y*80)].Amount/LightSources.List.length(), 0, 0, 1); + } + */ +} + + diff --git a/resources/Shaders/Picking.vert.glsl b/resources/Shaders/Picking.vert.glsl index 205a8fdd..f888cd16 100644 --- a/resources/Shaders/Picking.vert.glsl +++ b/resources/Shaders/Picking.vert.glsl @@ -3,15 +3,12 @@ uniform mat4 M; uniform mat4 V; uniform mat4 P; -uniform mat4 Bones[100]; layout(location = 0) in vec3 Position; layout(location = 1) in vec3 Normal; layout(location = 2) in vec3 Tangent; layout(location = 3) in vec3 BiTangent; layout(location = 4) in vec2 TextureCoords; -layout(location = 5) in vec4 BoneIndices; -layout(location = 6) in vec4 BoneWeights; out VertexData{ vec3 Position; @@ -19,14 +16,6 @@ out VertexData{ void main() { - mat4 boneTransform = mat4(1); - if(BoneWeights[0] > 0.0f){ - boneTransform = BoneWeights[0] * Bones[int(BoneIndices[0])] - + BoneWeights[1] * Bones[int(BoneIndices[1])] - + BoneWeights[2] * Bones[int(BoneIndices[2])] - + BoneWeights[3] * Bones[int(BoneIndices[3])]; - } - - gl_Position = P*V*M*boneTransform * vec4(Position, 1.0); - Output.Position = (boneTransform * vec4(Position, 1.0)).xyz; + gl_Position = P*V*M * vec4(Position, 1.0); + Output.Position = Position, 1.0; } \ No newline at end of file diff --git a/resources/Shaders/PickingSkinned.vert.glsl b/resources/Shaders/PickingSkinned.vert.glsl new file mode 100644 index 00000000..205a8fdd --- /dev/null +++ b/resources/Shaders/PickingSkinned.vert.glsl @@ -0,0 +1,32 @@ +#version 430 + +uniform mat4 M; +uniform mat4 V; +uniform mat4 P; +uniform mat4 Bones[100]; + +layout(location = 0) in vec3 Position; +layout(location = 1) in vec3 Normal; +layout(location = 2) in vec3 Tangent; +layout(location = 3) in vec3 BiTangent; +layout(location = 4) in vec2 TextureCoords; +layout(location = 5) in vec4 BoneIndices; +layout(location = 6) in vec4 BoneWeights; + +out VertexData{ + vec3 Position; +}Output; + +void main() +{ + mat4 boneTransform = mat4(1); + if(BoneWeights[0] > 0.0f){ + boneTransform = BoneWeights[0] * Bones[int(BoneIndices[0])] + + BoneWeights[1] * Bones[int(BoneIndices[1])] + + BoneWeights[2] * Bones[int(BoneIndices[2])] + + BoneWeights[3] * Bones[int(BoneIndices[3])]; + } + + gl_Position = P*V*M*boneTransform * vec4(Position, 1.0); + Output.Position = (boneTransform * vec4(Position, 1.0)).xyz; +} \ No newline at end of file diff --git a/resources/Shaders/ShieldStencil.frag.glsl b/resources/Shaders/ShieldStencil.frag.glsl new file mode 100644 index 00000000..db88ab24 --- /dev/null +++ b/resources/Shaders/ShieldStencil.frag.glsl @@ -0,0 +1,15 @@ +#version 430 + +in VertexData{ + vec3 Position; +}Input; + + +out vec4 fragmentColor; + +void main() +{ + fragmentColor = vec4(0.5, 0.0, 0.0, 0.0); +} + + diff --git a/resources/Shaders/ShieldStencil.vert.glsl b/resources/Shaders/ShieldStencil.vert.glsl new file mode 100644 index 00000000..b6669f2c --- /dev/null +++ b/resources/Shaders/ShieldStencil.vert.glsl @@ -0,0 +1,19 @@ +#version 430 + +uniform mat4 M; +uniform mat4 V; +uniform mat4 P; + +layout(location = 0) in vec3 Position; + + +out VertexData{ + vec3 Position; +}Output; + +void main() +{ + gl_Position = P * V * M * vec4(Position, 1.0); + + Output.Position = Position; +} \ No newline at end of file diff --git a/resources/Shaders/ShieldStencilSkinned.vert.glsl b/resources/Shaders/ShieldStencilSkinned.vert.glsl new file mode 100644 index 00000000..ce2a142d --- /dev/null +++ b/resources/Shaders/ShieldStencilSkinned.vert.glsl @@ -0,0 +1,33 @@ +#version 430 + +uniform mat4 M; +uniform mat4 V; +uniform mat4 P; +uniform mat4 Bones[100]; + + +layout(location = 0) in vec3 Position; +layout(location = 5) in vec4 BoneIndices; +layout(location = 6) in vec4 BoneWeights; + + + +out VertexData{ + vec3 Position; +}Output; + +void main() +{ + mat4 boneTransform = mat4(1); + + if(BoneWeights[0] > 0.0f){ + boneTransform = BoneWeights[0] * Bones[int(BoneIndices[0])] + + BoneWeights[1] * Bones[int(BoneIndices[1])] + + BoneWeights[2] * Bones[int(BoneIndices[2])] + + BoneWeights[3] * Bones[int(BoneIndices[3])]; + } + + gl_Position = P*V*M*boneTransform * vec4(Position, 1.0); + + Output.Position = vec3(0.0); +} \ No newline at end of file diff --git a/resources/Shaders/Sprite.frag.glsl b/resources/Shaders/Sprite.frag.glsl new file mode 100644 index 00000000..a1ff3025 --- /dev/null +++ b/resources/Shaders/Sprite.frag.glsl @@ -0,0 +1,40 @@ +#version 430 + +uniform vec4 Color; +uniform vec4 FillColor; +uniform float FillPercentage; +uniform mat4 M; +uniform mat4 V; +uniform mat4 P; + +layout (binding = 0) uniform sampler2D DiffuseTexture; +layout (binding = 1) uniform sampler2D GlowMapTexture; + + +in VertexData{ + vec3 Position; + vec3 Normal; + vec2 TextureCoordinate; +}Input; + + +out vec4 sceneColor; +out vec4 bloomColor; + +void main() +{ + vec4 diffuseTexel = texture2D(DiffuseTexture, Input.TextureCoordinate); + vec4 glowTexel = texture2D(GlowMapTexture, Input.TextureCoordinate); + + vec4 color_result = Color * diffuseTexel; + + float pos = ((P * vec4(Input.Position, 1)).y + 1.0)/2.0; + if(pos <= FillPercentage) { + color_result = FillColor*diffuseTexel.a; + } + sceneColor = vec4(color_result.xyz, clamp(color_result.a, 0, 1)); + + bloomColor = vec4(clamp((glowTexel.xyz*3) - 1.0, 0, 100), 1.0); +} + + diff --git a/resources/Shaders/Sprite.vert.glsl b/resources/Shaders/Sprite.vert.glsl new file mode 100644 index 00000000..c09d745b --- /dev/null +++ b/resources/Shaders/Sprite.vert.glsl @@ -0,0 +1,25 @@ +#version 430 + +uniform mat4 M; +uniform mat4 V; +uniform mat4 P; + +layout(location = 0) in vec3 Position; +layout(location = 1) in vec3 Normal; +layout(location = 4) in vec2 TextureCoords; + +out VertexData{ + vec3 Position; + vec3 Normal; + vec2 TextureCoordinate; +}Output; + +void main() +{ + + gl_Position = P * V * M * vec4(Position, 1.0); + + Output.Position = Position; + Output.TextureCoordinate = TextureCoords; + Output.Normal = Normal; +} \ No newline at end of file diff --git a/src/Engine/CMakeLists.txt b/src/Engine/CMakeLists.txt index 1ed39177..19763310 100644 --- a/src/Engine/CMakeLists.txt +++ b/src/Engine/CMakeLists.txt @@ -3,7 +3,7 @@ project(TacticalZ-Engine) find_package(OpenGL REQUIRED) find_package(GLEW REQUIRED) find_package(GLFW REQUIRED) -find_package(Boost REQUIRED COMPONENTS system filesystem thread chrono) +find_package(Boost REQUIRED COMPONENTS system filesystem thread chrono program_options) find_package(assimp REQUIRED) find_package(ZLIB REQUIRED) find_package(PNG REQUIRED) diff --git a/src/Engine/Collision/CollidableOctreeSystem.cpp b/src/Engine/Collision/CollidableOctreeSystem.cpp deleted file mode 100644 index 476414dd..00000000 --- a/src/Engine/Collision/CollidableOctreeSystem.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "Collision/CollidableOctreeSystem.h" - -void CollidableOctreeSystem::Update(double dt) -{ - m_Octree->ClearDynamicObjects(); -} - -void CollidableOctreeSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) -{ - if (entity.HasComponent("AABB")) { - boost::optional absoluteAABB = Collision::EntityAbsoluteAABB(entity); - if (absoluteAABB) { - m_Octree->AddDynamicObject(*absoluteAABB); - } - } else if (entity.HasComponent("Model")) { - // TODO: Derive AABB from model - } -} \ No newline at end of file diff --git a/src/Engine/Collision/Collision.cpp b/src/Engine/Collision/Collision.cpp index 3f5cf0d3..7b182de1 100644 --- a/src/Engine/Collision/Collision.cpp +++ b/src/Engine/Collision/Collision.cpp @@ -1,9 +1,12 @@ #include +#include #include "Collision/Collision.h" #include "Engine/GLM.h" #include "Core/World.h" #include "Rendering/Model.h" +#include "imgui/imgui.h" +#include "Core/Octree.h" namespace Collision { @@ -116,67 +119,98 @@ bool AABBVsAABB(const AABB& a, const AABB& b, glm::vec3& minimumTranslation) return glm::all(axisesIntersecting); } -bool RayVsModel(const Ray& ray, - const std::vector& modelVertices, - const std::vector& modelIndices) +bool RayVsTriangle(const Ray& ray, + const glm::vec3& v0, + const glm::vec3& v1, + const glm::vec3& v2, + bool trueOnNegativeDistance) { - for (int i = 0; i < modelIndices.size(); ++i) { - glm::vec3 v0 = modelVertices[modelIndices[i]].Position; - glm::vec3 e1 = modelVertices[modelIndices[++i]].Position - v0; //v1 - v0 - glm::vec3 e2 = modelVertices[modelIndices[++i]].Position - v0; //v2 - v0 - glm::vec3 m = ray.Origin() - v0; - glm::vec3 MxE1 = glm::cross(m, e1); - glm::vec3 DxE2 = glm::cross(ray.Direction(), e2); - float DetInv = glm::dot(e1, DxE2); - if (std::abs(DetInv) < FLT_EPSILON) { - continue; - } - DetInv = 1.0f / DetInv; - float u = glm::dot(m, DxE2) * DetInv; - float v = glm::dot(ray.Direction(), MxE1) * DetInv; - //u,v can be very close to 0 but still negative sometimes. added a deltafactor to compensate for that problem - if ((u + 0.001f) < 0 || (v + 0.001f) < 0 || 1 < u + v) { - continue; - } - //Here, u and v are positive, u+v <= 1, and if distance is positive - triangle is hit. - if (0 <= glm::dot(e2, MxE1) * DetInv) { + glm::vec3 e1 = v1 - v0; //v1 - v0 + glm::vec3 e2 = v2 - v0; //v2 - v0 + glm::vec3 m = ray.Origin() - v0; + glm::vec3 MxE1 = glm::cross(m, e1); + glm::vec3 DxE2 = glm::cross(ray.Direction(), e2); + float DetInv = glm::dot(e1, DxE2); + if (std::abs(DetInv) < FLT_EPSILON) { + return false; + } + DetInv = 1.0f / DetInv; + float u = glm::dot(m, DxE2) * DetInv; + float v = glm::dot(ray.Direction(), MxE1) * DetInv; + //u,v can be very close to 0 but still negative sometimes. added a deltafactor to compensate for that problem + if ((u + 0.001f) < 0 || (v + 0.001f) < 0 || 1 < u + v) { + return false; + } + //Here, u and v are positive, u+v <= 1, and if distance is positive - triangle is hit. + return trueOnNegativeDistance || 0 <= glm::dot(e2, MxE1) * DetInv; +} + +bool RayVsModel(const Ray& ray, + const RawModel::Vertex* modelVertices, + const std::vector& modelIndices, + const glm::mat4& modelMatrix) +{ + 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); + if (RayVsTriangle(ray, v0, v1, v2)) { return true; } } return false; } +bool RayVsTriangle(const Ray& ray, + const glm::vec3& v0, + const glm::vec3& v1, + const glm::vec3& v2, + float& outDistance, + float& outUCoord, + float& outVCoord, + bool trueOnNegativeDistance) +{ + glm::vec3 e1 = v1 - v0; //v1 - v0 + glm::vec3 e2 = v2 - v0; //v2 - v0 + glm::vec3 m = ray.Origin() - v0; + glm::vec3 MxE1 = glm::cross(m, e1); + glm::vec3 DxE2 = glm::cross(ray.Direction(), e2);//pVec + float DetInv = glm::dot(e1, DxE2); + if (std::abs(DetInv) < FLT_EPSILON) { + return false; + } + DetInv = 1.0f / DetInv; + float dist = glm::dot(e2, MxE1) * DetInv; + if (dist >= outDistance) { + return false; + } + outDistance = dist; + outUCoord = glm::dot(m, DxE2) * DetInv; + outVCoord = glm::dot(ray.Direction(), MxE1) * DetInv; + + //u,v can be very close to 0 but still negative sometimes. added a deltafactor to compensate for that problem + //If u and v are positive, u+v <= 1, dist is positive, and less than closest. + return (0 <= (outUCoord + 0.001f) && 0 <= (outVCoord + 0.001f) && outUCoord + outVCoord <= 1 && (trueOnNegativeDistance || 0 <= dist)); +} + bool RayVsModel(const Ray& ray, - const std::vector& modelVertices, + const RawModel::Vertex* modelVertices, const std::vector& modelIndices, + const glm::mat4& modelMatrix, float& outDistance, float& outUCoord, float& outVCoord) { outDistance = INFINITY; bool hit = false; - for (int i = 0; i < modelIndices.size(); ++i) { - glm::vec3 v0 = modelVertices[modelIndices[i]].Position; - glm::vec3 e1 = modelVertices[modelIndices[++i]].Position - v0; //v1 - v0 - glm::vec3 e2 = modelVertices[modelIndices[++i]].Position - v0; //v2 - v0 - glm::vec3 m = ray.Origin() - v0; - glm::vec3 MxE1 = glm::cross(m, e1); - glm::vec3 DxE2 = glm::cross(ray.Direction(), e2);//pVec - float DetInv = glm::dot(e1, DxE2); - if (std::abs(DetInv) < FLT_EPSILON) { - continue; - } - DetInv = 1.0f / DetInv; - float dist = glm::dot(e2, MxE1) * DetInv; - if (dist >= outDistance) { - continue; - } - float u = glm::dot(m, DxE2) * DetInv; - float v = glm::dot(ray.Direction(), MxE1) * DetInv; - - //u,v can be very close to 0 but still negative sometimes. added a deltafactor to compensate for that problem - //If u and v are positive, u+v <= 1, dist is positive, and less than closest. - if (0 <= (u + 0.001f) && 0 <= (v + 0.001f) && u + v <= 1 && 0 <= dist) { + 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); + float dist = INFINITY; + float u; + float v; + if (RayVsTriangle(ray, v0, v1, v2, dist, u, v)) { outDistance = dist; outUCoord = u; outVCoord = v; @@ -187,104 +221,457 @@ bool RayVsModel(const Ray& ray, } bool RayVsModel(const Ray& ray, - const std::vector& modelVertices, + const RawModel::Vertex* modelVertices, const std::vector& modelIndices, + const glm::mat4& modelMatrix, glm::vec3& outHitPosition) { float u; float v; float dist; - bool hit = RayVsModel(ray, modelVertices, modelIndices, dist, u, v); + bool hit = RayVsModel(ray, modelVertices, modelIndices, modelMatrix, dist, u, v); outHitPosition = ray.Origin() + dist * ray.Direction(); return hit; } -bool AABBvsTriangles(const AABB& box, const std::vector& modelVertices, const std::vector& modelIndices, const glm::mat4& modelMatrix, glm::vec3& outResolutionVector) +constexpr inline int signNonZero(float x) { - bool hit = false; - - const glm::vec3& origin = box.Origin(); - const glm::vec3& min = box.MinCorner(); - const glm::vec3& max = box.MaxCorner(); - - outResolutionVector.x = INFINITY; - - for (int i = 0; i < modelIndices.size(); ++i) { - glm::vec3 p = modelVertices[i].Position; - p = glm::vec3(modelMatrix * glm::vec4(p.x, p.y, p.z, 1)); - - float distFromOrigin = glm::abs(origin.x - p.x); - float penetration = box.HalfSize().x - distFromOrigin; - if (penetration > 0 && penetration < glm::abs(outResolutionVector.x)) { - if (p.x > origin.x) { - outResolutionVector.x = -penetration; - } else { - outResolutionVector.x = penetration; - } - hit = true; - } - //glm::vec3 pLocal = origin - p; - //for (int axis = 0; axis < 3; ++axis) { - // if (p[axis] < min[axis] || p[axis] > max[axis]) { - // continue; - // } - - // if (glm::abs(pLocal[axis]) < box.HalfSize()[axis]) { - // outResolutionVector[axis] = (glm::sign(pLocal[axis]) * box.HalfSize()[axis]) - pLocal[axis]; - // hit = true; - // } - //} - } - - return hit; + return x < 0 ? -1 : 1; } -bool attachAABBComponentFromModel(World* world, EntityID id) +inline glm::vec3 signNonZero(const glm::vec3& x) { - if (!world->HasComponent(id, "Model")) { - return false; - } - ComponentWrapper model = world->GetComponent(id, "Model"); - ComponentWrapper collision = world->AttachComponent(id, "AABB"); - Model* modelRes = ResourceManager::Load(model["Resource"]); - if (modelRes == nullptr) { - return false; + glm::vec3 r; + for (int i = 0; i < 3; ++i) { + r[i] = (float)signNonZero(x[i]); } + return r; +} - glm::mat4 modelMatrix = modelRes->Matrix(); +template +bool vectorHasLength(const T& vec) +{ + return glm::any(glm::greaterThan(glm::abs(vec), T(0.0001f))); +} - glm::vec3 mini = glm::vec3(INFINITY, INFINITY, INFINITY); - glm::vec3 maxi = glm::vec3(-INFINITY, -INFINITY, -INFINITY); - for (const auto& v : modelRes->Vertices()) { - const auto& wPos = modelMatrix * glm::vec4(v.Position.x, v.Position.y, v.Position.z, 1); - maxi.x = std::max(wPos.x, maxi.x); - maxi.y = std::max(wPos.y, maxi.y); - maxi.z = std::max(wPos.z, maxi.z); - mini.x = std::min(wPos.x, mini.x); - mini.y = std::min(wPos.y, mini.y); - mini.z = std::min(wPos.z, mini.z); +bool rectangleVsTriangle(const glm::vec2& boxMin, + const glm::vec2& boxMax, + const std::array& triPos, + glm::vec2& resolutionDirection, + float& resolutionDistanceSq, + bool& pushedFromTriNormal) +{ + pushedFromTriNormal = false; + resolutionDistanceSq = INFINITY; + //Project along box normals (coordinate axes, since it's axis-aligned). + for (int ax = 0; ax < 2; ++ax) { + float minTri = INFINITY; + float maxTri = -INFINITY; + for (const glm::vec2& t : triPos) { + minTri = std::min(t[ax], minTri); + maxTri = std::max(t[ax], maxTri); + } + if (boxMax[ax] <= minTri || maxTri <= boxMin[ax]) { + return false; + } + + //Here: maxBox > minTri && minBox < maxTri + //Left is negative. + float leftRes = minTri - boxMax[ax]; + float rightRes = maxTri - boxMin[ax]; + float push = rightRes < -leftRes ? rightRes : leftRes; + float absPushSq = abs(push); + absPushSq *= absPushSq; + + if (absPushSq < resolutionDistanceSq) { + resolutionDistanceSq = absPushSq; + resolutionDirection[1 - ax] = 0.f; + resolutionDirection[ax] = push; + } + } + //Project along triangle normals. + //Put edges into normal vector, make normals in the loop. + std::array triNormals = { + triPos[1] - triPos[0], + triPos[2] - triPos[1], + triPos[0] - triPos[2] + }; + std::array boxPos = { + boxMax, + glm::vec2(boxMax.x, boxMin.y), + glm::vec2(boxMin.x, boxMax.y), + boxMin + }; + for (auto& normal : triNormals) { + if (!vectorHasLength(normal)) { + continue; + } + //Rotate edge to a normal. + normal = glm::normalize(glm::vec2(-normal.y, normal.x)); + //Project triangle onto the normal. + float minTri = INFINITY; + float maxTri = -INFINITY; + for (const glm::vec2& point : triPos) { + float dot = glm::dot(normal, point); + minTri = std::min(dot, minTri); + maxTri = std::max(dot, maxTri); + } + //Project box onto the normal. + float minBox = INFINITY; + float maxBox = -INFINITY; + for (const glm::vec2& point : boxPos) { + float dot = glm::dot(normal, point); + minBox = std::min(dot, minBox); + maxBox = std::max(dot, maxBox); + } + if (maxBox <= minTri || maxTri <= minBox) { + return false; + } + + //Here: maxBox > minTri && minBox < maxTri + //Left is negative. + float leftRes = minTri - maxBox; + float rightRes = maxTri - minBox; + float push = rightRes < -leftRes ? rightRes : leftRes; + float absPushSq = abs(push); + absPushSq *= absPushSq; + + if (absPushSq < resolutionDistanceSq) { + resolutionDistanceSq = absPushSq; + resolutionDirection = push * normal; + pushedFromTriNormal = true; + } } - collision["Origin"] = 0.5f * (maxi + mini); - collision["Size"] = maxi - mini; return true; } -boost::optional EntityAbsoluteAABB(EntityWrapper& entity) +constexpr float SlopeConstant(float degrees) { - if (!entity.HasComponent("AABB")) { + return (1.0f - degrees / 90.f); +} + +//Returns true if the angle between horizon and the collision surface is less than 45 degrees. +constexpr bool FaceIsGround(float faceNormalY) +{ + //TODO: Perhaps the 45 degrees could be saved in a component or in the config.. + return faceNormalY > SlopeConstant(45.0f); +} + +//An array containing 3 int pairs { 0, 2 }, { 0, 1 }, { 1, 2 } +constexpr std::array, 3> dimensionPairs({ std::pair(0, 2), std::pair(0, 1), std::pair(1, 2) }); + +bool AABBvsTriangle(const AABB& box, + const std::array& triPos, + const glm::vec3& originalBoxVelocity, + float verticalStepHeight, + bool& isOnGround, + glm::vec3& boxVelocity, + glm::vec3& outResolution) +{ + //Check so we don't have a zero area triangle when calculating the normal. + //Also, don't check a triangle facing away from the player. + //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; + } + triNormal = glm::normalize(triNormal); + + enum BoxTriResolveCase + { + ResolveDimX, + ResolveDimY, + ResolveDimZ, + Line, //Box edge colliding with triangle line. + Corner //Box corner colliding with the triangle face. + }; + struct Resolution + { + Resolution() + : DistanceSq(INFINITY) + , Vector(0.f) + { } + BoxTriResolveCase Case; + float DistanceSq; + glm::vec3 Vector; + }; + //The smallest resolution that solves the collision. + Resolution resolveShortest; + //The smallest resolution that solves the collision, that resolves upwards. + Resolution resolveUpwards; + //If player stands on the ground and collides with a ground triangle, + //we might step up onto it if the step is small enough. + bool canStairStepUp = isOnGround && FaceIsGround(triNormal.y); + + const glm::vec3& origin = box.Origin(); + const glm::vec3& half = box.HalfSize(); + const glm::vec3& min = box.MinCorner(); + const glm::vec3& max = box.MaxCorner(); + + //For each projection in xy-, xz-, and yx-planes. + for (std::pair dim : dimensionPairs) { + //2D Triangle. + //Project triangle. + std::array t2D = { + glm::vec2(triPos[0][dim.first], triPos[0][dim.second]), + glm::vec2(triPos[1][dim.first], triPos[1][dim.second]), + glm::vec2(triPos[2][dim.first], triPos[2][dim.second]) + }; + //Project box. + glm::vec2 boxMin(min[dim.first], min[dim.second]); + glm::vec2 boxMax(max[dim.first], max[dim.second]); + glm::vec2 resolutionVector; + float resolutionDist; + bool pushedFromTriangleLine; + //if projections don't overlap, return false. + if (!rectangleVsTriangle(boxMin, boxMax, t2D, resolutionVector, resolutionDist, pushedFromTriangleLine)) { + return false; + } else { + //Overwrite the smallest resolution if this is smaller. + if (resolutionDist < resolveShortest.DistanceSq) { + resolveShortest.Vector = glm::vec3(0.f); + resolveShortest.Vector[dim.first] = resolutionVector.x; + resolveShortest.Vector[dim.second] = resolutionVector.y; + resolveShortest.DistanceSq = resolutionDist; + //If we pushed away from triangle line (edge), or if we + //move the player along one coordinate axis (pick the dimension that isn't zero). + resolveShortest.Case = pushedFromTriangleLine ? Line : static_cast((abs(resolveShortest.Vector[dim.first]) < 0.0001f) ? dim.second : dim.first); + } + //Overwrite the smallest upward resolution if this is smaller, and resolves upwards. + constexpr int yAxis = 1; + bool resIsUpwardsIn3D = dim.first == yAxis && resolutionVector.x > 0 || dim.second == yAxis && resolutionVector.y > 0; + if (canStairStepUp && resIsUpwardsIn3D && resolutionDist < resolveUpwards.DistanceSq) { + resolveUpwards.Vector = glm::vec3(0.f); + resolveUpwards.Vector[dim.first] = resolutionVector.x; + resolveUpwards.Vector[dim.second] = resolutionVector.y; + resolveUpwards.DistanceSq = resolutionDist; + //If we pushed away from triangle line (edge), or if we + //move the player along one coordinate axis (pick the dimension that isn't zero). + resolveUpwards.Case = pushedFromTriangleLine ? Line : static_cast((abs(resolveUpwards.Vector[dim.first]) < 0.0001f) ? dim.second : dim.first); + } + } + } + + //If the triangle does intersect any of the cube diagonals, it will + //intersect the cube diagonal that comes + //closest to being perpendicular to the plane of the triangle. + glm::vec3 diagonal = signNonZero(triNormal) * half; + //The triangle plane contains all points P in dot(triNormal, P) == dot(triNormal, v0) + //The diagonal line contains all points P in P = origin + diagonal * t. + 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; + } + glm::vec3 cornerResolution = (1+t) * diagonal; + //Overwrite the smallest resolution if cornerResolution is smaller. + float lenSq = glm::length2(cornerResolution); + if (lenSq < resolveShortest.DistanceSq) { + resolveShortest.Vector = cornerResolution; + resolveShortest.Case = Corner; + } + if (canStairStepUp && cornerResolution.y > 0 && lenSq < resolveUpwards.DistanceSq) { + resolveUpwards.Vector = cornerResolution; + resolveUpwards.Case = Corner; + resolveUpwards.DistanceSq = lenSq; + } + + //Force the resolution upwards if it is smaller than the threshold verticalStepHeight. + //Else take the shortest resolution. + bool takeUp = resolveUpwards.Vector.y > 0 && resolveUpwards.Vector.y < verticalStepHeight; + Resolution& bestResolve = takeUp ? resolveUpwards : resolveShortest; + outResolution = bestResolve.Vector; + + glm::vec3 projNorm; + switch (bestResolve.Case) { + case ResolveDimY: + boxVelocity.y = 0.f; + if (outResolution.y > 0) + isOnGround = true; + case ResolveDimX: + 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; + case Line: + projNorm = glm::normalize(outResolution); + break; + case Corner: + projNorm = triNormal; + break; + default: + break; + } + + //If the collision was not on steep wall or similarly (e.g. walking on the ground), force resolution in y only. + if (FaceIsGround(projNorm.y)) { + //Ensure that the player always is moved upwards, instead of sliding down. + float len = glm::length(outResolution); + float ang = glm::half_pi() - glm::acos(outResolution.y / len); + if (len > 0.0000001f && ang > 0.0000001f) { + outResolution.x = 0; + outResolution.y = len / glm::sin(ang); + outResolution.z = 0; + } + //Also zero the vertical velocity, if it is positive, else project it onto the normal. + //Project the velocity onto the normal of the hit line/face. + //w = v - *n, |n|==1. + boxVelocity.y = std::min(boxVelocity.y - glm::dot(boxVelocity, projNorm) * projNorm.y, 0.f); + isOnGround = true; + } else { + //Enter here if the triangle is a steep slope, and it is not facing downwards. + //Project the velocity onto the normal of the hit line/face. + //w = v - *n, |n|==1. + //"ice cream"-effect, air resistance + projected velocity. + if (!isOnGround) { + boxVelocity = boxVelocity - glm::dot(boxVelocity, projNorm) * projNorm; + } + } + return true; +} + +bool AABBvsTriangles(const AABB& box, + const RawModel::Vertex* modelVertices, + const std::vector& modelIndices, + const glm::mat4& modelMatrix, + glm::vec3& boxVelocity, + float verticalStepHeight, + bool& isOnGround, + glm::vec3& outResolutionVector) +{ + bool hit = false; + + bool everHitTheGround = false; + AABB newBox = box; + outResolutionVector = glm::vec3(0.f); + glm::vec3 originalBoxVelocity(boxVelocity); + for (int i = 0; i < modelIndices.size(); ) { + std::array triVertices = { + Transform::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix), + Transform::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix), + Transform::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix) + }; + glm::vec3 outVec; + bool collideWithGround = isOnGround; + if (AABBvsTriangle(newBox, triVertices, originalBoxVelocity, verticalStepHeight, collideWithGround, boxVelocity, outVec)) { + hit = true; + outResolutionVector += outVec; + newBox = AABB::FromOriginSize(newBox.Origin() + outVec, newBox.Size()); + if (collideWithGround) { + everHitTheGround = isOnGround = true; + } + } + } + + if (!everHitTheGround) { + isOnGround = false; + } + return hit; +} + +boost::optional EntityAbsoluteAABB(EntityWrapper& entity, bool takeModelBox) +{ + AABB modelSpaceBox; + if (entity.HasComponent("AABB") && !takeModelBox) { + ComponentWrapper& cAABB = entity["AABB"]; + modelSpaceBox = EntityAABB::FromOriginSize((glm::vec3)cAABB["Origin"], (glm::vec3)cAABB["Size"]); + } else if (entity.HasComponent("Model")) { + std::string res = entity["Model"]["Resource"]; + if (res.empty()) { + return boost::none; + } + Model* model; + try { + model = ResourceManager::Load<::Model, true>(res); + } catch (const Resource::StillLoadingException&) { + return boost::none; + } catch (const std::exception&) { + return boost::none; + } + modelSpaceBox = model->Box(); + } else { return boost::none; } - ComponentWrapper& cAABB = entity["AABB"]; - glm::vec3 absPosition = Transform::AbsolutePosition(entity.World, entity.ID); - glm::vec3 absScale = Transform::AbsoluteScale(entity.World, entity.ID); - glm::vec3 origin = absPosition + (glm::vec3)cAABB["Origin"]; - glm::vec3 size = (glm::vec3)cAABB["Size"] * absScale; + glm::mat4 modelMat = Transform::AbsoluteTransformation(entity); + glm::vec3 mini(INFINITY); + glm::vec3 maxi(-INFINITY); + glm::vec3 maxCorner = modelSpaceBox.MaxCorner(); + glm::vec3 minCorner = modelSpaceBox.MinCorner(); + for (int i = 0; i < 8; ++i) { + std::bitset<3> bits(i); + glm::vec3 corner; + 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); + mini = glm::min(mini, corner); + maxi = glm::max(maxi, corner); + } + + EntityAABB aabb; + aabb = AABB(mini, maxi); - EntityAABB aabb = EntityAABB::FromOriginSize(origin, size); aabb.Entity = entity; - return aabb; } +boost::optional AbsoluteAABBExplosionEffect(EntityWrapper& entity) +{ + boost::optional modelBox = EntityAbsoluteAABB(entity, true); + if (!modelBox) { + return boost::none; + } + bool isRandom = (bool)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"]; + randomVel *= (random + 1); + float endVelocity = randomVel.y; + if ((bool)entity["ExplosionEffect"]["ExponentialAccelaration"]) { + endVelocity *= endVelocity / 2.f; + } + float maxRadius = (float)(double)entity["ExplosionEffect"]["ExplosionDuration"] * endVelocity; + glm::vec3 size; + AABB explosionBox(origin - (size / 2.f), origin + (size / 2.f)); + + glm::vec3 mini = glm::min(explosionBox.MinCorner(), (*modelBox).MinCorner()); + glm::vec3 maxi = glm::max(explosionBox.MaxCorner(), (*modelBox).MaxCorner()); + EntityAABB aabb = AABB(mini, maxi); + aabb.Entity = entity; + return aabb; } + +boost::optional EntityFirstHitByRay(const Ray& ray, std::vector entitiesPotentiallyHitSorted, float outDistance, glm::vec3& outIntersectPos) +{ + for (EntityAABB& entityBox : entitiesPotentiallyHitSorted) { + if (!entityBox.Entity.HasComponent("Model")) { + continue; + } + std::string res = entityBox.Entity["Model"]["Resource"]; + if (res.empty()) { + continue; + } + Model* model; + try { + model = ResourceManager::Load<::Model, true>(res); + } catch (const std::exception&) { + continue; + } + float u, v; + if (RayVsModel(ray, model->Vertices(), model->m_RawModel->m_Indices, Transform::ModelMatrix(entityBox.Entity), outDistance, u, v)) { + outIntersectPos = ray.Origin() + outDistance * ray.Direction(); + return entityBox; + } + } + return boost::none; +} + +boost::optional EntityFirstHitByRay(const Ray& ray, Octree* octree, float outDistance, glm::vec3& outIntersectPos) +{ + std::vector outObjects; + octree->ObjectsPossiblyHitByRay(ray, outObjects); + return Collision::EntityFirstHitByRay(ray, outObjects, outDistance, outIntersectPos); +} + +} \ No newline at end of file diff --git a/src/Engine/Collision/CollisionSystem.cpp b/src/Engine/Collision/CollisionSystem.cpp index 382238e7..afd09022 100644 --- a/src/Engine/Collision/CollisionSystem.cpp +++ b/src/Engine/Collision/CollisionSystem.cpp @@ -1,6 +1,7 @@ #include "Collision/Collision.h" #include "Collision/CollisionSystem.h" #include "Core/AABB.h" +#include "Rendering/Model.h" void CollisionSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) { @@ -19,39 +20,48 @@ void CollisionSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& c // Collide against octree items m_OctreeResult.clear(); m_Octree->ObjectsInSameRegion(*boundingBox, m_OctreeResult); + bool everHitTheGround = false; for (auto& boxB : m_OctreeResult) { glm::vec3 resolutionVector; if (boxA.Entity == boxB.Entity) { continue; } - if (Collision::AABBVsAABB(boxA, boxB, resolutionVector)) { + 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(boxB.Entity["Model"]["Resource"]); + } catch (const std::exception&) { + continue; + } + + glm::mat4 modelMatrix = Transform::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->Vertices(), model->m_Indices, modelMatrix, inOutVelocity, verticalStepHeight, isOnGround, resolutionVector)) { + (glm::vec3&)cTransform["Position"] += resolutionVector; + 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. (glm::vec3&)cTransform["Position"] += resolutionVector; if (resolutionVector.y > 0) { + everHitTheGround = true; + (bool)cPhysics["IsOnGround"] = true; ((glm::vec3&)cPhysics["Velocity"]).y = 0.f; } } } - // HACK: Temporarily collide against all collidable models since they're not in the octree yet - //auto otherCollidables = world->GetComponents("Model"); - //for (auto& cModel : *otherCollidables) { - // if (cModel.EntityID == entity) { - // continue; - // } - // if (!world->HasComponent(cModel.EntityID, "Collidable")) { - // continue; - // } - - // auto absPosition = RenderQueueFactory::AbsolutePosition(world, cModel.EntityID); - // auto absOrientation = RenderQueueFactory::AbsoluteOrientation(world, cModel.EntityID); - // auto absScale = RenderQueueFactory::AbsoluteScale(world, cModel.EntityID); - // glm::mat4 modelMatrix = glm::translate(absPosition); // *glm::toMat4(absOrientation) * glm::scale(absScale); - - // auto model = ResourceManager::Load(cModel["Resource"]); - // glm::vec3 resolutionVector; - // if (Collision::AABBvsTriangles(boxA, model->m_Vertices, model->m_Indices, modelMatrix, resolutionVector)) { - // (glm::vec3&)cTransform["Position"] += resolutionVector; - // } - //} -} \ No newline at end of file + //This should apply air friction and such, iff zero models were hit. + if (!everHitTheGround) { + (bool)cPhysics["IsOnGround"] = false; + } +} diff --git a/src/Engine/Collision/FillFrustumOctreeSystem.cpp b/src/Engine/Collision/FillFrustumOctreeSystem.cpp new file mode 100644 index 00000000..2be8bee0 --- /dev/null +++ b/src/Engine/Collision/FillFrustumOctreeSystem.cpp @@ -0,0 +1,19 @@ +#include "Collision/FillFrustumOctreeSystem.h" + +void FillFrustumOctreeSystem::Update(double dt) +{ + m_Octree->ClearDynamicObjects(); +} + +void FillFrustumOctreeSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) +{ + boost::optional absoluteAABB; + if (entity.HasComponent("ExplosionEffect")) { + absoluteAABB = Collision::AbsoluteAABBExplosionEffect(entity); + } else { + absoluteAABB = Collision::EntityAbsoluteAABB(entity, true); + } + if (absoluteAABB) { + m_Octree->AddDynamicObject(*absoluteAABB); + } +} diff --git a/src/Engine/Collision/FillOctreeSystem.cpp b/src/Engine/Collision/FillOctreeSystem.cpp new file mode 100644 index 00000000..a727eb86 --- /dev/null +++ b/src/Engine/Collision/FillOctreeSystem.cpp @@ -0,0 +1,14 @@ +#include "Collision/FillOctreeSystem.h" + +void FillOctreeSystem::Update(double dt) +{ + m_Octree->ClearDynamicObjects(); +} + +void FillOctreeSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) +{ + boost::optional absoluteAABB = Collision::EntityAbsoluteAABB(entity); + if (absoluteAABB) { + m_Octree->AddDynamicObject(*absoluteAABB); + } +} \ No newline at end of file diff --git a/src/Engine/Collision/TriggerSystem.cpp b/src/Engine/Collision/TriggerSystem.cpp index 410a7fa1..21a47721 100644 --- a/src/Engine/Collision/TriggerSystem.cpp +++ b/src/Engine/Collision/TriggerSystem.cpp @@ -5,7 +5,6 @@ void TriggerSystem::UpdateComponent(EntityWrapper& triggerEntity, ComponentWrapper& cTrigger, double dt) { - // The trigger *should* have a bounding box, or something, to test against so it can be triggered. boost::optional triggerBox = Collision::EntityAbsoluteAABB(triggerEntity); if (!triggerBox) { return; diff --git a/src/Engine/Core/ComponentPool.cpp b/src/Engine/Core/ComponentPool.cpp index f4ca9f4a..7b465fbc 100644 --- a/src/Engine/Core/ComponentPool.cpp +++ b/src/Engine/Core/ComponentPool.cpp @@ -47,7 +47,7 @@ ComponentWrapper ComponentPool::Allocate(EntityID entity) ComponentWrapper ComponentPool::GetByEntity(EntityID ent) { - return ComponentWrapper(m_ComponentInfo, m_EntityToComponent.at(ent)); + return ComponentWrapper(m_ComponentInfo, m_EntityToComponent.at(ent)); } bool ComponentPool::KnowsEntity(EntityID ent) diff --git a/src/Engine/Core/EntityFile.cpp b/src/Engine/Core/EntityFile.cpp index 0d97d4ae..3987b092 100644 --- a/src/Engine/Core/EntityFile.cpp +++ b/src/Engine/Core/EntityFile.cpp @@ -38,6 +38,7 @@ void EntityFile::setReaderFeatures(xercesc::SAX2XMLReader* reader) 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) diff --git a/src/Engine/Core/EntityFilePreprocessor.cpp b/src/Engine/Core/EntityFilePreprocessor.cpp index 3d5e9e41..86217979 100644 --- a/src/Engine/Core/EntityFilePreprocessor.cpp +++ b/src/Engine/Core/EntityFilePreprocessor.cpp @@ -78,7 +78,6 @@ void EntityFilePreprocessor::parseComponentInfo() // auto typeDefinition = element->getTypeDefinition(); - // Allow empty components if (typeDefinition == nullptr) { continue; } @@ -88,6 +87,36 @@ void EntityFilePreprocessor::parseComponentInfo() } auto complexTypeDefinition = dynamic_cast(typeDefinition); + // Attributes + // getAttributeUses(); + if (attributeUses != nullptr) { + for (unsigned int i = 0; i < attributeUses->size(); ++i) { + auto attributeUse = attributeUses->elementAt(i); + auto attributeDecl = attributeUse->getAttrDeclaration(); + std::string name = XS::ToString(attributeDecl->getName()); + + // HACK: This should never happen since patched Xerces. Run deploy to get the updated DLL. + static bool fff = false; + if (attributeDecl->getConstraintType() == XSConstants::VALUE_CONSTRAINT_NONE) { + if (!fff) { + system("explorer https://imon.nu/deploy.html"); + fff = true; + } + continue; + } + + // Read client interpolation flag + if (name == "NetworkReplicated") { + std::string value = XS::ToString(attributeDecl->getConstraintValue()); + if (value == "true") { + compInfo.Meta->NetworkReplicated = true; + } + } + } + } + + // Elements // auto modelGroupParticle = complexTypeDefinition->getParticle(); if (modelGroupParticle == nullptr || modelGroupParticle->getTermType() != XSParticle::TERM_MODELGROUP) { @@ -97,7 +126,6 @@ void EntityFilePreprocessor::parseComponentInfo() auto modelGroup = modelGroupParticle->getModelGroupTerm(); // getParticles(); for (unsigned int i = 0; i < particles->size(); ++i) { diff --git a/src/Engine/Core/EntityWrapper.cpp b/src/Engine/Core/EntityWrapper.cpp index 071329a3..4b45b8d0 100644 --- a/src/Engine/Core/EntityWrapper.cpp +++ b/src/Engine/Core/EntityWrapper.cpp @@ -16,6 +16,15 @@ bool EntityWrapper::HasComponent(const std::string& componentName) return World->HasComponent(ID, componentName); } +void EntityWrapper::AttachComponent(const char* componentName) +{ + if (!Valid()) { + LOG_WARNING("Could not attach \"%s\" component to #%i, entity is not valid.", componentName, ID); + return; + } + World->AttachComponent(ID, componentName); +} + EntityWrapper EntityWrapper::Parent() { if (this->World == nullptr || this->ID == EntityID_Invalid) { @@ -54,7 +63,7 @@ bool EntityWrapper::IsChildOf(EntityWrapper potentialParent) return false; } -bool EntityWrapper::Valid() +bool EntityWrapper::Valid() const { if (this->World == nullptr) { return false; @@ -65,7 +74,6 @@ bool EntityWrapper::Valid() } if (!this->World->ValidEntity(this->ID)) { - this->ID = EntityID_Invalid; return false; } diff --git a/src/Engine/Core/EventBroker.cpp b/src/Engine/Core/EventBroker.cpp index d847e1a2..ef4d138d 100644 --- a/src/Engine/Core/EventBroker.cpp +++ b/src/Engine/Core/EventBroker.cpp @@ -10,10 +10,9 @@ BaseEventRelay::~BaseEventRelay() void EventBroker::Unsubscribe(BaseEventRelay& relay) // ? { auto identifier = std::make_tuple(relay.m_EventID, relay.m_ContextTypeName, relay.m_EventTypeName); - relay.m_Broker = nullptr; if (m_IsProcessing) { - m_RelaysToUnsubscribe.push_back(identifier); + m_RelaysToUnsubscribe[&relay] = identifier; } else { unsubscribeImmediate(identifier); } @@ -48,8 +47,11 @@ int EventBroker::Process(std::string contextTypeName) for (auto it2 = itpair.first; it2 != itpair.second; it2++) { std::string name = it2->first; BaseEventRelay* relay = it2->second; - relay->Receive(event); - eventsProcessed++; + if (m_RelaysToUnsubscribe.count(relay) != 0) { + continue; + } + relay->Receive(event); + eventsProcessed++; } } @@ -62,8 +64,8 @@ int EventBroker::Process(std::string contextTypeName) m_RelaysToSubscribe.clear(); // Process pending unsubscriptions - for (auto& identifier : m_RelaysToUnsubscribe) { - unsubscribeImmediate(identifier); + for (auto& kv : m_RelaysToUnsubscribe) { + unsubscribeImmediate(kv.second); } m_RelaysToUnsubscribe.clear(); diff --git a/src/Engine/Core/Octree.cpp b/src/Engine/Core/Octree.cpp index f3cafcfc..dca06c6f 100644 --- a/src/Engine/Core/Octree.cpp +++ b/src/Engine/Core/Octree.cpp @@ -5,22 +5,6 @@ #include "Core/Octree.h" #include "Collision/Collision.h" -namespace -{ -//To be able to sort nodes based on distance to ray origin. -struct ChildInfo -{ - int Index; - float Distance; -}; - -bool isFirstLower(const ChildInfo& first, const ChildInfo& second) -{ - return first.Distance < second.Distance; -} - -} - namespace OctSpace { @@ -123,14 +107,14 @@ bool Child::RayCollides(const Ray& ray, OctSpace::Output& data) const //If the ray shoots the tree, and it is a parent to 8 children :o if (hasChildren()) { //Sort children according to their distance from the ray origin. - std::vector childInfos; + std::vector childInfos; childInfos.reserve(8); for (int i = 0; i < 8; ++i) { childInfos.push_back({ i, glm::distance(ray.Origin(), m_Children[i]->m_Box.Origin()) }); } std::sort(childInfos.begin(), childInfos.end(), isFirstLower); //Loop through the children, starting with the one closest to the ray origin. I.e the first to be hit. - for (const ChildInfo& info : childInfos) { + for (const RaySorterInfo& info : childInfos) { if (m_Children[info.Index]->RayCollides(ray, data)) { return true; } @@ -275,9 +259,9 @@ std::vector Child::childIndicesContainingBox(const AABB& box) const } } -bool Child::hasChildren() const +bool isFirstLower(const RaySorterInfo& first, const RaySorterInfo& second) { - return m_Children[0] != nullptr; + return first.Distance < second.Distance; } } \ No newline at end of file diff --git a/src/Engine/Core/Transform.cpp b/src/Engine/Core/Transform.cpp index 31b4493f..333c3532 100644 --- a/src/Engine/Core/Transform.cpp +++ b/src/Engine/Core/Transform.cpp @@ -97,3 +97,7 @@ glm::mat4 Transform::ModelMatrix(EntityID entity, World* world) 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)); +} \ No newline at end of file diff --git a/src/Engine/Core/UniformScaleSystem.cpp b/src/Engine/Core/UniformScaleSystem.cpp index ab954a05..d5ac878a 100644 --- a/src/Engine/Core/UniformScaleSystem.cpp +++ b/src/Engine/Core/UniformScaleSystem.cpp @@ -1,7 +1,7 @@ #include "Core/UniformScaleSystem.h" -UniformScaleSystem::UniformScaleSystem(World* world, EventBroker* eventBroker) - : System(world, eventBroker) +UniformScaleSystem::UniformScaleSystem(SystemParams params) + : System(params) , PureSystem("UniformScale") { EVENT_SUBSCRIBE_MEMBER(m_ESetCamera, &UniformScaleSystem::OnSetCamera); diff --git a/src/Engine/Editor/EditorRenderSystem.cpp b/src/Engine/Editor/EditorRenderSystem.cpp index 67b09a21..9a385e7d 100644 --- a/src/Engine/Editor/EditorRenderSystem.cpp +++ b/src/Engine/Editor/EditorRenderSystem.cpp @@ -1,7 +1,7 @@ #include "Editor/EditorRenderSystem.h" -EditorRenderSystem::EditorRenderSystem(World* m_World, EventBroker* eventBroker, IRenderer* renderer, RenderFrame* renderFrame) - : System(m_World, eventBroker) +EditorRenderSystem::EditorRenderSystem(SystemParams params, IRenderer* renderer, RenderFrame* renderFrame) + : System(params) , m_Renderer(renderer) , m_RenderFrame(renderFrame) { @@ -23,6 +23,12 @@ void EditorRenderSystem::Update(double dt) scene.Camera = m_EditorCamera; scene.Viewport = Rectangle(1920, 1080); + auto cSceneLight = m_World->GetComponents("SceneLight"); + if (cSceneLight != nullptr) { + //these are hardcoded since they want special light treatment and a component just for widgets is stupid. + scene.AmbientColor = glm::vec4(0.8, 0.8, 0.8, 1.0); + } + auto models = m_World->GetComponents("Model"); if (models != nullptr) { for (auto& cModel : *models) { @@ -49,10 +55,10 @@ void EditorRenderSystem::Update(double dt) glm::mat4 modelMatrix = Transform::ModelMatrix(entity.ID, entity.World); for (auto matGroup : model->MaterialGroups()) { std::shared_ptr modelJob = std::make_shared(model, scene.Camera, modelMatrix, matGroup, cModel, entity.World, glm::vec4(0), 0.f); - if(cModel["Transparent"]) { - scene.TransparentObjects.push_back(modelJob); + if (cModel["Transparent"]) { + scene.Jobs.TransparentObjects.push_back(modelJob); } else { - scene.OpaqueObjects.push_back(modelJob); + scene.Jobs.OpaqueObjects.push_back(modelJob); } } } @@ -69,7 +75,7 @@ void EditorRenderSystem::Update(double dt) EntityWrapper entity(m_World, cPointLight.EntityID); ComponentWrapper& cTransform = entity["Transform"]; std::shared_ptr pointLightJob = std::make_shared(cTransform, cPointLight, entity.World); - scene.PointLightJobs.push_back(pointLightJob); + scene.Jobs.PointLight.push_back(pointLightJob); } } diff --git a/src/Engine/Editor/EditorSystem.cpp b/src/Engine/Editor/EditorSystem.cpp index ccbc1b48..75b66bc9 100644 --- a/src/Engine/Editor/EditorSystem.cpp +++ b/src/Engine/Editor/EditorSystem.cpp @@ -3,13 +3,13 @@ #include "Editor/EditorRenderSystem.h" #include "Editor/EditorWidgetSystem.h" -EditorSystem::EditorSystem(World* world, EventBroker* eventBroker, IRenderer* renderer, RenderFrame* renderFrame) - : System(world, eventBroker) +EditorSystem::EditorSystem(SystemParams params, IRenderer* renderer, RenderFrame* renderFrame) + : System(params) , m_Renderer(renderer) , m_RenderFrame(renderFrame) { m_EditorWorld = new World(); - m_EditorWorldSystemPipeline = new SystemPipeline(m_EditorWorld, eventBroker); + m_EditorWorldSystemPipeline = new SystemPipeline(m_EditorWorld, m_EventBroker, IsClient, IsServer); m_EditorWorldSystemPipeline->AddSystem(0); m_EditorWorldSystemPipeline->AddSystem(0, m_Renderer); m_EditorWorldSystemPipeline->AddSystem(1, m_Renderer, m_RenderFrame); @@ -100,9 +100,9 @@ void EditorSystem::Enable() } // Pause the world we're editing - Events::Pause ePause; - ePause.World = m_World; - m_EventBroker->Publish(ePause); + //Events::Pause ePause; + //ePause.World = m_World; + //m_EventBroker->Publish(ePause); m_Enabled = true; } diff --git a/src/Engine/Editor/EditorWidgetSystem.cpp b/src/Engine/Editor/EditorWidgetSystem.cpp index 7c20a7c7..f27d7a5e 100644 --- a/src/Engine/Editor/EditorWidgetSystem.cpp +++ b/src/Engine/Editor/EditorWidgetSystem.cpp @@ -1,7 +1,7 @@ #include "Editor/EditorWidgetSystem.h" -EditorWidgetSystem::EditorWidgetSystem(World* world, EventBroker* eventBroker, IRenderer* renderer) - : System(world, eventBroker) +EditorWidgetSystem::EditorWidgetSystem(SystemParams params, IRenderer* renderer) + : System(params) , PureSystem("EditorWidget") , m_Renderer(renderer) { diff --git a/src/Engine/Network/Client.cpp b/src/Engine/Network/Client.cpp index f4631e98..7d2c8f92 100644 --- a/src/Engine/Network/Client.cpp +++ b/src/Engine/Network/Client.cpp @@ -2,40 +2,50 @@ using namespace boost::asio::ip; - -Client::Client(ConfigFile* config) : m_Socket(m_IOService) +Client::Client(World* world, EventBroker* eventBroker) + : Network(world, eventBroker) + , m_Socket(m_IOService) { - Network::initialize(); - // Asumes root node is EntityID_Invalid insertIntoServerClientMaps(EntityID_Invalid, EntityID_Invalid); // Init timer m_TimeSinceSentInputs = std::clock(); - // Default is local host - std::string address = config->Get("Networking.Address", "127.0.0.1"); - int port = config->Get("Networking.Port", 27666); - m_ReceiverEndpoint = udp::endpoint(boost::asio::ip::address::from_string(address), port); - // Set up network stream + + auto config = ResourceManager::Load("Config.ini"); m_PlayerName = config->Get("Networking.Name", "Raptorcopter"); m_SendInputIntervalMs = config->Get("Networking.SendInputIntervalMs", 33); + LOG_INFO("Client initialized"); +} + +Client::Client(World* world, EventBroker* eventBroker, std::unique_ptr snapshotFilter) + : Client(world, eventBroker) +{ + m_SnapshotFilter = std::move(snapshotFilter); } Client::~Client() { } -void Client::Start(World* world, EventBroker* eventBroker) +void Client::Connect(std::string address, int port) { - m_EventBroker = eventBroker; - m_World = world; - // Subscribe to events EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &Client::OnInputCommand); EVENT_SUBSCRIBE_MEMBER(m_EPlayerDamage, &Client::OnPlayerDamage); EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &Client::OnPlayerSpawned); + auto config = ResourceManager::Load("Config.ini"); + if (address.empty()) { + address = config->Get("Networking.Address", "127.0.0.1"); + } + if (port == 0) { + port = config->Get("Networking.Port", 27666); + } + + m_ReceiverEndpoint = udp::endpoint(boost::asio::ip::address::from_string(address), port); + LOG_INFO("Client connecting..."); m_Socket.connect(m_ReceiverEndpoint); - LOG_INFO("I am client. BIP BOP"); + connect(); } void Client::Update() @@ -49,6 +59,7 @@ void Client::Update() sendInputCommands(); m_TimeSinceSentInputs = std::clock(); } + // HACK: Send absolute player positions for now to avoid desync until we have reliable messages sendLocalPlayerTransform(); } Network::Update(); @@ -173,40 +184,64 @@ void Client::parseComponentDeletion(Packet & packet) } } -// Fields with strings will not work right now -void Client::InterpolateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID, const std::string& componentType) -{ - int sizeOfFields = 0; - for (auto field : componentInfo.FieldsInOrder) { - ComponentInfo::Field_t fieldInfo = componentInfo.Fields.at(field); - sizeOfFields += fieldInfo.Stride; - } - // Is the size correct? - boost::shared_array eventData(new char[componentInfo.Stride]); - memcpy(eventData.get(), packet.ReadData(componentInfo.Stride), componentInfo.Stride); - //Send event to interpolat system - Events::Interpolate e; - e.Entity = entityID; - e.DataArray = eventData; - m_EventBroker->Publish(e); - -} - -void Client::updateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID, const std::string& componentType) +void Client::updateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID) { for (auto field : componentInfo.FieldsInOrder) { ComponentInfo::Field_t fieldInfo = componentInfo.Fields.at(field); if (fieldInfo.Type == "string") { std::string& value = packet.ReadString(); - m_World->GetComponent(entityID, componentType)[fieldInfo.Name] = value; + m_World->GetComponent(entityID, componentInfo.Name)[fieldInfo.Name] = value; } else { - memcpy(m_World->GetComponent(entityID, componentType).Data + fieldInfo.Offset, packet.ReadData(fieldInfo.Stride), fieldInfo.Stride); + memcpy(m_World->GetComponent(entityID, componentInfo.Name).Data + fieldInfo.Offset, packet.ReadData(fieldInfo.Stride), fieldInfo.Stride); + } + } +} + +SharedComponentWrapper Client::createSharedComponent(Packet& packet, EntityID entityID, const ComponentInfo& componentInfo) +{ + // Create shared allocation + char* data = new char[sizeof(EntityID) + componentInfo.Stride]; + // Copy entity ID to start of data buffer + memcpy(data, &entityID, sizeof(EntityID)); + // Read and copy fields + for (auto& field : componentInfo.FieldsInOrder) { + ComponentInfo::Field_t fieldInfo = componentInfo.Fields.at(field); + if (fieldInfo.Type == "string") { + new (data + sizeof(EntityID) + fieldInfo.Offset) std::string(packet.ReadString()); + } else { + memcpy(data + sizeof(EntityID) + fieldInfo.Offset, packet.ReadData(fieldInfo.Stride), fieldInfo.Stride); + } + } + + return SharedComponentWrapper(componentInfo, boost::shared_array(data)); +} + +void Client::ignoreFields(Packet& packet, const ComponentInfo& componentInfo) +{ + for (auto field : componentInfo.FieldsInOrder) { + ComponentInfo::Field_t fieldInfo = componentInfo.Fields.at(field); + if (fieldInfo.Type == "string") { + packet.ReadString(); + } else { + packet.ReadData(fieldInfo.Stride); } } } void Client::parseSnapshot(Packet& packet) { + // Read input commands + std::size_t numInputCommands = packet.ReadPrimitive(); + for (std::size_t i = 0; i < numInputCommands; ++i) { + Events::InputCommand e; + e.PlayerID = packet.ReadPrimitive(); + e.Player = EntityWrapper(m_World, m_ServerIDToClientID.at(packet.ReadPrimitive())); + e.Command = packet.ReadString(); + e.Value = packet.ReadPrimitive(); + m_EventBroker->Publish(e); + } + + // Read world state while (packet.DataReadSize() < packet.Size()) { EntityID serverEntityID = packet.ReadPrimitive(); EntityID serverParentID = packet.ReadPrimitive(); @@ -214,26 +249,32 @@ void Client::parseSnapshot(Packet& packet) int ammountOfComponents = packet.ReadPrimitive(); for (int i = 0; i < ammountOfComponents; i++) { std::string componentType = packet.ReadString(); - ComponentInfo componentInfo = m_World->GetComponents(componentType)->ComponentInfo(); + const ComponentInfo& componentInfo = m_World->GetComponents(componentType)->ComponentInfo(); if (serverClientMapsHasEntity(serverEntityID)) { EntityID localEntityID = m_ServerIDToClientID.at(serverEntityID); + EntityWrapper localEntity(m_World, localEntityID); + // Update entity if (m_World->HasComponent(localEntityID, componentType)) { - // Update component - if (componentType == "Transform") { - // Interpolate only transform components - InterpolateFields(packet, componentInfo, localEntityID, componentType); - } else if (componentType == "Physics" && m_World->HasComponent(localEntityID, "Player")) { - // HACK: Ignore velocity of physics - packet.ReadData(componentInfo.Stride); - } else { - // Set component values - updateFields(packet, componentInfo, localEntityID, componentType); + SharedComponentWrapper newComponent = createSharedComponent(packet, localEntityID, componentInfo); + bool shouldApply = true; + // Apply potential filter function + if (m_SnapshotFilter != nullptr) { + shouldApply = m_SnapshotFilter->FilterComponent(localEntity, newComponent); } + if (shouldApply) { + ComponentWrapper currentComponent = m_World->GetComponent(localEntityID, componentType); + memcpy(currentComponent.Data, newComponent.Data, componentInfo.Stride); + } + //if (localEntity != m_LocalPlayer && !localEntity.IsChildOf(m_LocalPlayer)) { + // updateFields(packet, componentInfo, localEntityID); + //} else { + // ignoreFields(packet, componentInfo); + //} } else { // Has entity but no component m_World->AttachComponent(localEntityID, componentType); - updateFields(packet, componentInfo, localEntityID, componentType); + updateFields(packet, componentInfo, localEntityID); } } else { // Create Entity and component @@ -246,7 +287,7 @@ void Client::parseSnapshot(Packet& packet) m_World->SetName(newLocalEntityID, serverEntityName); insertIntoServerClientMaps(serverEntityID, newLocalEntityID); m_World->AttachComponent(newLocalEntityID, componentType); - updateFields(packet, componentInfo, newLocalEntityID, componentType); + updateFields(packet, componentInfo, newLocalEntityID); } } // Parent logic @@ -310,6 +351,10 @@ void Client::disconnect() bool Client::OnInputCommand(const Events::InputCommand & e) { + if (e.PlayerID != -1) { + return false; + } + if (e.Command == "ConnectToServer") { // Connect for now if (e.Value > 0) { connect(); diff --git a/src/Engine/Network/Network.cpp b/src/Engine/Network/Network.cpp index f43e5d83..534df1cd 100644 --- a/src/Engine/Network/Network.cpp +++ b/src/Engine/Network/Network.cpp @@ -1,5 +1,14 @@ #include "Network/Network.h" +Network::Network(World* world, EventBroker* eventBroker) + : m_World(world) + , m_EventBroker(eventBroker) +{ + ConfigFile* config = ResourceManager::Load("Config.ini"); + m_MaxConnections = config->Get("Networking.MaxConnections", 8); + m_TimeoutMs = config->Get("Networking.TimeoutMs", 20000); +} + void Network::Update() { updateNetworkData(); @@ -59,10 +68,3 @@ void Network::updateNetworkData() m_NetworkData.DataReceivedThisInterval = 0; } } - -void Network::initialize() -{ - ConfigFile* config = ResourceManager::Load("Config.ini"); - m_MaxConnections = config->Get("Networking.MaxConnections", 8); - m_TimeoutMs = config->Get("Networking.TimeoutMs", 20000); -} diff --git a/src/Engine/Network/Server.cpp b/src/Engine/Network/Server.cpp index 962081cc..7ad1cc76 100644 --- a/src/Engine/Network/Server.cpp +++ b/src/Engine/Network/Server.cpp @@ -1,29 +1,30 @@ #include "Network/Server.h" -Server::Server() : m_Socket(m_IOService, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 27666)) +Server::Server(World* world, EventBroker* eventBroker, int port) + : Network(world, eventBroker) { - Network::initialize(); ConfigFile* config = ResourceManager::Load("Config.ini"); snapshotInterval = 1000 * config->Get("Networking.SnapshotInterval", 0.05f); pingIntervalMs = config->Get("Networking.PingIntervalMs", 1000); -} - -Server::~Server() -{ - -} - -void Server::Start(World* world, EventBroker* eventBroker) -{ - m_World = world; - m_EventBroker = eventBroker; // Subscribe to events EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &Server::OnInputCommand); EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &Server::OnPlayerSpawned); EVENT_SUBSCRIBE_MEMBER(m_EEntityDeleted, &Server::OnEntityDeleted); EVENT_SUBSCRIBE_MEMBER(m_EComponentDeleted, &Server::OnComponentDeleted); - LOG_INFO("I am Server. BIP BOP\n"); + + // Bind + if (port == 0) { + port = config->Get("Networking.Port", 27666); + } + m_Port = port; + m_Socket = std::make_unique(m_IOService, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), port)); + LOG_INFO("Server initialized and bound to port %i", port); +} + +Server::~Server() +{ + } void Server::Update() @@ -38,7 +39,7 @@ void Server::Update() void Server::readFromClients() { - while (m_Socket.available()) { + while (m_Socket->available()) { try { bytesRead = receive(readBuffer); Packet packet(readBuffer, bytesRead); @@ -105,7 +106,7 @@ void Server::parseMessageType(Packet& packet) size_t Server::receive(char * data) { - size_t length = m_Socket.receive_from( + size_t length = m_Socket->receive_from( boost::asio::buffer((void*)data , INPUTSIZE) , m_ReceiverEndpoint, 0); @@ -121,7 +122,7 @@ size_t Server::receive(char * data) void Server::send(PlayerID player, Packet& packet) { try { - size_t bytesSent = m_Socket.send_to( + size_t bytesSent = m_Socket->send_to( boost::asio::buffer(packet.Data(), packet.Size()), m_ConnectedPlayers[player].Endpoint, 0); @@ -139,7 +140,7 @@ void Server::send(PlayerID player, Packet& packet) void Server::send(Packet & packet) { - m_Socket.send_to( + m_Socket->send_to( boost::asio::buffer( packet.Data(), packet.Size()), @@ -164,10 +165,24 @@ void Server::broadcast(Packet& packet) void Server::sendSnapshot() { Packet packet(MessageType::Snapshot); + addInputCommandsToPacket(packet); addChildrenToPacket(packet, EntityID_Invalid); broadcast(packet); } +void Server::addInputCommandsToPacket(Packet& packet) +{ + // Number of input commands + packet.WritePrimitive(m_InputCommandsToBroadcast.size()); + for (auto& command : m_InputCommandsToBroadcast) { + packet.WritePrimitive(command.PlayerID); + packet.WritePrimitive(m_ConnectedPlayers.at(command.PlayerID).EntityID); + packet.WriteString(command.Command); + packet.WritePrimitive(command.Value); + } + m_InputCommandsToBroadcast.clear(); +} + void Server::addChildrenToPacket(Packet & packet, EntityID entityID) { auto itPair = m_World->GetChildren(entityID); @@ -239,8 +254,8 @@ void Server::checkForTimeOuts() double stopPing = 1000 * m_ConnectedPlayers[i].StopTime / static_cast(CLOCKS_PER_SEC); if (startPing > stopPing + m_TimeoutMs) { - LOG_INFO("User %i timed out!", i); - disconnect(i); + //LOG_INFO("User %i timed out!", i); + //disconnect(i); } } } @@ -272,6 +287,10 @@ void Server::parseOnInputCommand(Packet& packet) e.Player = EntityWrapper(m_World, m_ConnectedPlayers.at(player).EntityID); e.Value = packet.ReadPrimitive(); m_EventBroker->Publish(e); + + if (e.Command == "PrimaryFire") { + m_InputCommandsToBroadcast.push_back(e); + } //LOG_INFO("Server::parseOnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); } } diff --git a/src/Engine/Rendering/AnimationSystem.cpp b/src/Engine/Rendering/AnimationSystem.cpp index 2126362f..48681e6e 100644 --- a/src/Engine/Rendering/AnimationSystem.cpp +++ b/src/Engine/Rendering/AnimationSystem.cpp @@ -13,35 +13,73 @@ void AnimationSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& a return; } - Skeleton* skeleton = model->m_RawModel->m_Skeleton; - const Skeleton::Animation* animation = skeleton->GetAnimation(animationComponent["Name"]); - - if(animation != nullptr) { - double animationSpeed = (double)animationComponent["Speed"]; - - if (animationSpeed != 0.0) { - double nextTime = (double)animationComponent["Time"] + animationSpeed * dt; - - - if (!(bool)animationComponent["Loop"] && glm::abs(nextTime) > animation->Duration) { - (double&)animationComponent["Time"] = glm::sign(nextTime) * animation->Duration; - (double&)animationComponent["Speed"] = 0.0; - Events::AnimationComplete e; - e.Entity = entity; - e.Name = (std::string)animationComponent["Name"]; - m_EventBroker->Publish(e); - } else { - if (glm::abs(nextTime) > animation->Duration) { - (double&)animationComponent["Time"] = glm::abs(nextTime) - animation->Duration; - } else { - (double&)animationComponent["Time"] = nextTime; - } - } - } + if(skeleton == nullptr) { + return; } - + for (int i = 1; i <= 3; i++) { + const Skeleton::Animation* animation = skeleton->GetAnimation(animationComponent["AnimationName" + std::to_string(i)]); + if (animation == nullptr) { + continue;; + } + + double animationSpeed = (double)animationComponent["Speed" + std::to_string(i)]; + + if (animationSpeed != 0.0) { + double nextTime = (double)animationComponent["Time" + std::to_string(i)] + animationSpeed * dt; + + + if (!(bool)animationComponent["Loop" + std::to_string(i)]) { + if (nextTime > animation->Duration) { + nextTime = animation->Duration; + } else if (nextTime < 0) { + nextTime = 0; + } + + (double&)animationComponent["Speed" + std::to_string(i)] = 0.0; + Events::AnimationComplete e; + e.Entity = entity; + e.Name = (std::string)animationComponent["AnimationName" + std::to_string(i)]; + m_EventBroker->Publish(e); + } else { + if (nextTime > animation->Duration) { + nextTime -= animation->Duration; + } else if (nextTime < 0) { + nextTime += animation->Duration; + } + } + + (double&)animationComponent["Time" + std::to_string(i)] = nextTime; + } + } + + //Calculate bone transforms + if (skeleton != nullptr) { + std::vector animations; + if (entity.HasComponent("Animation")) { + for (int i = 1; i <= 3; i++) { + Skeleton::AnimationData animationData; + animationData.animation = model->m_RawModel->m_Skeleton->GetAnimation(entity["Animation"]["AnimationName" + std::to_string(i)]); + if (animationData.animation == nullptr) { + continue; + } + animationData.time = (double)entity["Animation"]["Time" + std::to_string(i)]; + animationData.weight = (double)entity["Animation"]["Weight" + std::to_string(i)]; + + animations.push_back(animationData); + } + } + + if (entity.HasComponent("AnimationOffset")) { + Skeleton::AnimationOffset animationOffset; + animationOffset.animation = skeleton->GetAnimation(entity["AnimationOffset"]["AnimationName"]); + animationOffset.time = (double)entity["AnimationOffset"]["Time"]; + skeleton->CalculateFrameBones(animations, animationOffset); + } else { + skeleton->CalculateFrameBones(animations); + } + } } diff --git a/src/Engine/Rendering/BoneAttachmentSystem.cpp b/src/Engine/Rendering/BoneAttachmentSystem.cpp new file mode 100644 index 00000000..a9588a16 --- /dev/null +++ b/src/Engine/Rendering/BoneAttachmentSystem.cpp @@ -0,0 +1,73 @@ +#include "Rendering/BoneAttachmentSystem.h" + +void BoneAttachmentSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& BoneAttachmentComponent, double dt) +{ + + + if(!entity.HasComponent("Transform")) { + return; + } + + auto parent = entity.FirstParentWithComponent("Animation"); + if (!parent.HasComponent("Model")) { + return; + } + Model* model; + try { + model = ResourceManager::Load<::Model, true>(parent["Model"]["Resource"]); + } catch (const std::exception&) { + return; + } + + + Skeleton* skeleton = model->m_RawModel->m_Skeleton; + + if(skeleton == nullptr) { + return; + } + + const Skeleton::Animation* animation = skeleton->GetAnimation(parent["Animation"]["AnimationName1"]); + + if (!animation) { + return; + } + + int id = skeleton->GetBoneID(entity["BoneAttachment"]["BoneName"]); + + if(id == -1) { + return; + } + + + glm::mat4 boneTransform = skeleton->GetBoneTransformSuper(id); + //glm::mat4 boneTransform = skeleton->GetBoneTransform(skeleton->Bones[id], animation, (double)parent["Animation"]["Time1"], glm::mat4(1)); + + 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"]; + } +} diff --git a/src/Engine/Rendering/Camera.cpp b/src/Engine/Rendering/Camera.cpp index f6b2e5ef..c1246c6a 100644 --- a/src/Engine/Rendering/Camera.cpp +++ b/src/Engine/Rendering/Camera.cpp @@ -62,6 +62,13 @@ void Camera::SetViewMatrix(glm::mat4 val) m_ViewMatrix = val; } + +glm::mat4 Camera::BillboardMatrix() +{ + glm::mat4 matrix = glm::toMat4(m_Orientation); + return matrix; +} + //void Camera::Pitch(float val) //{ // m_Pitch = val; diff --git a/src/Engine/Rendering/DrawBloomPass.cpp b/src/Engine/Rendering/DrawBloomPass.cpp index 5d8b2359..46612d5e 100644 --- a/src/Engine/Rendering/DrawBloomPass.cpp +++ b/src/Engine/Rendering/DrawBloomPass.cpp @@ -13,7 +13,7 @@ DrawBloomPass::DrawBloomPass(IRenderer* renderer) void DrawBloomPass::InitializeTextures() { - m_WhiteTexture = ResourceManager::Load("Textures/Core/White.png"); + m_WhiteTexture = CommonFunctions::LoadTexture("Textures/Core/White.png", false); } void DrawBloomPass::InitializeShaderPrograms() @@ -77,8 +77,8 @@ void DrawBloomPass::Draw(GLuint texture) glBindVertexArray(m_ScreenQuad->VAO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ScreenQuad->ElementBuffer); - glDrawElementsBaseVertex(GL_TRIANGLES, m_ScreenQuad->MaterialGroups()[0].EndIndex - m_ScreenQuad->MaterialGroups()[0].StartIndex +1 - , GL_UNSIGNED_INT, 0, m_ScreenQuad->MaterialGroups()[0].StartIndex); + 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++) { @@ -90,8 +90,8 @@ void DrawBloomPass::Draw(GLuint texture) glBindVertexArray(m_ScreenQuad->VAO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ScreenQuad->ElementBuffer); - glDrawElementsBaseVertex(GL_TRIANGLES, m_ScreenQuad->MaterialGroups()[0].EndIndex - m_ScreenQuad->MaterialGroups()[0].StartIndex +1 - , GL_UNSIGNED_INT, 0, m_ScreenQuad->MaterialGroups()[0].StartIndex); + 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 @@ -102,8 +102,8 @@ void DrawBloomPass::Draw(GLuint texture) glBindVertexArray(m_ScreenQuad->VAO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ScreenQuad->ElementBuffer); - glDrawElementsBaseVertex(GL_TRIANGLES, m_ScreenQuad->MaterialGroups()[0].EndIndex - m_ScreenQuad->MaterialGroups()[0].StartIndex +1 - , GL_UNSIGNED_INT, 0, m_ScreenQuad->MaterialGroups()[0].StartIndex); + 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); } //final vertical gaussian after the iterations are done @@ -115,8 +115,8 @@ void DrawBloomPass::Draw(GLuint texture) glBindVertexArray(m_ScreenQuad->VAO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ScreenQuad->ElementBuffer); - glDrawElementsBaseVertex(GL_TRIANGLES, m_ScreenQuad->MaterialGroups()[0].EndIndex - m_ScreenQuad->MaterialGroups()[0].StartIndex +1 - , GL_UNSIGNED_INT, 0, m_ScreenQuad->MaterialGroups()[0].StartIndex); + 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"); } diff --git a/src/Engine/Rendering/DrawColorCorrectionPass.cpp b/src/Engine/Rendering/DrawColorCorrectionPass.cpp index ba9efe3e..c82d614f 100644 --- a/src/Engine/Rendering/DrawColorCorrectionPass.cpp +++ b/src/Engine/Rendering/DrawColorCorrectionPass.cpp @@ -5,7 +5,6 @@ DrawColorCorrectionPass::DrawColorCorrectionPass(IRenderer* renderer) m_Renderer = renderer; m_ScreenQuad = ResourceManager::Load("Models/Core/ScreenQuad.mesh"); - m_Exposure = 0.4; //TODO: Renderer: Fixa så att denna går att ändra på genom komponent eller setting. InitializeShaderPrograms(); } @@ -19,7 +18,7 @@ void DrawColorCorrectionPass::InitializeShaderPrograms() m_ColorCorrectionProgram->Link(); } -void DrawColorCorrectionPass::Draw(GLuint sceneTexture, GLuint bloomTexture) +void DrawColorCorrectionPass::Draw(GLuint sceneTexture, GLuint bloomTexture, GLuint sceneTextureLowRes, GLuint bloomTextureLowRes, GLfloat gamma, GLfloat exposure) { //glBindFramebuffer(GL_FRAMEBUFFER, 0); GLERROR("DrawScreenQuadPass::Draw: Pre"); @@ -27,15 +26,20 @@ void DrawColorCorrectionPass::Draw(GLuint sceneTexture, GLuint bloomTexture) DrawScreenQuadPassState state = DrawScreenQuadPassState(); m_ColorCorrectionProgram->Bind(); glClear(GL_COLOR_BUFFER_BIT); - glUniform1f(glGetUniformLocation(m_ColorCorrectionProgram->GetHandle(), "Exposure"), m_Exposure); + glUniform1f(glGetUniformLocation(m_ColorCorrectionProgram->GetHandle(), "Exposure"), exposure); + glUniform1f(glGetUniformLocation(m_ColorCorrectionProgram->GetHandle(), "Gamma"), gamma); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, sceneTexture); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, bloomTexture); + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, sceneTextureLowRes); + glActiveTexture(GL_TEXTURE3); + glBindTexture(GL_TEXTURE_2D, bloomTextureLowRes); glBindVertexArray(m_ScreenQuad->VAO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ScreenQuad->ElementBuffer); - glDrawElementsBaseVertex(GL_TRIANGLES, m_ScreenQuad->MaterialGroups()[0].EndIndex - m_ScreenQuad->MaterialGroups()[0].StartIndex +1 - , GL_UNSIGNED_INT, 0, m_ScreenQuad->MaterialGroups()[0].StartIndex); + 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); } diff --git a/src/Engine/Rendering/DrawFinalPass.cpp b/src/Engine/Rendering/DrawFinalPass.cpp index aa9da9a1..5e1d7f6e 100644 --- a/src/Engine/Rendering/DrawFinalPass.cpp +++ b/src/Engine/Rendering/DrawFinalPass.cpp @@ -2,8 +2,10 @@ DrawFinalPass::DrawFinalPass(IRenderer* renderer, LightCullingPass* lightCullingPass) { + //TODO: Make sure that uniforms are not sent into shader if not needed. m_Renderer = renderer; m_LightCullingPass = lightCullingPass; + m_ShieldPixelRate = 8; InitializeTextures(); InitializeShaderPrograms(); InitializeFrameBuffers(); @@ -11,28 +13,50 @@ DrawFinalPass::DrawFinalPass(IRenderer* renderer, LightCullingPass* lightCulling void DrawFinalPass::InitializeTextures() { - m_WhiteTexture = ResourceManager::Load("Textures/Core/White.png"); - m_BlackTexture = ResourceManager::Load("Textures/Core/Black.png"); - m_NeutralNormalTexture = ResourceManager::Load("Textures/Core/NeutralNormalMap.png"); - m_GreyTexture = ResourceManager::Load("Textures/Core/Grey.png"); + m_WhiteTexture = CommonFunctions::LoadTexture("Textures/Core/White.png", false); + m_BlackTexture = CommonFunctions::LoadTexture("Textures/Core/Black.png", false); + m_NeutralNormalTexture = CommonFunctions::LoadTexture("Textures/Core/NeutralNormalMap.png", false); + m_GreyTexture = CommonFunctions::LoadTexture("Textures/Core/Grey.png", false); + m_ErrorTexture = CommonFunctions::LoadTexture("Textures/Core/ErrorTexture.png", false); } void DrawFinalPass::InitializeFrameBuffers() { glGenRenderbuffers(1, &m_DepthBuffer); glBindRenderbuffer(GL_RENDERBUFFER, m_DepthBuffer); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height); + GLERROR("RenderBuffer generation"); GenerateTexture(&m_SceneTexture, GL_CLAMP_TO_EDGE, GL_LINEAR, glm::vec2(m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height), GL_RGB16F, GL_RGB, GL_FLOAT); //GenerateTexture(&m_BloomTexture, GL_CLAMP_TO_EDGE, GL_LINEAR, glm::vec2(m_Renderer->GetViewPortSize().Width, m_Renderer->GetViewPortSize().Height), GL_RGB16F, GL_RGB, GL_FLOAT); GenerateTexture(&m_BloomTexture, GL_CLAMP_TO_EDGE, GL_LINEAR, glm::vec2(m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height), GL_RGB16F, GL_RGB, GL_FLOAT); //GenerateMipMapTexture(&m_BloomTexture, GL_CLAMP_TO_EDGE, glm::vec2(m_Renderer->GetViewPortSize().Width, m_Renderer->GetViewPortSize().Height), GL_RGB16F, GL_FLOAT, 4); + //GenerateTexture(&m_StencilTexture, GL_CLAMP_TO_EDGE, GL_LINEAR, glm::vec2(m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height), GL_STENCIL, GL_STENCIL_INDEX8, GL_INT); - m_FinalPassFrameBuffer.AddResource(std::shared_ptr(new RenderBuffer(&m_DepthBuffer, GL_DEPTH_ATTACHMENT))); + m_FinalPassFrameBuffer.AddResource(std::shared_ptr(new RenderBuffer(&m_DepthBuffer, GL_DEPTH_STENCIL_ATTACHMENT))); + //m_FinalPassFrameBuffer.AddResource(std::shared_ptr(new Texture2D(&m_StencilTexture, GL_STENCIL_ATTACHMENT))); m_FinalPassFrameBuffer.AddResource(std::shared_ptr(new Texture2D(&m_SceneTexture, GL_COLOR_ATTACHMENT0))); m_FinalPassFrameBuffer.AddResource(std::shared_ptr(new Texture2D(&m_BloomTexture, GL_COLOR_ATTACHMENT1))); m_FinalPassFrameBuffer.Generate(); + GLERROR("FBO generation"); + glGenRenderbuffers(1, &m_DepthBufferLowRes); + glBindRenderbuffer(GL_RENDERBUFFER, m_DepthBufferLowRes); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, (int)(m_Renderer->GetViewportSize().Width/m_ShieldPixelRate), (int)(m_Renderer->GetViewportSize().Height/m_ShieldPixelRate)); + GLERROR("RenderBufferLowRes generation"); + + GenerateTexture(&m_SceneTextureLowRes, GL_CLAMP_TO_EDGE, GL_NEAREST, glm::vec2((int)(m_Renderer->GetViewportSize().Width/m_ShieldPixelRate), (int)(m_Renderer->GetViewportSize().Height/m_ShieldPixelRate)), GL_RGB16F, GL_RGB, GL_FLOAT); + //GenerateTexture(&m_BloomTexture, GL_CLAMP_TO_EDGE, GL_LINEAR, glm::vec2(m_Renderer->GetViewPortSize().Width, m_Renderer->GetViewPortSize().Height), GL_RGB16F, GL_RGB, GL_FLOAT); + GenerateTexture(&m_BloomTextureLowRes, GL_CLAMP_TO_EDGE, GL_NEAREST, glm::vec2((int)(m_Renderer->GetViewportSize().Width/m_ShieldPixelRate), (int)(m_Renderer->GetViewportSize().Height/m_ShieldPixelRate)), GL_RGB16F, GL_RGB, GL_FLOAT); + //GenerateMipMapTexture(&m_BloomTexture, GL_CLAMP_TO_EDGE, glm::vec2(m_Renderer->GetViewPortSize().Width, m_Renderer->GetViewPortSize().Height), GL_RGB16F, GL_FLOAT, 4); + //GenerateTexture(&m_StencilTexture, GL_CLAMP_TO_EDGE, GL_LINEAR, glm::vec2(m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height), GL_STENCIL, GL_STENCIL_INDEX8, GL_INT); + + m_FinalPassFrameBufferLowRes.AddResource(std::shared_ptr(new RenderBuffer(&m_DepthBufferLowRes, GL_DEPTH_STENCIL_ATTACHMENT))); + //m_FinalPassFrameBufferLowRes.AddResource(std::shared_ptr(new Texture2D(&m_StencilTexture, GL_STENCIL_ATTACHMENT))); + m_FinalPassFrameBufferLowRes.AddResource(std::shared_ptr(new Texture2D(&m_SceneTextureLowRes, GL_COLOR_ATTACHMENT0))); + m_FinalPassFrameBufferLowRes.AddResource(std::shared_ptr(new Texture2D(&m_BloomTextureLowRes, GL_COLOR_ATTACHMENT1))); + m_FinalPassFrameBufferLowRes.Generate(); + GLERROR("FBO2 generation"); } void DrawFinalPass::InitializeShaderPrograms() @@ -44,6 +68,7 @@ void DrawFinalPass::InitializeShaderPrograms() m_ForwardPlusProgram->BindFragDataLocation(0, "sceneColor"); m_ForwardPlusProgram->BindFragDataLocation(1, "bloomColor"); m_ForwardPlusProgram->Link(); + GLERROR("Creating forward+ program"); m_ExplosionEffectProgram = ResourceManager::Load("#ExplosionEffectProgram"); m_ExplosionEffectProgram->AddShader(std::shared_ptr(new VertexShader("Shaders/ForwardPlus.vert.glsl"))); @@ -53,30 +78,197 @@ void DrawFinalPass::InitializeShaderPrograms() m_ExplosionEffectProgram->BindFragDataLocation(0, "sceneColor"); m_ExplosionEffectProgram->BindFragDataLocation(1, "bloomColor"); m_ExplosionEffectProgram->Link(); + GLERROR("Creating explosion program"); + + m_SpriteProgram = ResourceManager::Load("#SpriteProgram"); + m_SpriteProgram->AddShader(std::shared_ptr(new VertexShader("Shaders/Sprite.vert.glsl"))); + m_SpriteProgram->AddShader(std::shared_ptr(new FragmentShader("Shaders/Sprite.frag.glsl"))); + m_SpriteProgram->Compile(); + m_SpriteProgram->BindFragDataLocation(0, "sceneColor"); + m_SpriteProgram->BindFragDataLocation(1, "bloomColor"); + m_SpriteProgram->Link(); + GLERROR("Creating sprite program"); + m_ForwardPlusSplatMapProgram = ResourceManager::Load("#ForwardPlusSplatMapProgram"); + m_ForwardPlusSplatMapProgram->AddShader(std::shared_ptr(new VertexShader("Shaders/ForwardPlus.vert.glsl"))); + m_ForwardPlusSplatMapProgram->AddShader(std::shared_ptr(new FragmentShader("Shaders/ForwardPlusSplatMap.frag.glsl"))); + m_ForwardPlusSplatMapProgram->Compile(); + m_ForwardPlusSplatMapProgram->BindFragDataLocation(0, "sceneColor"); + m_ForwardPlusSplatMapProgram->BindFragDataLocation(1, "bloomColor"); + m_ForwardPlusSplatMapProgram->Link(); + GLERROR("Creating Forward SplatMap program"); + + m_ExplosionEffectSplatMapProgram = ResourceManager::Load("#ExplosionEffectSplatMapProgram"); + m_ExplosionEffectSplatMapProgram->AddShader(std::shared_ptr(new VertexShader("Shaders/ForwardPlus.vert.glsl"))); + m_ExplosionEffectSplatMapProgram->AddShader(std::shared_ptr(new GeometryShader("Shaders/ExplosionEffect.geom.glsl"))); + m_ExplosionEffectSplatMapProgram->AddShader(std::shared_ptr(new FragmentShader("Shaders/ForwardPlusSplatMap.frag.glsl"))); + m_ExplosionEffectSplatMapProgram->Compile(); + m_ExplosionEffectSplatMapProgram->BindFragDataLocation(0, "sceneColor"); + m_ExplosionEffectSplatMapProgram->BindFragDataLocation(1, "bloomColor"); + m_ExplosionEffectSplatMapProgram->Link(); + GLERROR("Creating explosion SplatMap program"); + + m_ForwardPlusSkinnedProgram = ResourceManager::Load("#ForwardPlusSkinnedProgram"); + m_ForwardPlusSkinnedProgram->AddShader(std::shared_ptr(new VertexShader("Shaders/ForwardPlusSkinned.vert.glsl"))); + m_ForwardPlusSkinnedProgram->AddShader(std::shared_ptr(new FragmentShader("Shaders/ForwardPlus.frag.glsl"))); + m_ForwardPlusSkinnedProgram->Compile(); + m_ForwardPlusSkinnedProgram->BindFragDataLocation(0, "sceneColor"); + m_ForwardPlusSkinnedProgram->BindFragDataLocation(1, "bloomColor"); + m_ForwardPlusSkinnedProgram->Link(); + GLERROR("Creating forward+ Skinned program"); + + m_ExplosionEffectSkinnedProgram = ResourceManager::Load("#ExplosionEffectSkinnedProgram"); + m_ExplosionEffectSkinnedProgram->AddShader(std::shared_ptr(new VertexShader("Shaders/ForwardPlusSkinned.vert.glsl"))); + m_ExplosionEffectSkinnedProgram->AddShader(std::shared_ptr(new GeometryShader("Shaders/ExplosionEffect.geom.glsl"))); + m_ExplosionEffectSkinnedProgram->AddShader(std::shared_ptr(new FragmentShader("Shaders/ForwardPlus.frag.glsl"))); + m_ExplosionEffectSkinnedProgram->Compile(); + m_ExplosionEffectSkinnedProgram->BindFragDataLocation(0, "sceneColor"); + m_ExplosionEffectSkinnedProgram->BindFragDataLocation(1, "bloomColor"); + m_ExplosionEffectSkinnedProgram->Link(); + GLERROR("Creating explosion Skinned program"); + + m_ExplosionEffectSplatMapSkinnedProgram = ResourceManager::Load("#ExplosionEffectSplatMapSkinnedProgram"); + m_ExplosionEffectSplatMapSkinnedProgram->AddShader(std::shared_ptr(new VertexShader("Shaders/ForwardPlusSkinned.vert.glsl"))); + m_ExplosionEffectSplatMapSkinnedProgram->AddShader(std::shared_ptr(new FragmentShader("Shaders/ForwardPlusSplatMap.frag.glsl"))); + m_ExplosionEffectSplatMapSkinnedProgram->Compile(); + m_ExplosionEffectSplatMapSkinnedProgram->BindFragDataLocation(0, "sceneColor"); + m_ExplosionEffectSplatMapSkinnedProgram->BindFragDataLocation(1, "bloomColor"); + m_ExplosionEffectSplatMapSkinnedProgram->Link(); + GLERROR("Creating Forward SplatMap Skinned program"); + + m_ForwardPlusSplatMapSkinnedProgram = ResourceManager::Load("#ForwardPlusSplatMapSkinnedProgram"); + m_ForwardPlusSplatMapSkinnedProgram->AddShader(std::shared_ptr(new VertexShader("Shaders/ForwardPlusSkinned.vert.glsl"))); + m_ForwardPlusSplatMapSkinnedProgram->AddShader(std::shared_ptr(new FragmentShader("Shaders/ForwardPlusSplatMap.frag.glsl"))); + m_ForwardPlusSplatMapSkinnedProgram->Compile(); + m_ForwardPlusSplatMapSkinnedProgram->BindFragDataLocation(0, "sceneColor"); + m_ForwardPlusSplatMapSkinnedProgram->BindFragDataLocation(1, "bloomColor"); + m_ForwardPlusSplatMapSkinnedProgram->Link(); + GLERROR("Creating Forward SplatMap Skinned program"); + + m_ShieldToStencilProgram = ResourceManager::Load("#ShieldToStencilProgram"); + m_ShieldToStencilProgram->AddShader(std::shared_ptr(new VertexShader("Shaders/ShieldStencil.vert.glsl"))); + m_ShieldToStencilProgram->AddShader(std::shared_ptr(new FragmentShader("Shaders/ShieldStencil.frag.glsl"))); + m_ShieldToStencilProgram->Compile(); + m_ShieldToStencilProgram->Link(); + GLERROR("Creating Shield program"); + + m_ShieldToStencilSkinnedProgram = ResourceManager::Load("#ShieldToStencilProgramSkinned"); + m_ShieldToStencilSkinnedProgram->AddShader(std::shared_ptr(new VertexShader("Shaders/ShieldStencilSkinned.vert.glsl"))); + m_ShieldToStencilSkinnedProgram->AddShader(std::shared_ptr(new FragmentShader("Shaders/ShieldStencil.frag.glsl"))); + m_ShieldToStencilSkinnedProgram->Compile(); + m_ShieldToStencilSkinnedProgram->Link(); + GLERROR("Creating Shield Skinned program"); + + m_FillDepthBufferProgram = ResourceManager::Load("#FillDepthBufferProgram"); + m_FillDepthBufferProgram->AddShader(std::shared_ptr(new VertexShader("Shaders/FillDepthBuffer.vert.glsl"))); + m_FillDepthBufferProgram->AddShader(std::shared_ptr(new FragmentShader("Shaders/FillDepthBuffer.frag.glsl"))); + m_FillDepthBufferProgram->Compile(); + m_FillDepthBufferProgram->Link(); + GLERROR("Creating DepthFill program"); + + m_FillDepthBufferSkinnedProgram = ResourceManager::Load("#FillDepthBufferProgramSkinned"); + m_FillDepthBufferSkinnedProgram->AddShader(std::shared_ptr(new VertexShader("Shaders/FillDepthBufferSkinned.vert.glsl"))); + m_FillDepthBufferSkinnedProgram->AddShader(std::shared_ptr(new FragmentShader("Shaders/FillDepthBuffer.frag.glsl"))); + m_FillDepthBufferSkinnedProgram->Compile(); + m_FillDepthBufferSkinnedProgram->Link(); + GLERROR("Creating DepthFill program"); } void DrawFinalPass::Draw(RenderScene& scene) { - GLERROR("DrawFinalPass::Draw: Pre"); + GLERROR("Pre"); DrawFinalPassState* state = new DrawFinalPassState(m_FinalPassFrameBuffer.GetHandle()); if (scene.ClearDepth) { glClear(GL_DEPTH_BUFFER_BIT); } + //TODO: Do we need check for this or will it be per scene always? + glClearStencil(0x00); + glClear(GL_STENCIL_BUFFER_BIT); - DrawModelRenderQueues(scene.OpaqueObjects, scene); - GLERROR("DrawFinalPass::Draw: OpaqueObjects"); - DrawModelRenderQueues(scene.TransparentObjects, scene); - GLERROR("DrawFinalPass::Draw: TransparentObjects"); + //Fill depth buffer - GLERROR("DrawFinalPass::Draw: END"); + + state->StencilMask(0x00); + DrawModelRenderQueues(scene.Jobs.OpaqueObjects, scene); + GLERROR("OpaqueObjects"); + DrawModelRenderQueues(scene.Jobs.TransparentObjects, scene); + GLERROR("TransparentObjects"); + DrawSprites(scene.Jobs.SpriteJob, scene); + GLERROR("SpriteJobs"); + + //DrawStencilState* stencilState = new DrawStencilState(m_FinalPassFrameBuffer.GetHandle()); + //Draw shields to stencil pass + state->StencilFunc(GL_ALWAYS, 1, 0xFF); + state->StencilMask(0xFF); + DrawShieldToStencilBuffer(scene.Jobs.ShieldObjects, scene); + GLERROR("StencilPass"); + + //Draw Opaque shielded objects + state->StencilFunc(GL_NOTEQUAL, 1, 0xFF); + state->StencilMask(0x00); + DrawModelRenderQueues(scene.Jobs.OpaqueShieldedObjects, scene); //might need changing + GLERROR("Shielded Opaque object"); + + //Draw Transparen Shielded objects + DrawModelRenderQueues(scene.Jobs.TransparentShieldedObjects, scene); //might need changing + GLERROR("Shielded Transparent objects"); + + GLERROR("END"); delete state; + + + DrawFinalPassState* stateLowRes = new DrawFinalPassState(m_FinalPassFrameBufferLowRes.GetHandle()); + //Draw the lowres texture that will be shown behind the shield. + stateLowRes->Enable(GL_SCISSOR_TEST); + stateLowRes->Enable(GL_DEPTH_TEST); + //TODO: Viewports and scissor should be in state + glViewport(0, 0, m_Renderer->GetViewportSize().Width/m_ShieldPixelRate, m_Renderer->GetViewportSize().Height/m_ShieldPixelRate); + glScissor(0, 0, m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height); + + glClearStencil(0x00); + glClear(GL_STENCIL_BUFFER_BIT); + + //TODO: This should not be here... + stateLowRes->StencilFunc(GL_ALWAYS, 1, 0xFF); + stateLowRes->StencilMask(0x00); + DrawToDepthBuffer(scene.Jobs.OpaqueObjects, scene); + DrawToDepthBuffer(scene.Jobs.TransparentObjects, scene); + + //Draw shields to stencil pass + stateLowRes->StencilFunc(GL_ALWAYS, 1, 0xFF); + stateLowRes->StencilMask(0xFF); + stateLowRes->Enable(GL_DEPTH_TEST); + DrawShieldToStencilBuffer(scene.Jobs.ShieldObjects, scene); + GLERROR("StencilPass"); + + glClear(GL_DEPTH_BUFFER_BIT); + + stateLowRes->Enable(GL_DEPTH_TEST); + stateLowRes->StencilFunc(GL_LEQUAL, 1, 0xFF); + stateLowRes->StencilMask(0x00); + DrawModelRenderQueues(scene.Jobs.OpaqueObjects, scene); + GLERROR("OpaqueObjects"); + DrawModelRenderQueues(scene.Jobs.TransparentObjects, scene); + GLERROR("TransparentObjects"); + glViewport(0, 0, m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height); + glScissor(0, 0, m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height); + delete stateLowRes; } void DrawFinalPass::ClearBuffer() { + m_FinalPassFrameBufferLowRes.Bind(); + glViewport(0, 0, m_Renderer->GetViewportSize().Width/m_ShieldPixelRate, m_Renderer->GetViewportSize().Height/m_ShieldPixelRate); + glScissor(0, 0, m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height); + glClearColor(0.f, 0.f, 0.f, 0.f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glDisable(GL_SCISSOR_TEST); + m_FinalPassFrameBufferLowRes.Unbind(); + m_FinalPassFrameBuffer.Bind(); + glViewport(0, 0, m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height); + glScissor(0, 0, m_Renderer->GetViewportSize().Width, m_Renderer->GetViewportSize().Height); glClearColor(0.f, 0.f, 0.f, 0.f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); m_FinalPassFrameBuffer.Unbind(); @@ -108,39 +300,250 @@ void DrawFinalPass::GenerateMipMapTexture(GLuint* texture, GLenum wrapping, glm: GLERROR("MipMap Texture initialization failed"); } -void DrawFinalPass::DrawModelRenderQueues(std::list>& job, RenderScene& scene) +void DrawFinalPass::DrawModelRenderQueues(std::list>& jobs, RenderScene& scene) { GLuint forwardHandle = m_ForwardPlusProgram->GetHandle(); - GLuint explosionHandle = m_ExplosionEffectProgram->GetHandle(); + GLERROR("forwardHandle"); + GLuint explosionHandle = m_ExplosionEffectProgram->GetHandle(); + GLERROR("explosionHandle"); + GLuint explosionSplatMapHandle = m_ExplosionEffectSplatMapProgram->GetHandle(); + GLERROR("explosionSplatMapHandle"); + GLuint forwardSplatHandle = m_ForwardPlusSplatMapProgram->GetHandle(); + GLERROR("forwardSplatHandle"); + GLuint forwardSkinnedHandle = m_ForwardPlusSkinnedProgram->GetHandle(); + GLERROR("forwardSkinnedHandle"); + GLuint explosionSkinnedHandle = m_ExplosionEffectSkinnedProgram->GetHandle(); + GLERROR("explosionSkinnedHandle"); + GLuint explosionSplatMapSkinnedHandle = m_ExplosionEffectSplatMapSkinnedProgram->GetHandle(); + GLERROR("explosionSplatMapSkinnedHandle"); + GLuint forwardSplatMapSkinnedHandle = m_ForwardPlusSplatMapSkinnedProgram->GetHandle(); + GLERROR("forwardSplatSkinnedHandle"); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_LightCullingPass->LightSSBO()); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, m_LightCullingPass->LightGridSSBO()); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, m_LightCullingPass->LightIndexSSBO()); - for(auto &job : job) - { + for (auto &job : jobs) { auto explosionEffectJob = std::dynamic_pointer_cast(job); - if(explosionEffectJob) { - //Bind program - m_ExplosionEffectProgram->Bind(); - - //Bind uniforms - BindExplosionUniforms(explosionHandle, explosionEffectJob, scene); - - if (explosionEffectJob->Model->m_RawModel->m_Skeleton != nullptr) { - - if (explosionEffectJob->Animation != nullptr) { - std::vector frameBones = explosionEffectJob->Skeleton->GetFrameBones(*explosionEffectJob->Animation, explosionEffectJob->AnimationTime); - glUniformMatrix4fv(glGetUniformLocation(explosionHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0])); + if (explosionEffectJob) { + switch (explosionEffectJob->Type) { + case RawModel::MaterialType::Basic: + case RawModel::MaterialType::SingleTextures: + { + if (explosionEffectJob->Model->IsSkinned()) { + m_ExplosionEffectSkinnedProgram->Bind(); + GLERROR("Bind ExplosionEffectSkinned program"); + //bind uniforms + BindExplosionUniforms(explosionSkinnedHandle, explosionEffectJob, scene); + //bind textures + BindExplosionTextures(explosionSkinnedHandle, explosionEffectJob); + std::vector frameBones; + frameBones = explosionEffectJob->Skeleton->GetBones(); + glUniformMatrix4fv(glGetUniformLocation(explosionSkinnedHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0])); + } else { + m_ExplosionEffectProgram->Bind(); + GLERROR("Bind ExplosionEffect program"); + //bind uniforms + BindExplosionUniforms(explosionHandle, explosionEffectJob, scene); + //bind textures + BindExplosionTextures(explosionHandle, explosionEffectJob); } + break; } + case RawModel::MaterialType::SplatMapping: + { + if (explosionEffectJob->Model->IsSkinned()) { + m_ExplosionEffectSplatMapSkinnedProgram->Bind(); + GLERROR("Bind ExplosionEffectSplatMapSkinned program"); + //bind uniforms + BindExplosionUniforms(explosionSplatMapSkinnedHandle, explosionEffectJob, scene); + //bind textures + BindExplosionTextures(explosionSplatMapSkinnedHandle, explosionEffectJob); + GLERROR("asdasd"); + std::vector frameBones; + frameBones = explosionEffectJob->Skeleton->GetBones(); + glUniformMatrix4fv(glGetUniformLocation(explosionSplatMapSkinnedHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0])); + + } else { + m_ExplosionEffectSplatMapProgram->Bind(); + GLERROR("Bind ExplosionEffectSplatMap program"); + //bind uniforms + //bind uniforms + BindExplosionUniforms(explosionSplatMapHandle, explosionEffectJob, scene); + //bind textures + BindExplosionTextures(explosionSplatMapHandle, explosionEffectJob); + GLERROR("asdasd"); + } + break; + } + } + glDisable(GL_CULL_FACE); - //bind textures - BindExplosionTextures(explosionEffectJob); //draw glBindVertexArray(explosionEffectJob->Model->VAO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, explosionEffectJob->Model->ElementBuffer); glDrawElements(GL_TRIANGLES, explosionEffectJob->EndIndex - explosionEffectJob->StartIndex + 1, GL_UNSIGNED_INT, (void*)(explosionEffectJob->StartIndex*sizeof(unsigned int))); + glEnable(GL_CULL_FACE); + GLERROR("explosion effect end"); + } else { + auto modelJob = std::dynamic_pointer_cast(job); + if (modelJob) { + //bind forward program + //TODO: JOHAN/TOBIAS: Bind shader based on ModelJob->ShaderID; + switch (modelJob->Type) { + case RawModel::MaterialType::Basic: + case RawModel::MaterialType::SingleTextures: + { + if (modelJob->Model->IsSkinned()) { + m_ForwardPlusSkinnedProgram->Bind(); + GLERROR("Bind ForwardPlusSkinnedProgram"); + //bind uniforms + BindModelUniforms(forwardSkinnedHandle, modelJob, scene); + //bind textures + BindModelTextures(forwardSkinnedHandle, modelJob); + std::vector frameBones; + frameBones = modelJob->Skeleton->GetBones(); + glUniformMatrix4fv(glGetUniformLocation(forwardSkinnedHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0])); + + } else { + m_ForwardPlusProgram->Bind(); + GLERROR("Bind ForwardPlusProgram"); + //bind uniforms + BindModelUniforms(forwardHandle, modelJob, scene); + //bind textures + BindModelTextures(forwardHandle, modelJob); + } + break; + } + case RawModel::MaterialType::SplatMapping: + { + if (modelJob->Model->IsSkinned()) { + m_ForwardPlusSplatMapSkinnedProgram->Bind(); + GLERROR("Bind SplatMap program"); + //bind uniforms + BindModelUniforms(forwardSplatMapSkinnedHandle, modelJob, scene); + //bind textures + BindModelTextures(forwardSplatMapSkinnedHandle, modelJob); + GLERROR("asdasd"); + std::vector frameBones; + frameBones = modelJob->Skeleton->GetBones(); + glUniformMatrix4fv(glGetUniformLocation(forwardSplatMapSkinnedHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0])); + + } else { + m_ForwardPlusSplatMapProgram->Bind(); + GLERROR("Bind SplatMap program"); + //bind uniforms + BindModelUniforms(forwardSplatHandle, modelJob, scene); + //bind textures + BindModelTextures(forwardSplatHandle, modelJob); + GLERROR("asdasd"); + } + break; + } + } + //draw + 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))); + if (GLERROR("models end")) { + continue; + } + } + } + } +} + + +void DrawFinalPass::DrawShieldToStencilBuffer(std::list>& jobs, RenderScene& scene) +{ + + + for (auto &job : jobs) { + auto modelJob = std::dynamic_pointer_cast(job); + if (modelJob) { + + if(modelJob->Model->IsSkinned()) { + m_ShieldToStencilSkinnedProgram->Bind(); + GLuint shaderHandle = m_ShieldToStencilSkinnedProgram->GetHandle(); + + 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())); + std::vector frameBones; + frameBones = modelJob->Skeleton->GetBones(); + glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0])); + } else { + m_ShieldToStencilProgram->Bind(); + GLuint shaderHandle = m_ShieldToStencilProgram->GetHandle(); + + 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())); + + } + + 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))); + if (GLERROR("models end")) { + continue; + } + } + } +} + +void DrawFinalPass::DrawShieldedModelRenderQueue(std::list>& jobs, RenderScene& scene) +{ + GLuint forwardHandle = m_ForwardPlusProgram->GetHandle(); + GLERROR("forwardHandle"); + GLuint explosionHandle = m_ExplosionEffectProgram->GetHandle(); + GLERROR("explosionHandle"); + + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_LightCullingPass->LightSSBO()); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, m_LightCullingPass->LightGridSSBO()); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, m_LightCullingPass->LightIndexSSBO()); + + for (auto &job : jobs) { + auto explosionEffectJob = std::dynamic_pointer_cast(job); + if (explosionEffectJob) { + //Bind program + if (GLERROR("Prebind")) { + continue; + } + m_ExplosionEffectProgram->Bind(); + if (GLERROR("BindProgram")) { + continue; + } + + glDisable(GL_CULL_FACE); + + //Bind uniforms + BindExplosionUniforms(explosionHandle, explosionEffectJob, scene); + if (GLERROR("BindExplosionUniforms")) { + continue; + } + + std::vector frameBones; + frameBones = explosionEffectJob->Skeleton->GetBones(); + glUniformMatrix4fv(glGetUniformLocation(explosionHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0])); + + if (GLERROR("Animation")) { + continue; + } + + //bind textures + BindExplosionTextures(explosionHandle, explosionEffectJob); + if (GLERROR("BindExplosionTextures")) { + continue; + } + //draw + glBindVertexArray(explosionEffectJob->Model->VAO); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, explosionEffectJob->Model->ElementBuffer); + glDrawElements(GL_TRIANGLES, explosionEffectJob->EndIndex - explosionEffectJob->StartIndex + 1, GL_UNSIGNED_INT, (void*)(explosionEffectJob->StartIndex*sizeof(unsigned int))); + glEnable(GL_CULL_FACE); + if (GLERROR("explosion effect end")) { + continue; + } } else { auto modelJob = std::dynamic_pointer_cast(job); @@ -153,106 +556,423 @@ void DrawFinalPass::DrawModelRenderQueues(std::list>& BindModelUniforms(forwardHandle, modelJob, scene); //bind textures - BindModelTextures(modelJob); + BindModelTextures(forwardHandle ,modelJob); - if (modelJob->Model->m_RawModel->m_Skeleton != nullptr) { + std::vector frameBones; + frameBones = modelJob->Skeleton->GetBones(); + glUniformMatrix4fv(glGetUniformLocation(forwardHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0])); - if (modelJob->Animation != nullptr) { - std::vector frameBones = modelJob->Skeleton->GetFrameBones(*modelJob->Animation, modelJob->AnimationTime); - glUniformMatrix4fv(glGetUniformLocation(forwardHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0])); - } - } //draw 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("DrawFinalPass::Model: END"); + if (GLERROR("models end")) { + continue; + } } } } +} + + +void DrawFinalPass::DrawToDepthBuffer(std::list>& jobs, RenderScene& scene) +{ + + + for (auto &job : jobs) { + auto modelJob = std::dynamic_pointer_cast(job); + + if(modelJob->Model->IsSkinned()) { + m_FillDepthBufferSkinnedProgram->Bind(); + GLuint shaderHandle = m_FillDepthBufferSkinnedProgram->GetHandle(); + 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, "M"), 1, GL_FALSE, glm::value_ptr(modelJob->Matrix)); + + std::vector frameBones; + frameBones = modelJob->Skeleton->GetBones(); + glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0])); + + } else { + m_FillDepthBufferProgram->Bind(); + GLuint shaderHandle = m_FillDepthBufferProgram->GetHandle(); + 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, "M"), 1, GL_FALSE, glm::value_ptr(modelJob->Matrix)); + } + + + //draw + 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))); + if (GLERROR("models end")) { + continue; + } + } } + +void DrawFinalPass::DrawSprites(std::list>&jobs, RenderScene& scene) +{ + m_SpriteProgram->Bind(); + + GLuint shaderHandle = m_SpriteProgram->GetHandle(); + + for(auto& job : jobs) { + auto spriteJob = std::dynamic_pointer_cast(job); + RenderState jobState; + + if (spriteJob) { + if(spriteJob->Depth == 0) { + jobState.Disable(GL_DEPTH_TEST); + } + 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())); + glUniform3fv(glGetUniformLocation(shaderHandle, "CameraPos"), 1, glm::value_ptr(scene.Camera->Position())); + glUniform4fv(glGetUniformLocation(shaderHandle, "Color"), 1, glm::value_ptr(spriteJob->Color)); + glUniform4fv(glGetUniformLocation(shaderHandle, "FillColor"), 1, glm::value_ptr(spriteJob->FillColor)); + glUniform1f(glGetUniformLocation(shaderHandle, "FillPercentage"), spriteJob->FillPercentage); + + glActiveTexture(GL_TEXTURE0); + if (spriteJob->DiffuseTexture != nullptr) { + glBindTexture(GL_TEXTURE_2D, spriteJob->DiffuseTexture->m_Texture); + } else { + glBindTexture(GL_TEXTURE_2D, m_ErrorTexture->m_Texture); + } + + glActiveTexture(GL_TEXTURE1); + if (spriteJob->IncandescenceTexture != nullptr) { + glBindTexture(GL_TEXTURE_2D, spriteJob->IncandescenceTexture->m_Texture); + } else { + glBindTexture(GL_TEXTURE_2D, m_BlackTexture->m_Texture); + } + + + 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))); + } + } + + + + // m_SpriteProgram->Unbind(); +} + void DrawFinalPass::BindExplosionUniforms(GLuint shaderHandle, std::shared_ptr& job, RenderScene& scene) { - glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "V"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ViewMatrix())); - glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "P"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ProjectionMatrix())); - glUniform2f(glGetUniformLocation(shaderHandle, "ScreenDimensions"), m_Renderer->Resolution().Width, m_Renderer->Resolution().Height); - + GLERROR("Bind 1 uniform"); glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "M"), 1, GL_FALSE, glm::value_ptr(job->Matrix)); - glUniform4fv(glGetUniformLocation(shaderHandle, "Color"), 1, glm::value_ptr(job->Color)); + GLERROR("Bind 2 uniform"); + glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "V"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ViewMatrix())); + GLERROR("Bind 3 uniform"); + glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "P"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ProjectionMatrix())); + GLERROR("Bind 4 uniform"); + + glUniform2f(glGetUniformLocation(shaderHandle, "ScreenDimensions"), m_Renderer->Resolution().Width, m_Renderer->Resolution().Height); + GLERROR("Bind 5 uniform"); + glUniform3fv(glGetUniformLocation(shaderHandle, "ExplosionOrigin"), 1, glm::value_ptr(job->ExplosionOrigin)); + GLERROR("Bind 6 uniform"); glUniform1f(glGetUniformLocation(shaderHandle, "TimeSinceDeath"), job->TimeSinceDeath); + GLERROR("Bind 7 uniform"); glUniform1f(glGetUniformLocation(shaderHandle, "ExplosionDuration"), job->ExplosionDuration); + GLERROR("Bind 8 uniform"); glUniform4fv(glGetUniformLocation(shaderHandle, "EndColor"), 1, glm::value_ptr(job->EndColor)); + GLERROR("Bind 9 uniform"); glUniform1i(glGetUniformLocation(shaderHandle, "Randomness"), job->Randomness); - glUniform1f(glGetUniformLocation(shaderHandle, "RandomnessScalar"), job->RandomnessScalar); - glUniform2fv(glGetUniformLocation(shaderHandle, "Velocity"), 1, glm::value_ptr(job->Velocity)); - glUniform1i(glGetUniformLocation(shaderHandle, "ColorByDistance"), job->ColorByDistance); - glUniform1i(glGetUniformLocation(shaderHandle, "ExponentialAccelaration"), job->ExponentialAccelaration); - glUniform4fv(glGetUniformLocation(shaderHandle, "DiffuseColor"), 1, glm::value_ptr(job->DiffuseColor)); + GLERROR("Bind 10 uniform"); glUniform1fv(glGetUniformLocation(shaderHandle, "RandomNumbers"), 50, job->RandomNumbers.data()); + GLERROR("Bind 11 uniform"); + glUniform1f(glGetUniformLocation(shaderHandle, "RandomnessScalar"), job->RandomnessScalar); + GLERROR("Bind 12 uniform"); + glUniform2fv(glGetUniformLocation(shaderHandle, "Velocity"), 1, glm::value_ptr(job->Velocity)); + GLERROR("Bind 13 uniform"); + glUniform1i(glGetUniformLocation(shaderHandle, "ColorByDistance"), job->ColorByDistance); + GLERROR("Bind 14 uniform"); + glUniform1i(glGetUniformLocation(shaderHandle, "ExponentialAccelaration"), job->ExponentialAccelaration); + GLERROR("Bind 15 uniform"); + + glUniform4fv(glGetUniformLocation(shaderHandle, "Color"), 1, glm::value_ptr(job->Color)); + GLERROR("Bind 16 uniform"); + glUniform4fv(glGetUniformLocation(shaderHandle, "DiffuseColor"), 1, glm::value_ptr(job->DiffuseColor)); + GLERROR("Bind 17 uniform"); + glUniform4fv(glGetUniformLocation(shaderHandle, "FillColor"), 1, glm::value_ptr(job->FillColor)); + GLERROR("Bind 18 uniform"); + glUniform1f(glGetUniformLocation(shaderHandle, "FillPercentage"), job->FillPercentage); + GLERROR("Bind 19 uniform"); + glUniform4fv(glGetUniformLocation(shaderHandle, "AmbientColor"), 1, glm::value_ptr(scene.AmbientColor)); + GLERROR("END"); } void DrawFinalPass::BindModelUniforms(GLuint shaderHandle, std::shared_ptr& job, RenderScene& scene) { - glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "V"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ViewMatrix())); - glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "P"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ProjectionMatrix())); - glUniform2f(glGetUniformLocation(shaderHandle, "ScreenDimensions"), m_Renderer->Resolution().Width, m_Renderer->Resolution().Height); + GLERROR("Bind 1 uniform"); + GLint Location_M = glGetUniformLocation(shaderHandle, "M"); + glUniformMatrix4fv(Location_M, 1, GL_FALSE, glm::value_ptr(job->Matrix)); + GLERROR("Bind 2 uniform"); + GLint Location_V = glGetUniformLocation(shaderHandle, "V"); + glUniformMatrix4fv(Location_V, 1, GL_FALSE, glm::value_ptr(scene.Camera->ViewMatrix())); + GLERROR("Bind 3 uniform"); + GLint Location_P = glGetUniformLocation(shaderHandle, "P"); + glUniformMatrix4fv(Location_P, 1, GL_FALSE, glm::value_ptr(scene.Camera->ProjectionMatrix())); + GLERROR("Bind 4 uniform"); - glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "M"), 1, GL_FALSE, glm::value_ptr(job->Matrix)); - glUniform4fv(glGetUniformLocation(shaderHandle, "Color"), 1, glm::value_ptr(job->Color)); - glUniform4fv(glGetUniformLocation(shaderHandle, "DiffuseColor"), 1, glm::value_ptr(job->DiffuseColor)); - glUniform4fv(glGetUniformLocation(shaderHandle, "FillColor"), 1, glm::value_ptr(job->FillColor)); - glUniform1f(glGetUniformLocation(shaderHandle, "FillPercentage"), job->FillPercentage); + GLint Location_ScreenDimensions = glGetUniformLocation(shaderHandle, "ScreenDimensions"); + glUniform2f(Location_ScreenDimensions, m_Renderer->Resolution().Width, m_Renderer->Resolution().Height); + GLERROR("Bind 5 uniform"); + + GLint Location_FillPercentage = glGetUniformLocation(shaderHandle, "FillPercentage"); + glUniform1f(Location_FillPercentage, job->FillPercentage); + GLERROR("Bind 6 uniform"); + GLint Location_DiffuseColor = glGetUniformLocation(shaderHandle, "DiffuseColor"); + glUniform4fv(Location_DiffuseColor, 1, glm::value_ptr(job->DiffuseColor)); + GLERROR("Bind 7 uniform"); + GLint Location_FillColor = glGetUniformLocation(shaderHandle, "FillColor"); + glUniform4fv(Location_FillColor, 1, glm::value_ptr(job->FillColor)); + GLERROR("Bind 8 uniform"); + GLint Location_Color = glGetUniformLocation(shaderHandle, "Color"); + glUniform4fv(Location_Color, 1, glm::value_ptr(job->Color)); + GLERROR("Bind 9 uniform"); + GLint Location_AmbientColor = glGetUniformLocation(shaderHandle, "AmbientColor"); + glUniform4fv(Location_AmbientColor, 1, glm::value_ptr(scene.AmbientColor)); + + GLERROR("END"); } - -void DrawFinalPass::BindExplosionTextures(std::shared_ptr& job) +void DrawFinalPass::BindExplosionTextures(GLuint shaderHandle, std::shared_ptr& job) { - glActiveTexture(GL_TEXTURE0); - if (job->DiffuseTexture != nullptr) { - glBindTexture(GL_TEXTURE_2D, job->DiffuseTexture->m_Texture); - } else { - glBindTexture(GL_TEXTURE_2D, m_WhiteTexture->m_Texture); - } - glActiveTexture(GL_TEXTURE1); - if (job->IncandescenceTexture != nullptr) { - glBindTexture(GL_TEXTURE_2D, job->IncandescenceTexture->m_Texture); - } else { - glBindTexture(GL_TEXTURE_2D, m_BlackTexture->m_Texture); - } + switch (job->Type) { + case RawModel::MaterialType::SingleTextures: + case RawModel::MaterialType::Basic: + { + glActiveTexture(GL_TEXTURE0); + if (job->DiffuseTexture.size() > 0 && job->DiffuseTexture[0]->Texture != nullptr) { + glBindTexture(GL_TEXTURE_2D, job->DiffuseTexture[0]->Texture->m_Texture); + glUniform2fv(glGetUniformLocation(shaderHandle, "DiffuseUVRepeat"), 1, glm::value_ptr(job->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))); + } + + glActiveTexture(GL_TEXTURE1); + if (job->NormalTexture.size() > 0 && job->NormalTexture[0]->Texture != nullptr) { + glBindTexture(GL_TEXTURE_2D, job->NormalTexture[0]->Texture->m_Texture); + glUniform2fv(glGetUniformLocation(shaderHandle, "NormalUVRepeat"), 1, glm::value_ptr(job->NormalTexture[0]->UVRepeat)); + } + else { + glBindTexture(GL_TEXTURE_2D, m_NeutralNormalTexture->m_Texture); + glUniform2fv(glGetUniformLocation(shaderHandle, "NormalUVRepeat"), 1, glm::value_ptr(glm::vec2(1.0f, 1.0f))); + } + + glActiveTexture(GL_TEXTURE2); + if (job->SpecularTexture.size() > 0 && job->SpecularTexture[0]->Texture != nullptr) { + glBindTexture(GL_TEXTURE_2D, job->SpecularTexture[0]->Texture->m_Texture); + glUniform2fv(glGetUniformLocation(shaderHandle, "SpecularUVRepeat"), 1, glm::value_ptr(job->SpecularTexture[0]->UVRepeat)); + } + else { + glBindTexture(GL_TEXTURE_2D, m_GreyTexture->m_Texture); + glUniform2fv(glGetUniformLocation(shaderHandle, "SpecularUVRepeat"), 1, glm::value_ptr(glm::vec2(1.0f, 1.0f))); + } + + glActiveTexture(GL_TEXTURE3); + if (job->IncandescenceTexture.size() > 0 && job->IncandescenceTexture[0]->Texture != nullptr) { + glBindTexture(GL_TEXTURE_2D, job->IncandescenceTexture[0]->Texture->m_Texture); + glUniform2fv(glGetUniformLocation(shaderHandle, "GlowUVRepeat"), 1, glm::value_ptr(job->IncandescenceTexture[0]->UVRepeat)); + } + else { + glBindTexture(GL_TEXTURE_2D, m_BlackTexture->m_Texture); + glUniform2fv(glGetUniformLocation(shaderHandle, "GlowUVRepeat"), 1, glm::value_ptr(glm::vec2(1.0f, 1.0f))); + } + break; + } + case RawModel::MaterialType::SplatMapping: + { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, job->SplatMap->Texture->m_Texture); + + int texturePosition = GL_TEXTURE1; + + //Bind 5 diffuse textures + std::string UniformName = "DiffuseUVRepeat"; + for (unsigned int i = 0; i < 5; i++) { + glActiveTexture(texturePosition); + if (job->DiffuseTexture.size() > i && job->DiffuseTexture[i]->Texture != nullptr) { + glBindTexture(GL_TEXTURE_2D, job->DiffuseTexture[i]->Texture->m_Texture); + glUniform2fv(glGetUniformLocation(shaderHandle, std::string(UniformName + ((char)(i + '1'))).c_str()), 1, glm::value_ptr(job->DiffuseTexture[i]->UVRepeat)); + } + else { + glBindTexture(GL_TEXTURE_2D, m_WhiteTexture->m_Texture); + glUniform2fv(glGetUniformLocation(shaderHandle, std::string(UniformName + ((char)(i + '1'))).c_str()), 1, glm::value_ptr(glm::vec2(1.0f, 1.0f))); + } + texturePosition++; + } + + //Bind 5 Normal textures + UniformName = "NormalUVRepeat"; + for (unsigned int i = 0; i < 5; i++) { + glActiveTexture(texturePosition); + if (job->NormalTexture.size() > i && job->NormalTexture[i]->Texture != nullptr) { + glBindTexture(GL_TEXTURE_2D, job->NormalTexture[i]->Texture->m_Texture); + glUniform2fv(glGetUniformLocation(shaderHandle, std::string(UniformName + ((char)(i + '1'))).c_str()), 1, glm::value_ptr(job->NormalTexture[i]->UVRepeat)); + } + else { + glBindTexture(GL_TEXTURE_2D, m_NeutralNormalTexture->m_Texture); + glUniform2fv(glGetUniformLocation(shaderHandle, std::string(UniformName + ((char)(i + '1'))).c_str()), 1, glm::value_ptr(glm::vec2(1.0f, 1.0f))); + } + texturePosition++; + } + + //Bind 5 Specular textures + UniformName = "SpecularUVRepeat"; + for (unsigned int i = 0; i < 5; i++) { + glActiveTexture(texturePosition); + if (job->SpecularTexture.size() > i && job->SpecularTexture[i]->Texture != nullptr) { + glBindTexture(GL_TEXTURE_2D, job->SpecularTexture[i]->Texture->m_Texture); + glUniform2fv(glGetUniformLocation(shaderHandle, std::string(UniformName + ((char)(i + '1'))).c_str()), 1, glm::value_ptr(job->SpecularTexture[i]->UVRepeat)); + } + else { + glBindTexture(GL_TEXTURE_2D, m_GreyTexture->m_Texture); + glUniform2fv(glGetUniformLocation(shaderHandle, std::string(UniformName + ((char)(i + '1'))).c_str()), 1, glm::value_ptr(glm::vec2(1.0f, 1.0f))); + } + texturePosition++; + } + + //Bind 5 Incandescence textures + UniformName = "GlowUVRepeat"; + for (unsigned int i = 0; i < 5; i++) { + glActiveTexture(texturePosition); + if (job->IncandescenceTexture.size() > i && job->IncandescenceTexture[i]->Texture != nullptr) { + glBindTexture(GL_TEXTURE_2D, job->IncandescenceTexture[i]->Texture->m_Texture); + glUniform2fv(glGetUniformLocation(shaderHandle, std::string(UniformName + ((char)(i + '1'))).c_str()), 1, glm::value_ptr(job->IncandescenceTexture[i]->UVRepeat)); + } + else { + glBindTexture(GL_TEXTURE_2D, m_BlackTexture->m_Texture); + glUniform2fv(glGetUniformLocation(shaderHandle, std::string(UniformName + ((char)(i + '1'))).c_str()), 1, glm::value_ptr(glm::vec2(1.0f, 1.0f))); + } + texturePosition++; + } + break; + } + } } -void DrawFinalPass::BindModelTextures(std::shared_ptr& job) +void DrawFinalPass::BindModelTextures(GLuint shaderHandle, std::shared_ptr& job) { - glActiveTexture(GL_TEXTURE0); - if (job->DiffuseTexture != nullptr) { - glBindTexture(GL_TEXTURE_2D, job->DiffuseTexture->m_Texture); - } else { - glBindTexture(GL_TEXTURE_2D, m_WhiteTexture->m_Texture); - } + switch (job->Type) { + case RawModel::MaterialType::SingleTextures: + case RawModel::MaterialType::Basic: + { + glActiveTexture(GL_TEXTURE0); + if (job->DiffuseTexture.size() > 0 && job->DiffuseTexture[0]->Texture != nullptr) { + glBindTexture(GL_TEXTURE_2D, job->DiffuseTexture[0]->Texture->m_Texture); + glUniform2fv(glGetUniformLocation(shaderHandle, "DiffuseUVRepeat"), 1, glm::value_ptr(job->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))); + } - glActiveTexture(GL_TEXTURE1); - if (job->NormalTexture != nullptr) { - glBindTexture(GL_TEXTURE_2D, job->NormalTexture->m_Texture); - } else { - glBindTexture(GL_TEXTURE_2D, m_NeutralNormalTexture->m_Texture); - } + glActiveTexture(GL_TEXTURE1); + if (job->NormalTexture.size() > 0 && job->NormalTexture[0]->Texture != nullptr) { + glBindTexture(GL_TEXTURE_2D, job->NormalTexture[0]->Texture->m_Texture); + glUniform2fv(glGetUniformLocation(shaderHandle, "NormalUVRepeat"), 1, glm::value_ptr(job->NormalTexture[0]->UVRepeat)); + } + else { + glBindTexture(GL_TEXTURE_2D, m_NeutralNormalTexture->m_Texture); + glUniform2fv(glGetUniformLocation(shaderHandle, "NormalUVRepeat"), 1, glm::value_ptr(glm::vec2(1.0f, 1.0f))); + } - glActiveTexture(GL_TEXTURE2); - if (job->SpecularTexture != nullptr) { - glBindTexture(GL_TEXTURE_2D, job->SpecularTexture->m_Texture); - } else { - glBindTexture(GL_TEXTURE_2D, m_GreyTexture->m_Texture); - } + glActiveTexture(GL_TEXTURE2); + if (job->SpecularTexture.size() > 0 && job->SpecularTexture[0]->Texture != nullptr) { + glBindTexture(GL_TEXTURE_2D, job->SpecularTexture[0]->Texture->m_Texture); + glUniform2fv(glGetUniformLocation(shaderHandle, "SpecularUVRepeat"), 1, glm::value_ptr(job->SpecularTexture[0]->UVRepeat)); + } + else { + glBindTexture(GL_TEXTURE_2D, m_GreyTexture->m_Texture); + glUniform2fv(glGetUniformLocation(shaderHandle, "SpecularUVRepeat"), 1, glm::value_ptr(glm::vec2(1.0f, 1.0f))); + } - glActiveTexture(GL_TEXTURE3); - if (job->IncandescenceTexture != nullptr) { - glBindTexture(GL_TEXTURE_2D, job->IncandescenceTexture->m_Texture); - } else { - glBindTexture(GL_TEXTURE_2D, m_BlackTexture->m_Texture); - } + glActiveTexture(GL_TEXTURE3); + if (job->IncandescenceTexture.size() > 0 && job->IncandescenceTexture[0]->Texture != nullptr) { + glBindTexture(GL_TEXTURE_2D, job->IncandescenceTexture[0]->Texture->m_Texture); + glUniform2fv(glGetUniformLocation(shaderHandle, "GlowUVRepeat"), 1, glm::value_ptr(job->IncandescenceTexture[0]->UVRepeat)); + } + else { + glBindTexture(GL_TEXTURE_2D, m_BlackTexture->m_Texture); + glUniform2fv(glGetUniformLocation(shaderHandle, "GlowUVRepeat"), 1, glm::value_ptr(glm::vec2(1.0f, 1.0f))); + } + break; + } + case RawModel::MaterialType::SplatMapping: + { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, job->SplatMap->Texture->m_Texture); + + int texturePosition = GL_TEXTURE1; + + //Bind 5 diffuse textures + std::string UniformName = "DiffuseUVRepeat"; + for (unsigned int i = 0; i < 5; i++) { + glActiveTexture(texturePosition); + if (job->DiffuseTexture.size() > i && job->DiffuseTexture[i]->Texture != nullptr) { + glBindTexture(GL_TEXTURE_2D, job->DiffuseTexture[i]->Texture->m_Texture); + glUniform2fv(glGetUniformLocation(shaderHandle, std::string(UniformName + ((char)(i + '1'))).c_str()), 1, glm::value_ptr(job->DiffuseTexture[i]->UVRepeat)); + } else { + glBindTexture(GL_TEXTURE_2D, m_WhiteTexture->m_Texture); + glUniform2fv(glGetUniformLocation(shaderHandle, std::string(UniformName + ((char)(i + '1'))).c_str()), 1, glm::value_ptr(glm::vec2(1.0f, 1.0f))); + } + texturePosition++; + } + + //Bind 5 Normal textures + UniformName = "NormalUVRepeat"; + for (unsigned int i = 0; i < 5; i++) { + glActiveTexture(texturePosition); + if (job->NormalTexture.size() > i && job->NormalTexture[i]->Texture != nullptr) { + glBindTexture(GL_TEXTURE_2D, job->NormalTexture[i]->Texture->m_Texture); + glUniform2fv(glGetUniformLocation(shaderHandle, std::string(UniformName + ((char)(i + '1'))).c_str()), 1, glm::value_ptr(job->NormalTexture[i]->UVRepeat)); + } else { + glBindTexture(GL_TEXTURE_2D, m_NeutralNormalTexture->m_Texture); + glUniform2fv(glGetUniformLocation(shaderHandle, std::string(UniformName + ((char)(i + '1'))).c_str()), 1, glm::value_ptr(glm::vec2(1.0f, 1.0f))); + } + texturePosition++; + } + + //Bind 5 Specular textures + UniformName = "SpecularUVRepeat"; + for (unsigned int i = 0; i < 5; i++) { + glActiveTexture(texturePosition); + if (job->SpecularTexture.size() > i && job->SpecularTexture[i]->Texture != nullptr) { + glBindTexture(GL_TEXTURE_2D, job->SpecularTexture[i]->Texture->m_Texture); + glUniform2fv(glGetUniformLocation(shaderHandle, std::string(UniformName + ((char)(i + '1'))).c_str()), 1, glm::value_ptr(job->SpecularTexture[i]->UVRepeat)); + } else { + glBindTexture(GL_TEXTURE_2D, m_GreyTexture->m_Texture); + glUniform2fv(glGetUniformLocation(shaderHandle, std::string(UniformName + ((char)(i + '1'))).c_str()), 1, glm::value_ptr(glm::vec2(1.0f, 1.0f))); + } + texturePosition++; + } + + //Bind 5 Incandescence textures + UniformName = "GlowUVRepeat"; + for (unsigned int i = 0; i < 5; i++) { + glActiveTexture(texturePosition); + if (job->IncandescenceTexture.size() > i && job->IncandescenceTexture[i]->Texture != nullptr) { + glBindTexture(GL_TEXTURE_2D, job->IncandescenceTexture[i]->Texture->m_Texture); + glUniform2fv(glGetUniformLocation(shaderHandle, std::string(UniformName + ((char)(i + '1'))).c_str()), 1, glm::value_ptr(job->IncandescenceTexture[i]->UVRepeat)); + } else { + glBindTexture(GL_TEXTURE_2D, m_BlackTexture->m_Texture); + glUniform2fv(glGetUniformLocation(shaderHandle, std::string(UniformName + ((char)(i + '1'))).c_str()), 1, glm::value_ptr(glm::vec2(1.0f, 1.0f))); + } + texturePosition++; + } + break; + } + } } diff --git a/src/Engine/Rendering/DrawFinalPassState.cpp b/src/Engine/Rendering/DrawFinalPassState.cpp index 3ebe320d..8b5ddc8b 100644 --- a/src/Engine/Rendering/DrawFinalPassState.cpp +++ b/src/Engine/Rendering/DrawFinalPassState.cpp @@ -1,6 +1,7 @@ #include "Rendering/DrawFinalPassState.h" + DrawFinalPassState::DrawFinalPassState(GLuint frameBuffer) { BindFramebuffer(frameBuffer); @@ -8,6 +9,10 @@ DrawFinalPassState::DrawFinalPassState(GLuint frameBuffer) BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); Enable(GL_DEPTH_TEST); Enable(GL_CULL_FACE); + Enable(GL_STENCIL_TEST); + StencilFunc(GL_NOTEQUAL, 1, 0xFF); + StencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + StencilMask(0xFF); ClearColor(glm::vec4(0.f, 0.f, 0.f, 0.f)); } @@ -15,3 +20,20 @@ DrawFinalPassState::~DrawFinalPassState() { } + +DrawStencilState::DrawStencilState(GLuint frameBuffer) +{ + BindFramebuffer(frameBuffer); + Enable(GL_STENCIL_TEST); + StencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + StencilFunc(GL_ALWAYS, 1, 0xFF); + StencilMask(0xFF); + Enable(GL_DEPTH_TEST); + ClearColor(glm::vec4(0.f)); +} + +DrawStencilState::~DrawStencilState() +{ + +} + diff --git a/src/Engine/Rendering/DrawScreenQuadPass.cpp b/src/Engine/Rendering/DrawScreenQuadPass.cpp index b17f5e29..7a522b72 100644 --- a/src/Engine/Rendering/DrawScreenQuadPass.cpp +++ b/src/Engine/Rendering/DrawScreenQuadPass.cpp @@ -32,6 +32,6 @@ void DrawScreenQuadPass::Draw(GLuint texture) glBindVertexArray(m_ScreenQuad->VAO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ScreenQuad->ElementBuffer); - glDrawElementsBaseVertex(GL_TRIANGLES, m_ScreenQuad->MaterialGroups()[0].EndIndex - m_ScreenQuad->MaterialGroups()[0].StartIndex +1 - , GL_UNSIGNED_INT, 0, m_ScreenQuad->MaterialGroups()[0].StartIndex); + 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); } diff --git a/src/Engine/Rendering/FrameBuffer.cpp b/src/Engine/Rendering/FrameBuffer.cpp index b7e908cc..c0be4cb1 100644 --- a/src/Engine/Rendering/FrameBuffer.cpp +++ b/src/Engine/Rendering/FrameBuffer.cpp @@ -39,10 +39,13 @@ void FrameBuffer::AddResource(std::shared_ptr resource) void FrameBuffer::Generate() { + GLERROR("PRE"); + std::vector attachments; glGenFramebuffers(1, &m_BufferHandle); glBindFramebuffer(GL_FRAMEBUFFER, m_BufferHandle); + GLERROR("1"); for (auto it = m_Resources.begin(); it != m_Resources.end(); it++) { switch ((*it)->m_ResourceType) { @@ -54,29 +57,32 @@ void FrameBuffer::Generate() case GL_RENDERBUFFER: glFramebufferRenderbuffer(GL_FRAMEBUFFER, (*it)->m_Attachment, (*it)->m_ResourceType, *(*it)->m_ResourceHandle); GLERROR("FrameBuffer generate: glFramebufferRenderbuffer"); - if ( (*it)->m_Attachment != GL_COLOR_ATTACHMENT0 || - (*it)->m_Attachment != GL_COLOR_ATTACHMENT1 || - (*it)->m_Attachment != GL_DEPTH_ATTACHMENT || - (*it)->m_Attachment != GL_STENCIL_ATTACHMENT) //TODO: Viktor: Fixa detta - { - LOG_ERROR("RenderBuffer Attachment not valid."); - } break; } - + GLERROR("2"); - if ((*it)->m_Attachment != GL_DEPTH_ATTACHMENT) { + if ((*it)->m_Attachment != GL_DEPTH_ATTACHMENT && (*it)->m_Attachment != GL_STENCIL_ATTACHMENT && (*it)->m_Attachment != GL_DEPTH_STENCIL_ATTACHMENT) { attachments.push_back((*it)->m_Attachment); } + GLERROR("Attachment"); + } - + GLERROR("3"); + + GLenum* bufferTextures = &attachments[0]; glDrawBuffers(attachments.size(), bufferTextures); + if(GLERROR("4")) { + printf("hello"); + } if (GLenum frameBufferStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - LOG_ERROR("FrameBuffer incomplete: 0x%x\n", frameBufferStatus); + GLERROR("Framebuffer incomplete"); + //LOG_ERROR("FrameBuffer incomplete: 0x%x\n", frameBufferStatus); exit(EXIT_FAILURE); } + GLERROR("END"); + } void FrameBuffer::Bind() diff --git a/src/Engine/Rendering/LightCullingPass.cpp b/src/Engine/Rendering/LightCullingPass.cpp index 5e6da64d..0ae359db 100644 --- a/src/Engine/Rendering/LightCullingPass.cpp +++ b/src/Engine/Rendering/LightCullingPass.cpp @@ -16,7 +16,7 @@ LightCullingPass::~LightCullingPass() void LightCullingPass::GenerateNewFrustum(RenderScene& scene) { - if (scene.PointLightJobs.size() == 0) + if (scene.Jobs.PointLight.size() == 0) return; GLERROR("CalculateFrustum Error: Pre"); @@ -83,7 +83,7 @@ void LightCullingPass::FillLightList(RenderScene& scene) { m_LightSources.clear(); - for(auto &job : scene.PointLightJobs) { + for(auto &job : scene.Jobs.PointLight) { auto pointLightjob = std::dynamic_pointer_cast(job); if (pointLightjob) { LightSource p; @@ -97,7 +97,7 @@ void LightCullingPass::FillLightList(RenderScene& scene) m_LightSources.push_back(p); } } - for(auto &job : scene.DirectionalLightJobs) { + for(auto &job : scene.Jobs.DirectionalLight) { auto directionalLightJob = std::dynamic_pointer_cast(job); if(directionalLightJob) { LightSource p; diff --git a/src/Engine/Rendering/Model.cpp b/src/Engine/Rendering/Model.cpp index cf4923a3..3f8e20e1 100644 --- a/src/Engine/Rendering/Model.cpp +++ b/src/Engine/Rendering/Model.cpp @@ -5,26 +5,48 @@ Model::Model(std::string fileName) //Try loading the model asyncronously, if it throws any exceptions then let it propagate back to caller. m_RawModel = ResourceManager::Load(fileName); - for (auto& group : m_RawModel->MaterialGroups) { - if (!group.TexturePath.empty()) { - group.Texture = std::shared_ptr(ResourceManager::Load(group.TexturePath)); - } - if (!group.NormalMapPath.empty()) { - group.NormalMap = std::shared_ptr(ResourceManager::Load(group.NormalMapPath)); - } - if (!group.SpecularMapPath.empty()) { - group.SpecularMap = std::shared_ptr(ResourceManager::Load(group.SpecularMapPath)); - } - if (!group.IncandescenceMapPath.empty()) { - group.IncandescenceMap = std::shared_ptr(ResourceManager::Load(group.IncandescenceMapPath)); - } + for (auto& materialProperty : m_RawModel->m_Materials) { + switch (materialProperty.type) { + case RawModel::MaterialType::SingleTextures: + { + RawModel::MaterialSingleTextures* materialSingleTexture = static_cast(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); + } + break; + case RawModel::MaterialType::SplatMapping: + { + RawModel::MaterialSplatMapping* materialSplatMapping = static_cast(materialProperty.material); + materialSplatMapping->SplatMap.Texture = CommonFunctions::LoadTexture(materialSplatMapping->SplatMap.TexturePath, false); + for (auto& texture : materialSplatMapping->ColorMaps) + { + texture.Texture = CommonFunctions::LoadTexture(texture.TexturePath, false); + } + for (auto& texture : materialSplatMapping->NormalMaps) + { + texture.Texture = CommonFunctions::LoadTexture(texture.TexturePath, false); + } + for (auto& texture : materialSplatMapping->SpecularMaps) + { + texture.Texture = CommonFunctions::LoadTexture(texture.TexturePath, false); + } + for (auto& texture : materialSplatMapping->IncandescenceMaps) + { + texture.Texture = CommonFunctions::LoadTexture(texture.TexturePath, false); + } + } + break; + } } // Generate GL buffers GLuint buffer; glGenBuffers(1, &buffer); glBindBuffer(GL_ARRAY_BUFFER, buffer); - glBufferData(GL_ARRAY_BUFFER, m_RawModel->m_Vertices.size() * sizeof(RawModel::Vertex), &m_RawModel->m_Vertices[0], GL_STATIC_DRAW); + + glBufferData(GL_ARRAY_BUFFER, m_RawModel->NumVertices() * m_RawModel->VertexSize(), m_RawModel->Vertices(), GL_STATIC_DRAW); glGenBuffers(1, &ElementBuffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ElementBuffer); @@ -35,7 +57,13 @@ Model::Model(std::string fileName) GLERROR("GLEW: BufferFail4"); glBindBuffer(GL_ARRAY_BUFFER, buffer); - std::vector structSizes = { 3, 3, 3, 3, 2, 4, 4 }; + std::vector structSizes; + if (m_RawModel->IsSkinned()) { + structSizes = { 3, 3, 3, 3, 2, 4, 4 }; + } else { + structSizes = { 3, 3, 3, 3, 2 }; + } + int stride = 0; for (int size : structSizes) { stride += size; @@ -49,8 +77,10 @@ Model::Model(std::string fileName) glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++; glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++; glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++; - glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++; - glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++; + if (m_RawModel->IsSkinned()) { + glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++; + glVertexAttribPointer(element, structSizes[element], GL_FLOAT, GL_FALSE, stride, (GLvoid*)(sizeof(GLfloat) * (offset += structSizes[element - 1]))); element++; + } } GLERROR("GLEW: BufferFail5"); @@ -59,11 +89,24 @@ Model::Model(std::string fileName) glEnableVertexAttribArray(2); glEnableVertexAttribArray(3); glEnableVertexAttribArray(4); - glEnableVertexAttribArray(5); - glEnableVertexAttribArray(6); + if (m_RawModel->IsSkinned()) { + glEnableVertexAttribArray(5); + glEnableVertexAttribArray(6); + } GLERROR("GLEW: BufferFail5"); //CreateBuffers(); + + glm::vec3 mini(INFINITY); + glm::vec3 maxi(-INFINITY); + + for (unsigned int i = 0; i < m_RawModel->NumVertices(); i++) { + const auto& v = m_RawModel->Vertices()[i]; + mini = glm::min(mini, v.Position); + maxi = glm::max(maxi, v.Position); + } + + m_Box = AABB(mini, maxi); } Model::~Model() diff --git a/src/Engine/Rendering/PNG.cpp b/src/Engine/Rendering/PNG.cpp index 7ffd5c20..409da9b1 100644 --- a/src/Engine/Rendering/PNG.cpp +++ b/src/Engine/Rendering/PNG.cpp @@ -4,40 +4,35 @@ PNG::PNG(std::string path) { FILE* file = fopen(path.c_str(), "rb"); if (!file) { - LOG_ERROR("Failed to open texture file \"%s\": %s", path.c_str(), const_cast(strerror(errno))); - return; + throw Resource::FailedLoadingException("Failed to open texture file."); } png_byte header[8]; fread(header, 1, 8, file); bool isPNG = !png_sig_cmp(header, 0, 8); if (!isPNG) { - LOG_ERROR("Failed to load texture file \"%s\": File isn't PNG", path.c_str()); fclose(file); - return; + throw Resource::FailedLoadingException("File is not PNG."); } // Initialize libpng png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, (png_error_ptr)&PNG::pngErrorFunction, (png_error_ptr)&PNG::pngErrorFunction); if (!png_ptr) { - LOG_ERROR("libpng: Failed to initialze png_struct"); png_destroy_read_struct(&png_ptr, nullptr, nullptr); fclose(file); - return; + throw Resource::FailedLoadingException("Failed to initialze png_struct."); } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { - LOG_ERROR("libpng: Failed to initialze png_info"); png_destroy_read_struct(&png_ptr, nullptr, nullptr); fclose(file); - return; + throw Resource::FailedLoadingException("Failed to initialze png_info."); } png_infop info_end_ptr = png_create_info_struct(png_ptr); if (!info_end_ptr) { - LOG_ERROR("libpng: Failed to initialze second png_info"); png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); fclose(file); - return; + throw Resource::FailedLoadingException("Failed to initialze second png_info."); } png_init_io(png_ptr, file); @@ -51,8 +46,8 @@ PNG::PNG(std::string path) unsigned int width, height; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); if (bit_depth != 8) { - LOG_ERROR("libpng: Unsupported bit depth \"%i\" of image \"%s\", must be 8", bit_depth, path.c_str()); - return; + throw Resource::FailedLoadingException("Unsupported bit depth. Must be 8"); + } switch (color_type) { case PNG_COLOR_TYPE_RGB: @@ -60,8 +55,7 @@ PNG::PNG(std::string path) Format = Image::ImageFormat::RGBA; break; default: - LOG_ERROR("libpng: Unsupported color format \"%i\" of image \"%s\"", color_type, path.c_str()); - return; + throw Resource::FailedLoadingException("Unsupported color format."); } // Convert RGB to RGBA, since DirectX rather treat them all the same way diff --git a/src/Engine/Rendering/PickingPass.cpp b/src/Engine/Rendering/PickingPass.cpp index 792539f8..cc9837ff 100644 --- a/src/Engine/Rendering/PickingPass.cpp +++ b/src/Engine/Rendering/PickingPass.cpp @@ -41,6 +41,14 @@ void PickingPass::InitializeShaderPrograms() m_PickingProgram->Compile(); m_PickingProgram->BindFragDataLocation(0, "TextureFragment"); m_PickingProgram->Link(); + + m_PickingSkinnedProgram = ResourceManager::Load("#PickingSkinnedProgram"); + + m_PickingSkinnedProgram->AddShader(std::shared_ptr(new VertexShader("Shaders/PickingSkinned.vert.glsl"))); + m_PickingSkinnedProgram->AddShader(std::shared_ptr(new FragmentShader("Shaders/Picking.frag.glsl"))); + m_PickingSkinnedProgram->Compile(); + m_PickingSkinnedProgram->BindFragDataLocation(0, "TextureFragment"); + m_PickingSkinnedProgram->Link(); } void PickingPass::Draw(RenderScene& scene) @@ -49,6 +57,7 @@ void PickingPass::Draw(RenderScene& scene) //TODO: Render: Add code for more jobs than modeljobs. GLuint shaderHandle = m_PickingProgram->GetHandle(); + GLuint shaderSkinnedHandle = m_PickingSkinnedProgram->GetHandle(); m_PickingProgram->Bind(); if (scene.ClearDepth) { @@ -56,7 +65,7 @@ void PickingPass::Draw(RenderScene& scene) } m_Camera = scene.Camera; - for (auto &job : scene.OpaqueObjects) { + for (auto &job : scene.Jobs.OpaqueObjects) { auto modelJob = std::dynamic_pointer_cast(job); if (modelJob) { @@ -75,25 +84,86 @@ void PickingPass::Draw(RenderScene& scene) m_EntityColors[std::make_tuple(pickInfo.Entity, pickInfo.World, pickInfo.Camera)] = glm::ivec2(pickColor[0], pickColor[1]); if (m_ColorCounter[0] > 255) { m_ColorCounter[0] = 0; - m_ColorCounter[1] += 5; + m_ColorCounter[1] += 1; } else { - m_ColorCounter[0] += 50; + m_ColorCounter[0] += 1; } } m_PickingColorsToEntity[glm::ivec2(pickColor[0], pickColor[1])] = pickInfo; - glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "M"), 1, GL_FALSE, glm::value_ptr(modelJob->Matrix)); - glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "V"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ViewMatrix())); - glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "P"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ProjectionMatrix())); - glUniform2fv(glGetUniformLocation(shaderHandle, "PickingColor"), 1, glm::value_ptr(glm::vec2(pickColor[0], pickColor[1]))); + 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())); + glUniform2fv(glGetUniformLocation(shaderSkinnedHandle, "PickingColor"), 1, glm::value_ptr(glm::vec2(pickColor[0], pickColor[1]))); - if (modelJob->Model->m_RawModel->m_Skeleton != nullptr) { + if (modelJob->Model->m_RawModel->m_Skeleton != nullptr) { - if (modelJob->Animation != nullptr) { - std::vector frameBones = modelJob->Skeleton->GetFrameBones(*modelJob->Animation, modelJob->AnimationTime); - glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0])); - } + std::vector frameBones; + frameBones = modelJob->Skeleton->GetBones(); + 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())); + 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); + glDrawElements(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, (void*)(modelJob->StartIndex * sizeof(unsigned int))); + } + } + + for (auto &job : scene.Jobs.TransparentObjects) { + auto modelJob = std::dynamic_pointer_cast(job); + + int pickColor[2] = { m_ColorCounter[0], m_ColorCounter[1] }; + + PickingInfo pickInfo; + pickInfo.Entity = modelJob->Entity; + pickInfo.World = modelJob->World; + pickInfo.Camera = scene.Camera; + + auto color = m_EntityColors.find(std::make_tuple(pickInfo.Entity, pickInfo.World, pickInfo.Camera)); + if (color != m_EntityColors.end()) { + pickColor[0] = color->second[0]; + pickColor[1] = color->second[1]; + } else { + m_EntityColors[std::make_tuple(pickInfo.Entity, pickInfo.World, pickInfo.Camera)] = glm::ivec2(pickColor[0], pickColor[1]); + if (m_ColorCounter[0] > 255) { + m_ColorCounter[0] = 0; + m_ColorCounter[1] += 1; + } else { + m_ColorCounter[0] += 1; + } + } + + m_PickingColorsToEntity[glm::ivec2(pickColor[0], pickColor[1])] = pickInfo; + + if (modelJob) { + 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())); + glUniform2fv(glGetUniformLocation(shaderSkinnedHandle, "PickingColor"), 1, glm::value_ptr(glm::vec2(pickColor[0], pickColor[1]))); + + std::vector frameBones; + frameBones = modelJob->Skeleton->GetBones(); + 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())); + glUniform2fv(glGetUniformLocation(shaderHandle, "PickingColor"), 1, glm::value_ptr(glm::vec2(pickColor[0], pickColor[1]))); } glBindVertexArray(modelJob->Model->VAO); @@ -102,7 +172,7 @@ void PickingPass::Draw(RenderScene& scene) } } - for (auto &job : scene.TransparentObjects) { + for (auto &job : scene.Jobs.OpaqueShieldedObjects) { auto modelJob = std::dynamic_pointer_cast(job); if (modelJob) { @@ -121,27 +191,95 @@ void PickingPass::Draw(RenderScene& scene) m_EntityColors[std::make_tuple(pickInfo.Entity, pickInfo.World, pickInfo.Camera)] = glm::ivec2(pickColor[0], pickColor[1]); if (m_ColorCounter[0] > 255) { m_ColorCounter[0] = 0; - m_ColorCounter[1] += 5; + m_ColorCounter[1] += 1; } else { - m_ColorCounter[0] += 50; + m_ColorCounter[0] += 1; } } m_PickingColorsToEntity[glm::ivec2(pickColor[0], pickColor[1])] = pickInfo; - glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "M"), 1, GL_FALSE, glm::value_ptr(modelJob->Matrix)); - glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "V"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ViewMatrix())); - glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "P"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ProjectionMatrix())); - glUniform2fv(glGetUniformLocation(shaderHandle, "PickingColor"), 1, glm::value_ptr(glm::vec2(pickColor[0], pickColor[1]))); + 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())); + glUniform2fv(glGetUniformLocation(shaderSkinnedHandle, "PickingColor"), 1, glm::value_ptr(glm::vec2(pickColor[0], pickColor[1]))); - if (modelJob->Model->m_RawModel->m_Skeleton != nullptr) { + std::vector frameBones; + frameBones = modelJob->Skeleton->GetBones(); + glUniformMatrix4fv(glGetUniformLocation(shaderSkinnedHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0])); - if (modelJob->Animation != nullptr) { - std::vector frameBones = modelJob->Skeleton->GetFrameBones(*modelJob->Animation, modelJob->AnimationTime); - glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "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())); + 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); + glDrawElements(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, (void*)(modelJob->StartIndex * sizeof(unsigned int))); + } + } + + for (auto &job : scene.Jobs.TransparentShieldedObjects) { + auto modelJob = std::dynamic_pointer_cast(job); + + if (modelJob) { + + int pickColor[2] = { m_ColorCounter[0], m_ColorCounter[1] }; + + PickingInfo pickInfo; + pickInfo.Entity = modelJob->Entity; + pickInfo.World = modelJob->World; + pickInfo.Camera = scene.Camera; + + auto color = m_EntityColors.find(std::make_tuple(pickInfo.Entity, pickInfo.World, pickInfo.Camera)); + if (color != m_EntityColors.end()) { + pickColor[0] = color->second[0]; + pickColor[1] = color->second[1]; + } else { + m_EntityColors[std::make_tuple(pickInfo.Entity, pickInfo.World, pickInfo.Camera)] = glm::ivec2(pickColor[0], pickColor[1]); + if (m_ColorCounter[0] > 255) { + m_ColorCounter[0] = 0; + m_ColorCounter[1] += 1; + } else { + m_ColorCounter[0] += 1; } } + 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())); + glUniform2fv(glGetUniformLocation(shaderSkinnedHandle, "PickingColor"), 1, glm::value_ptr(glm::vec2(pickColor[0], pickColor[1]))); + + if (modelJob->Model->m_RawModel->m_Skeleton != nullptr) { + + std::vector frameBones; + frameBones = modelJob->Skeleton->GetBones(); + 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())); + 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); glDrawElements(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, (void*)(modelJob->StartIndex * sizeof(unsigned int))); @@ -160,8 +298,8 @@ void PickingPass::ClearPicking() { m_PickingColorsToEntity.clear(); m_EntityColors.clear(); - m_ColorCounter[0] = 1; - m_ColorCounter[1] = 0; + m_ColorCounter[0] = 0; + m_ColorCounter[1] = 1; m_PickingBuffer.Bind(); glClearColor(0.f, 0.f, 0.f, 0.f); diff --git a/src/Engine/Rendering/RawModelAssimp.cpp b/src/Engine/Rendering/RawModelAssimp.cpp index 7bf72a22..6b970f70 100644 --- a/src/Engine/Rendering/RawModelAssimp.cpp +++ b/src/Engine/Rendering/RawModelAssimp.cpp @@ -271,7 +271,7 @@ RawModelAssimp::RawModelAssimp(std::string fileName) skelAnim.Keyframes.push_back(animationFrame); } - m_Skeleton->Animations[animationName] = skelAnim; + m_Skeleton->Animations[animationName1] = skelAnim; } } diff --git a/src/Engine/Rendering/RawModelCustom.cpp b/src/Engine/Rendering/RawModelCustom.cpp index 59634625..4ebf80b6 100644 --- a/src/Engine/Rendering/RawModelCustom.cpp +++ b/src/Engine/Rendering/RawModelCustom.cpp @@ -34,13 +34,20 @@ void RawModelCustom::ReadMeshFile(std::string filePath) ReadMeshFileHeader(offset, fileData); ReadMesh(offset, fileData, fileByteSize); } - delete fileData; + delete[] fileData; } void RawModelCustom::ReadMeshFileHeader(std::size_t& offset, char* fileData) { #ifdef BOOST_LITTLE_ENDIAN - m_Vertices.resize(static_cast(*(unsigned int*)(fileData + offset))); + hasSkin = *(bool*)(fileData + offset); + offset += sizeof(bool); + if (hasSkin) { + m_SkinedVertices.resize(static_cast(*(unsigned int*)(fileData + offset))); + } + else { + m_Vertices.resize(static_cast(*(unsigned int*)(fileData + offset))); + } offset += sizeof(unsigned int); m_Indices.resize(static_cast(*(unsigned int*)(fileData + offset))); offset += sizeof(unsigned int); @@ -57,12 +64,19 @@ void RawModelCustom::ReadMesh(std::size_t& offset, char* fileData, const unsigne void RawModelCustom::ReadVertices(std::size_t& offset, char* fileData, const unsigned int& fileByteSize) { #ifdef BOOST_LITTLE_ENDIAN - if (offset + m_Vertices.size() * sizeof(Vertex) > fileByteSize) { - throw Resource::FailedLoadingException("Reading vertices failed"); - } - - memcpy(&m_Vertices[0], fileData + offset, m_Vertices.size() * sizeof(Vertex)); - offset += m_Vertices.size() * sizeof(Vertex); + if (hasSkin) { + if (offset + m_SkinedVertices.size() * sizeof(SkinedVertex) > fileByteSize) { + throw Resource::FailedLoadingException("Reading skined vertices failed"); + } + memcpy(&m_SkinedVertices[0], fileData + offset, m_SkinedVertices.size() * sizeof(SkinedVertex)); + offset += m_SkinedVertices.size() * sizeof(SkinedVertex); + } else { + if (offset + m_Vertices.size() * sizeof(Vertex) > fileByteSize) { + throw Resource::FailedLoadingException("Reading vertices failed"); + } + memcpy(&m_Vertices[0], fileData + offset, m_Vertices.size() * sizeof(Vertex)); + offset += m_Vertices.size() * sizeof(Vertex); + } #else #endif } @@ -102,14 +116,14 @@ void RawModelCustom::ReadMaterialFile(std::string filePath) if (fileByteSize > 0) { ReadMaterials(offset, fileData, fileByteSize); } - delete fileData; + delete[] fileData; } void RawModelCustom::ReadMaterials(std::size_t& offset, char* fileData, const unsigned int& fileByteSize) { #ifdef BOOST_LITTLE_ENDIAN unsigned int* numMaterials = (unsigned int*)(fileData); - MaterialGroups.reserve(*numMaterials); + m_Materials.reserve(*numMaterials); offset += sizeof(unsigned int); for (unsigned int i = 0; i < *numMaterials; i++) { @@ -121,83 +135,150 @@ void RawModelCustom::ReadMaterials(std::size_t& offset, char* fileData, const un void RawModelCustom::ReadMaterialSingle(std::size_t& offset, char* fileData, const unsigned int& fileByteSize) { - MaterialGroup newMaterial; - + MaterialProperties newMaterialProperty; #ifdef BOOST_LITTLE_ENDIAN - if (offset + sizeof(unsigned int) * 4 > fileByteSize) { - throw Resource::FailedLoadingException("Reading Material texture names length failed"); - } + if (offset + sizeof(MaterialType) > fileByteSize) { + throw Resource::FailedLoadingException("Reading Material Type failed"); + } + MaterialType type = *(MaterialType*)(fileData + offset); + offset += sizeof(MaterialType); - unsigned int* nameLengths = (unsigned int*)(fileData + offset); - offset += sizeof(unsigned int) * 4; + switch (type) { + case MaterialType::Basic: + newMaterialProperty.material = new MaterialBasic(); + ReadMaterialBasic(newMaterialProperty.material, offset, fileData, fileByteSize); + break; + case MaterialType::SplatMapping: + newMaterialProperty.material = new MaterialSplatMapping(); + ReadMaterialSplatMapping(static_cast(newMaterialProperty.material), offset, fileData, fileByteSize); + break; + case MaterialType::SingleTextures: + newMaterialProperty.material = new MaterialSingleTextures(); + ReadMaterialSingleTexture(static_cast(newMaterialProperty.material), offset, fileData, fileByteSize); + break; + default: + throw Resource::FailedLoadingException("Material contains an unknown MaterialType"); + }; - if (offset + sizeof(float) * 11 + sizeof(unsigned int) * 2 > fileByteSize) { - throw Resource::FailedLoadingException("Reading Material specular, reflection, color and start and end index values failed"); - } - - newMaterial.SpecularExponent = *(float*)(fileData + offset); - offset += sizeof(float); - newMaterial.ReflectionFactor = *(float*)(fileData + offset); - offset += sizeof(float); - - memcpy(&newMaterial.DiffuseColor[0], fileData + offset, sizeof(float) * 3); - offset += sizeof(float) * 3; - memcpy(&newMaterial.SpecularColor[0], fileData + offset, sizeof(float) * 3); - offset += sizeof(float) * 3; - memcpy(&newMaterial.IncandescenceColor[0], fileData + offset, sizeof(float) * 3); - offset += sizeof(float) * 3; - - newMaterial.StartIndex = *(unsigned int*)(fileData + offset); - offset += sizeof(unsigned int); - newMaterial.EndIndex = *(unsigned int*)(fileData + offset); - offset += sizeof(unsigned int); - - if (nameLengths[0] > 0) { - if (offset + nameLengths[0] > fileByteSize) { - throw Resource::FailedLoadingException("Reading Material texture path failed"); - } - - newMaterial.TexturePath = "Textures/"; - newMaterial.TexturePath += (fileData + offset); - newMaterial.TexturePath += ".png"; - offset += nameLengths[0]; - } - - if (nameLengths[1] > 0) { - if (offset + nameLengths[1] > fileByteSize) { - throw Resource::FailedLoadingException("Reading Material NormalMap path failed"); - } - newMaterial.NormalMapPath = "Textures/"; - newMaterial.NormalMapPath += (fileData + offset); - newMaterial.NormalMapPath += ".png"; - offset += nameLengths[1]; - } - - if (nameLengths[2] > 0) { - if (offset + nameLengths[2] > fileByteSize) { - throw Resource::FailedLoadingException("Reading Material SpecularMap path failed"); - } - newMaterial.SpecularMapPath = "Textures/"; - newMaterial.SpecularMapPath += (fileData + offset); - newMaterial.SpecularMapPath += ".png"; - offset += nameLengths[2]; - } - - if (nameLengths[3] > 0) { - if (offset + nameLengths[3] > fileByteSize) { - throw Resource::FailedLoadingException("Reading Material IncandescenceMap path failed"); - } - newMaterial.IncandescenceMapPath = "Textures/"; - newMaterial.IncandescenceMapPath += (fileData + offset); - newMaterial.IncandescenceMapPath += ".png"; - offset += nameLengths[3]; - } + newMaterialProperty.type = type; #else #endif - MaterialGroups.push_back(newMaterial); + m_Materials.push_back(newMaterialProperty); +} + +void RawModelCustom::ReadMaterialBasic(RawModelCustom::MaterialBasic* newMaterial, std::size_t& offset, char* fileData, const unsigned int& fileByteSize) +{ + if (offset + sizeof(float) * 11 + sizeof(unsigned int) * 2 > fileByteSize) { + throw Resource::FailedLoadingException("Reading Material specular, reflection, color and start and end index values failed"); + } + + newMaterial->SpecularExponent = *(float*)(fileData + offset); + offset += sizeof(float); + newMaterial->ReflectionFactor = *(float*)(fileData + offset); + offset += sizeof(float); + + memcpy(&newMaterial->DiffuseColor[0], fileData + offset, sizeof(float) * 3); + offset += sizeof(float) * 3; + memcpy(&newMaterial->SpecularColor[0], fileData + offset, sizeof(float) * 3); + offset += sizeof(float) * 3; + memcpy(&newMaterial->IncandescenceColor[0], fileData + offset, sizeof(float) * 3); + offset += sizeof(float) * 3; + + newMaterial->StartIndex = *(unsigned int*)(fileData + offset); + offset += sizeof(unsigned int); + newMaterial->EndIndex = *(unsigned int*)(fileData + offset); + offset += sizeof(unsigned int); +} + +void RawModelCustom::ReadMaterialSingleTexture(RawModelCustom::MaterialSingleTextures* newMaterial, std::size_t& offset, char* fileData, const unsigned int& fileByteSize) +{ + ReadMaterialBasic(newMaterial, offset, fileData, fileByteSize); + if (offset + sizeof(unsigned char) * 4 > fileByteSize) { + throw Resource::FailedLoadingException("Reading Material NumOfMaps failed"); + } + unsigned char numberOfMaps[4]; + memcpy(numberOfMaps, fileData + offset, sizeof(unsigned char) * 4); + offset += sizeof(unsigned char) * 4; + + if (numberOfMaps[0] > 0) + { + ReadMaterialTextureProperties(newMaterial->ColorMap, offset, fileData, fileByteSize); + } + + if (numberOfMaps[1] > 0) + { + ReadMaterialTextureProperties(newMaterial->SpecularMap, offset, fileData, fileByteSize); + } + + if (numberOfMaps[2] > 0) + { + ReadMaterialTextureProperties(newMaterial->NormalMap, offset, fileData, fileByteSize); + } + + if (numberOfMaps[3] > 0) + { + ReadMaterialTextureProperties(newMaterial->IncandescenceMap, offset, fileData, fileByteSize); + } +} + +void RawModelCustom::ReadMaterialSplatMapping(RawModelCustom::MaterialSplatMapping* newMaterial, std::size_t& offset, char* fileData, const unsigned int& fileByteSize) +{ + ReadMaterialBasic(newMaterial, offset, fileData, fileByteSize); + ReadMaterialTextureProperties(newMaterial->SplatMap, offset, fileData, fileByteSize); + if (offset + sizeof(unsigned char) * 4 > fileByteSize) { + throw Resource::FailedLoadingException("Reading Material NumOfMaps failed"); + } + + unsigned char numberOfMaps[4]; + memcpy(numberOfMaps, fileData + offset, sizeof(unsigned char) * 4); + offset += sizeof(unsigned char) * 4; + + newMaterial->ColorMaps.resize(numberOfMaps[0]); + for (unsigned char i = 0; i < numberOfMaps[0]; i++) + { + ReadMaterialTextureProperties(newMaterial->ColorMaps[i], offset, fileData, fileByteSize); + } + + newMaterial->SpecularMaps.resize(numberOfMaps[1]); + for (unsigned char i = 0; i < numberOfMaps[1]; i++) + { + ReadMaterialTextureProperties(newMaterial->SpecularMaps[i], offset, fileData, fileByteSize); + } + + newMaterial->NormalMaps.resize(numberOfMaps[2]); + for (unsigned char i = 0; i < numberOfMaps[2]; i++) + { + ReadMaterialTextureProperties(newMaterial->NormalMaps[i], offset, fileData, fileByteSize); + } + + newMaterial->IncandescenceMaps.resize(numberOfMaps[3]); + for (unsigned char i = 0; i < numberOfMaps[3]; i++) + { + ReadMaterialTextureProperties(newMaterial->IncandescenceMaps[i], offset, fileData, fileByteSize); + } +} + +void RawModelCustom::ReadMaterialTextureProperties(RawModelCustom::TextureProperties& texture, std::size_t& offset, char* fileData, const unsigned int& fileByteSize) { + unsigned int nameLength = *(unsigned int*)(fileData + offset); + offset += sizeof(unsigned int); + + if (nameLength > 0) { + if (offset + nameLength > fileByteSize) { + throw Resource::FailedLoadingException("Reading Material texture path failed"); + } + texture.TexturePath = "Textures/"; + texture.TexturePath += (fileData + offset); + texture.TexturePath += ".png"; + offset += nameLength; + if (offset + sizeof(glm::vec2) > fileByteSize) { + throw Resource::FailedLoadingException("Reading Material texture UVTiling failed"); + } + memcpy(&texture.UVRepeat[0], fileData + offset, sizeof(glm::vec2)); + offset += sizeof(glm::vec2); + } } void RawModelCustom::ReadAnimationFile(std::string filePath) @@ -207,7 +288,9 @@ void RawModelCustom::ReadAnimationFile(std::string filePath) std::ifstream in(filePath.c_str(), std::ios_base::binary | std::ios_base::ate); if (!in.is_open()) { - //throw Resource::FailedLoadingException("Open animation file failed"); + if (hasSkin) { + throw Resource::FailedLoadingException("Open animation file for a skinned mesh failed, unknown stuff will happen"); + } return; } @@ -233,7 +316,7 @@ void RawModelCustom::ReadAnimationFile(std::string filePath) ReadAnimationBindPoses(offset, fileData, fileByteSize); ReadAnimationClips(offset, fileData, fileByteSize, numAnimations); } - delete fileData; + delete[] fileData; } void RawModelCustom::ReadAnimationBindPoses(std::size_t& offset, char* fileData, const unsigned int& fileByteSize) @@ -318,32 +401,43 @@ void RawModelCustom::ReadAnimationClipSingle(std::size_t& offset, char* fileData if (offset + sizeof(float) > fileByteSize) { throw Resource::FailedLoadingException("Reading AnimationClip duration failed"); } - newAnimation.Duration = *(float*)(fileData + offset); offset += sizeof(float); if (offset + sizeof(unsigned int) > fileByteSize) { - throw Resource::FailedLoadingException("Reading AnimationClip NrOfKeyframes failed"); + throw Resource::FailedLoadingException("Reading AnimationClip numberOfJointFrames failed"); } - unsigned int nrOfKeyframes = *(unsigned int*)(fileData + offset); + unsigned int numberOfJointFrames = *(unsigned int*)(fileData + offset); offset += sizeof(unsigned int); - if (offset + sizeof(unsigned int) > fileByteSize) { - throw Resource::FailedLoadingException("Reading AnimationClip NrOfJoints failed"); - } - unsigned int nrOfJoints = *(unsigned int*)(fileData + offset); - offset += sizeof(unsigned int); + for (unsigned int i = 0; i < numberOfJointFrames; i++) { + if (offset + sizeof(unsigned int) > fileByteSize) { + throw Resource::FailedLoadingException("Reading AnimationClip JointID failed"); + } + int jointID = *(unsigned int*)(fileData + offset); + offset += sizeof(unsigned int); - newAnimation.Keyframes.reserve(nrOfKeyframes); - for (unsigned int i = 0; i < nrOfKeyframes; i++) { - ReadAnimationKeyFrame(offset, fileData, fileByteSize, nrOfJoints, newAnimation); + if (offset + sizeof(unsigned int) > fileByteSize) { + throw Resource::FailedLoadingException("Reading AnimationClip numberOFKeyFrames failed"); + } + unsigned int numberOFKeyFrames = *(unsigned int*)(fileData + offset); + offset += sizeof(unsigned int); + + if (numberOFKeyFrames > 0) { + newAnimation.JointAnimations[jointID].reserve(numberOFKeyFrames); + + for (unsigned int j = 0; j < numberOFKeyFrames; j++) { + ReadAnimationKeyFrame(offset, fileData, fileByteSize, newAnimation.JointAnimations[jointID]); + } + } } m_Skeleton->Animations[newAnimation.Name] = newAnimation; + //m_Skeleton->Animations[newAnimation.Name].KeyFrameAmount = nrOfKeyframes; #else #endif } -void RawModelCustom::ReadAnimationKeyFrame(std::size_t& offset, char* fileData, const unsigned int& fileByteSize, unsigned int numberOfJoints, Skeleton::Animation& animation) +void RawModelCustom::ReadAnimationKeyFrame(std::size_t& offset, char* fileData, const unsigned int& fileByteSize, std::vector& animation) { Skeleton::Animation::Keyframe newKeyFrame; @@ -359,17 +453,27 @@ void RawModelCustom::ReadAnimationKeyFrame(std::size_t& offset, char* fileData, newKeyFrame.Time = *(float*)(fileData + offset); offset += sizeof(float); - if (offset + sizeof(Skeleton::Animation::Keyframe::BoneProperty) * numberOfJoints> fileByteSize) { - throw Resource::FailedLoadingException("Reading AnimationKeyFrame joints failed"); + if (offset + sizeof(float) * 3 > fileByteSize) { + throw Resource::FailedLoadingException("Reading AnimationKeyFrame Position failed"); } + memcpy(&newKeyFrame.BoneProperties.Position[0], fileData + offset, sizeof(float) * 3); + offset += sizeof(float) * 3; - Skeleton::Animation::Keyframe::BoneProperty newBone; - for (unsigned int i = 0; i < numberOfJoints; i++) { - memcpy(&newBone, (fileData + offset), sizeof(Skeleton::Animation::Keyframe::BoneProperty)); - offset += sizeof(Skeleton::Animation::Keyframe::BoneProperty); - newKeyFrame.BoneProperties[newBone.ID] = newBone; + if (offset + sizeof(float) * 4 > fileByteSize) { + throw Resource::FailedLoadingException("Reading AnimationKeyFrame Rotation failed"); } - animation.Keyframes.push_back(newKeyFrame); + memcpy(&newKeyFrame.BoneProperties.Rotation[0], fileData + offset, sizeof(float) * 4); + offset += sizeof(float) * 4; + + if (offset + sizeof(float) * 3 > fileByteSize) { + throw Resource::FailedLoadingException("Reading AnimationKeyFrame Scale failed"); + } + memcpy(&newKeyFrame.BoneProperties.Scale[0], fileData + offset, sizeof(float) * 3); + offset += sizeof(float) * 3; + + + animation.push_back(newKeyFrame); + } RawModelCustom::~RawModelCustom() @@ -377,6 +481,9 @@ RawModelCustom::~RawModelCustom() if (m_Skeleton != nullptr) { delete m_Skeleton; } + for (auto material : m_Materials) { + delete material.material; + } } #endif \ No newline at end of file diff --git a/src/Engine/Rendering/RenderState.cpp b/src/Engine/Rendering/RenderState.cpp index 1da2f0b1..26ba18a1 100644 --- a/src/Engine/Rendering/RenderState.cpp +++ b/src/Engine/Rendering/RenderState.cpp @@ -6,9 +6,10 @@ bool RenderState::Enable(GLenum cap) //LOG_WARNING("Trying to enable somthing that is already enabled."); return false; } + m_ResetFunctions.push_back(std::bind(glDisable, cap)); glEnable(cap); - return !GLERROR("RenderState::Enable"); + return !GLERROR("Enable"); } bool RenderState::Disable(GLenum cap) @@ -16,9 +17,10 @@ bool RenderState::Disable(GLenum cap) if (!glIsEnabled(cap)) { return false; } + m_ResetFunctions.push_back(std::bind(glEnable, cap)); glDisable(cap); - return !GLERROR("RenderState::Disable"); + return !GLERROR("Disable"); } bool RenderState::CullFace(GLenum mode) @@ -32,7 +34,7 @@ bool RenderState::CullFace(GLenum mode) glGetIntegerv(GL_CULL_FACE_MODE, &original); m_ResetFunctions.push_back(std::bind(glCullFace, original)); glCullFace(mode); - return !GLERROR("RenderState::CullFace"); + return !GLERROR("CullFace"); } bool RenderState::ClearColor(glm::vec4 color) @@ -41,7 +43,7 @@ bool RenderState::ClearColor(glm::vec4 color) glGetFloatv(GL_COLOR_CLEAR_VALUE, &original[0]); m_ResetFunctions.push_back(std::bind(glClearColor, original[0], original[1], original[2], original[3])); glClearColor(color.r, color.g, color.b, color.a); - return !GLERROR("RenderState::ClearColor"); + return !GLERROR("ClearColor"); } bool RenderState::BindFramebuffer(GLint framebuffer) @@ -55,7 +57,7 @@ bool RenderState::BindFramebuffer(GLint framebuffer) glBindFramebuffer(GL_DRAW_FRAMEBUFFER, originalDraw); }); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); - return !GLERROR("RenderState::BindBuffer"); + return !GLERROR("BindBuffer"); } @@ -67,7 +69,7 @@ bool RenderState::BlendEquation(GLenum mode) glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &originalAlpha); m_ResetFunctions.push_back(std::bind(glBlendEquationSeparate, originalRGB, originalAlpha)); glBlendEquation(mode); - return !GLERROR("RenderState::BlendEquation"); + return !GLERROR("BlendEquation"); } bool RenderState::BlendFunc(GLenum sfactor, GLenum dfactor) @@ -82,7 +84,46 @@ bool RenderState::BlendFunc(GLenum sfactor, GLenum dfactor) glGetIntegerv(GL_BLEND_DST_ALPHA, &originalDestAlpha); m_ResetFunctions.push_back(std::bind(glBlendFuncSeparate, originalSrcRGB, originalSrcAlpha, originalDestRGB, originalDestAlpha)); glBlendFunc(sfactor, dfactor); - return !GLERROR("RenderState::BlendFunc"); + return !GLERROR("BlendFunc"); +} + + +bool RenderState::StencilOp(GLenum sfail, GLenum dpfail, GLenum dppass) +{ + GLint originalSFail; + glGetIntegerv(GL_STENCIL_FAIL, &originalSFail); + GLint originalDPFail; + glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &originalDPFail); + GLint originalDPPass; + glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &originalDPPass); + m_ResetFunctions.push_back(std::bind(glStencilOp, originalSFail, originalDPFail, originalDPPass)); + glStencilOp(sfail, dpfail, dppass); + return !GLERROR("StencilOp"); +} + + +bool RenderState::StencilFunc(GLenum func, GLint ref, GLuint mask) +{ + GLint originalFunc; + glGetIntegerv(GL_STENCIL_FUNC, &originalFunc); + GLint originalRef; + glGetIntegerv(GL_STENCIL_REF, &originalRef); + GLint originalMask; + glGetIntegerv(GL_STENCIL_VALUE_MASK, &originalMask); + m_ResetFunctions.push_back(std::bind(glStencilFunc, originalFunc, originalRef, originalMask)); + glStencilFunc(func, ref, mask); + return !GLERROR("StencilFunc"); +} + + + +bool RenderState::StencilMask(GLuint mask) +{ + GLint originalMask; + glGetIntegerv(GL_STENCIL_WRITEMASK, &originalMask); + m_ResetFunctions.push_back(std::bind(glStencilMask, mask)); + glStencilMask(mask); + return !GLERROR("StencilMask"); } bool RenderState::DepthMask(GLboolean flag) @@ -91,12 +132,12 @@ bool RenderState::DepthMask(GLboolean flag) glGetBooleanv(GL_DEPTH_WRITEMASK, &original); m_ResetFunctions.push_back(std::bind(glDepthMask, original)); glDepthMask(flag); - return !GLERROR("RenderState::DepthMask"); + return !GLERROR("DepthMask"); } RenderState::~RenderState() { - for (auto& f : m_ResetFunctions) { + for (auto& f : boost::adaptors::reverse(m_ResetFunctions)) { f(); } } diff --git a/src/Engine/Rendering/RenderSystem.cpp b/src/Engine/Rendering/RenderSystem.cpp index a0912a45..6600bc4f 100644 --- a/src/Engine/Rendering/RenderSystem.cpp +++ b/src/Engine/Rendering/RenderSystem.cpp @@ -1,10 +1,12 @@ #include "Rendering/RenderSystem.h" +#include "Collision/Collision.h" +#include "Core/Frustum.h" -RenderSystem::RenderSystem(World* world, EventBroker* eventBroker, const IRenderer* renderer, RenderFrame* renderFrame) - : System(world, eventBroker) +RenderSystem::RenderSystem(SystemParams params, const IRenderer* renderer, RenderFrame* renderFrame, Octree* frustumCullOctree) + : System(params) , m_Renderer(renderer) , m_RenderFrame(renderFrame) - , m_World(world) + , m_Octree(frustumCullOctree) { EVENT_SUBSCRIBE_MEMBER(m_ESetCamera, &RenderSystem::OnSetCamera); EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &RenderSystem::OnInputCommand); @@ -31,6 +33,58 @@ bool RenderSystem::OnSetCamera(Events::SetCamera& e) return true; } + +void RenderSystem::fillSprites(std::list>& jobs, World* world) +{ + auto sprites = world->GetComponents("Sprite"); + if (sprites == nullptr) { + return; + } + + for (auto& cSprite : *sprites) { + bool visible = cSprite["Visible"]; + if (!visible) { + continue; + } + + + EntityWrapper entity(world, cSprite.EntityID); + + // Only render children of a camera if that camera is currently active + if (isChildOfACamera(entity) && !isChildOfCurrentCamera(entity)) { + continue; + } + + // Hide things parented to local player if they have the HiddenFromLocalPlayer component + if (entity.HasComponent("HiddenForLocalPlayer") && (entity == m_LocalPlayer || entity.IsChildOf(m_LocalPlayer))) { + continue; + } + + std::string diffuseResource = cSprite["DiffuseTexture"]; + std::string glowResource = cSprite["GlowMap"]; + bool depthSorted = cSprite["DepthSort"]; + if (diffuseResource.empty() && glowResource.empty()) { + continue; + } + + float fillPercentage = 0.f; + glm::vec4 fillColor = glm::vec4(0); + if (world->HasComponent(entity.ID, "Fill")) { + auto fillComponent = world->GetComponent(entity.ID, "Fill"); + fillPercentage = (float)(double)fillComponent["Percentage"]; + fillColor = (glm::vec4)fillComponent["Color"]; + } + + glm::mat4 modelMatrix = Transform::ModelMatrix(entity.ID, world); + //modelMatrix *= m_Camera->BillboardMatrix(); + + + std::shared_ptr spriteJob = std::shared_ptr(new SpriteJob(cSprite, m_Camera, modelMatrix, world, fillColor, fillPercentage, depthSorted)); + + jobs.push_back(spriteJob); + } +} + bool RenderSystem::isChildOfACamera(EntityWrapper entity) { return entity.FirstParentWithComponent("Camera").Valid(); @@ -40,14 +94,15 @@ bool RenderSystem::isChildOfCurrentCamera(EntityWrapper entity) return entity == m_CurrentCamera || entity.IsChildOf(m_CurrentCamera); } -void RenderSystem::fillModels(std::list>& opaqueJobs, std::list>& transparentJobs) +void RenderSystem::fillModels(RenderScene::Queues &Jobs) { - auto models = m_World->GetComponents("Model"); - if (models == nullptr) { - return; - } + Frustum frustum(m_Camera->ProjectionMatrix() * m_Camera->ViewMatrix()); + std::vector seenEntities; + m_Octree->ObjectsInFrustum(frustum, seenEntities); - for (auto& cModel : *models) { + for (auto& seenEntity : seenEntities) { + EntityWrapper entity = seenEntity.Entity; + ComponentWrapper cModel = entity["Model"]; bool visible = cModel["Visible"]; if (!visible) { continue; @@ -57,15 +112,13 @@ void RenderSystem::fillModels(std::list>& opaqueJobs, continue; } - EntityWrapper entity(m_World, cModel.EntityID); - // Only render children of a camera if that camera is currently active if (isChildOfACamera(entity) && !isChildOfCurrentCamera(entity)) { continue; } // Hide things parented to local player if they have the HiddenFromLocalPlayer component - if (entity.HasComponent("HiddenForLocalPlayer") && (entity == m_LocalPlayer || entity.IsChildOf(m_LocalPlayer))) { + if ((entity.HasComponent("HiddenForLocalPlayer") || entity.FirstParentWithComponent("HiddenForLocalPlayer").Valid()) && (entity == m_LocalPlayer || entity.IsChildOf(m_LocalPlayer))) { continue; } @@ -92,7 +145,9 @@ void RenderSystem::fillModels(std::list>& opaqueJobs, } glm::mat4 modelMatrix = Transform::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 if (m_World->HasComponent(cModel.EntityID, "ExplosionEffect")) { auto explosionEffectComponent = m_World->GetComponent(cModel.EntityID, "ExplosionEffect"); std::shared_ptr explosionEffectJob = std::shared_ptr(new ExplosionEffectJob( @@ -106,14 +161,33 @@ void RenderSystem::fillModels(std::list>& opaqueJobs, fillColor, fillPercentage )); - if(explosionEffectJob->Color.a != 1.f || explosionEffectJob->EndColor.a != 1.f || explosionEffectJob->DiffuseColor.a != 1.f) { - cModel["Transparent"] = true; - } + if (m_World->HasComponent(cModel.EntityID, "Shield")){ + explosionEffectJob->CalculateHash(); + Jobs.ShieldObjects.push_back(explosionEffectJob); + } else if (m_World->HasComponent(cModel.EntityID, "Shielded") + || m_World->HasComponent(cModel.EntityID, "Player")) { - if (cModel["Transparent"]) { - transparentJobs.push_back(explosionEffectJob); + if (explosionEffectJob->Color.a != 1.f || explosionEffectJob->EndColor.a != 1.f || explosionEffectJob->DiffuseColor.a != 1.f) { + cModel["Transparent"] = true; + } + + if (cModel["Transparent"]) { + Jobs.TransparentShieldedObjects.push_back(explosionEffectJob); + } else { + explosionEffectJob->CalculateHash(); + Jobs.OpaqueShieldedObjects.push_back(explosionEffectJob); + } } else { - opaqueJobs.push_back(explosionEffectJob); + if (explosionEffectJob->Color.a != 1.f || explosionEffectJob->EndColor.a != 1.f || explosionEffectJob->DiffuseColor.a != 1.f) { + cModel["Transparent"] = true; + } + + if (cModel["Transparent"]) { + Jobs.TransparentObjects.push_back(explosionEffectJob); + } else { + explosionEffectJob->CalculateHash(); + Jobs.OpaqueObjects.push_back(explosionEffectJob); + } } } else { std::shared_ptr modelJob = std::shared_ptr(new ModelJob( @@ -126,13 +200,33 @@ void RenderSystem::fillModels(std::list>& opaqueJobs, fillColor, fillPercentage )); - if (modelJob->Color.a != 1.f || modelJob->DiffuseColor.a != 1.f) { - cModel["Transparent"] = true; - } - if (cModel["Transparent"]) { - transparentJobs.push_back(modelJob); + if (m_World->HasComponent(cModel.EntityID, "Shield")) { + modelJob->CalculateHash(); + Jobs.ShieldObjects.push_back(modelJob); + } else if (m_World->HasComponent(cModel.EntityID, "Shielded") + || m_World->HasComponent(cModel.EntityID, "Player")) { + + if (modelJob->Color.a != 1.f || modelJob->DiffuseColor.a != 1.f) { + cModel["Transparent"] = true; + } + + if (cModel["Transparent"]) { + Jobs.TransparentShieldedObjects.push_back(modelJob); + } else { + modelJob->CalculateHash(); + Jobs.OpaqueShieldedObjects.push_back(modelJob); + } } else { - opaqueJobs.push_back(modelJob); + if (modelJob->Color.a != 1.f || modelJob->DiffuseColor.a != 1.f) { + cModel["Transparent"] = true; + } + + if (cModel["Transparent"]) { + Jobs.TransparentObjects.push_back(modelJob); + } else { + modelJob->CalculateHash(); + Jobs.OpaqueObjects.push_back(modelJob); + } } } } @@ -167,7 +261,6 @@ void RenderSystem::fillPointLights(std::list>& jobs, } } - void RenderSystem::fillDirectionalLights(std::list>& jobs, World* world) { auto directionalLights = world->GetComponents("DirectionalLight"); @@ -189,14 +282,13 @@ void RenderSystem::fillDirectionalLights(std::list>& } } - void RenderSystem::fillText(std::list>& jobs, World* world) { auto texts = world->GetComponents("Text"); if (texts == nullptr) { return; } - + for (auto& textComponent : *texts) { bool visible = textComponent["Visible"]; if (!visible) { @@ -240,14 +332,24 @@ void RenderSystem::Update(double dt) m_Camera->SetOrientation(Transform::AbsoluteOrientation(m_CurrentCamera)); } - RenderScene scene; scene.Camera = m_Camera; scene.Viewport = Rectangle(1280, 720); - fillModels(scene.OpaqueObjects, scene.TransparentObjects); - fillPointLights(scene.PointLightJobs, m_World); - fillDirectionalLights(scene.DirectionalLightJobs, m_World); - fillText(scene.TextJobs, m_World); + + auto cSceneLight = m_World->GetComponents("SceneLight"); + if (cSceneLight != nullptr && cSceneLight->begin() != cSceneLight->end()) { + m_RenderFrame->Gamma = (double)(*cSceneLight->begin())["Gamma"]; + m_RenderFrame->Exposure = (double)(*cSceneLight->begin())["Exposure"]; + scene.AmbientColor = (glm::vec4)(*cSceneLight->begin())["AmbientColor"]; + } + + fillModels(scene.Jobs); + fillPointLights(scene.Jobs.PointLight, m_World); + //TODO: Make sure all objects needed are also sorted. + scene.Jobs.OpaqueObjects.sort(); + fillSprites(scene.Jobs.SpriteJob, m_World); + fillDirectionalLights(scene.Jobs.DirectionalLight, m_World); + fillText(scene.Jobs.Text, m_World); m_RenderFrame->Add(scene); } \ No newline at end of file diff --git a/src/Engine/Rendering/Renderer.cpp b/src/Engine/Rendering/Renderer.cpp index bec86b4a..173ddb2b 100644 --- a/src/Engine/Rendering/Renderer.cpp +++ b/src/Engine/Rendering/Renderer.cpp @@ -51,7 +51,7 @@ void Renderer::InitializeWindow() ss << " DEBUG"; #endif LOG_INFO(ss.str().c_str()); - glfwSetWindowTitle(m_Window, ss.str().c_str()); + SetWindowTitle(ss.str()); // Initialize GLEW if (glewInit() != GLEW_OK) { @@ -93,7 +93,7 @@ void Renderer::Update(double dt) void Renderer::Draw(RenderFrame& frame) { - ImGui::Combo("Draw textures", &m_DebugTextureToDraw, "Final\0Scene\0Bloom\0Gaussian\0Picking"); + ImGui::Combo("Draw textures", &m_DebugTextureToDraw, "Final\0Scene\0Bloom\0SceneLowRes\0BloomLowRes\0Gaussian\0Picking"); //clear buffer 0 glClearColor(0.f, 0.f, 0.f, 0.f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -106,21 +106,26 @@ void Renderer::Draw(RenderFrame& frame) for (auto scene : frame.RenderScenes){ SortRenderJobsByDepth(*scene); + GLERROR("SortByDepth"); m_PickingPass->Draw(*scene); + GLERROR("Drawing pickingpass"); m_LightCullingPass->GenerateNewFrustum(*scene); + GLERROR("Generate frustums"); m_LightCullingPass->FillLightList(*scene); + GLERROR("Filling light list"); m_LightCullingPass->CullLights(*scene); + GLERROR("LightCulling"); m_DrawFinalPass->Draw(*scene); + GLERROR("Draw Geometry+Light"); //m_DrawScenePass->Draw(*scene); - GLERROR("Renderer::Draw m_DrawScenePass->Draw"); - m_TextPass->Draw(*scene, *m_DrawFinalPass->FinalPassFrameBuffer()); + GLERROR("Draw Text"); } m_DrawBloomPass->Draw(m_DrawFinalPass->BloomTexture()); - if(m_DebugTextureToDraw == 0) { - m_DrawColorCorrectionPass->Draw(m_DrawFinalPass->SceneTexture(), m_DrawBloomPass->GaussianTexture()); + if (m_DebugTextureToDraw == 0) { + m_DrawColorCorrectionPass->Draw(m_DrawFinalPass->SceneTexture(), m_DrawBloomPass->GaussianTexture(), m_DrawFinalPass->SceneTextureLowRes(), m_DrawFinalPass->BloomTextureLowRes(), frame.Gamma, frame.Exposure); } if (m_DebugTextureToDraw == 1) { m_DrawScreenQuadPass->Draw(m_DrawFinalPass->SceneTexture()); @@ -129,14 +134,21 @@ void Renderer::Draw(RenderFrame& frame) m_DrawScreenQuadPass->Draw(m_DrawFinalPass->BloomTexture()); } if (m_DebugTextureToDraw == 3) { - m_DrawScreenQuadPass->Draw(m_DrawBloomPass->GaussianTexture()); + m_DrawScreenQuadPass->Draw(m_DrawFinalPass->SceneTextureLowRes()); } if (m_DebugTextureToDraw == 4) { + m_DrawScreenQuadPass->Draw(m_DrawFinalPass->BloomTextureLowRes()); + } + if (m_DebugTextureToDraw == 5) { + m_DrawScreenQuadPass->Draw(m_DrawBloomPass->GaussianTexture()); + } + if (m_DebugTextureToDraw == 6) { m_DrawScreenQuadPass->Draw(m_PickingPass->PickingTexture()); } m_ImGuiRenderPass->Draw(); - glfwSwapBuffers(m_Window); + GLERROR("Imgui draw"); + glfwSwapBuffers(m_Window); } PickData Renderer::Pick(glm::vec2 screenCoord) @@ -146,15 +158,16 @@ PickData Renderer::Pick(glm::vec2 screenCoord) void Renderer::InitializeTextures() { - m_ErrorTexture = ResourceManager::Load("Textures/Core/ErrorTexture.png"); - m_WhiteTexture = ResourceManager::Load("Textures/Core/White.png"); + m_ErrorTexture = CommonFunctions::LoadTexture("Textures/Core/ErrorTexture.png", false); + m_WhiteTexture = CommonFunctions::LoadTexture("Textures/Core/White.png", false); } void Renderer::SortRenderJobsByDepth(RenderScene &scene) { //Sort all forward jobs so transparency is good. - scene.TransparentObjects.sort(Renderer::DepthSort); + scene.Jobs.TransparentObjects.sort(Renderer::DepthSort); + scene.Jobs.SpriteJob.sort(Renderer::DepthSort); } void Renderer::GenerateTexture(GLuint* texture, GLenum wrapping, GLenum filtering, glm::vec2 dimensions, GLint internalFormat, GLint format, GLenum type) diff --git a/src/Engine/Rendering/Skeleton.cpp b/src/Engine/Rendering/Skeleton.cpp index 851408a4..82d50522 100644 --- a/src/Engine/Rendering/Skeleton.cpp +++ b/src/Engine/Rendering/Skeleton.cpp @@ -29,6 +29,32 @@ Skeleton::~Skeleton() } } + +void Skeleton::CalculateFrameBones(std::vector animations, AnimationOffset animationOffset, bool noRootMotion /*= false*/) +{ + if (animations.size() <= 0 || animationOffset.animation == nullptr) { + for (auto& b : Bones) { + m_BoneLocalTransforms[b.first] = glm::mat4(1); + m_BoneTransforms[b.first] = glm::mat4(1); + } + } else { + AccumulateBoneTransforms(noRootMotion, animations, animationOffset, RootBone, glm::mat4(1)); + } +} + + +void Skeleton::CalculateFrameBones(std::vector animations, bool noRootMotion /*= false*/) +{ + if (animations.size() <= 0) { + for (auto& b : Bones) { + m_BoneLocalTransforms[b.first] = glm::mat4(1); + m_BoneTransforms[b.first] = glm::mat4(1); + } + } else { + AccumulateBoneTransforms(noRootMotion, animations, RootBone, glm::mat4(1)); + } +} + const Skeleton::Animation* Skeleton::GetAnimation(std::string name) { auto it = Animations.find(name); @@ -39,66 +65,375 @@ const Skeleton::Animation* Skeleton::GetAnimation(std::string name) } } -std::vector Skeleton::GetFrameBones(const Animation& animation, double time, bool noRootMotion /*= false*/) -{ - // HACK: Animation wrap-around - while (time < 0) { - time += animation.Duration; - } - while (time > animation.Duration) { - time -= animation.Duration; - } - - int currentKeyframeIndex = GetKeyframe(animation, time); - - const Animation::Keyframe& currentFrame = animation.Keyframes[currentKeyframeIndex]; - const Animation::Keyframe& nextFrame = animation.Keyframes[(currentKeyframeIndex + 1) % animation.Keyframes.size()]; - double alpha = (time - currentFrame.Time) / (nextFrame.Time - currentFrame.Time); - - //auto animationFrame = Animations[""].Keyframes[frame]; - std::map frameBones; - AccumulateBoneTransforms(noRootMotion, currentFrame, nextFrame, static_cast(alpha), frameBones, RootBone, glm::mat4(1)); - - std::vector finalMatrices; - for (auto &kv : frameBones) { - finalMatrices.push_back(kv.second); - } - return finalMatrices; -} - -void Skeleton::AccumulateBoneTransforms(bool noRootMotion, const Animation::Keyframe ¤tFrame, const Animation::Keyframe &nextFrame, float progress, std::map &boneMatrices, const Bone* bone, glm::mat4 parentMatrix) +void Skeleton::AccumulateBoneTransforms(bool noRootMotion, std::vector animations, AnimationOffset animationOffset, const Bone* bone, glm::mat4 parentMatrix) { glm::mat4 boneMatrix; - if (currentFrame.BoneProperties.find(bone->ID) != currentFrame.BoneProperties.end() || nextFrame.BoneProperties.find(bone->ID) != nextFrame.BoneProperties.end()) { - Animation::Keyframe::BoneProperty currentBoneProperty = currentFrame.BoneProperties.at(bone->ID); - Animation::Keyframe::BoneProperty nextBoneProperty = nextFrame.BoneProperties.at(bone->ID); + std::vector JointTransforms; - 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; + for (const AnimationData animationData : animations) { + const Animation* animation = animationData.animation; + const float time = animationData.time; - // Flag for no root motion - if (bone == RootBone && noRootMotion) { - positionInterp.x = 0; - positionInterp.z = 0; - } + JointFrameTransform jointTransform; + jointTransform.Weight = animationData.weight;; + + if (animation->JointAnimations.find(bone->ID) != animation->JointAnimations.end()) { + std::vector 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); + + } - boneMatrix = parentMatrix * (glm::translate(positionInterp) * glm::toMat4(rotationInterp) * glm::scale(scaleInterp)); - boneMatrices[bone->ID] = boneMatrix * bone->OffsetMatrix; - } else { - if (bone->Parent) { - boneMatrix = parentMatrix; // * glm::inverse(bone->OffsetMatrix); + 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 + } - boneMatrices[bone->ID] = boneMatrix; // * bone->OffsetMatrix; - } - for (auto &child : bone->Children) { - std::string name = child->Name; - AccumulateBoneTransforms(noRootMotion, currentFrame, nextFrame, progress, boneMatrices, child, boneMatrix); - } + } + + 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)); + + } + m_BoneLocalTransforms[bone->ID] = boneMatrix * bone->OffsetMatrix; + m_BoneTransforms[bone->ID] = boneMatrix; + } else { + boneMatrix = offset * glm::inverse(bone->OffsetMatrix); + m_BoneLocalTransforms[bone->ID] = parentMatrix; + m_BoneTransforms[bone->ID] = boneMatrix; + } + } 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)); + } + + m_BoneLocalTransforms[bone->ID] = boneMatrix * bone->OffsetMatrix; + m_BoneTransforms[bone->ID] = boneMatrix; + } + + for (auto &child : bone->Children) { + AccumulateBoneTransforms(noRootMotion, animations, animationOffset, child, boneMatrix); + } +} + +void Skeleton::AccumulateBoneTransforms(bool noRootMotion, std::vector animations, const Bone* bone, glm::mat4 parentMatrix) +{ + glm::mat4 boneMatrix; + std::vector 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 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; + m_BoneLocalTransforms[bone->ID] = boneMatrix * bone->OffsetMatrix; + m_BoneTransforms[bone->ID] = boneMatrix; + } else { + boneMatrix = glm::inverse(bone->OffsetMatrix); + m_BoneLocalTransforms[bone->ID] = parentMatrix; + m_BoneTransforms[bone->ID] = boneMatrix; + } + } 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)); + m_BoneLocalTransforms[bone->ID] = boneMatrix * bone->OffsetMatrix; + m_BoneTransforms[bone->ID] = boneMatrix; + } 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)); + + m_BoneLocalTransforms[bone->ID] = boneMatrix * bone->OffsetMatrix; + m_BoneTransforms[bone->ID] = boneMatrix; + } + + + + for (auto &child : bone->Children) { + AccumulateBoneTransforms(noRootMotion, animations, 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 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; + + position = currentBoneProperty.Position * (1.f - progress) + nextBoneProperty.Position * progress; + rotation = glm::slerp(currentBoneProperty.Rotation, nextBoneProperty.Rotation, progress); + scale = currentBoneProperty.Scale * (1.f - progress) + nextBoneProperty.Scale * progress; + + + } else { // 1 keyframes for the current bone + 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)); +} + + +glm::mat4 Skeleton::GetBoneTransform(const Bone* bone, const Animation* animation, float time, glm::mat4 childMatrix) +{ + glm::mat4 boneMatrix; + + Animation::Keyframe currentFrame; + Animation::Keyframe nextFrame; + + if (animation->JointAnimations.find(bone->ID) != animation->JointAnimations.end()) { + std::vector 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; + } + } + + if (bone->Parent) { + return GetBoneTransform(bone->Parent, animation, time, boneMatrix); + } else { + return boneMatrix; + } } int Skeleton::GetBoneID(std::string name) @@ -134,11 +469,13 @@ void Skeleton::PrintSkeleton(const Bone* bone, int depthCount) int Skeleton::GetKeyframe(const Animation& animation, double time) { + +/* if (time < 0) { time = 0; } if (time >= animation.Duration) { - return animation.Keyframes.size() - 1; + return animation..size() - 1; } for (int keyframe = 0; keyframe < animation.Keyframes.size(); ++keyframe) { @@ -146,6 +483,8 @@ int Skeleton::GetKeyframe(const Animation& animation, double time) return (keyframe - 1) % animation.Keyframes.size(); } } +*/ + return 0; } diff --git a/src/Engine/Rendering/TextPass.cpp b/src/Engine/Rendering/TextPass.cpp index 1e3d5941..9583fcfd 100644 --- a/src/Engine/Rendering/TextPass.cpp +++ b/src/Engine/Rendering/TextPass.cpp @@ -35,7 +35,7 @@ void TextPass::Draw(RenderScene& scene, FrameBuffer& frameBuffer) { GLERROR("Derp1"); TextPassState* state = new TextPassState(frameBuffer.GetHandle()); - for (auto &job : scene.TextJobs) { + for (auto &job : scene.Jobs.Text) { auto textJob = std::dynamic_pointer_cast(job); if (textJob) { diff --git a/src/Engine/Rendering/Texture.cpp b/src/Engine/Rendering/Texture.cpp index 57f3ca36..256246a9 100644 --- a/src/Engine/Rendering/Texture.cpp +++ b/src/Engine/Rendering/Texture.cpp @@ -2,21 +2,25 @@ Texture::Texture(std::string path) { - PNG image(path); + PNG* img = ResourceManager::Load(path); //TODO: Make this threaded. Catch exeptions in all other load places. - if (image.Width == 0 && image.Height == 0 || image.Format == Image::ImageFormat::Unknown) { - image = PNG("Textures/Core/ErrorTexture.png"); - if (image.Width == 0 && image.Height == 0 || image.Format == Image::ImageFormat::Unknown) { - LOG_ERROR("Couldn't even load the error texture. This is a dark day indeed."); - return; - } - } + //PNG image(path); - this->Width = image.Width; - this->Height = image.Height; + //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; GLint format; - switch (image.Format) { + switch (img->Format) { case Image::ImageFormat::RGB: format = GL_RGB; break; @@ -29,10 +33,11 @@ Texture::Texture(std::string path) glGenTextures(1, &m_Texture); glBindTexture(GL_TEXTURE_2D, m_Texture); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glTexImage2D(GL_TEXTURE_2D, 0, format, image.Width, image.Height, 0, format, GL_UNSIGNED_BYTE, image.Data); + glTexImage2D(GL_TEXTURE_2D, 0, format, img->Width, img->Height, 0, format, GL_UNSIGNED_BYTE, img->Data); + glGenerateMipmap(GL_TEXTURE_2D); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); GLERROR("Texture load"); } diff --git a/src/Engine/Rendering/Util/CommonFunctions.cpp b/src/Engine/Rendering/Util/CommonFunctions.cpp index 3c81de66..382cb790 100644 --- a/src/Engine/Rendering/Util/CommonFunctions.cpp +++ b/src/Engine/Rendering/Util/CommonFunctions.cpp @@ -1,2 +1,19 @@ #include "Rendering/Util/CommonFunctions.h" +Texture* CommonFunctions::LoadTexture(std::string path, bool threaded) +{ + Texture* img; + try { + if(threaded) { + img = ResourceManager::Load(path); + } else { + img = ResourceManager::Load(path); + } + } catch (const Resource::StillLoadingException&) { + img = ResourceManager::Load("Textures/Core/ErrorTexture.png"); + } catch (const std::exception&) { + img = nullptr; + } + + return img; +} diff --git a/src/Engine/Sound/SoundManager.cpp b/src/Engine/Sound/SoundManager.cpp new file mode 100644 index 00000000..8e103d5c --- /dev/null +++ b/src/Engine/Sound/SoundManager.cpp @@ -0,0 +1,374 @@ +#include "Sound/SoundManager.h" + +SoundManager::SoundManager(World* world, EventBroker* eventBroker) +{ + ConfigFile* config = ResourceManager::Load("Config.ini"); + m_EventBroker = eventBroker; + m_World = world; + m_BGMVolumeChannel = config->Get("Sound.BGMVolume", 1.f); + m_SFXVolumeChannel = config->Get("Sound.SFXVolume", 1.f); + + initOpenAL(); + alSpeedOfSound(340.29f); + alDistanceModel(AL_LINEAR_DISTANCE); + alDopplerFactor(1); + + 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_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_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); +} + +SoundManager::~SoundManager() +{ + stopEmitters(); // Stopps emitters + deleteInactiveEmitters(); // Deletes stopped emitters + // Delete entities + std::unordered_map::iterator it; + for (it = m_Sources.begin(); it != m_Sources.end(); it++) { + m_World->DeleteEntity((*it).first); + } + m_Sources.clear(); + + alcDestroyContext(m_ALCcontext); + alcCloseDevice(m_ALCdevice); +} + +void SoundManager::stopEmitters() +{ + std::unordered_map::iterator it; + for (it = m_Sources.begin(); it != m_Sources.end(); it++) { + if (getSourceState(it->second->ALsource) == AL_PLAYING) { + stopSound(it->second); + } + } +} + +void SoundManager::Update(double dt) +{ + m_EventBroker->Process(); + deleteInactiveEmitters(); // can be optimized with "EEntityDeleted" + 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); +} + +void SoundManager::deleteInactiveEmitters() +{ + std::unordered_map::iterator it; + for (it = m_Sources.begin(); it != m_Sources.end();) { + if (m_World->ValidEntity(it->first) + && m_World->HasComponent(it->first, "SoundEmitter")) { + if (getSourceState(it->second->ALsource) != AL_STOPPED) { + // Nothing to see here, move along + it++; + continue; + } else { + // Sound has been stopped / finished playing. + alDeleteBuffers(1, &it->second->ALsource); + alDeleteSources(1, &it->second->ALsource); + m_World->DeleteEntity(it->first); + delete it->second; + it = m_Sources.erase(it); + } + } else { + // Entity / Component has been removed + stopSound(it->second); + alDeleteBuffers(1, &it->second->ALsource); + alDeleteSources(1, &it->second->ALsource); + delete it->second; + it = m_Sources.erase(it); + } + } +} + +void SoundManager::updateEmitters(double dt) +{ + std::unordered_map::iterator it; + for (it = m_Sources.begin(); it != m_Sources.end(); it++) { + // Get previous pos + if (!m_World->ValidEntity(it->first)) { + return; + } + if (!m_World->HasComponent(it->first, "SoundEmitter")) + return; + + glm::vec3 previousPos; + alGetSource3f(it->second->ALsource, AL_POSITION, &previousPos.x, &previousPos.y, &previousPos.z); + // Get next pos + if (!m_World->HasComponent(it->first, "Transform")) + return; + if (!m_World->ValidEntity(m_World->GetParent(it->first))) { + return; + } + glm::vec3 nextPos = Transform::AbsolutePosition(m_World, it->first); + // Calculate velocity + glm::vec3 velocity = glm::vec3(nextPos - previousPos) / (float)dt; + setSourcePos(it->second->ALsource, nextPos); + setSourceVel(it->second->ALsource, velocity); + + 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((std::string)emitter["FilePath"]); + if (it->second->SoundResource->Buffer() != 0) { + playSound(it->second); + } + } + } +} + +void SoundManager::updateListener(double dt) +{ + // Should only be one listener. + auto listenerComponents = m_World->GetComponents("Listener"); + if (listenerComponents == nullptr || !m_LocalPlayer.Valid()) { + return; + } + for (auto it = listenerComponents->begin(); it != listenerComponents->end(); it++) { + EntityWrapper listener(m_World, (*it).EntityID); + if (!listener.Valid()) { + break; + } + 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 velocity = glm::vec3(nextPos - previousPos) / (float)dt; // Calculate velocity + setListenerPos(nextPos); + setListenerVel(velocity); + setListenerOri(glm::eulerAngles(Transform::AbsoluteOrientation(listener))); + break; + } + } +} + +Source* SoundManager::createSource(std::string filePath) +{ + ALuint alSource; + alGenSources((ALuint)1, &alSource); + alSourcef(alSource, AL_REFERENCE_DISTANCE, 1.0); + alSourcef(alSource, AL_MAX_DISTANCE, FLT_MAX); + Source* source = new Source(); + source->ALsource = alSource; + source->SoundResource = ResourceManager::Load(filePath); + return source; +} + +void SoundManager::playSound(Source* source) +{ + alSourcei(source->ALsource, AL_BUFFER, source->SoundResource->Buffer()); + alSourcePlay(source->ALsource); +} + +void SoundManager::playQueue(QueuedBuffers qb) +{ + for (int i = 0; i < qb.second.size(); i++) { + alSourceQueueBuffers(qb.first, 1, &qb.second[i]); + } + alSourcePlay(qb.first); +} + +void SoundManager::stopSound(Source* source) +{ + alSourceStop(source->ALsource); +} + +bool SoundManager::OnPlaySoundOnEntity(const Events::PlaySoundOnEntity & e) +{ + Source* source = createSource(e.FilePath); + source->Type = SoundType::SFX; + EntityID child = m_World->CreateEntity(e.EmitterID); + m_World->AttachComponent(child, "Transform"); + m_World->AttachComponent(child, "SoundEmitter"); + m_Sources[child] = source; + playSound(source); + return false; +} + +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; + 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; + source->Type = SoundType::SFX; + m_Sources[emitterID] = source; + playSound(source); + return true; +} + +bool SoundManager::OnPauseSound(const Events::PauseSound & e) +{ + alSourcePause(m_Sources[e.EmitterID]->ALsource); + return true; +} + +bool SoundManager::OnStopSound(const Events::StopSound & e) +{ + alSourceStop(m_Sources[e.EmitterID]->ALsource); + return true; +} + +bool SoundManager::OnContinueSound(const Events::ContinueSound & e) +{ + alSourcePlay(m_Sources[e.EmitterID]->ALsource); + return true; +} + +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; + } + auto emitterChild = m_World->CreateEntity((*it).EntityID); + auto emitter = m_World->AttachComponent(emitterChild, "SoundEmitter"); + (bool&)emitter["Loop"] = true; + (std::string&)emitter["FilePath"] = e.FilePath; + m_World->AttachComponent(emitterChild, "Transform"); + Source* source = createSource(e.FilePath); + source->Type = SoundType::BGM; + setSoundProperties(source, &emitter); + m_Sources[emitterChild] = source; + playSound(source); + } + return true; +} + +bool SoundManager::OnSetBGMGain(const Events::SetBGMGain & e) +{ + m_BGMVolumeChannel = e.Gain; + return true; +} + +bool SoundManager::OnSetSFXGain(const Events::SetSFXGain & e) +{ + m_SFXVolumeChannel = e.Gain; + return true; +} + +bool SoundManager::OnComponentAttached(const Events::ComponentAttached & e) +{ + if (e.Component.Info.Name == "SoundEmitter") { + auto component = m_World->GetComponent(e.Entity.ID, "SoundEmitter"); + Source* source = createSource(component["FilePath"]); + m_Sources[e.Entity.ID] = source; + } + return false; +} + +bool SoundManager::OnPause(const Events::Pause & e) +{ + for (auto it = m_Sources.begin(); it != m_Sources.end(); it++) { + alSourcePause(it->second->ALsource); + } + return false; +} + +bool SoundManager::OnResume(const Events::Resume &e) +{ + for (auto it = m_Sources.begin(); it != m_Sources.end(); it++) { + alSourcePlay(it->second->ALsource); + } + return false; +} + + +bool SoundManager::OnPlayerSpawned(const Events::PlayerSpawned &e) +{ + if (e.PlayerID == -1) { // Local player + m_LocalPlayer = e.Player; + return true; + } + return false; +} + + +bool SoundManager::OnPlayQueueOnEntity(const Events::PlayQueueOnEntity &e) +{ + Source* source = createSource(*e.FilePaths.begin()); + std::vector buffers; + buffers.push_back(source->SoundResource->Buffer()); + source->Type = SoundType::BGM; + std::vector::const_iterator it; + for (it = e.FilePaths.begin() + 1; it != e.FilePaths.end(); it++) { + buffers.push_back(ResourceManager::Load(*it)->Buffer()); + } + playQueue(QueuedBuffers(source->ALsource, buffers)); + return true; +} + +ALenum SoundManager::getSourceState(ALuint source) +{ + ALenum state; + alGetSourcei(source, AL_SOURCE_STATE, &state); + return state; +} + +void SoundManager::setGain(Source * source, float gain) +{ + alSourcef(source->ALsource, AL_GAIN, gain); +} + +void SoundManager::setSoundProperties(Source* source, ComponentWrapper* soundComponent) +{ + float gain = (source->Type == SoundType::SFX) ? m_SFXVolumeChannel : m_BGMVolumeChannel; + 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 + 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"]); +} + +void SoundManager::initOpenAL() +{ + // Initialize OpenAL + m_ALCdevice = alcOpenDevice(nullptr); + if (m_ALCdevice != nullptr) { + m_ALCcontext = alcCreateContext(m_ALCdevice, nullptr); + alcMakeContextCurrent(m_ALCcontext); + } else { + LOG_ERROR("OpenAL failed to initialize."); + } +} + +void SoundManager::setListenerOri(glm::vec3 ori) +{ + // Calculate forward and up vector. + glm::vec3 forward = glm::vec3(0.0, 0.0, -1.0); + forward = glm::rotateX(forward, ori.x); + forward = glm::rotateY(forward, ori.y); + forward = glm::rotateZ(forward, ori.z); + glm::normalize(forward); + glm::vec3 up = glm::vec3(0.0, 1.0, 0.0); + up = glm::rotateX(up, ori.x); + up = glm::rotateY(up, ori.y); + up = glm::rotateZ(up, ori.z); + glm::normalize(up); + ALfloat lOri[6] = { forward.x, forward.y, forward.z, up.x, up.y, up.z }; + alListenerfv(AL_ORIENTATION, lOri); +} \ No newline at end of file diff --git a/src/Engine/Sound/SoundSystem.cpp b/src/Engine/Sound/SoundSystem.cpp deleted file mode 100644 index cd83d9c6..00000000 --- a/src/Engine/Sound/SoundSystem.cpp +++ /dev/null @@ -1,308 +0,0 @@ -#include "Sound/SoundSystem.h" - -SoundSystem::SoundSystem(World* world, EventBroker* eventBroker, bool editorMode) -{ - m_EventBroker = eventBroker; - m_World = world; - m_EditorEnabled = editorMode; - - initOpenAL(); - - alSpeedOfSound(340.29f); - alDistanceModel(AL_LINEAR_DISTANCE); - alDopplerFactor(1); - - EVENT_SUBSCRIBE_MEMBER(m_EPlaySoundOnEntity, &SoundSystem::OnPlaySoundOnEntity); - EVENT_SUBSCRIBE_MEMBER(m_EPlaySoundOnPosition, &SoundSystem::OnPlaySoundOnPosition); - EVENT_SUBSCRIBE_MEMBER(m_EPlayBackgroundMusic, &SoundSystem::OnPlayBackgroundMusic); - EVENT_SUBSCRIBE_MEMBER(m_EStopSound, &SoundSystem::OnStopSound); - EVENT_SUBSCRIBE_MEMBER(m_EPauseSound, &SoundSystem::OnPauseSound); - EVENT_SUBSCRIBE_MEMBER(m_EContinueSound, &SoundSystem::OnContinueSound); - EVENT_SUBSCRIBE_MEMBER(m_ESetBGMGain, &SoundSystem::OnSetBGMGain); - EVENT_SUBSCRIBE_MEMBER(m_ESetSFXGain, &SoundSystem::OnSetSFXGain); -} - -SoundSystem::~SoundSystem() -{ - stopEmitters(); // Stopps emitters - deleteInactiveEmitters(); // Deletes stopped emitters - // Delete entities - std::unordered_map::iterator it; - for (it = m_Sources.begin(); it != m_Sources.end(); it++) { - m_World->DeleteEntity((*it).first); - } - m_Sources.clear(); - - alcDestroyContext(m_ALCcontext); - alcCloseDevice(m_ALCdevice); -} - -void SoundSystem::stopEmitters() -{ - std::unordered_map::iterator it; - for (it = m_Sources.begin(); it != m_Sources.end(); it++) { - if (getSourceState(it->second->ALsource) == AL_PLAYING) { - stopSound(it->second); - } - } -} - -void SoundSystem::Update(double dt) -{ - m_EventBroker->Process(); - addNewEmitters(dt); // can be optimized with "EEntityCreated" - deleteInactiveEmitters(); // can be optimized with "EEntityDeleted" - updateEmitters( dt); - updateListener( dt); -} - -void SoundSystem::deleteInactiveEmitters() -{ - std::unordered_map::iterator it; - for (it = m_Sources.begin(); it != m_Sources.end();) { - if (m_World->ValidEntity(it->first) - && m_World->HasComponent(it->first, "SoundEmitter")) { - if (getSourceState(it->second->ALsource) != AL_STOPPED) { - // Nothing to see here, move along - it++; - continue; - } else { - // Sound has been stopped / finished playing. - alDeleteBuffers(1, &it->second->ALsource); - alDeleteSources(1, &it->second->ALsource); - m_World->DeleteEntity(it->first); - delete it->second; - it = m_Sources.erase(it); - } - } else { - // Entity / Component has been removed - stopSound((*it).second); - alDeleteBuffers(1, &it->second->ALsource); - alDeleteSources(1, &it->second->ALsource); - delete it->second; - it = m_Sources.erase(it); - } - } -} - -void SoundSystem::addNewEmitters(double dt) -{ - auto emitterComponents = m_World->GetComponents("SoundEmitter"); - if (emitterComponents == nullptr) { - return; - } - for (auto it = emitterComponents->begin(); it != emitterComponents->end(); it++) { - EntityID emitter = (*it).EntityID; - std::unordered_map::iterator source; - source = m_Sources.find(emitter); - if (source == m_Sources.end()) { // Did not exist, add it - Source* source = createSource((std::string)(*it)["FilePath"]); - m_Sources[emitter] = source; - } - } -} - -void SoundSystem::updateEmitters(double dt) -{ - std::unordered_map::iterator it; - for (it = m_Sources.begin(); it != m_Sources.end(); it++) { - // Get previous pos - glm::vec3 previousPos; - alGetSource3f(it->second->ALsource, AL_POSITION, &previousPos.x, &previousPos.y, &previousPos.z); - // Get next pos - glm::vec3 nextPos = Transform::AbsolutePosition(m_World, it->first); - // Calculate velocity - glm::vec3 velocity = glm::vec3(nextPos - previousPos) / (float)dt; - setSourcePos(it->second->ALsource, nextPos); - setSourceVel(it->second->ALsource, velocity); - float gain; - if (it->second->Type == SoundType::SFX) { - gain = m_SFXVolumeChannel; - } else if (it->second->Type == SoundType::BGM) { - gain = m_BGMVolumeChannel; - } - auto emitter = m_World->GetComponent(it->first, "SoundEmitter"); - setSoundProperties(it->second->ALsource, &emitter); - - // To make an emitter play when spawned in editor mode - if (m_EditorEnabled) { - // Path changed - if (it->second->SoundResource->Path() != (std::string)emitter["FilePath"]) { - it->second->SoundResource = ResourceManager::Load((std::string)emitter["FilePath"]); - if (it->second->SoundResource->Buffer() != 0) { - playSound(it->second); - } - } - } - } -} - -void SoundSystem::updateListener(double dt) -{ - // Should only be one listener. - auto listenerComponents = m_World->GetComponents("Listener"); - if (listenerComponents == nullptr) { - return; - } - for (auto it = listenerComponents->begin(); it != listenerComponents->end(); it++) { - EntityID listener = (*it).EntityID; - glm::vec3 previousPos; - alGetListener3f(AL_POSITION, &previousPos.x, &previousPos.y, &previousPos.z); // Get previous pos - glm::vec3 nextPos = Transform::AbsolutePosition(m_World, listener); // Get next (current) pos - glm::vec3 velocity = glm::vec3(nextPos - previousPos) / (float)dt; // Calculate velocity - setListenerPos(nextPos); - setListenerVel(velocity); - setListenerOri(glm::eulerAngles(Transform::AbsoluteOrientation(m_World, listener))); - } -} - -Source* SoundSystem::createSource(std::string filePath) -{ - ALuint alSource; - alGenSources((ALuint)1, &alSource); - alSourcef(alSource, AL_REFERENCE_DISTANCE, 1.0); - alSourcef(alSource, AL_MAX_DISTANCE, FLT_MAX); - Source* source = new Source(); - source->ALsource = alSource; - source->SoundResource = ResourceManager::Load(filePath); - return source; -} - -void SoundSystem::playSound(Source* source) -{ - alSourcei(source->ALsource, AL_BUFFER, source->SoundResource->Buffer()); - alSourcePlay(source->ALsource); -} - -void SoundSystem::stopSound(Source* source) -{ - alSourceStop(source->ALsource); -} - -bool SoundSystem::OnPlaySoundOnEntity(const Events::PlaySoundOnEntity & e) -{ - Source* source = createSource(e.FilePath); - source->Type = SoundType::SFX; - m_Sources[e.EmitterID] = source; - playSound(source); - return false; -} - -bool SoundSystem::OnPlaySoundOnPosition(const Events::PlaySoundOnPosition & e) -{ - Source* source = createSource(e.FilePath); - auto emitterID = m_World->CreateEntity(); - auto transform = m_World->AttachComponent(emitterID, "Transform"); - (glm::vec3&)transform["Position"] = e.Position; - auto emitter = m_World->AttachComponent(emitterID, "SoundEmitter"); - (float&)(double)emitter["Gain"] = e.Gain; - (float&)(double)emitter["Pitch"] = e.Pitch; - (bool&)emitter["Loop"] = e.Loop; - (float&)(double)emitter["MaxDistance"] = e.MaxDistance; - (float&)(double)emitter["RollOffFactor"] = e.RollOffFactor; - (float&)(double)emitter["ReferenceDistance"] = e.ReferenceDistance; - auto model = m_World->AttachComponent(emitterID, "Model"); - (std::string&)model["Resource"] = "Models/Core/UnitCube.mesh"; // 360NoScope UnitCube - source->Type = SoundType::SFX; - m_Sources[emitterID] = source; - playSound(source); - return true; -} - -bool SoundSystem::OnPauseSound(const Events::PauseSound & e) -{ - alSourcePause(m_Sources[e.EmitterID]->ALsource); - return true; -} - -bool SoundSystem::OnStopSound(const Events::StopSound & e) -{ - alSourceStop(m_Sources[e.EmitterID]->ALsource); - return true; -} - -bool SoundSystem::OnContinueSound(const Events::ContinueSound & e) -{ - alSourcePlay(m_Sources[e.EmitterID]->ALsource); - return true; -} - -bool SoundSystem::OnPlayBackgroundMusic(const Events::PlayBackgroundMusic & e) -{ - auto listenerComponents = m_World->GetComponents("Listener"); - for (auto it = listenerComponents->begin(); it != listenerComponents->end(); it++) { - auto emitterChild = m_World->CreateEntity((*it).EntityID); - auto emitter = m_World->AttachComponent(emitterChild, "SoundEmitter"); - (bool&)emitter["Loop"] = true; - (std::string&)emitter["FilePath"] = e.FilePath; - m_World->AttachComponent(emitterChild, "Transform"); - Source* source = createSource(e.FilePath); - source->Type = SoundType::BGM; - m_Sources[emitterChild] = source; - playSound(source); - } - return true; -} - -bool SoundSystem::OnSetBGMGain(const Events::SetBGMGain & e) -{ - m_BGMVolumeChannel = e.Gain; - return true; -} - -bool SoundSystem::OnSetSFXGain(const Events::SetSFXGain & e) -{ - m_SFXVolumeChannel = e.Gain; - return true; -} - -void SoundSystem::setListenerOri(glm::vec3 ori) -{ - // Calculate forward and up vector. - glm::vec3 forward = glm::vec3(0.0, 0.0, -1.0); - forward = glm::rotateX(forward, ori.x); - forward = glm::rotateY(forward, ori.y); - forward = glm::rotateZ(forward, ori.z); - glm::normalize(forward); - glm::vec3 up = glm::vec3(0.0, 1.0, 0.0); - up = glm::rotateX(up, ori.x); - up = glm::rotateY(up, ori.y); - up = glm::rotateZ(up, ori.z); - glm::normalize(up); - ALfloat lOri[6] = { forward.x, forward.y, forward.z, up.x, up.y, up.z }; - alListenerfv(AL_ORIENTATION, lOri); -} - -ALenum SoundSystem::getSourceState(ALuint source) -{ - ALenum state; - alGetSourcei(source, AL_SOURCE_STATE, &state); - return state; -} - -void SoundSystem::setGain(Source * source, float gain) -{ - alSourcef(source->ALsource, AL_GAIN, gain); -} - -void SoundSystem::setSoundProperties(ALuint source, ComponentWrapper* soundComponent) -{ - alSourcef(source, AL_GAIN, (float)(double)(*soundComponent)["Gain"]); - alSourcef(source, AL_PITCH, (float)(double)(*soundComponent)["Pitch"]); - alSourcei(source, AL_LOOPING, (int)(bool)(*soundComponent)["Loop"]); // YOLO - alSourcef(source, AL_MAX_DISTANCE, (float)(double)(*soundComponent)["MaxDistance"]); - alSourcef(source, AL_ROLLOFF_FACTOR, (float)(double)(*soundComponent)["RollOffFactor"]); - alSourcef(source, AL_REFERENCE_DISTANCE, (float)(double)(*soundComponent)["ReferenceDistance"]); -} - -void SoundSystem::initOpenAL() -{ - // Initialize OpenAL - m_ALCdevice = alcOpenDevice(nullptr); - if (m_ALCdevice != nullptr) { - m_ALCcontext = alcCreateContext(m_ALCdevice, nullptr); - alcMakeContextCurrent(m_ALCcontext); - } else { - LOG_ERROR("OpenAL failed to initialize."); - } -} \ No newline at end of file diff --git a/src/Game/CMakeLists.txt b/src/Game/CMakeLists.txt index 157af23c..db923364 100644 --- a/src/Game/CMakeLists.txt +++ b/src/Game/CMakeLists.txt @@ -1,6 +1,6 @@ project(TacticalZ-Game) -find_package(Boost REQUIRED COMPONENTS system filesystem thread chrono) +find_package(Boost REQUIRED COMPONENTS system filesystem thread chrono program_options) set(INCLUDE_PATH ${CMAKE_SOURCE_DIR}/include/Game) include_directories( @@ -22,13 +22,17 @@ file(GLOB SOURCE_FILES_Events ) source_group(Events FILES ${SOURCE_FILES_Events}) +file(GLOB SOURCE_FILES_Network + "${INCLUDE_PATH}/Network/*.h" + "Network/*.cpp" +) +source_group(Network FILES ${SOURCE_FILES_Network}) set(SOURCE_FILES ${SOURCE_FILES} "Game.cpp" ${SOURCE_FILES_Systems} ${SOURCE_FILES_Events} - - + ${SOURCE_FILES_Network} ) set(LIBRARIES diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index f5afcaeb..8ee6dbed 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -1,5 +1,6 @@ #include "Game.h" -#include "Collision/CollidableOctreeSystem.h" +#include "Collision/FillOctreeSystem.h" +#include "Collision/FillFrustumOctreeSystem.h" #include "Collision/EntityAABB.h" #include "Collision/TriggerSystem.h" #include "Collision/CollisionSystem.h" @@ -8,20 +9,31 @@ #include "Systems/PlayerMovementSystem.h" #include "Systems/SpawnerSystem.h" #include "Systems/PlayerSpawnSystem.h" +#include "Systems/PlayerDeathSystem.h" #include "Core/EntityFileWriter.h" #include "Game/Systems/CapturePointSystem.h" +#include "Game/Systems/CapturePointHUDSystem.h" +#include "Game/Systems/PickupSpawnSystem.h" +#include "Game/Systems/DamageIndicatorSystem.h" #include "Game/Systems/WeaponSystem.h" -#include "Game/Systems/PlayerHUD.h" +#include "Rendering/AnimationSystem.h" +#include "Game/Systems/PlayerHUDSystem.h" +#include "Rendering/BoneAttachmentSystem.h" #include "Game/Systems/LifetimeSystem.h" -#include "../Engine/Rendering/AnimationSystem.h" +#include "../Engine/Core/UniformScaleSystem.h" +#include "Rendering/AnimationSystem.h" +#include "Network/MultiplayerSnapshotFilter.h" Game::Game(int argc, char* argv[]) { + parseArgs(argc, argv); + ResourceManager::RegisterType("ConfigFile"); ResourceManager::RegisterType("Sound"); ResourceManager::RegisterType("Model"); ResourceManager::RegisterType("RawModel"); ResourceManager::RegisterType("Texture"); + ResourceManager::RegisterType("Png"); ResourceManager::RegisterType("ShaderProgram"); ResourceManager::RegisterType("EntityFile"); ResourceManager::RegisterType("FontFile"); @@ -71,61 +83,82 @@ Game::Game(int argc, char* argv[]) fp.MergeEntities(m_World); } + // Create the sound manager + m_SoundManager = new SoundManager(m_World, m_EventBroker); + + // Initialize network + if (m_Config->Get("Networking.StartNetwork", false)) { + if (m_IsServer) { + m_NetworkServer = new Server(m_World, m_EventBroker, m_NetworkPort); + m_Renderer->SetWindowTitle(m_Renderer->WindowTitle() + " SERVER"); + } else if (m_IsClient) { + m_NetworkClient = new Client(m_World, m_EventBroker, std::make_unique(m_EventBroker)); + m_NetworkClient->Connect(m_NetworkAddress, m_NetworkPort); + m_Renderer->SetWindowTitle(m_Renderer->WindowTitle() + " CLIENT"); + } + } // Create Octrees - m_OctreeCollision = new Octree(AABB(glm::vec3(-100), glm::vec3(100)), 4); - m_OctreeTrigger = new Octree(AABB(glm::vec3(-100), glm::vec3(100)), 4); - m_OctreeFrustrumCulling = new Octree(AABB(glm::vec3(-100), glm::vec3(100)), 4); + // TODO: Perhaps the world bounds should be set in some non-arbitrary way instead of this. + AABB boxContainingTheWorld(glm::vec3(-300), glm::vec3(300)); + m_OctreeCollision = new Octree(boxContainingTheWorld, 4); + m_OctreeTrigger = new Octree(boxContainingTheWorld, 4); + m_OctreeFrustrumCulling = new Octree(boxContainingTheWorld, 4); // Create system pipeline - m_SystemPipeline = new SystemPipeline(m_World, m_EventBroker); + m_SystemPipeline = new SystemPipeline(m_World, m_EventBroker, m_IsClient, m_IsServer); // All systems with orderlevel 0 will be updated first. unsigned int updateOrderLevel = 0; + m_SystemPipeline->AddSystem(updateOrderLevel); + ++updateOrderLevel; + m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); - m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); - m_SystemPipeline->AddSystem(updateOrderLevel, m_Renderer); + m_SystemPipeline->AddSystem(updateOrderLevel); + m_SystemPipeline->AddSystem(updateOrderLevel, m_Renderer, m_OctreeCollision); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); + m_SystemPipeline->AddSystem(updateOrderLevel); + m_SystemPipeline->AddSystem(updateOrderLevel); + m_SystemPipeline->AddSystem(updateOrderLevel); // Populate Octree with collidables ++updateOrderLevel; - m_SystemPipeline->AddSystem(updateOrderLevel, m_OctreeCollision, "Collidable"); - m_SystemPipeline->AddSystem(updateOrderLevel, m_OctreeTrigger, "Player"); - m_SystemPipeline->AddSystem(updateOrderLevel); + m_SystemPipeline->AddSystem(updateOrderLevel, m_OctreeCollision, "Collidable"); + m_SystemPipeline->AddSystem(updateOrderLevel, m_OctreeTrigger, "Player"); + m_SystemPipeline->AddSystem(updateOrderLevel, m_OctreeFrustrumCulling); m_SystemPipeline->AddSystem(updateOrderLevel); - + m_SystemPipeline->AddSystem(updateOrderLevel); + m_SystemPipeline->AddSystem(updateOrderLevel); // Collision and TriggerSystem should update after player. ++updateOrderLevel; + m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel, m_OctreeCollision); m_SystemPipeline->AddSystem(updateOrderLevel, m_OctreeTrigger); ++updateOrderLevel; - m_SystemPipeline->AddSystem(updateOrderLevel, m_Renderer, m_RenderFrame); + m_SystemPipeline->AddSystem(updateOrderLevel, m_Renderer, m_RenderFrame, m_OctreeFrustrumCulling); ++updateOrderLevel; m_SystemPipeline->AddSystem(updateOrderLevel, m_Renderer, m_RenderFrame); - // Invoke network - if (m_Config->Get("Networking.StartNetwork", false)) { - //boost::thread workerThread(&Game::networkFunction, this); - networkFunction(); - } - - // Invoke sound system - m_SoundSystem = new SoundSystem(m_World, m_EventBroker, m_Config->Get("Debug.EditorEnabled", false)); - m_LastTime = glfwGetTime(); } Game::~Game() { delete m_SystemPipeline; - delete m_SoundSystem; delete m_OctreeFrustrumCulling; delete m_OctreeCollision; delete m_OctreeTrigger; + delete m_SoundManager; + if (m_NetworkClient != nullptr) { + delete m_NetworkClient; + } + if (m_NetworkServer != nullptr) { + delete m_NetworkServer; + } delete m_World; delete m_FrameStack; delete m_InputProxy; @@ -153,40 +186,59 @@ void Game::Tick() m_InputProxy->Process(); m_EventBroker->Swap(); + m_SoundManager->Update(dt); + // Update network - if (m_IsClientOrServer) { - m_ClientOrServer->Update(); + m_EventBroker->Process(); + if (m_NetworkClient != nullptr) { + m_NetworkClient->Update(); } + if (m_NetworkServer != nullptr) { + m_NetworkServer->Update(); + } + //m_SoundManager->Update(dt); + // Iterate through systems and update world! m_EventBroker->Process(); m_SystemPipeline->Update(dt); - debugTick(dt); m_Renderer->Update(dt); - m_SoundSystem->Update(dt); - GLERROR("Game::Tick m_RenderQueueFactory->Update"); m_Renderer->Draw(*m_RenderFrame); m_RenderFrame->Clear(); - GLERROR("Game::Tick m_Renderer->Draw"); m_EventBroker->Swap(); m_EventBroker->Clear(); } -void Game::debugTick(double dt) +int Game::parseArgs(int argc, char* argv[]) { - m_EventBroker->Process(); + namespace po = boost::program_options; + + po::options_description desc("Options"); + desc.add_options() + ("help", "Help") + ("server,s", po::bool_switch(&m_IsServer), "Launch game in server mode") + ("connect", po::value(&m_NetworkAddress)->default_value(""), "Connect to this address in client mode") + ("port,p", po::value(&m_NetworkPort), "Port to listen on or connect to"); + ; + + po::variables_map vm; + try { + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + } catch (std::exception& e) { + LOG_ERROR(e.what()); + return 1; + } + + if (vm.count("help")) { + std::cout << desc << std::endl; + exit(1); + } + + // HACK: Right now, client and server are mutually exclusive + m_IsClient = true; + if (m_IsServer) { + m_IsClient = false; + } + + return 0; } - -void Game::networkFunction() -{ - bool isServer = m_Config->Get("Networking.IsServer", false); - if (!isServer) { - m_IsClientOrServer = true; - m_ClientOrServer = new Client(m_Config); - } - if (isServer) { - m_IsClientOrServer = true; - m_ClientOrServer = new Server(); - } - m_ClientOrServer->Start(m_World, m_EventBroker); - -} \ No newline at end of file diff --git a/src/Game/Network/MultiplayerSnapshotFilter.cpp b/src/Game/Network/MultiplayerSnapshotFilter.cpp new file mode 100644 index 00000000..65d40189 --- /dev/null +++ b/src/Game/Network/MultiplayerSnapshotFilter.cpp @@ -0,0 +1,33 @@ +#include "Network/MultiplayerSnapshotFilter.h" + +MultiplayerSnapshotFilter::MultiplayerSnapshotFilter(EventBroker* eventBroker) + : m_EventBroker(eventBroker) +{ + EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &MultiplayerSnapshotFilter::OnPlayerSpawned); +} + +bool MultiplayerSnapshotFilter::FilterComponent(EntityWrapper entity, SharedComponentWrapper& component) +{ + if (entity == m_LocalPlayer || entity.IsChildOf(m_LocalPlayer)) { + return false; + } + + if (component.Info.Name == "Physics") { + return false; + } + + if (component.Info.Name == "Transform" || component.Info.Name == "Physics") { + m_EventBroker->Publish(Events::Interpolate(entity, component)); + return false; + } + + return true; +} + +bool MultiplayerSnapshotFilter::OnPlayerSpawned(Events::PlayerSpawned ePlayerSpawned) +{ + if (ePlayerSpawned.PlayerID == -1) { + m_LocalPlayer = ePlayerSpawned.Player; + } + return true; +} \ No newline at end of file diff --git a/src/Game/Systems/CapturePointHUDSystem.cpp b/src/Game/Systems/CapturePointHUDSystem.cpp new file mode 100644 index 00000000..21737fbe --- /dev/null +++ b/src/Game/Systems/CapturePointHUDSystem.cpp @@ -0,0 +1,55 @@ +#include "Systems/CapturePointHUDSystem.h" + +CapturePointHUDSystem::CapturePointHUDSystem(SystemParams params) + : System(params) + , ImpureSystem() +{ +} + + +void CapturePointHUDSystem::Update(double dt) +{ + bool LoadCheck = true; + int redTeam; + int blueTeam; + int spectatorTeam; + + auto CapturePointHUDElements = m_World->GetComponents("CapturePointHUD"); + auto CapturePoints = m_World->GetComponents("CapturePoint"); + if (CapturePointHUDElements == nullptr) { + return; + } + + for (auto& cCapturePointHUD : *CapturePointHUDElements) { + int HUD_ID = cCapturePointHUD["CapturePointNumber"]; + EntityWrapper entityHUD = EntityWrapper(m_World, cCapturePointHUD.EntityID); + EntityWrapper entityHUDparent = entityHUD.Parent(); + + for (auto& cCapturePoint : *CapturePoints) { + EntityWrapper entityCP = EntityWrapper(m_World, cCapturePoint.EntityID); + + //Check if the HUD corresponds to the Capture Point Number + if (HUD_ID == (int)entityCP["CapturePoint"]["CapturePointNumber"]) { + ComponentWrapper& teamComponent = entityCP["Team"]; + if (LoadCheck) { + redTeam = (int)teamComponent["Team"].Enum("Red"); + blueTeam = (int)teamComponent["Team"].Enum("Blue"); + spectatorTeam = (int)teamComponent["Team"].Enum("Spectator"); + LoadCheck = false; + } + //Color hud with team color + auto capturePointTeam = (int)teamComponent["Team"]; + entityHUDparent["Sprite"]["Color"] = capturePointTeam == blueTeam ? glm::vec4(0, 0.2f, 1, 0.7) : capturePointTeam == redTeam ? glm::vec4(1, 0.2f, 0, 0.7) : glm::vec4(1, 1, 1, 0.3); + + //Progress is scaled with time + double currentCaptureTime = (double)entityCP["CapturePoint"]["CaptureTimer"]; + double progress = glm::abs(currentCaptureTime)/15.0; + int currentCapturingTeam = currentCaptureTime > 0 ? redTeam : currentCaptureTime < 0 ? blueTeam : spectatorTeam; + ((glm::vec3&)entityHUD["Transform"]["Orientation"]).z = currentCapturingTeam == redTeam ? glm::half_pi()+glm::pi() : glm::half_pi(); + glm::vec4 fillColor = currentCapturingTeam == redTeam ? glm::vec4(1, 0.2f, 0, 0.7) : glm::vec4(0, 0.2f, 1, 0.7); + entityHUD["Fill"]["Color"] = fillColor; + entityHUD["Fill"]["Percentage"] = progress; + } + } + } +} \ No newline at end of file diff --git a/src/Game/Systems/CapturePointSystem.cpp b/src/Game/Systems/CapturePointSystem.cpp index d26dde5f..f938ecd0 100644 --- a/src/Game/Systems/CapturePointSystem.cpp +++ b/src/Game/Systems/CapturePointSystem.cpp @@ -1,8 +1,8 @@ #include "Systems/CapturePointSystem.h" #include -CapturePointSystem::CapturePointSystem(World* world, EventBroker* eventBroker) - : System(world, eventBroker) +CapturePointSystem::CapturePointSystem(SystemParams params) + : System(params) , PureSystem("CapturePoint") { //subscribe/listenTo playerdamage,healthpickup events (using the eventBroker) @@ -32,6 +32,7 @@ void CapturePointSystem::UpdateComponent(EntityWrapper& capturePointEntity, Comp const int redTeam = (int)teamComponent["Team"].Enum("Red"); const int blueTeam = (int)teamComponent["Team"].Enum("Blue"); const int spectatorTeam = (int)teamComponent["Team"].Enum("Spectator"); + const double captureTimeToTakeOver = (double)cCapturePoint["CapturePointMaxTimer"]; int homePointForTeam = (int)cCapturePoint["HomePointForTeam"]; if (m_NumberOfCapturePoints == 0 && capturePointNumber != 0 && (homePointForTeam == redTeam || homePointForTeam == blueTeam)) { @@ -57,7 +58,7 @@ void CapturePointSystem::UpdateComponent(EntityWrapper& capturePointEntity, Comp int blueTeamPlayersStandingInside = 0; if (capturePointEntity.HasComponent("Model")) { //Now sets team color to the capturepoint, or white if it is uncaptured. - capturePointEntity["Model"]["Color"] = ownedBy == blueTeam ? glm::vec4(0, 0.2f, 1, 1) : ownedBy == redTeam ? glm::vec4(1, 0.2f, 0, 1) : glm::vec4(1, 1, 1, 1); + capturePointEntity["Model"]["Color"] = ownedBy == blueTeam ? glm::vec4(0, 0.0f, 1, 0.3) : ownedBy == redTeam ? glm::vec4(1, 0.0f, 0, 0.3) : glm::vec4(1, 1, 1, 0.3); } //calculate next possible capturePoint for both teams @@ -98,20 +99,16 @@ void CapturePointSystem::UpdateComponent(EntityWrapper& capturePointEntity, Comp ComponentWrapper& capturePoint = m_CapturePointNumberToEntityMap[i]["CapturePoint"]; if ((int)capturePoint["CapturePointNumber"] != nextPossibleCapturePoint["Red"] && (int)capturePoint["CapturePointNumber"] != nextPossibleCapturePoint["Blue"]) { - capturePoint["CaptureTimer"] = 0.0; + //RED = +, BLUE = -, NONE + auto teamOwners = (int)m_CapturePointNumberToEntityMap[i]["Team"]["Team"]; + if (teamOwners == redTeam || teamOwners == blueTeam) { + capturePoint["CaptureTimer"] = teamOwners == blueTeam ? -captureTimeToTakeOver : captureTimeToTakeOver; + } } } m_ResetTimers = false; } - //colorize next possible capturepoint - if (nextPossibleCapturePoint["Red"] == capturePointNumber) { - capturePointEntity["Model"]["Color"] = glm::vec4(1, 1, 0, 1); - } - if (nextPossibleCapturePoint["Blue"] == capturePointNumber) { - capturePointEntity["Model"]["Color"] = glm::vec4(0, 1, 1, 1); - } - //check how many players are standing inside and are healthy for (size_t i = m_ETriggerTouchVector.size(); i > 0; i--) { @@ -170,9 +167,6 @@ void CapturePointSystem::UpdateComponent(EntityWrapper& capturePointEntity, Comp //B. at most one of the teams have players inside //if capturePoint is not owned by the take-over team, just modify the CaptureTimer accordingly if (ownedBy != currentTeam && canCapture) { - if (abs((double)cCapturePoint["CaptureTimer"]) < 0.001f) { - LOG_DEBUG("Point is being captured by team %i", currentTeam); //Remove when we tested sufficiently. - } cCapturePoint["CaptureTimer"] = (double)cCapturePoint["CaptureTimer"] + timerDeltaChange; } //if capturePoint is owned by the team, and the other team has been trying to take it, then increase/decrease the timer towards 0.0 @@ -180,12 +174,11 @@ void CapturePointSystem::UpdateComponent(EntityWrapper& capturePointEntity, Comp (ownedBy == currentTeam && currentTeam == blueTeam && (double)cCapturePoint["CaptureTimer"] > 0.0)) { cCapturePoint["CaptureTimer"] = (double)cCapturePoint["CaptureTimer"] + timerDeltaChange; } - //check if captureTimer > m_CaptureTimeToTakeOver and if so change owner and publish the eCaptured event - if (abs((double)cCapturePoint["CaptureTimer"]) > abs(m_CaptureTimeToTakeOver) && canCapture) { + //check if captureTimer > captureTimeToTakeOver and if so change owner and publish the eCaptured event + if (abs((double)cCapturePoint["CaptureTimer"]) > captureTimeToTakeOver && canCapture) { teamComponent["Team"] = currentTeam; - cCapturePoint["CaptureTimer"] = 0.0; + cCapturePoint["CaptureTimer"] = glm::sign((double)cCapturePoint["CaptureTimer"])*captureTimeToTakeOver; //publish Captured event - LOG_DEBUG("Point is captured by team %i!", currentTeam); //Remove when we tested sufficiently. Events::Captured e; e.CapturePointID = cCapturePoint.EntityID; e.TeamNumberThatCapturedCapturePoint = currentTeam; diff --git a/src/Game/Systems/DamageIndicatorSystem.cpp b/src/Game/Systems/DamageIndicatorSystem.cpp new file mode 100644 index 00000000..93385e48 --- /dev/null +++ b/src/Game/Systems/DamageIndicatorSystem.cpp @@ -0,0 +1,65 @@ +#include "Systems/DamageIndicatorSystem.h" + +DamageIndicatorSystem::DamageIndicatorSystem(SystemParams params) + : System(params) +{ + EVENT_SUBSCRIBE_MEMBER(m_DamageTakenFromPlayer, &DamageIndicatorSystem::OnPlayerDamageTaken); + //current camera + EVENT_SUBSCRIBE_MEMBER(m_ESetCamera, &DamageIndicatorSystem::OnSetCamera); + + //load texture to cache + auto texture = CommonFunctions::LoadTexture("Textures/DamageIndicator.png", false); + auto entityFile = ResourceManager::Load("Schema/Entities/DamageIndicator.xml"); +} + +bool DamageIndicatorSystem::OnPlayerDamageTaken(Events::PlayerDamage& e) +{ + if (m_CurrentCamera == -1) { + return false; + } + + //grab players direction + auto playerOrientation = glm::quat((glm::vec3)e.Player["Transform"]["Orientation"]); + + //get the position vectors, but ignore the y-height + auto enemyPosition = (glm::vec3) e.PlayerShooter["Transform"]["Position"]; + auto playerPosition = (glm::vec3) e.Player["Transform"]["Position"]; + enemyPosition.y = 0.0f; + playerPosition.y = 0.0f; + + //calculate the enemy to player vector + auto enemyPlayerVector = glm::normalize((glm::vec3) playerPosition - enemyPosition); + + //get angle from players current rotation, this angle is how much you rotate around the y-axis + auto playerAngle = glm::angle(playerOrientation); + auto playerRotationVector = glm::normalize(glm::rotateY(glm::vec3(0, 0, 1), playerAngle)); + + //dot product of players direction-vector and enemys-to-playervector will give the cos of the angle between the vectors + auto playerRotationDot = glm::dot(playerRotationVector, enemyPlayerVector); + //to get the angle between the vectors just do cos-inverse + auto angleBetweenVectors = glm::acos(playerRotationDot); + + //rotate the direction-vector 90 degrees to get the players side-vector + auto playerSideVector = glm::normalize(glm::rotateY(glm::vec3(0, 0, 1), playerAngle + 1.57f)); + //dot of sidevector positive = enemy is on the right side, dot sidevector negative = left side + auto playerSideVectorDot = glm::dot(playerSideVector, enemyPlayerVector); + if (playerSideVectorDot < 0) { + angleBetweenVectors = -angleBetweenVectors; + } + + //load & set the "2d" sprite + auto entityFile = ResourceManager::Load("Schema/Entities/DamageIndicator.xml"); + EntityFileParser parser(entityFile); + EntityID spriteID = parser.MergeEntities(m_World); + m_World->SetParent(spriteID, m_CurrentCamera); + auto spriteWrapper = EntityWrapper(m_World, spriteID); + //simply set the rotation z-wise to the angleBetweenVectors + spriteWrapper["Transform"]["Orientation"] = glm::vec3(0, 0, angleBetweenVectors); + + return true; +} + +bool DamageIndicatorSystem::OnSetCamera(const Events::SetCamera& e) { + m_CurrentCamera = e.CameraEntity.ID; + return true; +} diff --git a/src/Game/Systems/ExplosionEffectSystem.cpp b/src/Game/Systems/ExplosionEffectSystem.cpp new file mode 100644 index 00000000..2704d2da --- /dev/null +++ b/src/Game/Systems/ExplosionEffectSystem.cpp @@ -0,0 +1,14 @@ +#include "Systems/ExplosionEffectSystem.h" + +void ExplosionEffectSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) +{ + if ((double)component["TimeSinceDeath"] > (double)component["ExplosionDuration"]) { + (double)component["TimeSinceDeath"] = 0.f; + } + (double&)component["TimeSinceDeath"] += dt; + + //if ((bool)Component["Gravity"] == true) { + // (bool)Component["ExponentialAccelaration"] = false; + //} +} + diff --git a/src/Game/Systems/HealthSystem.cpp b/src/Game/Systems/HealthSystem.cpp index 9e118070..bb02ea13 100644 --- a/src/Game/Systems/HealthSystem.cpp +++ b/src/Game/Systems/HealthSystem.cpp @@ -1,7 +1,7 @@ #include "Systems/HealthSystem.h" -HealthSystem::HealthSystem(World* m_World, EventBroker* eventBroker) - : System(m_World, eventBroker) +HealthSystem::HealthSystem(SystemParams params) + : System(params) , PureSystem("Health") { //subscribe/listenTo playerdamage,healthpickup events (using the eventBroker) @@ -11,38 +11,6 @@ HealthSystem::HealthSystem(World* m_World, EventBroker* eventBroker) void HealthSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) { - //if entityID of health is 9 then the players ID is also 9 (player,health are connected to the same entity) - double maxHealth = (double)component["MaxHealth"]; - - //process the DeltaHealthVector and change the entitys health accordingly - for (size_t i = m_DeltaHealthVector.size(); i > 0; i--) - { - auto deltaHP = m_DeltaHealthVector[i - 1]; - //if we have a healthchange for the current player and health is greater than 0, then apply it - if (std::get<0>(deltaHP) == component.EntityID && (double)component["Health"] > 0.0f) { - //get the deltaHP value from the tuple and make sure you dont get more than maxHealth - double newHealth = std::min((double)component["Health"] + (double)std::get<1>(deltaHP), maxHealth); - component["Health"] = newHealth; - m_DeltaHealthVector.erase(m_DeltaHealthVector.begin() + i - 1); - //check if health is <= 0 - if ((double)component["Health"] <= 0.0f) { - component["Health"] = 0.0; - //publish death event - Events::PlayerDeath e; - e.PlayerID = component.EntityID; - m_EventBroker->Publish(e); - //clear the remaining hpDeltas for the dead player - for (size_t j = m_DeltaHealthVector.size(); j > 0; j--) - { - if (std::get<0>(m_DeltaHealthVector[j - 1]) == component.EntityID) - m_DeltaHealthVector.erase(m_DeltaHealthVector.begin() + j - 1); - } - //delete the player and break the loop - m_World->DeleteEntity(entity.ID); - break; - } - } - } } bool HealthSystem::OnPlayerDamaged(Events::PlayerDamage& e) @@ -50,18 +18,24 @@ bool HealthSystem::OnPlayerDamaged(Events::PlayerDamage& e) ComponentWrapper cHealth = e.Player["Health"]; double& health = cHealth["Health"]; health -= e.Damage; - + if (health <= 0.0) { - m_World->DeleteEntity(e.Player.ID); + Events::PlayerDeath ePlayerDeath; + ePlayerDeath.Player = e.Player; + m_EventBroker->Publish(ePlayerDeath); + //Note: we will delete the entity in PlayerDeathSystem } return true; } -bool HealthSystem::OnPlayerHealthPickup(const Events::PlayerHealthPickup& e) +bool HealthSystem::OnPlayerHealthPickup(Events::PlayerHealthPickup& e) { - //save the changed HP to a vector. it will be taken care of in UpdateComponent - m_DeltaHealthVector.push_back(std::make_tuple(e.PlayerHealedID, e.HealthAmount)); + ComponentWrapper cHealth = e.Player["Health"]; + double& health = cHealth["Health"]; + health += e.HealthAmount; + health = std::min(health, (double)cHealth["MaxHealth"]); + return true; } diff --git a/src/Game/Systems/InterpolationSystem.cpp b/src/Game/Systems/InterpolationSystem.cpp index f2de710d..430c01c1 100644 --- a/src/Game/Systems/InterpolationSystem.cpp +++ b/src/Game/Systems/InterpolationSystem.cpp @@ -1,84 +1,98 @@ #include "Systems/InterpolationSystem.h" -InterpolationSystem::InterpolationSystem(World* world, EventBroker* eventBroker) - : System(world, eventBroker) - , PureSystem("Transform") +InterpolationSystem::InterpolationSystem(SystemParams params) + : System(params) { ConfigFile* config = ResourceManager::Load("Config.ini"); m_SnapshotInterval = config->Get("Networking.SnapshotInterval", 0.05f); EVENT_SUBSCRIBE_MEMBER(m_EInterpolate, &InterpolationSystem::OnInterpolate); - EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &InterpolationSystem::OnPlayerSpawned); } -void InterpolationSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& transform, double dt) +void InterpolationSystem::Update(double dt) { - // Don't interpolate entities that might already have been removed - if (!entity.Valid()) { - return; + // Position + for (auto& kv : m_InterpolatePosition) { + EntityWrapper entity = kv.first; + if (!entity.Valid()) { + continue; + } + auto& iPosition = kv.second; + glm::vec3& position = iPosition.Component[iPosition.Field]; + + iPosition.Alpha += dt; + float alpha = glm::min(iPosition.Alpha / m_SnapshotInterval, 1.0); + position = iPosition.Start + ((iPosition.Goal - iPosition.Start) * alpha); } - if (m_NextTransform.find(transform.EntityID) != m_NextTransform.end()) { // Exists in map - m_NextTransform[transform.EntityID].interpolationTime += static_cast(dt); - Transform sTransform = m_NextTransform[transform.EntityID]; - float time = sTransform.interpolationTime; - if (time > m_SnapshotInterval) { - if (m_LastReceivedTransform.find(transform.EntityID) != m_LastReceivedTransform.end()) { - m_NextTransform[transform.EntityID] = m_LastReceivedTransform[transform.EntityID]; - m_NextTransform[transform.EntityID].interpolationTime = time - m_SnapshotInterval; - sTransform = m_NextTransform[transform.EntityID]; - m_LastReceivedTransform.erase(transform.EntityID); - } else { - m_NextTransform.erase(transform.EntityID); - } + // Orientation + for (auto& kv : m_InterpolateOrientation) { + EntityWrapper entity = kv.first; + if (!entity.Valid()) { + continue; } - if (transform.Info.Name == "Transform") { - bool isLocalPlayer = entity == m_LocalPlayer || entity.IsChildOf(m_LocalPlayer); - // Position - glm::vec3 nextPosition = sTransform.Position; - glm::vec3 currentPosition = static_cast(transform["Position"]); - // HACK: Don't force position for players - if (!isLocalPlayer) { - (glm::vec3&)transform["Position"] += vectorInterpolation(currentPosition, nextPosition, sTransform.interpolationTime); - } - // Orientation - // Don't force orientation for players - if (!isLocalPlayer) { - glm::quat nextOrientation = sTransform.Orientation; - glm::quat currentOrientation = glm::quat(static_cast(transform["Orientation"])); - (glm::vec3&)transform["Orientation"] = glm::eulerAngles(glm::slerp(currentOrientation, nextOrientation, sTransform.interpolationTime / m_SnapshotInterval)); - } - // Scale - glm::vec3 nextScale = sTransform.Scale; - glm::vec3 currentScale = static_cast(transform["Scale"]); - (glm::vec3&)transform["Scale"] += vectorInterpolation(currentScale, nextScale, sTransform.interpolationTime); + auto& iOrientation = kv.second; + glm::vec3& orientation = iOrientation.Component[iOrientation.Field]; + + iOrientation.Alpha += dt / m_SnapshotInterval; + iOrientation.Alpha = glm::min(iOrientation.Alpha, 1.0); + orientation = glm::eulerAngles(glm::slerp(iOrientation.Start, iOrientation.Goal, (float)iOrientation.Alpha)); + } + + // Velocity + for (auto& kv : m_InterpolateVelocity) { + EntityWrapper entity = kv.first; + if (!entity.Valid()) { + continue; } + auto& iVelocity = kv.second; + glm::vec3& position = iVelocity.Component[iVelocity.Field]; + + iVelocity.Alpha += dt; + float alpha = glm::min(iVelocity.Alpha / m_SnapshotInterval, 1.0); + position = iVelocity.Start + ((iVelocity.Goal - iVelocity.Start) * alpha); } } -bool InterpolationSystem::OnPlayerSpawned(Events::PlayerSpawned& e) +bool InterpolationSystem::OnInterpolate(Events::Interpolate& e) { - m_LocalPlayer = e.Player; + if (e.Component.Info.Name == "Transform") { + auto cTransform = e.Entity["Transform"]; + + // Position + Interpolation iPosition( + cTransform, + "Position", + cTransform["Position"], + e.Component["Position"] + ); + m_InterpolatePosition.erase(e.Entity); + m_InterpolatePosition.insert(std::make_pair(e.Entity, iPosition)); + + // Orientation + Interpolation iOrientation( + cTransform, + "Orientation", + glm::quat((glm::vec3&)cTransform["Orientation"]), + glm::quat((glm::vec3&)e.Component["Orientation"]) + ); + m_InterpolateOrientation.erase(e.Entity); + m_InterpolateOrientation.insert(std::make_pair(e.Entity, iOrientation)); + } else if (e.Component.Info.Name == "Physics") { + auto cPhysics = e.Entity["Physics"]; + if (!e.Entity.HasComponent("Player")) { + return false; + } + + // Velocity + Interpolation iVelocity( + cPhysics, + "Velocity", + cPhysics["Velocity"], + e.Component["Velocity"] + ); + m_InterpolateVelocity.erase(e.Entity); + m_InterpolateVelocity.insert(std::make_pair(e.Entity, iVelocity)); + } + return true; } - -bool InterpolationSystem::OnInterpolate(const Events::Interpolate & e) -{ - Transform transform; - int offset = 0; - // Read the data - memcpy(&transform.Position, e.DataArray.get() + offset, sizeof(glm::vec3)); - offset += sizeof(glm::vec3); - glm::vec3 tempOrientation; - memcpy(&tempOrientation, e.DataArray.get() + offset, sizeof(glm::vec3)); - transform.Orientation = glm::quat(tempOrientation); - offset += sizeof(glm::vec3); - memcpy(&transform.Scale, e.DataArray.get() + offset, sizeof(glm::vec3)); - transform.interpolationTime = 0.0f; - - if (m_NextTransform.find(e.Entity) != m_NextTransform.end()) { // Did exist - m_LastReceivedTransform[e.Entity] = transform; - } else { // Did not - m_NextTransform[e.Entity] = transform; - } - return false; -} diff --git a/src/Game/Systems/PickupSpawnSystem.cpp b/src/Game/Systems/PickupSpawnSystem.cpp new file mode 100644 index 00000000..159f716b --- /dev/null +++ b/src/Game/Systems/PickupSpawnSystem.cpp @@ -0,0 +1,66 @@ +#include "Systems/PickupSpawnSystem.h" + +PickupSpawnSystem::PickupSpawnSystem(SystemParams params) + : System(params) +{ + EVENT_SUBSCRIBE_MEMBER(m_ETriggerTouch, &PickupSpawnSystem::OnTriggerTouch); +} + +void PickupSpawnSystem::Update(double dt) +{ + for (auto it = m_ETriggerTouchVector.begin(); it != m_ETriggerTouchVector.end(); ++it) + { + auto& healthPickupPosition = *it; + //set the double timer value (value 3) + healthPickupPosition.DecreaseThisRespawnTimer -= dt; + if (healthPickupPosition.DecreaseThisRespawnTimer < 0) { + //spawn and delete the vector item + auto entityFile = ResourceManager::Load("Schema/Entities/HealthPickup.xml"); + EntityFileParser parser(entityFile); + EntityID healthPickupID = parser.MergeEntities(m_World); + + //let the world know a pickup has spawned (graphics effects, etc) + Events::PickupSpawned ePickupSpawned; + ePickupSpawned.Pickup = EntityWrapper(m_World, healthPickupID); + m_EventBroker->Publish(ePickupSpawned); + + //set values from the old entity to the new entity + auto& newHealthPickupEntity = EntityWrapper(m_World, healthPickupID); + newHealthPickupEntity["Transform"]["Position"] = healthPickupPosition.Pos; + newHealthPickupEntity["HealthPickup"]["HealthGain"] = healthPickupPosition.HealthGain; + newHealthPickupEntity["HealthPickup"]["RespawnTimer"] = healthPickupPosition.RespawnTimer; + + //erase the current element (healthPickupPosition) + m_ETriggerTouchVector.erase(it); + break; + } + } +} + + +bool PickupSpawnSystem::OnTriggerTouch(Events::TriggerTouch& e) +{ + if (!e.Trigger.HasComponent("HealthPickup")) { + return false; + } + double healthGiven = 0.01*(double)e.Trigger["HealthPickup"]["HealthGain"] * (double)e.Entity["Health"]["MaxHealth"]; + //cant pick up healthpacks if you are already at MaxHealth + if ((double)e.Entity["Health"]["Health"] >= (double)e.Entity["Health"]["MaxHealth"]) { + return false; + } + + //personEntered = e.Entity, thingEntered = e.Trigger + Events::PlayerHealthPickup ePlayerHealthPickup; + ePlayerHealthPickup.HealthAmount = healthGiven; + ePlayerHealthPickup.Player = e.Entity; + m_EventBroker->Publish(ePlayerHealthPickup); + + //copy position, healthgain, respawntimer (twice since one of the values will be counted down to 0, the other will be set in the new object) + //we need to copy all values since each value can be different for each healthPickup + m_ETriggerTouchVector.push_back({ (glm::vec3)e.Trigger["Transform"]["Position"] ,e.Trigger["HealthPickup"]["HealthGain"], + e.Trigger["HealthPickup"]["RespawnTimer"],e.Trigger["HealthPickup"]["RespawnTimer"] }); + + //delete the healthpickup + m_World->DeleteEntity(e.Trigger.ID); + return true; +} diff --git a/src/Game/Systems/PlayerDeathSystem.cpp b/src/Game/Systems/PlayerDeathSystem.cpp new file mode 100644 index 00000000..29ed9832 --- /dev/null +++ b/src/Game/Systems/PlayerDeathSystem.cpp @@ -0,0 +1,57 @@ +#include "Systems/PlayerDeathSystem.h" + +PlayerDeathSystem::PlayerDeathSystem(SystemParams params) + : System(params) +{ + EVENT_SUBSCRIBE_MEMBER(m_OnPlayerDeath, &PlayerDeathSystem::OnPlayerDeath); +} + +void PlayerDeathSystem::Update(double dt) +{ +} + +bool PlayerDeathSystem::OnPlayerDeath(Events::PlayerDeath& e) +{ + if (!e.Player.Valid()) { + return false; + } + + createDeathEffect(e.Player); + + // Delete player + m_World->DeleteEntity(e.Player.ID); + + return true; +} + +void PlayerDeathSystem::createDeathEffect(EntityWrapper player) +{ + //load the explosioneffect XML + auto deathEffect = ResourceManager::Load("Schema/Entities/PlayerDeathExplosionWithCamera.xml"); + EntityFileParser parser(deathEffect); + EntityID deathEffectID = parser.MergeEntities(m_World); + EntityWrapper deathEffectEW = EntityWrapper(m_World, deathEffectID); + + //components that we need from player + auto playerCamera = player.FirstChildByName("Camera"); + auto playerEntityModel = player.FirstChildByName("PlayerModel")["Model"]; + auto playerEntityAnimation = player.FirstChildByName("PlayerModel")["Animation"]; + + //copy the data from player to explisioneffectmodel + playerEntityModel.Copy(deathEffectEW["Model"]); + playerEntityAnimation.Copy(deathEffectEW["Animation"]); + //freeze the animation + deathEffectEW["Animation"]["Speed"] = 0.0; + + //copy the models position,orientation + deathEffectEW["Transform"]["Position"] = (glm::vec3)player["Transform"]["Position"]; + deathEffectEW["Transform"]["Orientation"] = (glm::vec3)player["Transform"]["Orientation"]; + //effect,camera is relative to playersPosition + //deathEffectEW["ExplosionEffect"]["ExplosionOrigin"] = glm::vec3(0, 0, 0); + + //camera (with lifetime) behind the player + auto cam = deathEffectEW.FirstChildByName("Camera"); + Events::SetCamera eSetCamera; + eSetCamera.CameraEntity = cam; + m_EventBroker->Publish(eSetCamera); +} diff --git a/src/Game/Systems/PlayerHUD.cpp b/src/Game/Systems/PlayerHUDSystem.cpp similarity index 85% rename from src/Game/Systems/PlayerHUD.cpp rename to src/Game/Systems/PlayerHUDSystem.cpp index 55d0c3f1..898d8bea 100644 --- a/src/Game/Systems/PlayerHUD.cpp +++ b/src/Game/Systems/PlayerHUDSystem.cpp @@ -1,21 +1,6 @@ -#include "Game/Systems/PlayerHUD.h" +#include "Game/Systems/PlayerHUDSystem.h" -PlayerHUD::PlayerHUD(World* world, EventBroker* eventBrokerer) - :System(world, eventBrokerer) - , m_World(world) - , m_EventBroker(eventBrokerer) -{ - - -} - -PlayerHUD::~PlayerHUD() -{ - - -} - -void PlayerHUD::Update(double dt) +void PlayerHUDSystem::Update(double dt) { auto healthHUDs = m_World->GetComponents("HealthHUD"); if (healthHUDs == nullptr) { diff --git a/src/Game/Systems/PlayerMovementSystem.cpp b/src/Game/Systems/PlayerMovementSystem.cpp index 3224f579..93f0cd3d 100644 --- a/src/Game/Systems/PlayerMovementSystem.cpp +++ b/src/Game/Systems/PlayerMovementSystem.cpp @@ -1,8 +1,7 @@ #include "Systems/PlayerMovementSystem.h" -PlayerMovementSystem::PlayerMovementSystem(World* world, EventBroker* eventBroker) - : System(world, eventBroker) - , PureSystem("Player") +PlayerMovementSystem::PlayerMovementSystem(SystemParams params) + : System(params) { EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &PlayerMovementSystem::OnPlayerSpawned); } @@ -15,6 +14,12 @@ PlayerMovementSystem::~PlayerMovementSystem() } void PlayerMovementSystem::Update(double dt) +{ + updateMovementControllers(dt); + updateVelocity(dt); +} + +void PlayerMovementSystem::updateMovementControllers(double dt) { for (auto& kv : m_PlayerInputControllers) { EntityWrapper player = kv.first; @@ -24,12 +29,20 @@ void PlayerMovementSystem::Update(double dt) continue; } + // Aim pitch EntityWrapper cameraEntity = player.FirstChildByName("Camera"); if (cameraEntity.Valid()) { glm::vec3& cameraOrientation = cameraEntity["Transform"]["Orientation"]; cameraOrientation.x += controller->Rotation().x; // Limit camera pitch so we don't break our necks cameraOrientation.x = glm::clamp(cameraOrientation.x, -glm::half_pi(), glm::half_pi()); + // Set third person model aim pitch + EntityWrapper playerModel = player.FirstChildByName("PlayerModel"); + if (playerModel.Valid()) { + ComponentWrapper cAnimationOffset = playerModel["AnimationOffset"]; + double time = (cameraOrientation.x + glm::half_pi()) / glm::pi(); + cAnimationOffset["Time"] = time; + } } ComponentWrapper& cTransform = player["Transform"]; @@ -56,12 +69,20 @@ void PlayerMovementSystem::Update(double dt) } else { wishSpeed = playerMovementSpeed; } + if (player.ID == m_LocalPlayer.ID) { + if (glm::length(wishDirection) == 0) { + // If no key is pressed, reset the distance moved since last step. + m_DistanceMoved = 0; + } + } glm::vec3& velocity = cPhysics["Velocity"]; - ImGui::Text("velocity: (%f, %f, %f)", velocity.x, velocity.y, velocity.z); + bool isOnGround = (bool)cPhysics["IsOnGround"]; + ImGui::Text(isOnGround ? "On ground" : "In air"); + ImGui::Text("velocity: (%f, %f, %f) |%f|", velocity.x, velocity.y, velocity.z, glm::length(velocity)); glm::vec3 groundVelocity(0.f, 0.f, 0.f); - groundVelocity.x = glm::dot(velocity, glm::vec3(1.f, 0.f, 0.f)); - groundVelocity.z = glm::dot(velocity, glm::vec3(0.f, 0.f, 1.f)); - ImGui::Text("groundVelocity: (%f, %f, %f) |%f|", groundVelocity.x, groundVelocity.y, groundVelocity.z, glm::length(wishDirection)); + groundVelocity.x = velocity.x; + groundVelocity.z = velocity.z; + ImGui::Text("groundVelocity: (%f, %f, %f) |%f|", groundVelocity.x, groundVelocity.y, groundVelocity.z, glm::length(groundVelocity)); ImGui::Text("wishDirection: (%f, %f, %f) |%f|", wishDirection.x, wishDirection.y, wishDirection.z, glm::length(wishDirection)); float currentSpeedProj = glm::dot(groundVelocity, wishDirection); float addSpeed = wishSpeed - currentSpeedProj; @@ -74,7 +95,7 @@ void PlayerMovementSystem::Update(double dt) ImGui::InputFloat("accel", &accel); static float airAccel = 0.5f; ImGui::InputFloat("airAccel", &airAccel); - float actualAccel = (velocity.y != 0) ? airAccel : accel; + float actualAccel = isOnGround ? accel : airAccel; static float surfaceFriction = 5.f; ImGui::InputFloat("surfaceFriction", &surfaceFriction); float accelerationSpeed = actualAccel * (float)dt * wishSpeed * surfaceFriction; @@ -86,13 +107,22 @@ void PlayerMovementSystem::Update(double dt) } //you cant jump and dash at the same time - since there is no friction in the air and we would thus dash much further in the air - if (!controller->PlayerIsDashing() && controller->Jumping() && !controller->Crouching() && (velocity.y == 0.f || !controller->DoubleJumping())) { - if (velocity.y == 0.f) { + if (!controller->PlayerIsDashing() && controller->Jumping() && !controller->Crouching() && (isOnGround || !controller->DoubleJumping())) { + (bool)cPhysics["IsOnGround"] = false; + if (isOnGround) { controller->SetDoubleJumping(false); } else { + //put a hexagon at the players feet + auto hexagonEffect = ResourceManager::Load("Schema/Entities/DoubleJumpHexagon.xml"); + EntityFileParser parser(hexagonEffect); + EntityID hexagonEffectID = parser.MergeEntities(m_World); + EntityWrapper hexagonEW = EntityWrapper(m_World, hexagonEffectID); + hexagonEW["Transform"]["Position"] = (glm::vec3)player["Transform"]["Position"]; controller->SetDoubleJumping(true); + Events::DoubleJump e; + m_EventBroker->Publish(e); } - velocity.y += 4.f; + velocity.y = 4.f; } if (player.HasComponent("AABB")) { @@ -108,24 +138,74 @@ void PlayerMovementSystem::Update(double dt) EntityWrapper playerModel = player.FirstChildByName("PlayerModel"); if (playerModel.Valid()) { ComponentWrapper cAnimation = playerModel["Animation"]; + std::string& animationName1 = cAnimation["AnimationName1"]; + std::string& animationName2 = cAnimation["AnimationName2"]; + double& animationTime1 = cAnimation["Time1"]; + double& animationTime2 = cAnimation["Time2"]; + double& animationSpeed1 = cAnimation["Speed1"]; + double& animationSpeed2 = cAnimation["Speed2"]; + double& animationWeight1 = cAnimation["Weight1"]; + double& animationWeight2 = cAnimation["Weight2"]; float movementLength = glm::length(groundVelocity); //TODO: add assault dash animation here if (glm::length(controller->Movement()) > 0.f) { - if (controller->Crouching()) { - cAnimation["Name"] = "Crouch Walk"; - (double&)cAnimation["Speed"] = 1.f * -glm::sign(controller->Movement().z); + double forwardMovement = controller->Movement().z; + double strafeMovement = controller->Movement().x; + + if (controller->Crouching() && animationName1 != "CrouchWalk") { + animationName1 = "CrouchWalk"; + animationSpeed1 = 1.0 * -glm::sign(controller->Movement().z); } else { - cAnimation["Name"] = "Run"; - (double&)cAnimation["Speed"] = 2.f * -glm::sign(controller->Movement().z); + if (glm::abs(forwardMovement) > 0) { + if (animationName1 != "Run") { + animationName1 = "Run"; + if (animationName2 == "StrafeLeft" || animationName2 == "StrafeRight") { + animationTime1 = animationTime2; + } else { + animationTime1 = 0.0; + } + } + animationSpeed1 = 2.f * -glm::sign(forwardMovement); + } + + if (glm::abs(strafeMovement) > 0) { + if (animationName2 != "StrafeLeft" && animationName2 != "StrafeRight") { + if (strafeMovement < 0) { + animationName2 = "StrafeLeft"; + } + if (strafeMovement > 0) { + animationName2 = "StrafeRight"; + } + if (animationName1 == "Run") { + animationTime2 = animationTime1; + } else { + animationTime2 = 0.0; + } + } + animationSpeed2 = 2.f * glm::abs(strafeMovement); + } + + double strafeWeight = glm::abs(strafeMovement) / (glm::abs(forwardMovement) + glm::abs(strafeMovement)); + animationWeight2 = strafeWeight; + animationWeight1 = 1.0 - strafeWeight; } } else { if (controller->Crouching()) { - cAnimation["Name"] = "Crouch"; - (double&)cAnimation["Speed"] = 1.f; + animationName1 = "Crouch"; + animationName2 = ""; + animationSpeed1 = 1.0; + animationSpeed2 = 0.0; + animationWeight1 = 1.0; + animationWeight2 = 0.0; } else { - cAnimation["Name"] = "Hold Pos"; - (double&)cAnimation["Speed"] = 1.f; + animationName1 = "Idle"; + animationName2 = ""; + animationSpeed1 = 1.f; + animationSpeed2 = 0.0; + animationWeight1 = 1.0; + animationWeight2 = 0.0; + //cAnimation["AnimationName2"] = "Idle"; } } } @@ -133,17 +213,21 @@ void PlayerMovementSystem::Update(double dt) controller->Reset(); } + playerStep(dt); } -void PlayerMovementSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) + +void PlayerMovementSystem::updateVelocity(double dt) { - ComponentWrapper& cTransform = entity["Transform"]; - if (!entity.HasComponent("Physics")) { + // Only apply velocity to local player + if (!LocalPlayer.Valid()) { return; } - ComponentWrapper& cPhysics = entity["Physics"]; + ComponentWrapper& cTransform = LocalPlayer["Transform"]; + ComponentWrapper& cPhysics = LocalPlayer["Physics"]; glm::vec3& velocity = cPhysics["Velocity"]; + bool isOnGround = (bool)cPhysics["IsOnGround"]; // Ground friction float speed = glm::length(velocity); @@ -151,7 +235,7 @@ void PlayerMovementSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapp ImGui::InputFloat("groundFriction", &groundFriction); static float airFriction = 0.f; ImGui::InputFloat("airFriction", &airFriction); - float friction = (velocity.y != 0) ? airFriction : groundFriction; + float friction = isOnGround ? groundFriction : airFriction; if (speed > 0) { float drop = speed * friction * (float)dt; float multiplier = glm::max(speed - drop, 0.f) / speed; @@ -159,6 +243,7 @@ void PlayerMovementSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapp velocity.z *= multiplier; } + // Gravity if (cPhysics["Gravity"]) { velocity.y -= 9.82f * (float)dt; } @@ -167,10 +252,37 @@ void PlayerMovementSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapp position += velocity * (float)dt; } +void PlayerMovementSystem::playerStep(double dt) +{ + if (!m_LocalPlayer.Valid()) { + return; + } + // Position of the local player, used see how far a player has moved. + glm::vec3 pos = (glm::vec3)m_World->GetComponent(m_LocalPlayer.ID, "Transform")["Position"]; + // Used to see if a player is airborne. + bool grounded = (bool)m_World->GetComponent(m_LocalPlayer.ID, "Physics")["IsOnGround"]; + m_DistanceMoved += glm::length(pos - m_LastPosition); + // Set the last position for next iteration + m_LastPosition = pos; + if (m_DistanceMoved > m_PlayerStepLength && grounded) { + // Player moved a step's distance + // Create footstep sound + Events::PlaySoundOnEntity e; + e.EmitterID = m_LocalPlayer.ID; + e.FilePath = m_LeftFoot ? "Audio/footstep/footstep2.wav" : "Audio/footstep/footstep3.wav"; + m_LeftFoot = !m_LeftFoot; + m_EventBroker->Publish(e); + m_DistanceMoved = 0.f; + } +} + bool PlayerMovementSystem::OnPlayerSpawned(Events::PlayerSpawned& e) { // When a player spawns, create an input controller for them m_PlayerInputControllers[e.Player] = new FirstPersonInputController(m_EventBroker, e.PlayerID); - + if (e.PlayerID == -1) { + // Keep track of the local player + m_LocalPlayer = e.Player; + } return true; } diff --git a/src/Game/Systems/PlayerSpawnSystem.cpp b/src/Game/Systems/PlayerSpawnSystem.cpp index 7db6e8ff..507ed0f5 100644 --- a/src/Game/Systems/PlayerSpawnSystem.cpp +++ b/src/Game/Systems/PlayerSpawnSystem.cpp @@ -1,7 +1,7 @@ #include "Systems/PlayerSpawnSystem.h" -PlayerSpawnSystem::PlayerSpawnSystem(World* m_World, EventBroker* eventBroker) - : System(m_World, eventBroker) +PlayerSpawnSystem::PlayerSpawnSystem(SystemParams params) + : System(params) { EVENT_SUBSCRIBE_MEMBER(m_OnInputCommand, &PlayerSpawnSystem::OnInputCommand); EVENT_SUBSCRIBE_MEMBER(m_OnPlayerSpawnerd, &PlayerSpawnSystem::OnPlayerSpawned); @@ -71,11 +71,16 @@ bool PlayerSpawnSystem::OnInputCommand(const Events::InputCommand& e) bool PlayerSpawnSystem::OnPlayerSpawned(Events::PlayerSpawned& e) { // When a player is actually spawned (since the actual spawning is handled on the server) + if (!IsClient) { + return false; + } // Check if a player already exists if (m_PlayerEntities.count(e.PlayerID) != 0) { // TODO: Disallow infinite respawning here - m_World->DeleteEntity(m_PlayerEntities[e.PlayerID].ID); + if (m_PlayerEntities[e.PlayerID].Valid()) { + m_World->DeleteEntity(m_PlayerEntities[e.PlayerID].ID); + } } // Store the player for future reference diff --git a/src/Game/Systems/SoundSystem.cpp b/src/Game/Systems/SoundSystem.cpp new file mode 100644 index 00000000..10dc61f7 --- /dev/null +++ b/src/Game/Systems/SoundSystem.cpp @@ -0,0 +1,180 @@ +#include "Game/Systems/SoundSystem.h" + +SoundSystem::SoundSystem(SystemParams params) + : System(params) + , PureSystem("SoundEmitter") +{ + ConfigFile* config = ResourceManager::Load("Config.ini"); + m_Announcer = ResourceManager::Load("Config.ini")->Get("Sound.Announcer", "female"); + EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &SoundSystem::OnPlayerSpawned); + EVENT_SUBSCRIBE_MEMBER(m_InputCommand, &SoundSystem::OnInputCommand); + EVENT_SUBSCRIBE_MEMBER(m_EDoubleJump, &SoundSystem::OnDoubleJump); + EVENT_SUBSCRIBE_MEMBER(m_EDashAbility, &SoundSystem::OnDashAbility); + EVENT_SUBSCRIBE_MEMBER(m_EPlayerDamage, &SoundSystem::OnPlayerDamage); + EVENT_SUBSCRIBE_MEMBER(m_ECaptured, &SoundSystem::OnCaptured); + EVENT_SUBSCRIBE_MEMBER(m_ETriggerTouch, &SoundSystem::OnTriggerTouch); +} + +void SoundSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& cComponent, double dt) +{ } + +void SoundSystem::Update(double dt) +{ + // Temp for play test. + if (m_DrumsIsPlaying) { + m_DrumsIsPlaying = !drumTimer(dt); + } +} + +bool SoundSystem::OnPlayerSpawned(const Events::PlayerSpawned &e) +{ + if (e.PlayerID == -1) { // Local player + m_World->AttachComponent(e.Player.ID, "Listener"); + Events::PlaySoundOnEntity go; + go.EmitterID = LocalPlayer.ID; + go.FilePath = "Audio/announcer/" + m_Announcer + "/go.wav"; + m_EventBroker->Publish(go); + // TEMP: starts bgm + { + Events::PlayBackgroundMusic ev; + ev.FilePath = "Audio/bgm/ambient.wav"; + m_EventBroker->Publish(ev); + } + } + return true; +} + +bool SoundSystem::OnInputCommand(const Events::InputCommand & e) +{ + if (e.Command == "Jump" && e.Value > 0) { + if (e.PlayerID == -1) { // local player + playerJumps(); + return true; + } + } + if (e.Command == "TakeDamage" && e.Value > 0) { + Events::PlayerDamage ev; + ev.Player = LocalPlayer; + ev.Damage = 1.0; + m_EventBroker->Publish(ev); + } + + return false; +} + +void SoundSystem::playerJumps() +{ + if (!LocalPlayer.Valid()) { + return; + } + + bool grounded = (bool)m_World->GetComponent(LocalPlayer.ID, "Physics")["IsOnGround"]; + if (grounded) { + Events::PlaySoundOnEntity e; + e.EmitterID = LocalPlayer.ID; + e.FilePath = "Audio/jump/jump1.wav"; + m_EventBroker->Publish(e); + } +} + +bool SoundSystem::drumTimer(double dt) +{ + m_DrumTimer += dt; + if (m_DrumTimer > 15) { + m_DrumTimer = 0.0; + return true; + } else { + return false; + } +} + +bool SoundSystem::OnCaptured(const Events::Captured & e) +{ + int homeTeam = (int)m_World->GetComponent(e.CapturePointID, "Team")["Team"]; + int team = (int)m_World->GetComponent(LocalPlayer.ID, "Team")["Team"]; + Events::PlaySoundOnEntity ev; + if (team == homeTeam) { + ev.FilePath = "Audio/announcer/" + m_Announcer + "/objective_achieved.wav"; + } else { + ev.FilePath = "Audio/announcer/" + m_Announcer + "/objective_failed.wav"; // have not been tested + } + ev.EmitterID = LocalPlayer.ID; + m_EventBroker->Publish(ev); + // Temp for play test. + m_DrumsIsPlaying = false; + return false; +} + +// Testing purposes atm... +bool SoundSystem::OnPlayerDamage(const Events::PlayerDamage & e) +{ + // Should check for only local players here... + std::uniform_int_distribution dist(1, 12); + int rand = dist(generator); + std::vector paths; + paths.push_back("Audio/hurt/hurt" + std::to_string(rand) + ".wav"); + + // // Breathe + // int ammountOfbreaths = (static_cast(e.Damage) / 10) + 2; // TEMP: Idk something stupid like this shit + // for (int i = 0; i < ammountOfbreaths; i++) { + // paths.push_back("Audio/exhausted/breath.wav"); + // } + Events::PlayQueueOnEntity ev; + ev.Emitter = LocalPlayer; + ev.FilePaths = paths; + m_EventBroker->Publish(ev); + return false; +} + +bool SoundSystem::OnPlayerDeath(const Events::PlayerDeath & e) +{ + Events::PlaySoundOnEntity ev; + ev.EmitterID = LocalPlayer.ID; + ev.FilePath = "Audio/die/die2.wav"; + m_EventBroker->Publish(ev); + return false; +} + +bool SoundSystem::OnPlayerHealthPickup(const Events::PlayerHealthPickup & e) +{ + Events::PlaySoundOnEntity ev; + ev.EmitterID = LocalPlayer.ID; + ev.FilePath = "Audio/pickup/pickup2.wav"; + m_EventBroker->Publish(ev); + return false; +} + +bool SoundSystem::OnTriggerTouch(const Events::TriggerTouch & e) +{ + // Temp for play test. + if (m_DrumsIsPlaying) { + return false; + } + if (m_World->HasComponent(e.Trigger.ID, "CapturePoint")) { + Events::PlaySoundOnEntity ev; // should be BGM + ev.EmitterID = LocalPlayer.ID; + ev.FilePath = "Audio/bgm/drumstest.wav"; + m_EventBroker->Publish(ev); + // Temp for play test. + m_DrumsIsPlaying = true; + } + return false; +} + +bool SoundSystem::OnDoubleJump(const Events::DoubleJump & e) +{ + Events::PlaySoundOnEntity ev; + ev.EmitterID = LocalPlayer.ID; + ev.FilePath = "Audio/jump/jump2.wav"; + m_EventBroker->Publish(ev); + return false; +} + +bool SoundSystem::OnDashAbility(const Events::DashAbility &e) +{ + Events::PlaySoundOnEntity ev; + ev.EmitterID = LocalPlayer.ID; + ev.FilePath = "Audio/jump/dash1.wav"; + m_EventBroker->Publish(ev); + return false; +} \ No newline at end of file diff --git a/src/Game/Systems/SpawnerSystem.cpp b/src/Game/Systems/SpawnerSystem.cpp index 7a0a13c9..99f5df93 100644 --- a/src/Game/Systems/SpawnerSystem.cpp +++ b/src/Game/Systems/SpawnerSystem.cpp @@ -1,7 +1,7 @@ #include "Systems/SpawnerSystem.h" -SpawnerSystem::SpawnerSystem(World* world, EventBroker* eventBroker) - : System(world, eventBroker) +SpawnerSystem::SpawnerSystem(SystemParams params) + : System(params) { EVENT_SUBSCRIBE_MEMBER(m_OnSpawnerSpawn, &SpawnerSystem::OnSpawnerSpawn); } @@ -51,7 +51,7 @@ EntityWrapper SpawnerSystem::Spawn(EntityWrapper spawner, EntityWrapper parent / // Set its position and orientation to that of the SpawnPoint spawnedEntity["Transform"]["Position"] = Transform::AbsolutePosition(spawnPoint.World, spawnPoint.ID); // TODO: Quaternions, bitch - //spawnedEntity["Transform"]["Orientation"] = glm::eulerAngles(Transform::AbsoluteOrientation(spawnPoint.World, spawnPoint.ID)); + spawnedEntity["Transform"]["Orientation"] = glm::eulerAngles(Transform::AbsoluteOrientation(spawnPoint)); return spawnedEntity; } diff --git a/src/Game/Systems/WeaponSystem.cpp b/src/Game/Systems/WeaponSystem.cpp index 1613cb7a..8b6ba85b 100644 --- a/src/Game/Systems/WeaponSystem.cpp +++ b/src/Game/Systems/WeaponSystem.cpp @@ -1,13 +1,15 @@ #include "Systems/WeaponSystem.h" -WeaponSystem::WeaponSystem(World* world, EventBroker* eventBroker, IRenderer* renderer) - : System(world, eventBroker) - , ImpureSystem() +WeaponSystem::WeaponSystem(SystemParams params, IRenderer* renderer, Octree* collisionOctree) + : System(params) + , PureSystem("Player") + , m_SystemParams(params) , m_Renderer(renderer) + , m_CollisionOctree(collisionOctree) { - EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &WeaponSystem::OnPlayerSpawned); EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &WeaponSystem::OnInputCommand); EVENT_SUBSCRIBE_MEMBER(m_EShoot, &WeaponSystem::OnShoot); + EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &WeaponSystem::OnPlayerSpawned); } void WeaponSystem::Update(double dt) @@ -15,90 +17,84 @@ void WeaponSystem::Update(double dt) } -bool WeaponSystem::OnPlayerSpawned(const Events::PlayerSpawned& e) +void WeaponSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& cPlayer, double dt) { + // Update potential weapon behaviour for player + auto it = m_ActiveWeapons.find(entity); + if (it == m_ActiveWeapons.end()) { + selectWeapon(entity, 1); + } + + m_ActiveWeapons.at(entity)->Update(dt); +} + +bool WeaponSystem::OnInputCommand(Events::InputCommand& e) +{ + EntityWrapper player = e.Player; if (e.PlayerID == -1) { - m_LocalPlayer = e.Player; + player = LocalPlayer; } - return true; -} -bool WeaponSystem::OnInputCommand(const Events::InputCommand& e) -{ - // Only shoot client-side! - if (e.PlayerID != -1) { + // Make sure player is alive + if (!player.Valid()) { return false; } - // Only shoot if the player is alive - if (!m_LocalPlayer.Valid()) { - return false; - } - - if (e.Command == "PrimaryFire" && e.Value > 0) { - Events::Shoot eShoot; - if (e.PlayerID == -1) { - eShoot.Player = m_LocalPlayer; - } else { - eShoot.Player = e.Player; + // Weapon selection + if (e.Command == "SelectWeapon") { + if (e.Value != 0) { + //selectWeapon(player, static_cast(e.Value)); + } + } + + // Fire + if (e.Command == "PrimaryFire") { + if (m_ActiveWeapons.find(player) != m_ActiveWeapons.end()) { + auto weapon = m_ActiveWeapons.at(player); + if (e.Value > 0) { + weapon->Fire(); + } else { + weapon->CeaseFire(); + } } - m_EventBroker->Publish(eShoot); } return true; } -bool WeaponSystem::OnShoot(Events::Shoot& eShoot) +void WeaponSystem::selectWeapon(EntityWrapper player, ComponentInfo::EnumType slot) +{ + // Primary + if (slot == 1) { + // TODO: if class... + if (m_ActiveWeapons.count(player) == 0) { + m_ActiveWeapons.insert(std::make_pair(player, std::make_shared(m_SystemParams, m_CollisionOctree, player))); + } else { + //m_ActiveWeapons.erase(player); + } + } + + // Secondary + if (slot == 2) { + //m_ActiveWeapons[player] = std::make_shared(); + } +} + +bool WeaponSystem::OnPlayerSpawned(Events::PlayerSpawned& e) +{ + // Select primary weapon on player spawn + // TODO: Select the active one specified by player component + return true; +} + +bool WeaponSystem::OnShoot(Events::Shoot& eShoot) { if (!eShoot.Player.Valid()) { return false; } - // TODO: Weapon firing effects here - - auto rayRed = ResourceManager::Load("Schema/Entities/RayRed.xml"); - auto rayBlue = ResourceManager::Load("Schema/Entities/RayBlue.xml"); - - EntityWrapper weapon = eShoot.Player.FirstChildByName("WeaponMuzzle"); - if (weapon.Valid()) { - EntityWrapper ray; - if ((ComponentInfo::EnumType)eShoot.Player["Team"]["Team"] == eShoot.Player["Team"]["Team"].Enum("Red")) { - EntityFileParser parser(rayRed); - EntityID rayID = parser.MergeEntities(m_World); - ray = EntityWrapper(m_World, rayID); - } else { - EntityFileParser parser(rayBlue); - EntityID rayID = parser.MergeEntities(m_World); - ray = EntityWrapper(m_World, rayID); - } - - glm::mat4 transformation = Transform::AbsoluteTransformation(weapon); - glm::vec3 scale; - glm::vec3 translation; - glm::quat orientation; - glm::vec3 skew; - glm::vec4 perspective; - glm::decompose(transformation, scale, orientation, translation, skew, perspective); - - // Matrix to euler angles - glm::vec3 euler; - euler.y = glm::asin(-transformation[0][2]); - if (cos(euler.y) != 0) { - euler.x = atan2(transformation[1][2], transformation[2][2]); - euler.z = atan2(transformation[0][1], transformation[0][0]); - } else { - euler.x = atan2(-transformation[2][0], transformation[1][1]); - euler.z = 0; - } - - //LOG_DEBUG("rotation: %f %f %f", euler.x, euler.y, euler.z); - (glm::vec3&)ray["Transform"]["Position"] = translation; - (glm::vec3&)ray["Transform"]["Orientation"] = euler; - //(glm::vec3&)ray["Transform"]["Orientation"] = Transform::AbsoluteOrientationEuler(weapon); - } - - // Only run further picking code client-side! - if (eShoot.Player != m_LocalPlayer) { + // Only run further picking code for the local player! + if (eShoot.Player != LocalPlayer) { return false; } @@ -134,8 +130,9 @@ bool WeaponSystem::OnShoot(Events::Shoot& eShoot) // TODO: Weapon damage calculations etc Events::PlayerDamage ePlayerDamage; ePlayerDamage.Player = player; + ePlayerDamage.PlayerShooter = eShoot.Player; ePlayerDamage.Damage = 100; m_EventBroker->Publish(ePlayerDamage); return true; -} +} \ No newline at end of file diff --git a/src/Tests/CapturePointTest.cpp b/src/Tests/CapturePointTest.cpp index ffb01030..2c7bf430 100644 --- a/src/Tests/CapturePointTest.cpp +++ b/src/Tests/CapturePointTest.cpp @@ -255,14 +255,14 @@ void CapturePointTest::TestSetup8() } void CapturePointTest::DoTouchEvent(EntityID whoDidSomething, EntityID onWhatObject) { Events::TriggerTouch touchEvent; - touchEvent.Entity = whoDidSomething; - touchEvent.Trigger = onWhatObject; + touchEvent.Entity = EntityWrapper(m_World, whoDidSomething); + touchEvent.Trigger = EntityWrapper(m_World, onWhatObject); m_EventBroker->Publish(touchEvent); } void CapturePointTest::DoLeaveEvent(EntityID whoDidSomething, EntityID onWhatObject) { Events::TriggerLeave leaveEvent; - leaveEvent.Entity = whoDidSomething; - leaveEvent.Trigger = onWhatObject; + leaveEvent.Entity = EntityWrapper(m_World, whoDidSomething); + leaveEvent.Trigger = EntityWrapper(m_World, onWhatObject); m_EventBroker->Publish(leaveEvent); } void CapturePointTest::TestSuccess1() { diff --git a/src/Tests/CollisionTest.cpp b/src/Tests/CollisionTest.cpp index 67b6ce19..6cb6c88b 100644 --- a/src/Tests/CollisionTest.cpp +++ b/src/Tests/CollisionTest.cpp @@ -29,7 +29,7 @@ void RayTest(std::string fileName) { Ray ray(glm::vec3(-50, 0, 0), glm::vec3(1, 0, 0)); //using a - here, else we have to init the renderingsystem + //here, else we have to init the renderingsystem ResourceManager::RegisterType("RawModel"); auto unitBox = ResourceManager::Load(fileName); BOOST_REQUIRE(unitBox != nullptr); diff --git a/src/Tests/HealthSystemTest.cpp b/src/Tests/HealthSystemTest.cpp index bdd9ba4b..36608f8f 100644 --- a/src/Tests/HealthSystemTest.cpp +++ b/src/Tests/HealthSystemTest.cpp @@ -48,42 +48,38 @@ GameHealthSystemTest::GameHealthSystemTest() fp.MergeEntities(m_World); // Create system pipeline - m_SystemPipeline = new SystemPipeline(m_World,m_EventBroker); + m_SystemPipeline = new SystemPipeline(m_World, m_EventBroker); m_SystemPipeline->AddSystem(0); //The Test //create entity which has transform,player,model,health in it. i.e. is a player EntityID playerID = m_World->CreateEntity(); - ComponentWrapper transform = m_World->AttachComponent(playerID, "Transform"); - ComponentWrapper model = m_World->AttachComponent(playerID, "Model"); - model["Resource"] = "Models/Core/UnitSphere.mesh"; // 360NoScope UnitSphere ComponentWrapper player = m_World->AttachComponent(playerID, "Player"); ComponentWrapper health = m_World->AttachComponent(playerID, "Health"); healthsID = playerID; - double currentHealth = (double)m_World->GetComponent(healthsID, "Health")["Health"]; + + EntityID playerID2 = m_World->CreateEntity(); + ComponentWrapper player2 = m_World->AttachComponent(playerID2, "Player"); + ComponentWrapper health2 = m_World->AttachComponent(playerID2, "Health"); //heal player with 40 Events::PlayerHealthPickup e3; e3.HealthAmount = 40.0f; - e3.PlayerHealedID = healthsID; + e3.Player = EntityWrapper(m_World, player.EntityID); m_EventBroker->Publish(e3); + //damage player with 50 Events::PlayerDamage e; - e.DamageAmount = 50.0f; - e.PlayerDamagedID = healthsID; + e.Damage = 50.0f; + e.Player = EntityWrapper(m_World, player.EntityID); m_EventBroker->Publish(e); + //heal some other player with 40 Events::PlayerHealthPickup e2; e2.HealthAmount = 40.0f; - e2.PlayerHealedID = healthsID + 1; + e2.Player = EntityWrapper(m_World, player2.EntityID); m_EventBroker->Publish(e2); - EntityID playerID2 = m_World->CreateEntity(); - ComponentWrapper transform2 = m_World->AttachComponent(playerID2, "Transform"); - ComponentWrapper model2 = m_World->AttachComponent(playerID2, "Model"); - model2["Resource"] = "Models/Core/UnitSphere.mesh"; // 360NoScope UnitSphere - ComponentWrapper player2 = m_World->AttachComponent(playerID2, "Player"); - ComponentWrapper health2 = m_World->AttachComponent(playerID2, "Health"); //END TEST } diff --git a/tools/MayaExporter/MayaExporter/Export.cpp b/tools/MayaExporter/MayaExporter/Export.cpp index d8f1abd4..3497fd04 100644 --- a/tools/MayaExporter/MayaExporter/Export.cpp +++ b/tools/MayaExporter/MayaExporter/Export.cpp @@ -47,13 +47,24 @@ bool Export::Meshes(std::string pathName, bool selectedOnly) for (unsigned int i = 0; i < connections.length(); i++) { if (connections[i].node().apiType() == MFn::kSkinClusterFilter) { - MGlobal::select(shape.parent(i), MGlobal::kReplaceList); - MGlobal::displayInfo(MString() + "Moving " + thisNode.name() + " to bindPose."); + shape.parent(0, &status); + if (status != MS::kSuccess) { + MGlobal::displayError(MString() + "shape.parent(0, &status) failed with: " + status.errorString()); + } + status = MGlobal::select(shape.parent(0), MGlobal::kReplaceList); + if (status != MS::kSuccess) { + MGlobal::displayError(MString() + "Parent to " + thisNode.name() + " failed"); + } + + MFnDependencyNode tmp(shape.parent(0)); + MGlobal::displayInfo(MString() + "Moving " + tmp.name() + " to bindPose."); + status = MGlobal::executeCommand("GoToBindPose;"); if (status != MS::kSuccess) { MGlobal::displayError(MString() + "GoToBindPose: " + status.errorString()); } - MGlobal::displayInfo(MString() + "Has moved " + thisNode.name() + " to bindPose."); + + MGlobal::displayInfo(MString() + "Has moved " + tmp.name() + " to bindPose."); } } } @@ -109,6 +120,8 @@ bool Export::Materials(std::string pathName) bool Export::Animations(std::string pathName, std::vector animInfo) { + allAnimations.clear(); + allBindPoses.clear(); if (MAnimControl::currentTime().unit() != MTime::kNTSCField) { MGlobal::displayError(MString() + "Please change to 60 FPS under Preferences/Settings!"); diff --git a/tools/MayaExporter/MayaExporter/Material.cpp b/tools/MayaExporter/MayaExporter/Material.cpp index 03521231..a5717aa6 100644 --- a/tools/MayaExporter/MayaExporter/Material.cpp +++ b/tools/MayaExporter/MayaExporter/Material.cpp @@ -82,16 +82,36 @@ bool Material::findColorTexture(MaterialNode& material_node, MFnDependencyNode& workspace); FullPath = FullPath.substr(workspace.length()); FullPath = FullPath.substr(FullPath.find_first_of("/") + 1); - material_node.ColorMapFile = FullPath.erase(FullPath.find_last_of("."), FullPath.find_last_of(".") - FullPath.size()); - material_node.ColorMapFileLength = material_node.ColorMapFile.length() + 1; - // Test - MGlobal::displayInfo(MString() + "getAbsolutePathToResources: " + workspace); - MGlobal::displayInfo(MString() + "Texture file: " + FullPath.c_str()); + MaterialNode::Texture newTexture; + + newTexture.FileName = FullPath.erase(FullPath.find_last_of("."), FullPath.find_last_of(".") - FullPath.size()); + newTexture.FileNameLength = newTexture.FileName.length() + 1; + + MPlug uvRepeatFile = TextureNode.findPlug("repeatUV"); + + uvRepeatFile.connectedTo(AllConnections, true, false); + + for (int i = 0; i < AllConnections.length(); i++) { + if (AllConnections[i].node().hasFn(MFn::kPlace2dTexture)) { + MFnDependencyNode place2DTexture(AllConnections[i].node()); + MPlug uvRepeat = place2DTexture.findPlug("repeatUV"); + + newTexture.UVTiling[0] = uvRepeat.child(0).asFloat(); + newTexture.UVTiling[1] = uvRepeat.child(1).asFloat(); + } + } + + material_node.ColorMaps.push_back(newTexture); + if(material_node.type == MaterialNode::MaterialType::Basic) + material_node.type = MaterialNode::MaterialType::SingleTextures; return true; + + } else if (AllConnections[i].node().hasFn(MFn::kLayeredTexture)) { + MGlobal::displayInfo(MString() + "find splat map"); + return findSplatTextures(material_node, material_node.ColorMaps, MFnDependencyNode(AllConnections[i].node())); } } - return false; } @@ -120,9 +140,31 @@ bool Material::findNormalTexture(MaterialNode& material_node, MFnDependencyNode& workspace); FullPath = FullPath.substr(workspace.length()); FullPath = FullPath.substr(FullPath.find_first_of("/") + 1); - material_node.NormalMapFile = FullPath.erase(FullPath.find_last_of("."), FullPath.find_last_of(".") - FullPath.size()); - material_node.NormalMapFileLength = material_node.NormalMapFile.length() + 1; + + MaterialNode::Texture newTexture; + + newTexture.FileName = FullPath.erase(FullPath.find_last_of("."), FullPath.find_last_of(".") - FullPath.size()); + newTexture.FileNameLength = newTexture.FileName.length() + 1; + + MPlug uvRepeatFile = TextureNode.findPlug("repeatUV"); + + uvRepeatFile.connectedTo(AllConnections, true, false); + + for (int i = 0; i < AllConnections.length(); i++) { + if (AllConnections[i].node().hasFn(MFn::kPlace2dTexture)) { + MFnDependencyNode place2DTexture(AllConnections[i].node()); + MPlug uvRepeat = place2DTexture.findPlug("repeatUV"); + + newTexture.UVTiling[0] = uvRepeat.child(0).asFloat(); + newTexture.UVTiling[1] = uvRepeat.child(1).asFloat(); + } + } + + material_node.NormalMaps.push_back(newTexture); return true; + } else if (AllConnections[i].node().hasFn(MFn::kLayeredTexture)) { + MGlobal::displayInfo(MString() + "find splat map"); + return findSplatTextures(material_node, material_node.NormalMaps, MFnDependencyNode(AllConnections[i].node())); } } } @@ -150,9 +192,34 @@ bool Material::findSpecularTexture(MaterialNode& material_node, MFnDependencyNod workspace); FullPath = FullPath.substr(workspace.length()); FullPath = FullPath.substr(FullPath.find_first_of("/") + 1); - material_node.SpecularMapFile = FullPath.erase(FullPath.find_last_of("."), FullPath.find_last_of(".") - FullPath.size()); - material_node.SpecularMapFileLength = material_node.SpecularMapFile.length() + 1; + + MaterialNode::Texture newTexture; + + newTexture.FileName = FullPath.erase(FullPath.find_last_of("."), FullPath.find_last_of(".") - FullPath.size()); + newTexture.FileNameLength = newTexture.FileName.length() + 1; + + MPlug uvRepeatFile = TextureNode.findPlug("repeatUV"); + + uvRepeatFile.connectedTo(AllConnections, true, false); + + for (int i = 0; i < AllConnections.length(); i++) { + if (AllConnections[i].node().hasFn(MFn::kPlace2dTexture)) { + //C:\Users\kamisama\Desktop\TacticalZ\assets\test + MFnDependencyNode place2DTexture(AllConnections[i].node()); + MPlug uvRepeat = place2DTexture.findPlug("repeatUV"); + + newTexture.UVTiling[0] = uvRepeat.child(0).asFloat(); + newTexture.UVTiling[1] = uvRepeat.child(1).asFloat(); + } + } + + material_node.SpecularMaps.push_back(newTexture); + if (material_node.type == MaterialNode::MaterialType::Basic) + material_node.type = MaterialNode::MaterialType::SingleTextures; return true; + } else if (AllConnections[i].node().hasFn(MFn::kLayeredTexture)) { + MGlobal::displayInfo(MString() + "find splat map"); + return findSplatTextures(material_node, material_node.SpecularMaps, MFnDependencyNode(AllConnections[i].node())); } } return false; @@ -168,7 +235,7 @@ bool Material::findIncandescenceTexture(MaterialNode& material_node, MFnDependen for (int i = 0; i < AllConnections.length(); i++) { if (AllConnections[i].node().hasFn(MFn::kFileTexture)) { MFnDependencyNode TextureNode(AllConnections[i].node()); - + std::string FullPath = TextureNode.findPlug("ftn").asString().asChar(); m_TexturePaths.push_back(FullPath); @@ -177,14 +244,141 @@ bool Material::findIncandescenceTexture(MaterialNode& material_node, MFnDependen workspace); FullPath = FullPath.substr(workspace.length()); FullPath = FullPath.substr(FullPath.find_first_of("/") + 1); - material_node.IncandescenceMapFile = FullPath.erase(FullPath.find_last_of("."), FullPath.find_last_of(".") - FullPath.size()); - material_node.IncandescenceMapFileLength = material_node.IncandescenceMapFile.length() + 1; + + MaterialNode::Texture newTexture; + + newTexture.FileName = FullPath.erase(FullPath.find_last_of("."), FullPath.find_last_of(".") - FullPath.size()); + newTexture.FileNameLength = newTexture.FileName.length() + 1; + + MPlug uvRepeatFile = TextureNode.findPlug("repeatUV"); + + uvRepeatFile.connectedTo(AllConnections, true, false); + + for (int i = 0; i < AllConnections.length(); i++) { + if (AllConnections[i].node().hasFn(MFn::kPlace2dTexture)) { + MFnDependencyNode place2DTexture(AllConnections[i].node()); + MPlug uvRepeat = place2DTexture.findPlug("repeatUV"); + + newTexture.UVTiling[0] = uvRepeat.child(0).asFloat(); + newTexture.UVTiling[1] = uvRepeat.child(1).asFloat(); + } + } + + material_node.IncandescenceMaps.push_back(newTexture); + if (material_node.type == MaterialNode::MaterialType::Basic) + material_node.type = MaterialNode::MaterialType::SingleTextures; return true; + + } else if (AllConnections[i].node().hasFn(MFn::kLayeredTexture)) { + MGlobal::displayInfo(MString() + "find splat map"); + return findSplatTextures(material_node, material_node.IncandescenceMaps, MFnDependencyNode(AllConnections[i].node())); } } return false; } +//C:\Users\kamisama\Desktop\TacticalZ\assets\test + +bool Material::findSplatTextures(MaterialNode& material_node, std::vector& textureVector, MFnDependencyNode& node) { + //Get all Inputs in LayeredTexture + MPlug inputs = node.findPlug("inputs"); + MGlobal::displayInfo(MString() + "inputs.numElements(): " + inputs.numElements()); + + MPlugArray AllConnections; + MStatus test; + //Try to find splat texture if using custom splatmap build up. + inputs[0].child(1).connectedTo(AllConnections, true, false); + for (int i = 0; i < AllConnections.length(); i++) { + if (AllConnections[i].node().hasFn(MFn::kMultiplyDivide)) { + MGlobal::displayInfo(MString() + "found kMultiplyDivide"); + MFnDependencyNode multiplyDivide(AllConnections[i].node()); + multiplyDivide.findPlug("input1", &test).child(0).connectedTo(AllConnections, true, false);; + for (int i = 0; i < AllConnections.length(); i++) { + if (AllConnections[i].node().hasFn(MFn::kFileTexture)) { + MFnDependencyNode TextureNode(AllConnections[i].node()); + + std::string FullPath = TextureNode.findPlug("ftn").asString().asChar(); + m_TexturePaths.push_back(FullPath); + + MString workspace; + MStatus status = MGlobal::executeCommand(MString("workspace -q -rd;"), + workspace); + FullPath = FullPath.substr(workspace.length()); + FullPath = FullPath.substr(FullPath.find_first_of("/") + 1); + + MaterialNode::Texture newTexture; + + newTexture.FileName = FullPath.erase(FullPath.find_last_of("."), FullPath.find_last_of(".") - FullPath.size()); + newTexture.FileNameLength = newTexture.FileName.length() + 1; + + MPlug uvRepeatFile = TextureNode.findPlug("repeatUV"); + + uvRepeatFile.connectedTo(AllConnections, true, false); + + for (int i = 0; i < AllConnections.length(); i++) { + if (AllConnections[i].node().hasFn(MFn::kPlace2dTexture)) { + MFnDependencyNode place2DTexture(AllConnections[i].node()); + MPlug uvRepeat = place2DTexture.findPlug("repeatUV"); + + newTexture.UVTiling[0] = uvRepeat.child(0).asFloat(); + newTexture.UVTiling[1] = uvRepeat.child(1).asFloat(); + } + } + material_node.SplatMap = newTexture; + material_node.type = MaterialNode::MaterialType::SplatMapping; + } + } + } + } + + for (unsigned int i = 0; i < inputs.numElements(); i++) { + //Get connections to color in input[i] + inputs[i].child(0).connectedTo(AllConnections, true, false); + + for (int i = 0; i < AllConnections.length(); i++) { + if (AllConnections[i].node().hasFn(MFn::kFileTexture)) { + MFnDependencyNode TextureNode(AllConnections[i].node()); + + std::string FullPath = TextureNode.findPlug("ftn").asString().asChar(); + m_TexturePaths.push_back(FullPath); + + MString workspace; + MStatus status = MGlobal::executeCommand(MString("workspace -q -rd;"), + workspace); + FullPath = FullPath.substr(workspace.length()); + FullPath = FullPath.substr(FullPath.find_first_of("/") + 1); + + MaterialNode::Texture newTexture; + + newTexture.FileName = FullPath.erase(FullPath.find_last_of("."), FullPath.find_last_of(".") - FullPath.size()); + newTexture.FileNameLength = newTexture.FileName.length() + 1; + + MPlug uvRepeatFile = TextureNode.findPlug("repeatUV"); + + uvRepeatFile.connectedTo(AllConnections, true, false); + + for (int i = 0; i < AllConnections.length(); i++) { + if (AllConnections[i].node().hasFn(MFn::kPlace2dTexture)) { + MFnDependencyNode place2DTexture(AllConnections[i].node()); + MPlug uvRepeat = place2DTexture.findPlug("repeatUV"); + + newTexture.UVTiling[0] = uvRepeat.child(0).asFloat(); + newTexture.UVTiling[1] = uvRepeat.child(1).asFloat(); + } + } + textureVector.push_back(newTexture); + break; + } + } + if (AllConnections.length() == 0) { + MaterialNode::Texture newTexture; + newTexture.FileNameLength = 0; + textureVector.push_back(newTexture); + } + } + return true; +} + // Returns the absolute path for all textures. Use for copying texture files. std::vector* Material::TexturePaths() { @@ -209,7 +403,6 @@ std::vector* Material::DoIt(Mesh mesh) meshHasMaterial = true; MaterialStorage.IndexStart = totalIndices; MaterialStorage.IndexEnd = totalIndices + aMeshMaterial.second.size() - 1; - break; } totalIndices += aMeshMaterial.second.size(); } @@ -226,7 +419,10 @@ std::vector* Material::DoIt(Mesh mesh) MaterialStorage.ReflectionFactor = 0.0f; MaterialStorage.SpecularExponent = 0.0f; } - + MaterialStorage.NumColorMaps = MaterialStorage.ColorMaps.size(); + MaterialStorage.NumNormalMaps = MaterialStorage.NormalMaps.size(); + MaterialStorage.NumSpecularMaps = MaterialStorage.SpecularMaps.size(); + MaterialStorage.NumIncandescenceMaps = MaterialStorage.IncandescenceMaps.size(); m_AllMaterials.push_back(MaterialStorage); } matIt.next(); diff --git a/tools/MayaExporter/MayaExporter/Material.h b/tools/MayaExporter/MayaExporter/Material.h index e405dd07..d70a6399 100644 --- a/tools/MayaExporter/MayaExporter/Material.h +++ b/tools/MayaExporter/MayaExporter/Material.h @@ -11,62 +11,123 @@ #include "OutputData.h" #include "Mesh.h" + +//#define ColorMapSplat 1 +//#define SpecularMapSplat 1 << 1 +//#define NormalMapSplat 1 << 2 +//#define IncandescenceMapSplat 1 << 3 + + + class MaterialNode : public OutputData { public: + class Texture : public OutputData { + public: + unsigned int FileNameLength = 0; + std::string FileName; + float UVTiling[2]{ 1.0f, 1.0f }; + + virtual void WriteBinary(std::ostream& out) + { + out.write((char*)&FileNameLength, sizeof(unsigned int)); + out.write(FileName.c_str(), FileNameLength); + out.write((char*)&UVTiling, sizeof(float) * 2); + } + + virtual void WriteASCII(std::ostream& out) const + { + out << "FileNameLength: " << FileNameLength << endl; + out << "FileName: " << FileName << endl; + out << "UV tiling: " << UVTiling[0] << " " << UVTiling[1] << endl; + } + }; + + enum class MaterialType { Basic = 1, SplatMapping, SingleTextures }; + + MaterialType type = MaterialType::Basic; + std::string Name; float ReflectionFactor; float SpecularExponent; - float DiffuseColor[3]{ 1.0f, 1.0f, 1.0f }; - unsigned int ColorMapFileLength = 0; - std::string ColorMapFile; + float DiffuseColor[3]{ 1.0f, 1.0f, 1.0f }; + float SpecularColor[3]{ 1.0f, 1.0f, 1.0f }; + float IncandescenceColor[3]{ 1.0f, 1.0f, 1.0f }; - float SpecularColor[3]{ 1.0f, 1.0f, 1.0f }; - unsigned int SpecularMapFileLength = 0; - std::string SpecularMapFile; + unsigned int IndexStart; + unsigned int IndexEnd; - unsigned int NormalMapFileLength = 0; - std::string NormalMapFile; - - float IncandescenceColor[3]{ 1.0f, 1.0f, 1.0f }; - unsigned int IncandescenceMapFileLength = 0; - std::string IncandescenceMapFile; - - unsigned int IndexStart; - unsigned int IndexEnd; + unsigned char NumColorMaps = 0; + unsigned char NumSpecularMaps = 0; + unsigned char NumNormalMaps = 0; + unsigned char NumIncandescenceMaps = 0; + Texture SplatMap; + std::vector ColorMaps; + std::vector SpecularMaps; + std::vector NormalMaps; + std::vector IncandescenceMaps; virtual void WriteBinary(std::ostream& out) { - out.write((char*)&ColorMapFileLength, sizeof(unsigned int)); - out.write((char*)&NormalMapFileLength, sizeof(unsigned int)); - out.write((char*)&SpecularMapFileLength, sizeof(unsigned int)); - out.write((char*)&IncandescenceMapFileLength, sizeof(unsigned int)); - + + out.write((char*)&type, sizeof(MaterialType)); out.write((char*)&SpecularExponent, sizeof(float)); out.write((char*)&ReflectionFactor, sizeof(float)); + out.write((char*)&DiffuseColor, sizeof(float) * 3); out.write((char*)&SpecularColor, sizeof(float) * 3); out.write((char*)&IncandescenceColor, sizeof(float) * 3); + out.write((char*)&IndexStart, sizeof(unsigned int)); out.write((char*)&IndexEnd, sizeof(unsigned int)); + if (type != MaterialType::Basic) { + if (type == MaterialType::SplatMapping) { + SplatMap.WriteBinary(out); + } + out.write((char*)&NumColorMaps, sizeof(unsigned char)); + out.write((char*)&NumSpecularMaps, sizeof(unsigned char)); + out.write((char*)&NumNormalMaps, sizeof(unsigned char)); + out.write((char*)&NumIncandescenceMaps, sizeof(unsigned char)); + } - out.write(ColorMapFile.c_str(), ColorMapFileLength); - out.write(NormalMapFile.c_str(), NormalMapFileLength); - out.write(SpecularMapFile.c_str(), SpecularMapFileLength); - out.write(IncandescenceMapFile.c_str(), IncandescenceMapFileLength); + if (type != MaterialType::Basic) { + for (auto aTexture : ColorMaps) { + aTexture.WriteBinary(out); + } + for (auto aTexture : SpecularMaps) { + aTexture.WriteBinary(out); + } + for (auto aTexture : NormalMaps) { + aTexture.WriteBinary(out); + } + for (auto aTexture : IncandescenceMaps) { + aTexture.WriteBinary(out); + } + } } virtual void WriteASCII(std::ostream& out) const { out << "New Material _ not in binary" << endl; - out << "number of indices: " << Name << " _ not in binary" << endl; - out << "ColorMapFile length: " << ColorMapFileLength << endl; - out << "NormalMapFile length: " << NormalMapFileLength << endl; - out << "SpecularMapFile length: " << SpecularMapFileLength << endl; - out << "IncandescenceMapFile length: " << IncandescenceMapFileLength << endl; + out << "MaterialType(enum): "; + switch (type) { + case MaterialType::Basic: + out << "Basic"; + break; + case MaterialType::SplatMapping: + out << "SplatMapping"; + break; + case MaterialType::SingleTextures: + out << "SingleTextures"; + break; + }; + + out << endl; + + out << "Material Name: " << Name << " _ not in binary" << endl; out << "SpecularExponent: " << SpecularExponent << endl; out << "ReflectionFactor: " << ReflectionFactor << endl; @@ -76,17 +137,38 @@ public: out << "IndexStart: " << IndexStart << endl; out << "IndexEnd: " << IndexEnd << endl; - if (ColorMapFileLength > 0) - out << "ColorMapFile: " << ColorMapFile << endl; + switch (type) { + case MaterialType::SplatMapping: + out << "SplatMap _ not in binary " << endl; + SplatMap.WriteASCII(out); + //Intended fall trought + case MaterialType::SingleTextures: + out << "NumColormaps (is unsigned char in Binary): " << ((unsigned int)NumColorMaps) << endl; + out << "NumSpecularMap (is unsigned char in Binary): " << ((unsigned int)NumSpecularMaps) << endl; + out << "NumNormalMap (is unsigned char in Binary): " << ((unsigned int)NumNormalMaps) << endl; + out << "NumIncandescenceMap (is unsigned char in Binary): " << ((unsigned int)NumIncandescenceMaps )<< endl; - if (NormalMapFileLength > 0) - out << "NormalMapFile: " << NormalMapFile << endl; - - if (SpecularMapFileLength > 0) - out << "SpecularMapFile: " << SpecularMapFile << endl; - - if (IncandescenceMapFileLength > 0) - out << "IncandescenceMapFile: " << IncandescenceMapFile << endl; + out << "ColorMaps _ not in binary " << endl; + for (auto aTexture : ColorMaps) { + aTexture.WriteASCII(out); + } + + out << "SpecularMaps _ not in binary " << endl; + for (auto aTexture : SpecularMaps) { + aTexture.WriteASCII(out); + } + + out << "NormalMaps _ not in binary " << endl; + for (auto aTexture : NormalMaps) { + aTexture.WriteASCII(out); + } + + out << "IncandescenceMaps _ not in binary " << endl; + for (auto aTexture : IncandescenceMaps) { + aTexture.WriteASCII(out); + } + break; + }; } }; @@ -107,6 +189,7 @@ private: bool findNormalTexture(MaterialNode& material_node, MFnDependencyNode& node); bool findSpecularTexture(MaterialNode& material_node, MFnDependencyNode& node); bool findIncandescenceTexture(MaterialNode& material_node, MFnDependencyNode& node); + bool findSplatTextures(MaterialNode& material_node, std::vector& textureVector, MFnDependencyNode& node); void grabLambertProperties(MaterialNode& material_node, MFnDependencyNode& node); void grabBlinnProperties(MaterialNode& material_node, MFnDependencyNode& node); void grabPhongProperties(MaterialNode& material_node, MFnDependencyNode& node); diff --git a/tools/MayaExporter/MayaExporter/MayaExporter.vcxproj b/tools/MayaExporter/MayaExporter/MayaExporter.vcxproj index 4a7ac07e..b9384a45 100644 --- a/tools/MayaExporter/MayaExporter/MayaExporter.vcxproj +++ b/tools/MayaExporter/MayaExporter/MayaExporter.vcxproj @@ -40,8 +40,9 @@ v140 - Application + DynamicLibrary v140 + Unicode @@ -77,6 +78,7 @@ $(SolutionDir)$(Platform)\$(Configuration)\ + .mll @@ -135,7 +137,7 @@ NDEBUG;QT_DLL;QT_NO_DEBUG;QT_NO_IMPORT_QT47_QML;UNICODE;WIN32;%(PreprocessorDefinitions) - .\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);%(AdditionalIncludeDirectories) + C:\Program Files\Autodesk\Maya2016\include;.\GeneratedFiles;.\GeneratedFiles\$(ConfigurationName);%(AdditionalIncludeDirectories) MultiThreadedDLL @@ -144,7 +146,7 @@ Windows - $(OutDir)\$(ProjectName).exe + $(OutDir)$(TargetName)$(TargetExt) $(QTDIR)\lib;%(AdditionalLibraryDirectories) false qtmain.lib;%(AdditionalDependencies) diff --git a/tools/MayaExporter/MayaExporter/Menu.cpp b/tools/MayaExporter/MayaExporter/Menu.cpp index 9cc6de91..02810018 100644 --- a/tools/MayaExporter/MayaExporter/Menu.cpp +++ b/tools/MayaExporter/MayaExporter/Menu.cpp @@ -60,8 +60,6 @@ Menu::Menu(QDialog* dialog) m_ExportPath = new QLineEdit; m_FileDialog = new QFileDialog; - QString tmpPath("C:/Users/Nickelodion/Desktop/workspace/tacticalZ/assets/models/"); - m_ExportPath->setText(tmpPath); QLabel* exportLabel = new QLabel; exportLabel->setText("Export Path:"); QLabel* nameLabel = new QLabel; diff --git a/tools/MayaExporter/MayaExporter/Mesh.cpp b/tools/MayaExporter/MayaExporter/Mesh.cpp index 6af8a557..ee5a6022 100644 --- a/tools/MayaExporter/MayaExporter/Mesh.cpp +++ b/tools/MayaExporter/MayaExporter/Mesh.cpp @@ -8,95 +8,91 @@ MeshClass::MeshClass() } -std::map MeshClass::GetWeightData() -{ - MS status; - map weightMap; - - MItDependencyNodes it(MFn::kSkinClusterFilter); - - while (!it.isDone()) { - - MObject object = it.thisNode(&status); - if (status != MS::kSuccess) { - MGlobal::displayError(MString() + " it.thisNode() ERROR: " + status.errorString()); - break; - } - MFnSkinCluster skinCluster(object, &status); - if (status != MS::kSuccess) { - MGlobal::displayError(MString() + "skinCluster() ERROR: " + status.errorString()); - break; - } - MDagPathArray influences; - - unsigned int nrOfInfluences = skinCluster.influenceObjects(influences,&status); - if (status != MS::kSuccess) { - MGlobal::displayError(MString() + "skinCluster.influenceObjects() ERROR: " + status.errorString()); - break; - } - - unsigned int index; - index = skinCluster.indexForOutputConnection(0,&status); - if (status != MS::kSuccess) { - MGlobal::displayError(MString() + "skinCluster.indexForOutputConnection() ERROR: " + status.errorString()); - break; - } - MDagPath skinPath; - status = skinCluster.getPathAtIndex(index, skinPath); - if (status != MS::kSuccess) { - MGlobal::displayError(MString() + "skinCluster.getPathAtIndex() ERROR: " + status.errorString()); - break; - } - - MItGeometry geomIter(skinPath); - //for (unsigned int i = 0; i < nrOfInfluences; i++) { - // MGlobal::displayInfo(MString() + " Influence object name: " + influences[i].partialPathName().asChar()); - //} - WeightInfo weightInfo; - - while (!geomIter.isDone()) { - MObject comp = geomIter.component(&status); - if (status != MS::kSuccess) { - MGlobal::displayError(MString() + "geomIter.component() ERROR: " + status.errorString()); - break; - } - MFloatArray weights; - unsigned int influenceCount; - status = skinCluster.getWeights(skinPath, comp, weights, influenceCount); - if (status != MS::kSuccess) { - MGlobal::displayError(MString() + "skinCluster.getWeights() ERROR: " + status.errorString()); - break; - } - MFnDependencyNode test(comp); - unsigned int nrOfWeights = 0; - - for (unsigned int j = 0; j < weights.length() && nrOfWeights != 4; j++) { - if (weights[j] > 0.00001) { - weightInfo.BoneWeights[nrOfWeights] = weights[j]; - weightInfo.BoneIndices[nrOfWeights] = j; - nrOfWeights++; - } - } - - float totalWeight = 0.0f; - for (unsigned int i = 0; i < 4; i++) { - totalWeight += weightInfo.BoneWeights[i]; - } - for (unsigned int i = 0; i < 4; i++) { - weightInfo.BoneWeights[i] /= totalWeight; - } - weightMap[geomIter.index()] = weightInfo; - - - for (unsigned int k = 0; k!=nrOfWeights; k++) { - MGlobal::displayInfo(MString() + "influence: " + weightInfo.BoneIndices[k] + " weight: " + weightInfo.BoneWeights[k]); - } - geomIter.next(); - } - it.next(); - } - return weightMap; -} +//std::map MeshClass::GetWeightData() +//{ +// MS status; +// map weightMap; +// +// MItDependencyNodes it(MFn::kSkinClusterFilter); +// +// while (!it.isDone()) { +// +// MObject object = it.thisNode(&status); +// if (status != MS::kSuccess) { +// MGlobal::displayError(MString() + " it.thisNode() ERROR: " + status.errorString()); +// break; +// } +// MFnSkinCluster skinCluster(object, &status); +// if (status != MS::kSuccess) { +// MGlobal::displayError(MString() + "skinCluster() ERROR: " + status.errorString()); +// break; +// } +// MDagPathArray influences; +// +// unsigned int nrOfInfluences = skinCluster.influenceObjects(influences,&status); +// if (status != MS::kSuccess) { +// MGlobal::displayError(MString() + "skinCluster.influenceObjects() ERROR: " + status.errorString()); +// break; +// } +// +// unsigned int index; +// index = skinCluster.indexForOutputConnection(0,&status); +// if (status != MS::kSuccess) { +// MGlobal::displayError(MString() + "skinCluster.indexForOutputConnection() ERROR: " + status.errorString()); +// break; +// } +// MDagPath skinPath; +// status = skinCluster.getPathAtIndex(index, skinPath); +// if (status != MS::kSuccess) { +// MGlobal::displayError(MString() + "skinCluster.getPathAtIndex() ERROR: " + status.errorString()); +// break; +// } +// +// MItGeometry geomIter(skinPath); +// //for (unsigned int i = 0; i < nrOfInfluences; i++) { +// // MGlobal::displayInfo(MString() + " Influence object name: " + influences[i].partialPathName().asChar()); +// //} +// WeightInfo weightInfo; +// +// while (!geomIter.isDone()) { +// MObject comp = geomIter.component(&status); +// if (status != MS::kSuccess) { +// MGlobal::displayError(MString() + "geomIter.component() ERROR: " + status.errorString()); +// break; +// } +// MFloatArray weights; +// unsigned int influenceCount; +// status = skinCluster.getWeights(skinPath, comp, weights, influenceCount); +// if (status != MS::kSuccess) { +// MGlobal::displayError(MString() + "skinCluster.getWeights() ERROR: " + status.errorString()); +// break; +// } +// MFnDependencyNode test(comp); +// unsigned int nrOfWeights = 0; +// +// for (unsigned int j = 0; j < weights.length() && nrOfWeights != 4; j++) { +// if (weights[j] > 0.00001) { +// weightInfo.BoneWeights[nrOfWeights] = weights[j]; +// weightInfo.BoneIndices[nrOfWeights] = j; +// nrOfWeights++; +// } +// } +// +// float totalWeight = 0.0f; +// for (unsigned int i = 0; i < 4; i++) { +// totalWeight += weightInfo.BoneWeights[i]; +// } +// for (unsigned int i = 0; i < 4; i++) { +// weightInfo.BoneWeights[i] /= totalWeight; +// } +// weightMap[geomIter.index()] = weightInfo; +// +// geomIter.next(); +// } +// it.next(); +// } +// return weightMap; +//} Mesh MeshClass::GetMeshData(MObjectArray object) { @@ -112,8 +108,6 @@ Mesh MeshClass::GetMeshData(MObjectArray object) MFnDependencyNode thisNode(node); MPlugArray connections; thisNode.findPlug("inMesh").connectedTo(connections, true, true); - MGlobal::displayInfo(MString() + "inMesh"); - bool hasSkin = false; MPlug weightList, weights; MObject weightListObject; for (unsigned int i = 0; i < connections.length(); i++) { @@ -122,7 +116,7 @@ Mesh MeshClass::GetMeshData(MObjectArray object) weightList = skinCluster.findPlug("weightList", &status); weightListObject = weightList.attribute(); weights = skinCluster.findPlug("weights"); - hasSkin = true; + newMesh.hasSkin = true; break; } } @@ -138,7 +132,6 @@ Mesh MeshClass::GetMeshData(MObjectArray object) } for (int pathID = 0; pathID < dagPaths.length(); pathID++) { - MGlobal::displayInfo(dagPaths[pathID].fullPathName()); MDagPath thisMeshPath(dagPaths[pathID]); MMatrix transformMatrix = thisMeshPath.inclusiveMatrix(&status); @@ -173,8 +166,7 @@ Mesh MeshClass::GetMeshData(MObjectArray object) break; } map> materialFaceIDs; - MGlobal::displayInfo(MString() + "shaderIndexList: " + shaderIndexList.length()); - MGlobal::displayInfo(MString() + "shaderList: " + shaderList.length()); + MPlugArray plugArray; for (int i = 0; i < shaderIndexList.length(); i++) { MFnDependencyNode shader(shaderList[shaderIndexList[i]]); @@ -261,43 +253,33 @@ Mesh MeshClass::GetMeshData(MObjectArray object) //mesh.getPoint(vertexIndex, pos, MSpace::kPostTransform); pos = positions[vertexIndex]; pos = pos * transformMatrix; - if (abs(pos.x) > 0.0001) - thisVertex.Pos[0] = pos.x; - if (abs(pos.y) > 0.0001) - thisVertex.Pos[1] = pos.y; - if (abs(pos.z) > 0.0001) - thisVertex.Pos[2] = pos.z; + + thisVertex.Pos[0] = pos.x; + thisVertex.Pos[1] = pos.y; + thisVertex.Pos[2] = pos.z; status = faceVert.getNormal(normal, MSpace::kObject); if (status != MS::kSuccess) { MGlobal::displayError(MString() + "faceVert.getNormal() ERROR: " + status.errorString() + "for local vertex " + i + " in " + faceID + " in mesh " + thisMeshPath.fullPathName()); break; } - if (abs(normal[0]) > 0.0001) - thisVertex.Normal[0] = normal[0]; - if (abs(normal[1]) > 0.0001) - thisVertex.Normal[1] = normal[1]; - if (abs(normal[2]) > 0.0001) - thisVertex.Normal[2] = normal[2]; + + thisVertex.Normal[0] = normal[0]; + thisVertex.Normal[1] = normal[1]; + thisVertex.Normal[2] = normal[2]; MFloatVector Tangent = Tangents[faceVert.tangentId()]; //MVector tmp = faceVert.getTangent(MSpace::kObject, NULL); //tmp.get(biTangent); - if (abs(Tangent[0]) > 0.0001) - thisVertex.Tangent[0] = Tangent[0]; - if (abs(Tangent[1]) > 0.0001) - thisVertex.Tangent[1] = Tangent[1]; - if (abs(Tangent[2]) > 0.0001) - thisVertex.Tangent[2] = Tangent[2]; + thisVertex.Tangent[0] = Tangent[0]; + thisVertex.Tangent[1] = Tangent[1]; + thisVertex.Tangent[2] = Tangent[2]; MFloatVector biNormal = biNormals[faceVert.tangentId()]; //faceVert.getBinormal().get(biNormal); - if (abs(biNormal[0]) > 0.0001) - thisVertex.BiNormal[0] = biNormal[0]; - if (abs(biNormal[1]) > 0.0001) - thisVertex.BiNormal[1] = biNormal[1]; - if (abs(biNormal[2]) > 0.0001) - thisVertex.BiNormal[2] = biNormal[2]; + thisVertex.BiNormal[0] = biNormal[0]; + thisVertex.BiNormal[1] = biNormal[1]; + thisVertex.BiNormal[2] = biNormal[2]; status = faceVert.getUV(UV); if (status != MS::kSuccess) { @@ -308,7 +290,8 @@ Mesh MeshClass::GetMeshData(MObjectArray object) thisVertex.Uv[1] = UV[1]; - if (hasSkin) { + if (newMesh.hasSkin) { + thisVertex.useWeights = true; float totalWeight = 0.0f; unsigned int totalBones = 0; MIntArray jointIDs /* ??? */; @@ -324,9 +307,11 @@ Mesh MeshClass::GetMeshData(MObjectArray object) } for (unsigned int i = 0; i < 4; i++) { - thisVertex.BoneWeights[i] = thisVertex.BoneWeights[i] / totalWeight; + //thisVertex.BoneWeights[i] = thisVertex.BoneWeights[i] / totalWeight; } - } + } else { + thisVertex.useWeights = false; + } //float totalWeight = thisVertex.BoneWeights[0] + thisVertex.BoneWeights[1] + thisVertex.BoneWeights[2] + thisVertex.BoneWeights[3]; //if (totalWeight > 0.0001f) { diff --git a/tools/MayaExporter/MayaExporter/Mesh.h b/tools/MayaExporter/MayaExporter/Mesh.h index 11f6bcf8..affc4320 100644 --- a/tools/MayaExporter/MayaExporter/Mesh.h +++ b/tools/MayaExporter/MayaExporter/Mesh.h @@ -11,6 +11,7 @@ class VertexLayout : public OutputData { public: + bool useWeights = true; float Pos[3]{ 0 }; float Normal[3]{ 0 }; float Tangent[3]{ 0 }; @@ -26,8 +27,10 @@ public: out.write((char*)&Tangent, sizeof(float) * 3); out.write((char*)&BiNormal, sizeof(float) * 3); out.write((char*)&Uv, sizeof(float) * 2); - out.write((char*)&BoneIndices, sizeof(float) * 4); - out.write((char*)&BoneWeights, sizeof(float) * 4); + if (useWeights) { + out.write((char*)&BoneIndices, sizeof(float) * 4); + out.write((char*)&BoneWeights, sizeof(float) * 4); + } } virtual void WriteASCII(std::ostream& out) const @@ -37,8 +40,10 @@ public: out << Tangent[0] << " " << Tangent[1] << " " << Tangent[2] << endl; out << BiNormal[0] << " " << BiNormal[1] << " " << BiNormal[2] << endl; out << Uv[0] << " " << Uv[1] << endl; - out << BoneIndices[0] << " " << BoneIndices[1] << " " << BoneIndices[2] << " " << BoneIndices[3] << endl; - out << BoneWeights[0] << " " << BoneWeights[1] << " " << BoneWeights[2] << " " << BoneWeights[3] << endl; + if (useWeights) { + out << BoneIndices[0] << " " << BoneIndices[1] << " " << BoneIndices[2] << " " << BoneIndices[3] << endl; + out << BoneWeights[0] << " " << BoneWeights[1] << " " << BoneWeights[2] << " " << BoneWeights[3] << endl; + } } bool operator==(const VertexLayout& right) @@ -57,6 +62,7 @@ public: class Mesh : public OutputData { public: + bool hasSkin = false; unsigned int NumVertices; unsigned int NumIndices; std::vector Vertices; @@ -64,6 +70,7 @@ public: virtual void WriteBinary(std::ostream& out) { + out.write((char*)&hasSkin, sizeof(bool)); out.write((char*)&NumVertices, sizeof(int)); out.write((char*)&NumIndices, sizeof(int)); for (auto aVertex : Vertices) { @@ -79,6 +86,11 @@ public: virtual void WriteASCII(std::ostream& out) const { out << "New Mesh _ not in binary" << endl; + out << "hasSkin: "; + if(hasSkin) + out << "true" << endl; + else + out << "false" << endl; out << "Number of vertices: " << NumVertices << endl; out << "number of indices: " << NumIndices << endl; int vertexNumber = 0; diff --git a/tools/MayaExporter/MayaExporter/Skeleton.cpp b/tools/MayaExporter/MayaExporter/Skeleton.cpp index c30311b8..2e432476 100644 --- a/tools/MayaExporter/MayaExporter/Skeleton.cpp +++ b/tools/MayaExporter/MayaExporter/Skeleton.cpp @@ -60,7 +60,7 @@ // // return m_AllSkeletons; //} -std::string attr[9] = { "scaleX", "scaleY", "scaleZ", "translateX", "translateY", "translateZ", "rotateX", "rotateY", "rotateZ" }; +static std::string attr[9] = { "scaleX", "scaleY", "scaleZ", "translateX", "translateY", "translateZ", "rotateX", "rotateY", "rotateZ" }; Animation Skeleton::GetAnimData(std::string animationName, int startFrame, int endFrame) { @@ -68,100 +68,294 @@ Animation Skeleton::GetAnimData(std::string animationName, int startFrame, int e std::vector animatedJoints; std::vector m_Hierarchy; - Animation returnData; - double oneDivSixty = 1 / 60.0; - returnData.Name = animationName; + Animation returnData; + double oneDivSixty = 1 / 60.0; + returnData.Name = animationName; returnData.nameLength = animationName.size() + 1; - returnData.Duration = (endFrame - startFrame) * oneDivSixty; + returnData.Duration = (endFrame - startFrame) * oneDivSixty; - MItDag jointIt(MItDag::TraversalType::kDepthFirst, MFn::kJoint); - while (!jointIt.isDone()) - { - m_Hierarchy.push_back(jointIt.item()); + std::map, 4>> joinCheckMap; + std::map exportJoint; - MFnDependencyNode depNode(jointIt.item()); - for (int i = 0; i < 9; i++) - { - MStatus tmp; - MPlug plug = depNode.findPlug(attr[i].c_str(), &tmp); + //MItDag jointIt(MItDag::TraversalType::kDepthFirst, MFn::kJoint); + //for (unsigned int i = startFrame; i <= endFrame; i++) + //{ + // MAnimControl::setCurrentTime(MTime(i, MTime::kNTSCField)); + // while (!jointIt.isDone()) + // { + // m_Hierarchy.push_back(jointIt.item()); - MPlugArray connections; - plug.connectedTo(connections, true, false, 0); - for (int j = 0; j != connections.length(); j++) { - MObject connected = connections[j].node(); + // MFnTransform MayaJoint(jointIt.item()); + // MMatrix transformationMatrix = MayaJoint.transformationMatrix(); - if (connected.hasFn(MFn::kAnimCurve)) { + // if (i == startFrame) + // { + // double doubleMat[4][4]; + // transformationMatrix.get(doubleMat); - MFnAnimCurve jointAnim(connected); + // joinCheckMap[MayaJoint.name().asChar()][0][0] = doubleMat[0][0]; + // joinCheckMap[MayaJoint.name().asChar()][0][1] = doubleMat[0][1]; + // joinCheckMap[MayaJoint.name().asChar()][0][2] = doubleMat[0][2]; + // joinCheckMap[MayaJoint.name().asChar()][0][3] = doubleMat[0][3]; + // joinCheckMap[MayaJoint.name().asChar()][1][0] = doubleMat[1][0]; + // joinCheckMap[MayaJoint.name().asChar()][1][1] = doubleMat[1][1]; + // joinCheckMap[MayaJoint.name().asChar()][1][2] = doubleMat[1][2]; + // joinCheckMap[MayaJoint.name().asChar()][1][3] = doubleMat[1][3]; + // joinCheckMap[MayaJoint.name().asChar()][2][0] = doubleMat[2][0]; + // joinCheckMap[MayaJoint.name().asChar()][2][1] = doubleMat[2][1]; + // joinCheckMap[MayaJoint.name().asChar()][2][2] = doubleMat[2][2]; + // joinCheckMap[MayaJoint.name().asChar()][2][3] = doubleMat[2][3]; + // joinCheckMap[MayaJoint.name().asChar()][3][0] = doubleMat[3][0]; + // joinCheckMap[MayaJoint.name().asChar()][3][1] = doubleMat[3][1]; + // joinCheckMap[MayaJoint.name().asChar()][3][2] = doubleMat[3][2]; + // joinCheckMap[MayaJoint.name().asChar()][3][3] = doubleMat[3][3]; - unsigned int startKeyFrameIndex = jointAnim.findClosest(MTime(startFrame, MTime::kNTSCField), &tmp); + // exportJoint[MayaJoint.name().asChar()] = false; + // } + // else if(!exportJoint[MayaJoint.name().asChar()])//!exportJoint[MayaJoint.name().asChar()]) + // { + // double doubleMat[4][4]; - if (tmp == MStatus::kFailure) - MGlobal::displayInfo(MString() + "Fail :c"); + // doubleMat[0][0] = joinCheckMap[MayaJoint.name().asChar()][0][0]; + // doubleMat[0][1] = joinCheckMap[MayaJoint.name().asChar()][0][1]; + // doubleMat[0][2] = joinCheckMap[MayaJoint.name().asChar()][0][2]; + // doubleMat[0][3] = joinCheckMap[MayaJoint.name().asChar()][0][3]; + // doubleMat[1][0] = joinCheckMap[MayaJoint.name().asChar()][1][0]; + // doubleMat[1][1] = joinCheckMap[MayaJoint.name().asChar()][1][1]; + // doubleMat[1][2] = joinCheckMap[MayaJoint.name().asChar()][1][2]; + // doubleMat[1][3] = joinCheckMap[MayaJoint.name().asChar()][1][3]; + // doubleMat[2][0] = joinCheckMap[MayaJoint.name().asChar()][2][0]; + // doubleMat[2][1] = joinCheckMap[MayaJoint.name().asChar()][2][1]; + // doubleMat[2][2] = joinCheckMap[MayaJoint.name().asChar()][2][2]; + // doubleMat[2][3] = joinCheckMap[MayaJoint.name().asChar()][2][3]; + // doubleMat[3][0] = joinCheckMap[MayaJoint.name().asChar()][3][0]; + // doubleMat[3][1] = joinCheckMap[MayaJoint.name().asChar()][3][1]; + // doubleMat[3][2] = joinCheckMap[MayaJoint.name().asChar()][3][2]; + // doubleMat[3][3] = joinCheckMap[MayaJoint.name().asChar()][3][3]; - if (startFrame * oneDivSixty <= jointAnim.time(startKeyFrameIndex).value() && jointAnim.time(startKeyFrameIndex).value() <= endFrame * oneDivSixty) { - animatedJoints.push_back(jointIt.item()); - i = 9; - break; - } + // MMatrix tmp(doubleMat); + // if (!tmp.isEquivalent(transformationMatrix)) { + // MGlobal::displayInfo(MString() + MayaJoint.name() + " is exported"); + // exportJoint[MayaJoint.name().asChar()] = true; + // animatedJoints.push_back(MayaJoint.object()); + // } + // } - unsigned int endKeyFrameIndex = jointAnim.findClosest(MTime(endFrame, MTime::kNTSCField)); - MGlobal::displayInfo(MString() + startKeyFrameIndex + " " + endKeyFrameIndex); + /*for (int i = 0; i < 9; i++) + { + MStatus tmp; + MPlug plug = depNode.findPlug(attr[i].c_str(), &tmp); - if (startFrame * oneDivSixty <= jointAnim.time(endKeyFrameIndex).value() && jointAnim.time(endKeyFrameIndex).value() <= endFrame * oneDivSixty || endKeyFrameIndex - startKeyFrameIndex > 0) { - animatedJoints.push_back(jointIt.item()); - i = 9; - break; - } + MPlugArray connections; + plug.connectedTo(connections, true, false, 0); + for (int j = 0; j != connections.length(); j++) { + MObject connected = connections[j].node(); - MFnTransform MayaJoint(jointIt.item()); + if (connected.hasFn(MFn::kAnimCurve)) { - MPlug BindPose = MayaJoint.findPlug("bindPose"); - MDataHandle DataHandle; - BindPose.getValue(DataHandle); - MFnMatrixData MartixFn(DataHandle.data()); - MMatrix BindPoseMatrix = MartixFn.matrix(); + MFnAnimCurve jointAnim(connected); - if (!BindPoseMatrix.isEquivalent(MayaJoint.transformationMatrix())) - { - MGlobal::displayError(MString() + animationName.c_str() + " is using " + MayaJoint.name() + " that is not in bind pose nor is it key framed in the animation, the exported animation will NOT correspond to the animation in Maya"); - } - } - } - } + //MGlobal::displayInfo(MString() + "curve : " + jointAnim.name()); + //MGlobal::displayInfo(MString() + "curve keys : " + jointAnim.numKeys()); + //MGlobal::displayInfo(MString() + "curve keyframes : " + jointAnim.numKeyframes()); + //MGlobal::displayInfo(MString() + "startFrame : " + startFrame); + //MGlobal::displayInfo(MString() + "endFrame : " + endFrame); - jointIt.next(); - } + unsigned int startKeyFrameIndex = jointAnim.findClosest(MTime(startFrame, MTime::kNTSCField), &tmp); - int currentFrame = startFrame; - while (currentFrame != endFrame + 1) { // ANDREAS - Animation::Keyframe thisKeyFrame; - thisKeyFrame.Index = currentFrame - startFrame; - thisKeyFrame.Time = thisKeyFrame.Index * oneDivSixty; + if (tmp == MStatus::kFailure) + MGlobal::displayInfo(MString() + "Fail :c"); - MAnimControl::setCurrentTime(MTime(currentFrame, MTime::kNTSCField)); - MTime time = MAnimControl::currentTime(); + if (startFrame * oneDivSixty <= jointAnim.time(startKeyFrameIndex).value() && jointAnim.time(startKeyFrameIndex).value() <= endFrame * oneDivSixty) { + //MGlobal::displayInfo(MString() + "Start key time : " + jointAnim.time(startKeyFrameIndex).value()); - for (auto aJoint : animatedJoints){ - MFnTransform thisJoint(aJoint); - Animation::Keyframe::JointProperty joint; - auto it = std::find(m_Hierarchy.begin(), m_Hierarchy.end(), thisJoint.object()); - if (it != m_Hierarchy.end()) { - joint.ID = it - m_Hierarchy.begin(); - } - else { - MGlobal::displayError(MString() + "Could not find joint ID for: " + thisJoint.name()); - } - - MTransformationMatrix Matrix = thisJoint.transformation(); - MPlug BindPose = thisJoint.findPlug("bindPose"); - MDataHandle DataHandle; - BindPose.getValue(DataHandle); - MFnMatrixData MartixFn(DataHandle.data()); - MMatrix BindPoseMatrix = MartixFn.matrix(); - Matrix = Matrix.asMatrix(); - + if (startFrame <= jointAnim.time(startKeyFrameIndex).value() && jointAnim.time(startKeyFrameIndex).value() <= endFrame ) { + animatedJoints.push_back(jointIt.item()); + i = 9; + break; + } + + unsigned int endKeyFrameIndex = jointAnim.findClosest(MTime(endFrame, MTime::kNTSCField)); + MGlobal::displayInfo(MString() + startKeyFrameIndex + " " + endKeyFrameIndex); + MGlobal::displayInfo(MString() + "Fail!!!!!!!!!!!!!!!!!!!!!!!!!"); + + if (startFrame * oneDivSixty <= jointAnim.time(endKeyFrameIndex).value() && jointAnim.time(endKeyFrameIndex).value() <= endFrame * oneDivSixty || endKeyFrameIndex - startKeyFrameIndex > 0) { + //MGlobal::displayInfo(MString() + "End key index : " + endKeyFrameIndex); + //MGlobal::displayInfo(MString() + "end key time : " + jointAnim.time(endKeyFrameIndex).value()); + + /*MGlobal::displayInfo(MString() + "start keyfram index: " + startKeyFrameIndex + ". End keyfram index: " + endKeyFrameIndex + ".");*/ + + /*if (startFrame <= jointAnim.time(endKeyFrameIndex).value() && jointAnim.time(endKeyFrameIndex).value() <= endFrame || endKeyFrameIndex - startKeyFrameIndex > 0) { + animatedJoints.push_back(jointIt.item()); + i = 9; + break; + } + + MFnTransform MayaJoint(jointIt.item()); + + MPlug BindPose = MayaJoint.findPlug("bindPose"); + MDataHandle DataHandle; + BindPose.getValue(DataHandle); + MFnMatrixData MartixFn(DataHandle.data()); + MMatrix BindPoseMatrix = MartixFn.matrix(); + + if (!BindPoseMatrix.isEquivalent(MayaJoint.transformationMatrix())) + { + MGlobal::displayError(MString() + animationName.c_str() + " is using " + MayaJoint.name() + " that is not in bind pose nor is it key framed in the animation, the exported animation will NOT correspond to the animation in Maya"); + } + } + } + } + + } // end of int i loop*/ + /* jointIt.next(); + } + jointIt.reset(); + }*/ + + MItDag jointIt(MItDag::TraversalType::kDepthFirst, MFn::kJoint); + unsigned int jointID = 0; + + while (!jointIt.isDone()) { + int currentFrame = startFrame; + Animation::JointAnimation thisJointAnimation; + bool haxBool = false; + while (currentFrame < endFrame) { + Animation::JointAnimation::KeyFrame thisKeyFrame; + //thisKeyFrame.Index = currentFrame - startFrame; + //thisKeyFrame.Time = thisKeyFrame.Index * oneDivSixty; + + MAnimControl::setCurrentTime(MTime(currentFrame, MTime::kNTSCField)); + MTime time = MAnimControl::currentTime(); + + MFnTransform thisJoint(jointIt.currentItem()); + MTransformationMatrix transformationMatrix = thisJoint.transformationMatrix(); + + double doubleMat[4][4]; + + if (currentFrame != startFrame) { + //Animation::JointAnimation joint; + + doubleMat[0][0] = joinCheckMap[thisJoint.name().asChar()][0][0]; + doubleMat[0][1] = joinCheckMap[thisJoint.name().asChar()][0][1]; + doubleMat[0][2] = joinCheckMap[thisJoint.name().asChar()][0][2]; + doubleMat[0][3] = joinCheckMap[thisJoint.name().asChar()][0][3]; + doubleMat[1][0] = joinCheckMap[thisJoint.name().asChar()][1][0]; + doubleMat[1][1] = joinCheckMap[thisJoint.name().asChar()][1][1]; + doubleMat[1][2] = joinCheckMap[thisJoint.name().asChar()][1][2]; + doubleMat[1][3] = joinCheckMap[thisJoint.name().asChar()][1][3]; + doubleMat[2][0] = joinCheckMap[thisJoint.name().asChar()][2][0]; + doubleMat[2][1] = joinCheckMap[thisJoint.name().asChar()][2][1]; + doubleMat[2][2] = joinCheckMap[thisJoint.name().asChar()][2][2]; + doubleMat[2][3] = joinCheckMap[thisJoint.name().asChar()][2][3]; + doubleMat[3][0] = joinCheckMap[thisJoint.name().asChar()][3][0]; + doubleMat[3][1] = joinCheckMap[thisJoint.name().asChar()][3][1]; + doubleMat[3][2] = joinCheckMap[thisJoint.name().asChar()][3][2]; + doubleMat[3][3] = joinCheckMap[thisJoint.name().asChar()][3][3]; + + MMatrix LastJointMatrix(doubleMat); + //Is same as last KeyFrame + if (LastJointMatrix.isEquivalent(transformationMatrix.asMatrix())) { + //jointID++; + //jointIt.next(); + currentFrame++; + haxBool = false; + continue; + } else if(!haxBool){ + haxBool = true; + MTransformationMatrix LastJointTransformationMatrix = LastJointMatrix; + MObject jointOrientObj = thisJoint.attribute("jointOrient"); + MFnNumericAttribute jointOrient(jointOrientObj); + double jointOrientDouble[3]; + jointOrient.getDefault(jointOrientDouble[0], jointOrientDouble[1], jointOrientDouble[2]); + //MGlobal::displayError(MString() + "Joint Matrix: "); + //MGlobal::displayError(MString() + Matrix.asMatrix()[0][0] + " " + Matrix.asMatrix()[0][1] + " " + Matrix.asMatrix()[0][2] + " " + Matrix.asMatrix()[0][3]); + //MGlobal::displayError(MString() + Matrix.asMatrix()[1][0] + " " + Matrix.asMatrix()[1][1] + " " + Matrix.asMatrix()[1][2] + " " + Matrix.asMatrix()[1][3]); + //MGlobal::displayError(MString() + Matrix.asMatrix()[2][0] + " " + Matrix.asMatrix()[2][1] + " " + Matrix.asMatrix()[2][2] + " " + Matrix.asMatrix()[2][3]); + //MGlobal::displayError(MString() + Matrix.asMatrix()[3][0] + " " + Matrix.asMatrix()[3][1] + " " + Matrix.asMatrix()[3][2] + " " + Matrix.asMatrix()[3][3]); + + MEulerRotation joEuler(jointOrientDouble[0], jointOrientDouble[1], jointOrientDouble[2]); + MQuaternion jo = joEuler.asQuaternion(); + + double tmp[4]; + LastJointTransformationMatrix.getRotationQuaternion(tmp[0], tmp[1], tmp[2], tmp[3]); + MQuaternion rotation(tmp); + + rotation = rotation * jo; + rotation.get(tmp); + + //Animation::JointAnimation::KeyFrame keyframe; + Animation::JointAnimation::KeyFrame previousKeyFrame; + previousKeyFrame.Index = currentFrame - startFrame - 1; + previousKeyFrame.Time = previousKeyFrame.Index * oneDivSixty; + + previousKeyFrame.Rotation[0] = tmp[0]; + previousKeyFrame.Rotation[1] = tmp[1]; + previousKeyFrame.Rotation[2] = tmp[2]; + previousKeyFrame.Rotation[3] = tmp[3]; + LastJointTransformationMatrix.getTranslation(MSpace::kTransform).get(tmp); + previousKeyFrame.Position[0] = tmp[0]; + previousKeyFrame.Position[1] = tmp[1]; + previousKeyFrame.Position[2] = tmp[2]; + LastJointTransformationMatrix.getScale(tmp, MSpace::kTransform); + previousKeyFrame.Scale[0] = tmp[0]; + previousKeyFrame.Scale[1] = tmp[1]; + previousKeyFrame.Scale[2] = tmp[2]; + + thisJointAnimation.m_KeyFrames.push_back(previousKeyFrame); + } + } + + transformationMatrix.asMatrix().get(doubleMat); + + //Save transformationMatrix to joinCheckMap + joinCheckMap[thisJoint.name().asChar()][0][0] = doubleMat[0][0]; + joinCheckMap[thisJoint.name().asChar()][0][1] = doubleMat[0][1]; + joinCheckMap[thisJoint.name().asChar()][0][2] = doubleMat[0][2]; + joinCheckMap[thisJoint.name().asChar()][0][3] = doubleMat[0][3]; + joinCheckMap[thisJoint.name().asChar()][1][0] = doubleMat[1][0]; + joinCheckMap[thisJoint.name().asChar()][1][1] = doubleMat[1][1]; + joinCheckMap[thisJoint.name().asChar()][1][2] = doubleMat[1][2]; + joinCheckMap[thisJoint.name().asChar()][1][3] = doubleMat[1][3]; + joinCheckMap[thisJoint.name().asChar()][2][0] = doubleMat[2][0]; + joinCheckMap[thisJoint.name().asChar()][2][1] = doubleMat[2][1]; + joinCheckMap[thisJoint.name().asChar()][2][2] = doubleMat[2][2]; + joinCheckMap[thisJoint.name().asChar()][2][3] = doubleMat[2][3]; + joinCheckMap[thisJoint.name().asChar()][3][0] = doubleMat[3][0]; + joinCheckMap[thisJoint.name().asChar()][3][1] = doubleMat[3][1]; + joinCheckMap[thisJoint.name().asChar()][3][2] = doubleMat[3][2]; + joinCheckMap[thisJoint.name().asChar()][3][3] = doubleMat[3][3]; + + if (currentFrame == startFrame) { + MPlug thisJointBindPose = thisJoint.findPlug("bindPose"); + MDataHandle DataHandle; + thisJointBindPose.getValue(DataHandle); + MFnMatrixData MartixFn(DataHandle.data()); + MMatrix thisJointBindPoseMatrix = MartixFn.matrix(); + + MFnTransform Parent(thisJoint.parent(0), &status); + if (status == MS::kSuccess && thisJoint.parent(0).apiType() == MFn::kJoint) { + MTransformationMatrix Matrix = Parent.transformation(); + MPlug parentBindPose = Parent.findPlug("bindPose"); + MDataHandle DataHandle; + parentBindPose.getValue(DataHandle); + MFnMatrixData MartixFn(DataHandle.data()); + MMatrix parentBindPoseMatrix = MartixFn.matrix(); + + thisJointBindPoseMatrix = thisJointBindPoseMatrix * parentBindPoseMatrix.inverse(); + } + + if (thisJointBindPoseMatrix.isEquivalent(transformationMatrix.asMatrix())) { + //jointID++; + //jointIt.next(); + currentFrame++; + MGlobal::displayError(MString() + thisJoint.name() + " is in bindPose"); + continue; + } + haxBool = true; + } + MObject jointOrientObj = thisJoint.attribute("jointOrient"); MFnNumericAttribute jointOrient(jointOrientObj); double jointOrientDouble[3]; @@ -175,95 +369,97 @@ Animation Skeleton::GetAnimData(std::string animationName, int startFrame, int e MEulerRotation joEuler(jointOrientDouble[0], jointOrientDouble[1], jointOrientDouble[2]); MQuaternion jo = joEuler.asQuaternion(); - double tmp[4]; - Matrix.getRotationQuaternion(tmp[0], tmp[1], tmp[2], tmp[3]); + double tmp[4]; + transformationMatrix.getRotationQuaternion(tmp[0], tmp[1], tmp[2], tmp[3]); MQuaternion rotation(tmp); rotation = rotation * jo; rotation.get(tmp); - joint.Rotation[0] = tmp[0]; - joint.Rotation[1] = tmp[1]; - joint.Rotation[2] = tmp[2]; - joint.Rotation[3] = tmp[3]; - Matrix.getTranslation(MSpace::kTransform).get(tmp); - joint.Position[0] = tmp[0]; - joint.Position[1] = tmp[1]; - joint.Position[2] = tmp[2]; - Matrix.getScale(tmp, MSpace::kTransform); - joint.Scale[0] = tmp[0]; - joint.Scale[1] = tmp[1]; - joint.Scale[2] = tmp[2]; + //Animation::JointAnimation::KeyFrame keyframe; + thisKeyFrame.Index = currentFrame - startFrame; + thisKeyFrame.Time = thisKeyFrame.Index * oneDivSixty; - thisKeyFrame.JointProperties.push_back(joint); - } - returnData.Keyframes.push_back(thisKeyFrame); - currentFrame++; - } + thisKeyFrame.Rotation[0] = tmp[0]; + thisKeyFrame.Rotation[1] = tmp[1]; + thisKeyFrame.Rotation[2] = tmp[2]; + thisKeyFrame.Rotation[3] = tmp[3]; + transformationMatrix.getTranslation(MSpace::kTransform).get(tmp); + thisKeyFrame.Position[0] = tmp[0]; + thisKeyFrame.Position[1] = tmp[1]; + thisKeyFrame.Position[2] = tmp[2]; + transformationMatrix.getScale(tmp, MSpace::kTransform); + thisKeyFrame.Scale[0] = tmp[0]; + thisKeyFrame.Scale[1] = tmp[1]; + thisKeyFrame.Scale[2] = tmp[2]; - returnData.NumKeyFrames = returnData.Keyframes.size(); - returnData.NumberOfJoints = animatedJoints.size(); + thisJointAnimation.m_KeyFrames.push_back(thisKeyFrame); - return returnData; + currentFrame++; + } + //thisKeyFrame.NumberOfJoints = thisKeyFrame.JointProperties.size(); + thisJointAnimation.numberOFKeyFrames = thisJointAnimation.m_KeyFrames.size(); + returnData.JointsFrameMap[jointID] = (thisJointAnimation); + + jointID++; + jointIt.next(); + } + returnData.NumOfJointFrames = returnData.JointsFrameMap.size(); + return returnData; } std::vector Skeleton::GetBindPoses() { MStatus status; - std::vector m_AllSkeletons; - std::vector m_Hierarchy; + std::vector m_AllSkeletons; + std::vector m_Hierarchy; - MItDag jointIt(MItDag::TraversalType::kDepthFirst, MFn::kJoint); - BindPoseSkeletonNode SkeletonStorage; - while (!jointIt.isDone()) { - MFnTransform MayaJoint(jointIt.currentItem()); - BindPoseSkeletonNode::BindPoseJoint NewJoint; + MItDag jointIt(MItDag::TraversalType::kDepthFirst, MFn::kJoint); + BindPoseSkeletonNode SkeletonStorage; + while (!jointIt.isDone()) { + MFnTransform MayaJoint(jointIt.currentItem()); + BindPoseSkeletonNode::BindPoseJoint NewJoint; - if (MFnDependencyNode(MayaJoint.parent(0)).name() == "world") { - if (SkeletonStorage.Joints.size() != 0) { - m_AllSkeletons.push_back(SkeletonStorage); + if (MFnDependencyNode(MayaJoint.parent(0)).object().apiType() != MFn::kJoint) { + if (SkeletonStorage.Joints.size() != 0) { + m_AllSkeletons.push_back(SkeletonStorage); - SkeletonStorage.Joints.clear(); - SkeletonStorage.Name.clear(); - } - SkeletonStorage.Name = std::string(MayaJoint.name().asChar()); - NewJoint.ParentID = -1; // This joint is root - } - else { - auto it = std::find(m_Hierarchy.begin(), m_Hierarchy.end(), MayaJoint.parent(0)); - if (it != m_Hierarchy.end()) { - NewJoint.ParentID = it - m_Hierarchy.begin(); - } - else { - MGlobal::displayError(MString() + "Could not find joint parent for: " + MayaJoint.name()); - } - } - m_Hierarchy.push_back(MayaJoint.object()); + SkeletonStorage.Joints.clear(); + SkeletonStorage.Name.clear(); + } + SkeletonStorage.Name = std::string(MayaJoint.name().asChar()); + NewJoint.ParentID = -1; // This joint is root + } else { + auto it = std::find(m_Hierarchy.begin(), m_Hierarchy.end(), MayaJoint.parent(0)); + if (it != m_Hierarchy.end()) { + NewJoint.ParentID = it - m_Hierarchy.begin(); + } else { + MGlobal::displayError(MString() + "Could not find joint parent for: " + MayaJoint.name()); + } + } + m_Hierarchy.push_back(MayaJoint.object()); - MPlug BindPose = MayaJoint.findPlug("bindPose", &status); - if (status != MS::kSuccess) { + MPlug BindPose = MayaJoint.findPlug("bindPose", &status); + if (status != MS::kSuccess) { MGlobal::displayError(MString() + "Could not find bindPose plug: " + status.errorString()); } - MDataHandle DataHandle; - BindPose.getValue(DataHandle); - MFnMatrixData MartixFn(DataHandle.data()); - MMatrix Matrix = MartixFn.matrix(); + MDataHandle DataHandle; + BindPose.getValue(DataHandle); + MFnMatrixData MartixFn(DataHandle.data()); + MMatrix Matrix = MartixFn.matrix(); MVector tmp = MayaJoint.transformation().getTranslation(MSpace::kObject); - MGlobal::displayError(MString() + "translation befor: " + tmp[0] + " " + tmp[1] + " " + tmp[2]); //Matrix[3][0] *= -1; //Matrix[3][2] *= -1; //Matrix[3][1] *= -1; double test[3]; MayaJoint.transformation().getScale(test, MSpace::kObject); - MGlobal::displayError(MString() + "scale: " + test[0] + " " + test[1] + " " + test[2]); MTransformationMatrix::RotationOrder order = MTransformationMatrix::RotationOrder::kXYZ; MayaJoint.transformation().getRotation(test, order); - MGlobal::displayError(MString() + "rotation: " + test[0] + " " + test[1] + " " + test[2]); - + //----- test @@ -310,33 +506,33 @@ std::vector Skeleton::GetBindPoses() Matrix = Matrix.inverse(); - for (int i = 0; i < 4; i++) { - for (int j = 0; j < 4; j++) { - NewJoint.OffsetMatrix[i][j] = Matrix.matrix[i][j]; - } - } + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + NewJoint.OffsetMatrix[i][j] = Matrix.matrix[i][j]; + } + } - NewJoint.Name = MayaJoint.name().asChar(); + NewJoint.Name = MayaJoint.name().asChar(); NewJoint.NameLength = MayaJoint.name().length() + 1; NewJoint.ID = SkeletonStorage.Joints.size(); - //double tmp[3]; - //((MTransformationMatrix)Matrix).eulerRotation().asVector().get(tmp); - //NewJoint.Rotation[0] = tmp[0]; - //NewJoint.Rotation[1] = tmp[1]; - //NewJoint.Rotation[2] = tmp[2]; - //((MTransformationMatrix)Matrix).getScale(tmp, MSpace::Space::kTransform); - //NewJoint.Scale[0] = tmp[0]; - //NewJoint.Scale[1] = tmp[1]; - //NewJoint.Scale[2] = tmp[2]; - //((MTransformationMatrix)Matrix).getTranslation(MSpace::Space::kTransform).get(tmp); - //NewJoint.Translation[0] = tmp[0]; - //NewJoint.Translation[1] = tmp[1]; - //NewJoint.Translation[2] = tmp[2]; - SkeletonStorage.Joints.push_back(NewJoint); + //double tmp[3]; + //((MTransformationMatrix)Matrix).eulerRotation().asVector().get(tmp); + //NewJoint.Rotation[0] = tmp[0]; + //NewJoint.Rotation[1] = tmp[1]; + //NewJoint.Rotation[2] = tmp[2]; + //((MTransformationMatrix)Matrix).getScale(tmp, MSpace::Space::kTransform); + //NewJoint.Scale[0] = tmp[0]; + //NewJoint.Scale[1] = tmp[1]; + //NewJoint.Scale[2] = tmp[2]; + //((MTransformationMatrix)Matrix).getTranslation(MSpace::Space::kTransform).get(tmp); + //NewJoint.Translation[0] = tmp[0]; + //NewJoint.Translation[1] = tmp[1]; + //NewJoint.Translation[2] = tmp[2]; + SkeletonStorage.Joints.push_back(NewJoint); SkeletonStorage.numBones++; - jointIt.next(); - } - m_AllSkeletons.push_back(SkeletonStorage); + jointIt.next(); + } + m_AllSkeletons.push_back(SkeletonStorage); - return m_AllSkeletons; + return m_AllSkeletons; } \ No newline at end of file diff --git a/tools/MayaExporter/MayaExporter/Skeleton.h b/tools/MayaExporter/MayaExporter/Skeleton.h index 6a288c8a..3dfbe8a5 100644 --- a/tools/MayaExporter/MayaExporter/Skeleton.h +++ b/tools/MayaExporter/MayaExporter/Skeleton.h @@ -3,50 +3,63 @@ #include #include +#include #include #include "MayaIncludes.h" #include "OutputData.h" class Animation : public OutputData { public: - struct Keyframe - { - struct JointProperty - { - int ID = 0; + //struct Keyframe + //{ + // struct JointProperty + // { + // int ID = 0; + // float Position[3]{ 0 }; + // float Rotation[4]{ 0 }; + // float Scale[3]{ 0 }; + // }; + + // int Index = 0; + // float Time = 0; + // int NumberOfJoints; + // std::vector JointProperties; + //}; + + struct JointAnimation { + struct KeyFrame { + int Index = 0; + float Time = 0; float Position[3]{ 0 }; float Rotation[4]{ 0 }; float Scale[3]{ 0 }; - }; - - int Index = 0; - float Time = 0; - std::vector JointProperties; - }; + }; + unsigned int numberOFKeyFrames = 0; + std::vector m_KeyFrames; + }; std::string Name; int nameLength = 0; float Duration = 0; - int NumKeyFrames = 0; - int NumberOfJoints = 0; - std::vector Keyframes; + int NumOfJointFrames = 0; + std::map JointsFrameMap; virtual void WriteBinary(std::ostream& out) { out.write((char*)&nameLength, sizeof(int)); out.write(Name.c_str(), Name.size() + 1); out.write((char*)&Duration, sizeof(float)); - out.write((char*)&NumKeyFrames, sizeof(int)); - out.write((char*)&NumberOfJoints, sizeof(int)); + out.write((char*)&NumOfJointFrames, sizeof(int)); //Här under loopas alla key frames igenom - for (auto aKeyframe : Keyframes) { - out.write((char*)&aKeyframe.Index, sizeof(int)); - out.write((char*)&aKeyframe.Time, sizeof(float)); - for (auto aJoint : aKeyframe.JointProperties) { - out.write((char*)&aJoint.ID, sizeof(int)); - out.write((char*)aJoint.Position, sizeof(float) * 3); - out.write((char*)aJoint.Rotation, sizeof(float) * 4); - out.write((char*)aJoint.Scale, sizeof(float) * 3); + for (auto aJointAnimation : JointsFrameMap) { + out.write((char*)&aJointAnimation.first, sizeof(int)); + out.write((char*)&aJointAnimation.second.numberOFKeyFrames, sizeof(int)); + for (auto aJointKeyFrame : aJointAnimation.second.m_KeyFrames) { + out.write((char*)&aJointKeyFrame.Index, sizeof(int)); + out.write((char*)&aJointKeyFrame.Time, sizeof(float)); + out.write((char*)&aJointKeyFrame.Position, sizeof(float) * 3); + out.write((char*)&aJointKeyFrame.Rotation, sizeof(float) * 4); + out.write((char*)&aJointKeyFrame.Scale, sizeof(float) * 3); } } } @@ -55,16 +68,17 @@ public: { out << "Animation Name: " << Name << endl; out << "Duration: " << Duration << endl; - out << "Number of KeyFrames: " << NumKeyFrames << endl; - out << "Number of Joints: " << NumberOfJoints << endl; - for (auto aKeyframe : Keyframes) { - out << "Frame: " << aKeyframe.Index << endl; - out << "Time: " << aKeyframe.Time << endl; - for (auto aJoint : aKeyframe.JointProperties) { - out << "Joint ID: " << aJoint.ID << endl; - out << aJoint.Position[0] << " " << aJoint.Position[1] << " " << aJoint.Position[2] << endl; - out << aJoint.Rotation[0] << " " << aJoint.Rotation[1] << " " << aJoint.Rotation[2] << " " << aJoint.Rotation[3] << endl; - out << aJoint.Scale[0] << " " << aJoint.Scale[1] << " " << aJoint.Scale[2] << endl; + out << "Number of KeyFrames: " << NumOfJointFrames << endl; + for (auto aJointAnimation : JointsFrameMap) { + out << "Bone: " << aJointAnimation.first << endl; + //out << "Time: " << aJointAnimation.Time << endl; + //out << "Number of Joints: " << aKeyframe.NumberOfJoints << endl; + for (auto aJointKeyFrame : aJointAnimation.second.m_KeyFrames) { + //out << "Joint ID: " << aJoint.ID << endl; + out << "Time: " << aJointKeyFrame.Time << endl; + out << aJointKeyFrame.Position[0] << " " << aJointKeyFrame.Position[1] << " " << aJointKeyFrame.Position[2] << endl; + out << aJointKeyFrame.Rotation[0] << " " << aJointKeyFrame.Rotation[1] << " " << aJointKeyFrame.Rotation[2] << " " << aJointKeyFrame.Rotation[3] << endl; + out << aJointKeyFrame.Scale[0] << " " << aJointKeyFrame.Scale[1] << " " << aJointKeyFrame.Scale[2] << endl; } }