Merge remote-tracking branch 'origin/master' into Animations
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
#include "Core/World.h"
|
||||
#include "Rendering/Model.h"
|
||||
#include "imgui/imgui.h"
|
||||
#include "Core/Octree.h"
|
||||
|
||||
namespace Collision
|
||||
{
|
||||
@@ -145,13 +146,14 @@ bool RayVsTriangle(const Ray& ray,
|
||||
}
|
||||
|
||||
bool RayVsModel(const Ray& ray,
|
||||
const std::vector<RawModel::Vertex>& modelVertices,
|
||||
const std::vector<unsigned int>& modelIndices)
|
||||
const RawModel::Vertex* modelVertices,
|
||||
const std::vector<unsigned int>& modelIndices,
|
||||
const glm::mat4& modelMatrix)
|
||||
{
|
||||
for (int i = 0; i < modelIndices.size(); ++i) {
|
||||
glm::vec3 v0 = modelVertices[modelIndices[i]].Position;
|
||||
glm::vec3 v1 = modelVertices[modelIndices[++i]].Position;
|
||||
glm::vec3 v2 = modelVertices[modelIndices[++i]].Position;
|
||||
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;
|
||||
}
|
||||
@@ -192,19 +194,20 @@ bool RayVsTriangle(const Ray& ray,
|
||||
}
|
||||
|
||||
bool RayVsModel(const Ray& ray,
|
||||
const std::vector<RawModel::Vertex>& modelVertices,
|
||||
const RawModel::Vertex* modelVertices,
|
||||
const std::vector<unsigned int>& 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 v1 = modelVertices[modelIndices[++i]].Position;
|
||||
glm::vec3 v2 = modelVertices[modelIndices[++i]].Position;
|
||||
float 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)) {
|
||||
@@ -218,14 +221,15 @@ bool RayVsModel(const Ray& ray,
|
||||
}
|
||||
|
||||
bool RayVsModel(const Ray& ray,
|
||||
const std::vector<RawModel::Vertex>& modelVertices,
|
||||
const RawModel::Vertex* modelVertices,
|
||||
const std::vector<unsigned int>& 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;
|
||||
}
|
||||
@@ -572,11 +576,11 @@ boost::optional<EntityAABB> EntityAbsoluteAABB(EntityWrapper& entity, bool takeM
|
||||
ComponentWrapper& cAABB = entity["AABB"];
|
||||
modelSpaceBox = EntityAABB::FromOriginSize((glm::vec3)cAABB["Origin"], (glm::vec3)cAABB["Size"]);
|
||||
} else if (entity.HasComponent("Model")) {
|
||||
Model* 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&) {
|
||||
@@ -638,4 +642,36 @@ boost::optional<EntityAABB> AbsoluteAABBExplosionEffect(EntityWrapper& entity)
|
||||
return aabb;
|
||||
}
|
||||
|
||||
boost::optional<EntityAABB> EntityFirstHitByRay(const Ray& ray, std::vector<EntityAABB> 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<EntityAABB> EntityFirstHitByRay(const Ray& ray, Octree<EntityAABB>* octree, float& outDistance, glm::vec3& outIntersectPos)
|
||||
{
|
||||
std::vector<EntityAABB> outObjects;
|
||||
octree->ObjectsPossiblyHitByRay(ray, outObjects);
|
||||
return Collision::EntityFirstHitByRay(ray, outObjects, outDistance, outIntersectPos);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -65,7 +65,6 @@ void EntityFilePreprocessor::parseComponentInfo()
|
||||
|
||||
// Name
|
||||
compInfo.Name = XS::ToString(element->getName());
|
||||
bool brk = compInfo.Name == "HiddenForLocalPlayer";
|
||||
// Known allocation
|
||||
compInfo.Meta->Allocation = m_ComponentCounts[compInfo.Name];
|
||||
// Annotation
|
||||
|
||||
@@ -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<ChildInfo> childInfos;
|
||||
std::vector<RaySorterInfo> 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,4 +259,9 @@ std::vector<int> Child::childIndicesContainingBox(const AABB& box) const
|
||||
}
|
||||
}
|
||||
|
||||
bool isFirstLower(const RaySorterInfo& first, const RaySorterInfo& second)
|
||||
{
|
||||
return first.Distance < second.Distance;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -390,8 +390,9 @@ bool Client::OnInputCommand(const Events::InputCommand & e)
|
||||
bool Client::OnPlayerDamage(const Events::PlayerDamage & e)
|
||||
{
|
||||
Packet packet(MessageType::OnPlayerDamage, m_SendPacketID);
|
||||
packet.WritePrimitive(m_ClientIDToServerID.at(e.Inflictor.ID));
|
||||
packet.WritePrimitive(m_ClientIDToServerID.at(e.Victim.ID));
|
||||
packet.WritePrimitive(e.Damage);
|
||||
packet.WritePrimitive(m_ClientIDToServerID.at(e.Player.ID));
|
||||
send(packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -299,8 +299,9 @@ void Server::parseOnInputCommand(Packet& packet)
|
||||
void Server::parseOnPlayerDamage(Packet & packet)
|
||||
{
|
||||
Events::PlayerDamage e;
|
||||
e.Inflictor = EntityWrapper(m_World, packet.ReadPrimitive<EntityID>());
|
||||
e.Victim = EntityWrapper(m_World, packet.ReadPrimitive<EntityID>());
|
||||
e.Damage = packet.ReadPrimitive<double>();
|
||||
e.Player = EntityWrapper(m_World, packet.ReadPrimitive<EntityID>());
|
||||
m_EventBroker->Publish(e);
|
||||
//LOG_DEBUG("Server::parseOnPlayerDamage: Command is %s. Value is %f. PlayerID is %i.", e.DamageAmount, e.PlayerDamagedID, e.TypeOfDamage.c_str());
|
||||
}
|
||||
|
||||
@@ -34,19 +34,32 @@ void AnimationSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& a
|
||||
if (!(bool)animationComponent["Loop" + std::to_string(i)]) {
|
||||
if (nextTime > animation->Duration) {
|
||||
nextTime = animation->Duration;
|
||||
Events::AnimationComplete e;
|
||||
e.Entity = entity;
|
||||
e.Name = (std::string)animationComponent["AnimationName" + std::to_string(i)];
|
||||
m_EventBroker->Publish(e);
|
||||
} else if (nextTime < 0) {
|
||||
Events::AnimationComplete e;
|
||||
e.Entity = entity;
|
||||
e.Name = (std::string)animationComponent["AnimationName" + std::to_string(i)];
|
||||
m_EventBroker->Publish(e);
|
||||
nextTime = 0;
|
||||
}
|
||||
|
||||
(double&)animationComponent["Speed" + std::to_string(i)] = 0.0;
|
||||
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) {
|
||||
Events::AnimationComplete e;
|
||||
e.Entity = entity;
|
||||
e.Name = (std::string)animationComponent["AnimationName" + std::to_string(i)];
|
||||
m_EventBroker->Publish(e);
|
||||
nextTime -= animation->Duration;
|
||||
} else if (nextTime < 0) {
|
||||
Events::AnimationComplete e;
|
||||
e.Entity = entity;
|
||||
e.Name = (std::string)animationComponent["AnimationName" + std::to_string(i)];
|
||||
m_EventBroker->Publish(e);
|
||||
nextTime += animation->Duration;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -13,7 +13,7 @@ DrawBloomPass::DrawBloomPass(IRenderer* renderer)
|
||||
|
||||
void DrawBloomPass::InitializeTextures()
|
||||
{
|
||||
m_WhiteTexture = ResourceManager::Load<Texture>("Textures/Core/White.png");
|
||||
m_WhiteTexture = CommonFunctions::LoadTexture("Textures/Core/White.png", false);
|
||||
}
|
||||
|
||||
void DrawBloomPass::InitializeShaderPrograms()
|
||||
|
||||
@@ -13,10 +13,11 @@ DrawFinalPass::DrawFinalPass(IRenderer* renderer, LightCullingPass* lightCulling
|
||||
|
||||
void DrawFinalPass::InitializeTextures()
|
||||
{
|
||||
m_WhiteTexture = ResourceManager::Load<Texture>("Textures/Core/White.png");
|
||||
m_BlackTexture = ResourceManager::Load<Texture>("Textures/Core/Black.png");
|
||||
m_NeutralNormalTexture = ResourceManager::Load<Texture>("Textures/Core/NeutralNormalMap.png");
|
||||
m_GreyTexture = ResourceManager::Load<Texture>("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()
|
||||
@@ -79,9 +80,17 @@ void DrawFinalPass::InitializeShaderPrograms()
|
||||
m_ExplosionEffectProgram->Link();
|
||||
GLERROR("Creating explosion program");
|
||||
|
||||
m_SpriteProgram = ResourceManager::Load<ShaderProgram>("#SpriteProgram");
|
||||
m_SpriteProgram->AddShader(std::shared_ptr<Shader>(new VertexShader("Shaders/Sprite.vert.glsl")));
|
||||
m_SpriteProgram->AddShader(std::shared_ptr<Shader>(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<ShaderProgram>("#ForwardPlusSplatMapProgram");
|
||||
m_ForwardPlusSplatMapProgram->AddShader(std::shared_ptr<Shader>(new VertexShader("Shaders/ForwardPlus.vert.glsl")));
|
||||
m_ForwardPlusSplatMapProgram->AddShader(std::shared_ptr<Shader>(new FragmentShader("Shaders/ForwardPlusSplatMap.frag.glsl")));
|
||||
m_ForwardPlusSplatMapProgram->AddShader(std::shared_ptr<Shader>(new FragmentShader("Shaders/ForwardPlusSplatMapRGB.frag.glsl")));
|
||||
m_ForwardPlusSplatMapProgram->Compile();
|
||||
m_ForwardPlusSplatMapProgram->BindFragDataLocation(0, "sceneColor");
|
||||
m_ForwardPlusSplatMapProgram->BindFragDataLocation(1, "bloomColor");
|
||||
@@ -91,7 +100,7 @@ void DrawFinalPass::InitializeShaderPrograms()
|
||||
m_ExplosionEffectSplatMapProgram = ResourceManager::Load<ShaderProgram>("#ExplosionEffectSplatMapProgram");
|
||||
m_ExplosionEffectSplatMapProgram->AddShader(std::shared_ptr<Shader>(new VertexShader("Shaders/ForwardPlus.vert.glsl")));
|
||||
m_ExplosionEffectSplatMapProgram->AddShader(std::shared_ptr<Shader>(new GeometryShader("Shaders/ExplosionEffect.geom.glsl")));
|
||||
m_ExplosionEffectSplatMapProgram->AddShader(std::shared_ptr<Shader>(new FragmentShader("Shaders/ForwardPlusSplatMap.frag.glsl")));
|
||||
m_ExplosionEffectSplatMapProgram->AddShader(std::shared_ptr<Shader>(new FragmentShader("Shaders/ForwardPlusSplatMapRGB.frag.glsl")));
|
||||
m_ExplosionEffectSplatMapProgram->Compile();
|
||||
m_ExplosionEffectSplatMapProgram->BindFragDataLocation(0, "sceneColor");
|
||||
m_ExplosionEffectSplatMapProgram->BindFragDataLocation(1, "bloomColor");
|
||||
@@ -119,7 +128,7 @@ void DrawFinalPass::InitializeShaderPrograms()
|
||||
|
||||
m_ExplosionEffectSplatMapSkinnedProgram = ResourceManager::Load<ShaderProgram>("#ExplosionEffectSplatMapSkinnedProgram");
|
||||
m_ExplosionEffectSplatMapSkinnedProgram->AddShader(std::shared_ptr<Shader>(new VertexShader("Shaders/ForwardPlusSkinned.vert.glsl")));
|
||||
m_ExplosionEffectSplatMapSkinnedProgram->AddShader(std::shared_ptr<Shader>(new FragmentShader("Shaders/ForwardPlusSplatMap.frag.glsl")));
|
||||
m_ExplosionEffectSplatMapSkinnedProgram->AddShader(std::shared_ptr<Shader>(new FragmentShader("Shaders/ForwardPlusSplatMapRGB.frag.glsl")));
|
||||
m_ExplosionEffectSplatMapSkinnedProgram->Compile();
|
||||
m_ExplosionEffectSplatMapSkinnedProgram->BindFragDataLocation(0, "sceneColor");
|
||||
m_ExplosionEffectSplatMapSkinnedProgram->BindFragDataLocation(1, "bloomColor");
|
||||
@@ -128,7 +137,7 @@ void DrawFinalPass::InitializeShaderPrograms()
|
||||
|
||||
m_ForwardPlusSplatMapSkinnedProgram = ResourceManager::Load<ShaderProgram>("#ForwardPlusSplatMapSkinnedProgram");
|
||||
m_ForwardPlusSplatMapSkinnedProgram->AddShader(std::shared_ptr<Shader>(new VertexShader("Shaders/ForwardPlusSkinned.vert.glsl")));
|
||||
m_ForwardPlusSplatMapSkinnedProgram->AddShader(std::shared_ptr<Shader>(new FragmentShader("Shaders/ForwardPlusSplatMap.frag.glsl")));
|
||||
m_ForwardPlusSplatMapSkinnedProgram->AddShader(std::shared_ptr<Shader>(new FragmentShader("Shaders/ForwardPlusSplatMapRGB.frag.glsl")));
|
||||
m_ForwardPlusSplatMapSkinnedProgram->Compile();
|
||||
m_ForwardPlusSplatMapSkinnedProgram->BindFragDataLocation(0, "sceneColor");
|
||||
m_ForwardPlusSplatMapSkinnedProgram->BindFragDataLocation(1, "bloomColor");
|
||||
@@ -184,6 +193,8 @@ void DrawFinalPass::Draw(RenderScene& 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
|
||||
@@ -312,7 +323,6 @@ void DrawFinalPass::DrawModelRenderQueues(std::list<std::shared_ptr<RenderJob>>&
|
||||
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<ExplosionEffectJob>(job);
|
||||
if (explosionEffectJob) {
|
||||
@@ -636,6 +646,55 @@ void DrawFinalPass::DrawToDepthBuffer(std::list<std::shared_ptr<RenderJob>>& job
|
||||
|
||||
}
|
||||
|
||||
|
||||
void DrawFinalPass::DrawSprites(std::list<std::shared_ptr<RenderJob>>&jobs, RenderScene& scene)
|
||||
{
|
||||
m_SpriteProgram->Bind();
|
||||
|
||||
GLuint shaderHandle = m_SpriteProgram->GetHandle();
|
||||
|
||||
for(auto& job : jobs) {
|
||||
auto spriteJob = std::dynamic_pointer_cast<SpriteJob>(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<ExplosionEffectJob>& job, RenderScene& scene)
|
||||
{
|
||||
GLERROR("Bind 1 uniform");
|
||||
@@ -891,7 +950,7 @@ void DrawFinalPass::BindModelTextures(GLuint shaderHandle, std::shared_ptr<Model
|
||||
|
||||
//Bind 5 diffuse textures
|
||||
std::string UniformName = "DiffuseUVRepeat";
|
||||
for (unsigned int i = 0; i < 5; i++) {
|
||||
for (unsigned int i = 0; i < 3; i++) {
|
||||
glActiveTexture(texturePosition);
|
||||
if (job->DiffuseTexture.size() > i && job->DiffuseTexture[i]->Texture != nullptr) {
|
||||
glBindTexture(GL_TEXTURE_2D, job->DiffuseTexture[i]->Texture->m_Texture);
|
||||
@@ -905,7 +964,7 @@ void DrawFinalPass::BindModelTextures(GLuint shaderHandle, std::shared_ptr<Model
|
||||
|
||||
//Bind 5 Normal textures
|
||||
UniformName = "NormalUVRepeat";
|
||||
for (unsigned int i = 0; i < 5; i++) {
|
||||
for (unsigned int i = 0; i < 3; i++) {
|
||||
glActiveTexture(texturePosition);
|
||||
if (job->NormalTexture.size() > i && job->NormalTexture[i]->Texture != nullptr) {
|
||||
glBindTexture(GL_TEXTURE_2D, job->NormalTexture[i]->Texture->m_Texture);
|
||||
@@ -919,7 +978,7 @@ void DrawFinalPass::BindModelTextures(GLuint shaderHandle, std::shared_ptr<Model
|
||||
|
||||
//Bind 5 Specular textures
|
||||
UniformName = "SpecularUVRepeat";
|
||||
for (unsigned int i = 0; i < 5; i++) {
|
||||
for (unsigned int i = 0; i < 3; i++) {
|
||||
glActiveTexture(texturePosition);
|
||||
if (job->SpecularTexture.size() > i && job->SpecularTexture[i]->Texture != nullptr) {
|
||||
glBindTexture(GL_TEXTURE_2D, job->SpecularTexture[i]->Texture->m_Texture);
|
||||
@@ -933,7 +992,7 @@ void DrawFinalPass::BindModelTextures(GLuint shaderHandle, std::shared_ptr<Model
|
||||
|
||||
//Bind 5 Incandescence textures
|
||||
UniformName = "GlowUVRepeat";
|
||||
for (unsigned int i = 0; i < 5; i++) {
|
||||
for (unsigned int i = 0; i < 3; i++) {
|
||||
glActiveTexture(texturePosition);
|
||||
if (job->IncandescenceTexture.size() > i && job->IncandescenceTexture[i]->Texture != nullptr) {
|
||||
glBindTexture(GL_TEXTURE_2D, job->IncandescenceTexture[i]->Texture->m_Texture);
|
||||
|
||||
@@ -10,60 +10,31 @@ Model::Model(std::string fileName)
|
||||
case RawModel::MaterialType::SingleTextures:
|
||||
{
|
||||
RawModel::MaterialSingleTextures* materialSingleTexture = static_cast<RawModel::MaterialSingleTextures*>(materialProperty.material);
|
||||
if (!materialSingleTexture->ColorMap.TexturePath.empty()) {
|
||||
materialSingleTexture->ColorMap.Texture = std::shared_ptr<Texture>(ResourceManager::Load<Texture>(materialSingleTexture->ColorMap.TexturePath));
|
||||
}
|
||||
if (!materialSingleTexture->NormalMap.TexturePath.empty()) {
|
||||
materialSingleTexture->NormalMap.Texture = std::shared_ptr<Texture>(ResourceManager::Load<Texture>(materialSingleTexture->NormalMap.TexturePath));
|
||||
}
|
||||
if (!materialSingleTexture->SpecularMap.TexturePath.empty()) {
|
||||
materialSingleTexture->SpecularMap.Texture = std::shared_ptr<Texture>(ResourceManager::Load<Texture>(materialSingleTexture->SpecularMap.TexturePath));
|
||||
}
|
||||
if (!materialSingleTexture->IncandescenceMap.TexturePath.empty()) {
|
||||
materialSingleTexture->IncandescenceMap.Texture = std::shared_ptr<Texture>(ResourceManager::Load<Texture>(materialSingleTexture->IncandescenceMap.TexturePath));
|
||||
}
|
||||
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<RawModel::MaterialSplatMapping*>(materialProperty.material);
|
||||
if (!materialSplatMapping->SplatMap.TexturePath.empty()) {
|
||||
materialSplatMapping->SplatMap.Texture = std::shared_ptr<Texture>(ResourceManager::Load<Texture>(materialSplatMapping->SplatMap.TexturePath));
|
||||
}
|
||||
materialSplatMapping->SplatMap.Texture = CommonFunctions::LoadTexture(materialSplatMapping->SplatMap.TexturePath, false);
|
||||
for (auto& texture : materialSplatMapping->ColorMaps)
|
||||
{
|
||||
if (!texture.TexturePath.empty()) {
|
||||
texture.Texture = std::shared_ptr<Texture>(ResourceManager::Load<Texture>(texture.TexturePath));
|
||||
}
|
||||
else {
|
||||
texture.Texture = nullptr;
|
||||
}
|
||||
texture.Texture = CommonFunctions::LoadTexture(texture.TexturePath, false);
|
||||
}
|
||||
for (auto& texture : materialSplatMapping->NormalMaps)
|
||||
{
|
||||
if (!texture.TexturePath.empty()) {
|
||||
texture.Texture = std::shared_ptr<Texture>(ResourceManager::Load<Texture>(texture.TexturePath));
|
||||
} else {
|
||||
texture.Texture = nullptr;
|
||||
}
|
||||
texture.Texture = CommonFunctions::LoadTexture(texture.TexturePath, false);
|
||||
}
|
||||
for (auto& texture : materialSplatMapping->SpecularMaps)
|
||||
{
|
||||
if (!texture.TexturePath.empty()) {
|
||||
texture.Texture = std::shared_ptr<Texture>(ResourceManager::Load<Texture>(texture.TexturePath));
|
||||
}
|
||||
else {
|
||||
texture.Texture = nullptr;
|
||||
}
|
||||
texture.Texture = CommonFunctions::LoadTexture(texture.TexturePath, false);
|
||||
}
|
||||
for (auto& texture : materialSplatMapping->IncandescenceMaps)
|
||||
{
|
||||
if (!texture.TexturePath.empty()) {
|
||||
texture.Texture = std::shared_ptr<Texture>(ResourceManager::Load<Texture>(texture.TexturePath));
|
||||
}
|
||||
else {
|
||||
texture.Texture = nullptr;
|
||||
}
|
||||
texture.Texture = CommonFunctions::LoadTexture(texture.TexturePath, false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -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<const char*>(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
|
||||
|
||||
@@ -277,8 +277,8 @@ void RawModelCustom::ReadMaterialTextureProperties(RawModelCustom::TextureProper
|
||||
throw Resource::FailedLoadingException("Reading Material texture UVTiling failed");
|
||||
}
|
||||
memcpy(&texture.UVRepeat[0], fileData + offset, sizeof(glm::vec2));
|
||||
offset += sizeof(glm::vec2);
|
||||
}
|
||||
offset += sizeof(glm::vec2);
|
||||
}
|
||||
|
||||
void RawModelCustom::ReadAnimationFile(std::string filePath)
|
||||
|
||||
@@ -33,6 +33,67 @@ bool RenderSystem::OnSetCamera(Events::SetCamera& e)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void RenderSystem::fillSprites(std::list<std::shared_ptr<RenderJob>>& 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);
|
||||
if (!isEntityVisible(entity)) {
|
||||
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> spriteJob = std::shared_ptr<SpriteJob>(new SpriteJob(cSprite, m_Camera, modelMatrix, world, fillColor, fillPercentage, depthSorted));
|
||||
|
||||
jobs.push_back(spriteJob);
|
||||
}
|
||||
}
|
||||
|
||||
bool RenderSystem::isEntityVisible(EntityWrapper& entity)
|
||||
{
|
||||
|
||||
// Only render children of a camera if that camera is currently active
|
||||
if (isChildOfACamera(entity) && !isChildOfCurrentCamera(entity)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Hide things parented to local player if they have the HiddenFromLocalPlayer component
|
||||
bool outOfBodyExperience = ResourceManager::Load<ConfigFile>("Config.ini")->Get<bool>("Debug.OutOfBodyExperience", false);
|
||||
if (entity.HasComponent("HiddenForLocalPlayer") && (entity == m_LocalPlayer || entity.IsChildOf(m_LocalPlayer)) && !outOfBodyExperience) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RenderSystem::isChildOfACamera(EntityWrapper entity)
|
||||
{
|
||||
return entity.FirstParentWithComponent("Camera").Valid();
|
||||
@@ -60,13 +121,7 @@ void RenderSystem::fillModels(RenderScene::Queues &Jobs)
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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.FirstParentWithComponent("HiddenForLocalPlayer").Valid()) && (entity == m_LocalPlayer || entity.IsChildOf(m_LocalPlayer))) {
|
||||
if (!isEntityVisible(entity)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -209,7 +264,6 @@ void RenderSystem::fillPointLights(std::list<std::shared_ptr<RenderJob>>& jobs,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RenderSystem::fillDirectionalLights(std::list<std::shared_ptr<RenderJob>>& jobs, World* world)
|
||||
{
|
||||
auto directionalLights = world->GetComponents("DirectionalLight");
|
||||
@@ -231,7 +285,6 @@ void RenderSystem::fillDirectionalLights(std::list<std::shared_ptr<RenderJob>>&
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RenderSystem::fillText(std::list<std::shared_ptr<RenderJob>>& jobs, World* world)
|
||||
{
|
||||
auto texts = world->GetComponents("Text");
|
||||
@@ -249,6 +302,11 @@ void RenderSystem::fillText(std::list<std::shared_ptr<RenderJob>>& jobs, World*
|
||||
continue;
|
||||
}
|
||||
|
||||
EntityWrapper entity(world, textComponent.EntityID);
|
||||
if (!isEntityVisible(entity)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Font* font;
|
||||
try {
|
||||
font = ResourceManager::Load<Font>(resource);
|
||||
@@ -297,6 +355,7 @@ void RenderSystem::Update(double dt)
|
||||
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);
|
||||
|
||||
@@ -106,16 +106,21 @@ 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());
|
||||
@@ -142,7 +147,8 @@ void Renderer::Draw(RenderFrame& frame)
|
||||
}
|
||||
|
||||
m_ImGuiRenderPass->Draw();
|
||||
glfwSwapBuffers(m_Window);
|
||||
GLERROR("Imgui draw");
|
||||
glfwSwapBuffers(m_Window);
|
||||
}
|
||||
|
||||
PickData Renderer::Pick(glm::vec2 screenCoord)
|
||||
@@ -152,8 +158,8 @@ PickData Renderer::Pick(glm::vec2 screenCoord)
|
||||
|
||||
void Renderer::InitializeTextures()
|
||||
{
|
||||
m_ErrorTexture = ResourceManager::Load<Texture>("Textures/Core/ErrorTexture.png");
|
||||
m_WhiteTexture = ResourceManager::Load<Texture>("Textures/Core/White.png");
|
||||
m_ErrorTexture = CommonFunctions::LoadTexture("Textures/Core/ErrorTexture.png", false);
|
||||
m_WhiteTexture = CommonFunctions::LoadTexture("Textures/Core/White.png", false);
|
||||
}
|
||||
|
||||
|
||||
@@ -161,6 +167,7 @@ void Renderer::SortRenderJobsByDepth(RenderScene &scene)
|
||||
{
|
||||
//Sort all forward jobs so transparency is good.
|
||||
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)
|
||||
|
||||
@@ -2,21 +2,25 @@
|
||||
|
||||
Texture::Texture(std::string path)
|
||||
{
|
||||
PNG image(path);
|
||||
PNG* img = ResourceManager::Load<PNG, true>(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,7 +33,7 @@ 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);
|
||||
|
||||
@@ -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<Texture, true>(path);
|
||||
} else {
|
||||
img = ResourceManager::Load<Texture, false>(path);
|
||||
}
|
||||
} catch (const Resource::StillLoadingException&) {
|
||||
img = ResourceManager::Load<Texture>("Textures/Core/ErrorTexture.png");
|
||||
} catch (const std::exception&) {
|
||||
img = nullptr;
|
||||
}
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,12 @@ file(GLOB SOURCE_FILES_Systems
|
||||
)
|
||||
source_group(Systems FILES ${SOURCE_FILES_Systems})
|
||||
|
||||
file(GLOB SOURCE_FILES_Systems_Weapon
|
||||
"${INCLUDE_PATH}/Systems/Weapon/*.h"
|
||||
"Systems/Weapon/*.cpp"
|
||||
)
|
||||
source_group(Systems\\Weapon FILES ${SOURCE_FILES_Systems_Weapon})
|
||||
|
||||
file(GLOB SOURCE_FILES_Events
|
||||
"${INCLUDE_PATH}/Events/*.h"
|
||||
"Events/*.cpp"
|
||||
@@ -31,6 +37,7 @@ set(SOURCE_FILES
|
||||
${SOURCE_FILES}
|
||||
"Game.cpp"
|
||||
${SOURCE_FILES_Systems}
|
||||
${SOURCE_FILES_Systems_Weapon}
|
||||
${SOURCE_FILES_Events}
|
||||
${SOURCE_FILES_Network}
|
||||
)
|
||||
|
||||
+8
-1
@@ -12,12 +12,15 @@
|
||||
#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/WeaponSystem.h"
|
||||
#include "Game/Systems/DamageIndicatorSystem.h"
|
||||
#include "Game/Systems/Weapon/WeaponSystem.h"
|
||||
#include "Rendering/AnimationSystem.h"
|
||||
#include "Game/Systems/PlayerHUDSystem.h"
|
||||
#include "Rendering/BoneAttachmentSystem.h"
|
||||
#include "Game/Systems/LifetimeSystem.h"
|
||||
#include "../Engine/Core/UniformScaleSystem.h"
|
||||
#include "Rendering/AnimationSystem.h"
|
||||
#include "Network/MultiplayerSnapshotFilter.h"
|
||||
|
||||
@@ -30,6 +33,7 @@ Game::Game(int argc, char* argv[])
|
||||
ResourceManager::RegisterType<Model>("Model");
|
||||
ResourceManager::RegisterType<RawModel>("RawModel");
|
||||
ResourceManager::RegisterType<Texture>("Texture");
|
||||
ResourceManager::RegisterType<PNG>("Png");
|
||||
ResourceManager::RegisterType<ShaderProgram>("ShaderProgram");
|
||||
ResourceManager::RegisterType<EntityFile>("EntityFile");
|
||||
ResourceManager::RegisterType<Font>("FontFile");
|
||||
@@ -118,13 +122,16 @@ Game::Game(int argc, char* argv[])
|
||||
m_SystemPipeline->AddSystem<WeaponSystem>(updateOrderLevel, m_Renderer, m_OctreeCollision);
|
||||
m_SystemPipeline->AddSystem<LifetimeSystem>(updateOrderLevel);
|
||||
m_SystemPipeline->AddSystem<CapturePointSystem>(updateOrderLevel);
|
||||
m_SystemPipeline->AddSystem<CapturePointHUDSystem>(updateOrderLevel);
|
||||
m_SystemPipeline->AddSystem<PickupSpawnSystem>(updateOrderLevel);
|
||||
m_SystemPipeline->AddSystem<DamageIndicatorSystem>(updateOrderLevel);
|
||||
// Populate Octree with collidables
|
||||
++updateOrderLevel;
|
||||
m_SystemPipeline->AddSystem<FillOctreeSystem>(updateOrderLevel, m_OctreeCollision, "Collidable");
|
||||
m_SystemPipeline->AddSystem<FillOctreeSystem>(updateOrderLevel, m_OctreeTrigger, "Player");
|
||||
m_SystemPipeline->AddSystem<FillFrustumOctreeSystem>(updateOrderLevel, m_OctreeFrustrumCulling);
|
||||
m_SystemPipeline->AddSystem<AnimationSystem>(updateOrderLevel);
|
||||
m_SystemPipeline->AddSystem<UniformScaleSystem>(updateOrderLevel);
|
||||
m_SystemPipeline->AddSystem<PlayerHUDSystem>(updateOrderLevel);
|
||||
// Collision and TriggerSystem should update after player.
|
||||
++updateOrderLevel;
|
||||
|
||||
@@ -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<float>()+glm::pi<float>() : glm::half_pi<float>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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, 0.3) : ownedBy == redTeam ? glm::vec4(1, 0.2f, 0, 0.3) : glm::vec4(1, 1, 1, 0.3);
|
||||
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, 0.3);
|
||||
}
|
||||
if (nextPossibleCapturePoint["Blue"] == capturePointNumber) {
|
||||
capturePointEntity["Model"]["Color"] = glm::vec4(0, 1, 1, 0.3);
|
||||
}
|
||||
|
||||
//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;
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
#include "Systems/DamageIndicatorSystem.h"
|
||||
|
||||
DamageIndicatorSystem::DamageIndicatorSystem(SystemParams params)
|
||||
: System(params)
|
||||
{
|
||||
EVENT_SUBSCRIBE_MEMBER(m_EPlayerDamage, &DamageIndicatorSystem::OnPlayerDamage);
|
||||
//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<EntityFile>("Schema/Entities/DamageIndicator.xml");
|
||||
}
|
||||
|
||||
bool DamageIndicatorSystem::OnPlayerDamage(Events::PlayerDamage& e)
|
||||
{
|
||||
if (m_CurrentCamera == EntityID_Invalid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (e.Victim != LocalPlayer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//grab players direction
|
||||
auto playerOrientation = glm::quat((glm::vec3)e.Victim["Transform"]["Orientation"]);
|
||||
|
||||
//get the position vectors, but ignore the y-height
|
||||
auto enemyPosition = (glm::vec3)e.Inflictor["Transform"]["Position"];
|
||||
auto playerPosition = (glm::vec3)e.Victim["Transform"]["Position"];
|
||||
enemyPosition.y = 0.0f;
|
||||
playerPosition.y = 0.0f;
|
||||
|
||||
//calculate the enemy to player vector
|
||||
auto enemyPlayerVector = glm::normalize(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<EntityFile>("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;
|
||||
}
|
||||
@@ -15,13 +15,13 @@ void HealthSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& comp
|
||||
|
||||
bool HealthSystem::OnPlayerDamaged(Events::PlayerDamage& e)
|
||||
{
|
||||
ComponentWrapper cHealth = e.Player["Health"];
|
||||
ComponentWrapper cHealth = e.Victim["Health"];
|
||||
double& health = cHealth["Health"];
|
||||
health -= e.Damage;
|
||||
|
||||
if (health <= 0.0) {
|
||||
Events::PlayerDeath ePlayerDeath;
|
||||
ePlayerDeath.Player = e.Player;
|
||||
ePlayerDeath.Player = e.Victim;
|
||||
m_EventBroker->Publish(ePlayerDeath);
|
||||
//Note: we will delete the entity in PlayerDeathSystem
|
||||
}
|
||||
|
||||
@@ -41,7 +41,9 @@ void PlayerDeathSystem::createDeathEffect(EntityWrapper player)
|
||||
playerEntityModel.Copy(deathEffectEW["Model"]);
|
||||
playerEntityAnimation.Copy(deathEffectEW["Animation"]);
|
||||
//freeze the animation
|
||||
deathEffectEW["Animation"]["Speed"] = 0.0;
|
||||
deathEffectEW["Animation"]["Speed1"] = 0.0;
|
||||
deathEffectEW["Animation"]["Speed2"] = 0.0;
|
||||
deathEffectEW["Animation"]["Speed3"] = 0.0;
|
||||
|
||||
//copy the models position,orientation
|
||||
deathEffectEW["Transform"]["Position"] = (glm::vec3)player["Transform"]["Position"];
|
||||
@@ -50,8 +52,10 @@ void PlayerDeathSystem::createDeathEffect(EntityWrapper player)
|
||||
//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);
|
||||
if (player == LocalPlayer) {
|
||||
auto cam = deathEffectEW.FirstChildByName("Camera");
|
||||
Events::SetCamera eSetCamera;
|
||||
eSetCamera.CameraEntity = cam;
|
||||
m_EventBroker->Publish(eSetCamera);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ void PlayerMovementSystem::updateMovementControllers(double dt)
|
||||
|
||||
float playerMovementSpeed = player["Player"]["MovementSpeed"];
|
||||
float playerCrouchSpeed = player["Player"]["CrouchSpeed"];
|
||||
glm::vec3& wishDirection = player["Player"]["CurrentWishDirection"];
|
||||
|
||||
if (player.HasComponent("Physics")) {
|
||||
ComponentWrapper cPhysics = player["Physics"];
|
||||
@@ -58,7 +59,7 @@ void PlayerMovementSystem::updateMovementControllers(double dt)
|
||||
if (player.HasComponent("DashAbility")) {
|
||||
controller->AssaultDashCheck(dt, ((glm::vec3)cPhysics["Velocity"]).y != 0.0f, player["DashAbility"]["CoolDownMaxTimer"]);
|
||||
}
|
||||
glm::vec3 wishDirection = controller->Movement() * glm::inverse(glm::quat(ori));
|
||||
wishDirection = controller->Movement() * glm::inverse(glm::quat(ori));
|
||||
//this makes sure you can only dash in the 4 directions: forw,backw,left,right
|
||||
if (controller->AssaultDashDoubleTapped() && controller->Movement().z != 0 && controller->Movement().x != 0) {
|
||||
wishDirection = glm::vec3(controller->Movement().x, 0, 0)* glm::inverse(glm::quat(ori));
|
||||
@@ -109,9 +110,15 @@ void PlayerMovementSystem::updateMovementControllers(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() && (isOnGround || !controller->DoubleJumping())) {
|
||||
(bool)cPhysics["IsOnGround"] = false;
|
||||
if (velocity.y == 0.f) {
|
||||
if (isOnGround) {
|
||||
controller->SetDoubleJumping(false);
|
||||
} else {
|
||||
//put a hexagon at the players feet
|
||||
auto hexagonEffect = ResourceManager::Load<EntityFile>("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);
|
||||
@@ -227,7 +234,8 @@ void PlayerMovementSystem::updateVelocity(double dt)
|
||||
float speed = glm::length(velocity);
|
||||
static float groundFriction = 7.f;
|
||||
ImGui::InputFloat("groundFriction", &groundFriction);
|
||||
static float airFriction = 0.f;
|
||||
static float airFriction = 2.f;
|
||||
|
||||
ImGui::InputFloat("airFriction", &airFriction);
|
||||
float friction = isOnGround ? groundFriction : airFriction;
|
||||
if (speed > 0) {
|
||||
|
||||
@@ -88,7 +88,8 @@ bool PlayerSpawnSystem::OnPlayerSpawned(Events::PlayerSpawned& e)
|
||||
|
||||
// Set the camera to the correct entity
|
||||
EntityWrapper cameraEntity = e.Player.FirstChildByName("Camera");
|
||||
if (cameraEntity.Valid()) {
|
||||
bool outOfBodyExperience = ResourceManager::Load<ConfigFile>("Config.ini")->Get<bool>("Debug.OutOfBodyExperience", false);
|
||||
if (cameraEntity.Valid() && !outOfBodyExperience) {
|
||||
Events::SetCamera e;
|
||||
e.CameraEntity = cameraEntity;
|
||||
m_EventBroker->Publish(e);
|
||||
|
||||
@@ -54,7 +54,7 @@ bool SoundSystem::OnInputCommand(const Events::InputCommand & e)
|
||||
}
|
||||
if (e.Command == "TakeDamage" && e.Value > 0) {
|
||||
Events::PlayerDamage ev;
|
||||
ev.Player = LocalPlayer;
|
||||
ev.Victim = LocalPlayer;
|
||||
ev.Damage = 1.0;
|
||||
m_EventBroker->Publish(ev);
|
||||
}
|
||||
|
||||
@@ -48,10 +48,12 @@ EntityWrapper SpawnerSystem::Spawn(EntityWrapper spawner, EntityWrapper parent /
|
||||
EntityFileParser parser(entityFile);
|
||||
EntityWrapper spawnedEntity(world, parser.MergeEntities(world, parent.ID));
|
||||
|
||||
// Set its position and orientation to that of the SpawnPoint
|
||||
spawnedEntity["Transform"]["Position"] = Transform::AbsolutePosition(spawnPoint.World, spawnPoint.ID);
|
||||
// TODO: Quaternions, bitch
|
||||
spawnedEntity["Transform"]["Orientation"] = glm::eulerAngles(Transform::AbsoluteOrientation(spawnPoint));
|
||||
if (spawnPoint != 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));
|
||||
}
|
||||
|
||||
return spawnedEntity;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,341 @@
|
||||
#include "Systems/Weapon/AssaultWeaponBehaviour.h"
|
||||
|
||||
AssaultWeaponBehaviour::AssaultWeaponBehaviour(SystemParams systemParams, IRenderer* renderer, Octree<EntityAABB>* collisionOctree, EntityWrapper player)
|
||||
: WeaponBehaviour(systemParams, renderer, collisionOctree, player)
|
||||
{
|
||||
m_FirstPersonModel = m_Player.FirstChildByName("Hands");
|
||||
EVENT_SUBSCRIBE_MEMBER(m_EAnimationComplete, &AssaultWeaponBehaviour::OnAnimationComplete);
|
||||
}
|
||||
|
||||
void AssaultWeaponBehaviour::Fire()
|
||||
{
|
||||
m_TimeSinceLastFire = 0.0;
|
||||
m_Firing = true;
|
||||
fireRound();
|
||||
}
|
||||
|
||||
void AssaultWeaponBehaviour::CeaseFire()
|
||||
{
|
||||
m_Firing = false;
|
||||
}
|
||||
|
||||
void AssaultWeaponBehaviour::Reload()
|
||||
{
|
||||
if (m_Reloading) {
|
||||
return;
|
||||
}
|
||||
|
||||
ComponentWrapper& cAssaultWeapon = m_Player["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;
|
||||
}
|
||||
|
||||
// Don't reload if we're completly out of ammo
|
||||
if (ammo == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_Reloading = true;
|
||||
m_ReloadTimer = cAssaultWeapon["ReloadTime"];
|
||||
playReloadAnimation();
|
||||
}
|
||||
|
||||
void AssaultWeaponBehaviour::Update(double dt)
|
||||
{
|
||||
if (m_Reloading) {
|
||||
m_ReloadTimer -= dt;
|
||||
// Re-enable glow on reload impersonator half-way through the animation
|
||||
if (m_ReloadTimer <= (double)m_Player["AssaultWeapon"]["ReloadTime"] / 2.0) {
|
||||
if (m_ReloadImpersonator.Valid()) {
|
||||
m_ReloadImpersonator["Model"]["GlowMap"] = true;
|
||||
}
|
||||
}
|
||||
if (m_ReloadTimer <= 0) {
|
||||
finishReload();
|
||||
}
|
||||
}
|
||||
|
||||
if (m_Firing && !m_Reloading) {
|
||||
m_TimeSinceLastFire += dt;
|
||||
ComponentWrapper& cAssaultWeapon = m_Player["AssaultWeapon"];
|
||||
if (m_TimeSinceLastFire >= 1.0 / ((double)cAssaultWeapon["RPM"] / 60.0)) {
|
||||
fireRound();
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_Firing && !m_Reloading) {
|
||||
playIdleAnimation();
|
||||
}
|
||||
|
||||
// Disable glow map on weapon if it's out of ammo
|
||||
// Make real first person weapon model visible again
|
||||
EntityWrapper firstPersonWeaponModel = m_Player.FirstChildByName("WeaponModel");
|
||||
if (firstPersonWeaponModel.Valid()) {
|
||||
firstPersonWeaponModel["Model"]["GlowMap"] = hasAmmo();
|
||||
}
|
||||
}
|
||||
|
||||
bool AssaultWeaponBehaviour::OnAnimationComplete(Events::AnimationComplete& e)
|
||||
{
|
||||
if (e.Entity != m_FirstPersonModel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//if (e.Name == "ShootRifle") {
|
||||
// if (!m_Firing) {
|
||||
// playIdleAnimation();
|
||||
// }
|
||||
//}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AssaultWeaponBehaviour::hasAmmo()
|
||||
{
|
||||
ComponentWrapper& cAssaultWeapon = m_Player["AssaultWeapon"];
|
||||
int& magAmmo = cAssaultWeapon["MagazineAmmo"];
|
||||
return magAmmo > 0;
|
||||
}
|
||||
|
||||
void AssaultWeaponBehaviour::fireRound()
|
||||
{
|
||||
if (m_Reloading) {
|
||||
return;
|
||||
}
|
||||
|
||||
ComponentWrapper& cAssaultWeapon = m_Player["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();
|
||||
viewPunch();
|
||||
playShootAnimation();
|
||||
bool hit = shoot(cAssaultWeapon["BaseDamage"]);
|
||||
if (hit) {
|
||||
showHitMarker();
|
||||
}
|
||||
|
||||
m_TimeSinceLastFire = 0.0;
|
||||
}
|
||||
|
||||
void AssaultWeaponBehaviour::spawnTracer()
|
||||
{
|
||||
if (!IsClient) {
|
||||
return;
|
||||
}
|
||||
|
||||
EntityWrapper spawner;
|
||||
if (m_Player == LocalPlayer) {
|
||||
spawner = m_Player.FirstChildByName("WeaponMuzzle");
|
||||
} else {
|
||||
spawner = m_Player.FirstChildByName("ThirdPersonWeaponMuzzle");
|
||||
}
|
||||
|
||||
if (!spawner.Valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
float distance = traceRayDistance(Transform::AbsolutePosition(spawner), Transform::AbsoluteOrientation(spawner) * glm::vec3(0, 0, -1));
|
||||
EntityWrapper ray = SpawnerSystem::Spawn(spawner);
|
||||
((glm::vec3&)ray["Transform"]["Scale"]).z = (distance / 100.f);
|
||||
}
|
||||
|
||||
float AssaultWeaponBehaviour::traceRayDistance(glm::vec3 origin, glm::vec3 direction)
|
||||
{
|
||||
// TODO: Cast a ray and size tracer appropriately
|
||||
float distance;
|
||||
glm::vec3 pos;
|
||||
auto entity = Collision::EntityFirstHitByRay(Ray(origin, direction), m_CollisionOctree, distance, pos);
|
||||
if (entity) {
|
||||
return distance;
|
||||
} else {
|
||||
return 100.f;
|
||||
}
|
||||
}
|
||||
|
||||
void AssaultWeaponBehaviour::playSound()
|
||||
{
|
||||
if (!IsClient) {
|
||||
return;
|
||||
}
|
||||
|
||||
Events::PlaySoundOnEntity e;
|
||||
e.EmitterID = m_Player.ID;
|
||||
e.FilePath = "Audio/laser/laser1.wav";
|
||||
m_EventBroker->Publish(e);
|
||||
}
|
||||
|
||||
void AssaultWeaponBehaviour::viewPunch()
|
||||
{
|
||||
EntityWrapper playerCamera = m_Player.FirstChildByName("Camera");
|
||||
if (!playerCamera.Valid()) {
|
||||
return;
|
||||
}
|
||||
float viewPunch = m_Player["AssaultWeapon"]["ViewPunch"];
|
||||
ComponentWrapper cTransform = playerCamera["Transform"];
|
||||
glm::vec3& orientation = cTransform["Orientation"];
|
||||
orientation.x += viewPunch;
|
||||
}
|
||||
|
||||
void AssaultWeaponBehaviour::finishReload()
|
||||
{
|
||||
ComponentWrapper& cAssaultWeapon = m_Player["AssaultWeapon"];
|
||||
int& magAmmo = cAssaultWeapon["MagazineAmmo"];
|
||||
int magSize = cAssaultWeapon["MagazineSize"];
|
||||
int& ammo = cAssaultWeapon["Ammo"];
|
||||
|
||||
// Throw away rounds in magazine to incentivise ammo sharing
|
||||
int toLoad = glm::min(magSize, ammo);
|
||||
magAmmo = toLoad;
|
||||
ammo -= toLoad;
|
||||
|
||||
// Make real first person weapon model visible again
|
||||
EntityWrapper firstPersonWeaponModel = m_Player.FirstChildByName("WeaponModel");
|
||||
firstPersonWeaponModel["Model"]["Visible"] = true;
|
||||
|
||||
m_Reloading = false;
|
||||
}
|
||||
|
||||
void AssaultWeaponBehaviour::playShootAnimation()
|
||||
{
|
||||
ComponentWrapper cAnimation = m_FirstPersonModel["Animation"];
|
||||
if (cAnimation["AnimationName1"] != "ShootRifle") {
|
||||
cAnimation["AnimationName1"] = "ShootRifle";
|
||||
cAnimation["Weight1"] = 1.0;
|
||||
cAnimation["Time1"] = 0.0;
|
||||
cAnimation["Speed1"] = 1.0;
|
||||
cAnimation["Loop1"] = true;
|
||||
}
|
||||
}
|
||||
|
||||
void AssaultWeaponBehaviour::playIdleAnimation()
|
||||
{
|
||||
if (!m_FirstPersonModel.Valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ComponentWrapper cAnimation = m_FirstPersonModel["Animation"];
|
||||
std::string& animationName1 = cAnimation["AnimationName1"];
|
||||
double& animationSpeed1 = cAnimation["Speed1"];
|
||||
|
||||
std::string animationToPlay = "Idle";
|
||||
double speedToSet = 1.0;
|
||||
|
||||
ComponentWrapper cPlayer = m_Player["Player"];
|
||||
glm::vec3 movementDirection = cPlayer["CurrentWishDirection"];
|
||||
if (glm::length2(movementDirection) > 0) {
|
||||
animationToPlay = "Run";
|
||||
ComponentWrapper cPhysics = m_Player["Physics"];
|
||||
speedToSet = glm::length((glm::vec3)cPhysics["Velocity"]) / (float)cPlayer["MovementSpeed"];
|
||||
}
|
||||
|
||||
if (animationName1 != animationToPlay) {
|
||||
cAnimation["AnimationName1"] = animationToPlay;
|
||||
cAnimation["Weight1"] = 1.0;
|
||||
cAnimation["Time1"] = 0.0;
|
||||
cAnimation["Loop1"] = true;
|
||||
}
|
||||
|
||||
if (animationSpeed1 != speedToSet) {
|
||||
cAnimation["Speed1"] = speedToSet;
|
||||
}
|
||||
}
|
||||
|
||||
void AssaultWeaponBehaviour::playReloadAnimation()
|
||||
{
|
||||
// Play animation
|
||||
ComponentWrapper cAnimation = m_FirstPersonModel["Animation"];
|
||||
cAnimation["AnimationName1"] = "ReloadSwitch";
|
||||
cAnimation["Weight1"] = 1.0;
|
||||
cAnimation["Time1"] = 0.0;
|
||||
cAnimation["Speed1"] = 0.5;
|
||||
cAnimation["Loop1"] = true;
|
||||
|
||||
// Hide weapon model and spawn the exploding version
|
||||
EntityWrapper firstPersonWeaponModel = m_Player.FirstChildByName("WeaponModel");
|
||||
EntityWrapper reloadSpawner = m_Player.FirstChildByName("FirstPersonReloadSpawner");
|
||||
m_ReloadImpersonator = SpawnerSystem::Spawn(reloadSpawner, reloadSpawner);
|
||||
firstPersonWeaponModel["Model"].Copy(m_ReloadImpersonator["Model"]);
|
||||
firstPersonWeaponModel["Model"]["Visible"] = false;
|
||||
}
|
||||
|
||||
bool AssaultWeaponBehaviour::shoot(double damage)
|
||||
{
|
||||
// Only do shooting clientside
|
||||
if (!IsClient) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only handle shooting for the local player
|
||||
if (m_Player != LocalPlayer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure the player isn't shooting from the grave
|
||||
if (!m_Player.Valid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Screen center, based on current resolution!
|
||||
Rectangle screenResolution = m_Renderer->GetViewportSize();
|
||||
glm::vec2 centerScreen = glm::vec2(screenResolution.Width / 2, screenResolution.Height / 2);
|
||||
|
||||
// Pick middle of screen
|
||||
PickData pickData = m_Renderer->Pick(centerScreen);
|
||||
if (pickData.Entity == EntityID_Invalid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
EntityWrapper victim(m_World, pickData.Entity);
|
||||
|
||||
// Don't let us shoot ourselves in the foot
|
||||
if (victim == LocalPlayer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only care about players being hit
|
||||
if (!victim.HasComponent("Player")) {
|
||||
victim = victim.FirstParentWithComponent("Player");
|
||||
}
|
||||
if (!victim.Valid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for friendly fire
|
||||
if ((ComponentInfo::EnumType)victim["Team"]["Team"] == (ComponentInfo::EnumType)m_Player["Team"]["Team"]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Deal damage!
|
||||
Events::PlayerDamage ePlayerDamage;
|
||||
ePlayerDamage.Inflictor = m_Player;
|
||||
ePlayerDamage.Victim = victim;
|
||||
ePlayerDamage.Damage = damage;
|
||||
m_EventBroker->Publish(ePlayerDamage);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AssaultWeaponBehaviour::showHitMarker()
|
||||
{
|
||||
// Show hit marker
|
||||
EntityWrapper hitMarkerSpawner = m_Player.FirstChildByName("HitMarkerSpawner");
|
||||
if (hitMarkerSpawner.Valid()) {
|
||||
SpawnerSystem::Spawn(hitMarkerSpawner, hitMarkerSpawner);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "Systems/WeaponSystem.h"
|
||||
#include "Systems/Weapon/WeaponSystem.h"
|
||||
|
||||
WeaponSystem::WeaponSystem(SystemParams params, IRenderer* renderer, Octree<EntityAABB>* collisionOctree)
|
||||
: System(params)
|
||||
@@ -8,7 +8,6 @@ WeaponSystem::WeaponSystem(SystemParams params, IRenderer* renderer, Octree<Enti
|
||||
, m_CollisionOctree(collisionOctree)
|
||||
{
|
||||
EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &WeaponSystem::OnInputCommand);
|
||||
EVENT_SUBSCRIBE_MEMBER(m_EShoot, &WeaponSystem::OnShoot);
|
||||
EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &WeaponSystem::OnPlayerSpawned);
|
||||
}
|
||||
|
||||
@@ -24,7 +23,8 @@ void WeaponSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& cPla
|
||||
if (it == m_ActiveWeapons.end()) {
|
||||
selectWeapon(entity, 1);
|
||||
}
|
||||
|
||||
|
||||
m_EventBroker->Process<WeaponBehaviour>();
|
||||
m_ActiveWeapons.at(entity)->Update(dt);
|
||||
}
|
||||
|
||||
@@ -59,6 +59,14 @@ bool WeaponSystem::OnInputCommand(Events::InputCommand& e)
|
||||
}
|
||||
}
|
||||
|
||||
// Reload
|
||||
if (e.Command == "Reload" && e.Value != 0) {
|
||||
if (m_ActiveWeapons.find(player) != m_ActiveWeapons.end()) {
|
||||
auto weapon = m_ActiveWeapons.at(player);
|
||||
weapon->Reload();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -68,7 +76,7 @@ void WeaponSystem::selectWeapon(EntityWrapper player, ComponentInfo::EnumType sl
|
||||
if (slot == 1) {
|
||||
// TODO: if class...
|
||||
if (m_ActiveWeapons.count(player) == 0) {
|
||||
m_ActiveWeapons.insert(std::make_pair(player, std::make_shared<AssaultWeaponBehaviour>(m_SystemParams, m_CollisionOctree, player)));
|
||||
m_ActiveWeapons.insert(std::make_pair(player, std::make_shared<AssaultWeaponBehaviour>(m_SystemParams, m_Renderer, m_CollisionOctree, player)));
|
||||
} else {
|
||||
//m_ActiveWeapons.erase(player);
|
||||
}
|
||||
@@ -84,54 +92,5 @@ 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;
|
||||
}
|
||||
|
||||
// Only run further picking code for the local player!
|
||||
if (eShoot.Player != LocalPlayer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Screen center, based on current resolution!
|
||||
// TODO: check if player has enough ammo and if weapon has a cooldown or not
|
||||
Rectangle screenResolution = m_Renderer->GetViewportSize();
|
||||
glm::vec2 centerScreen = glm::vec2(screenResolution.Width / 2, screenResolution.Height / 2);
|
||||
|
||||
// TODO: check if player has enough ammo and if weapon has a cooldown or not
|
||||
|
||||
// Pick middle of screen
|
||||
PickData pickData = m_Renderer->Pick(centerScreen);
|
||||
if (pickData.Entity == EntityID_Invalid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
EntityWrapper player(m_World, pickData.Entity);
|
||||
|
||||
// Only care about players being hit
|
||||
if (!player.HasComponent("Player")) {
|
||||
player = player.FirstParentWithComponent("Player");
|
||||
}
|
||||
if (!player.Valid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for friendly fire
|
||||
EntityWrapper shooter = eShoot.Player;
|
||||
if ((ComponentInfo::EnumType)player["Team"]["Team"] == (ComponentInfo::EnumType)shooter["Team"]["Team"]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Weapon damage calculations etc
|
||||
Events::PlayerDamage ePlayerDamage;
|
||||
ePlayerDamage.Player = player;
|
||||
ePlayerDamage.Damage = 100;
|
||||
m_EventBroker->Publish(ePlayerDamage);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -71,7 +71,7 @@ GameHealthSystemTest::GameHealthSystemTest()
|
||||
//damage player with 50
|
||||
Events::PlayerDamage e;
|
||||
e.Damage = 50.0f;
|
||||
e.Player = EntityWrapper(m_World, player.EntityID);
|
||||
e.Victim = EntityWrapper(m_World, player.EntityID);
|
||||
m_EventBroker->Publish(e);
|
||||
|
||||
//heal some other player with 40
|
||||
|
||||
Reference in New Issue
Block a user