diff --git a/include/Engine/Rendering/AnimationSystem.h b/include/Engine/Rendering/AnimationSystem.h index fd53022f..4f18b4a4 100644 --- a/include/Engine/Rendering/AnimationSystem.h +++ b/include/Engine/Rendering/AnimationSystem.h @@ -7,13 +7,12 @@ #include "../Core/System.h" #include "../Core/ResourceManager.h" #include "Rendering/Model.h" -#include "Rendering/EAnimationComplete.h" #include "Rendering/Skeleton.h" #include "Rendering/BlendTree.h" -#include "Rendering/EAnimationBlend.h" #include "Rendering/EAutoAnimationBlend.h" #include "../Input/EInputCommand.h" #include "../Core/EntityWrapper.h" +#include "Rendering/AutoBlendQueue.h" #include "imgui/imgui.h" @@ -27,10 +26,7 @@ private: void CreateBlendTrees(); void UpdateAnimations(double dt); void UpdateWeights(double dt); - void AnimationComplete(EntityWrapper animationEntity); - EventRelay m_EAnimationBlend; - bool OnAnimationBlend(Events::AnimationBlend& e); EventRelay m_EAutoAnimationBlend; bool OnAutoAnimationBlend(Events::AutoAnimationBlend& e); @@ -38,40 +34,7 @@ private: EventRelay m_EInputCommand; bool OnInputCommand(const Events::InputCommand& e); - struct BlendJob - { - EntityWrapper BlendEntity = EntityWrapper::Invalid; - double StartWeight; - double GoalWeight; - double Duration; - double CurrentTime = 0.0; - }; - - struct QueuedBlendJob : BlendJob - { - EntityWrapper AnimationEntity = EntityWrapper::Invalid; - }; - - struct AutoBlendJob - { - EntityWrapper RootNode = EntityWrapper::Invalid; - double Duration; - double CurrentTime = 0.0; - double Delay = 0.0; - BlendTree::AutoBlendInfo BlendInfo; - }; - - - std::list m_AutoBlendJobs; - std::unordered_map m_QueuedAutoBlendJobs; - std::list m_BlendJobs; - std::list m_QueuedBlendJobs; - - char m_AnimationName1[20] = "Run"; - float m_BlendTime1 = 0.5f; - - char m_AnimationName2[20] = "Jump"; - float m_BlendTime2 = 0.5f; + std::unordered_map m_AutoBlendQueues; }; #endif \ No newline at end of file diff --git a/include/Engine/Rendering/AutoBlendQueue.h b/include/Engine/Rendering/AutoBlendQueue.h index 12dd249e..3c808408 100644 --- a/include/Engine/Rendering/AutoBlendQueue.h +++ b/include/Engine/Rendering/AutoBlendQueue.h @@ -5,6 +5,7 @@ #include "Skeleton.h" #include "Model.h" #include "BlendTree.h" +#include "../Core/EntityWrapper.h" class AutoBlendQueue { @@ -15,11 +16,29 @@ public: double Duration; double CurrentTime = 0.0; double Delay = 0.0; + EntityWrapper AnimationEntity = EntityWrapper::Invalid; BlendTree::AutoBlendInfo BlendInfo; }; + struct AutoblendNode + { + AutoBlendJob BlendJob; + double StartTime; + double EndTime; + }; + + AutoBlendQueue() { }; + + void Insert(AutoBlendJob autoBlendJob); + void UpdateTime(double dt); + + void PrintQueue(); + bool HasActiveBlendJob(); + std::shared_ptr GetBlendTree(); + + AutoBlendQueue::AutoBlendJob& GetActiveBlendJob(); private: - std::map m_BlendQueue; + std::list m_BlendQueue; }; diff --git a/include/Engine/Rendering/BlendTree.h b/include/Engine/Rendering/BlendTree.h index 5605707a..2c5f1aa8 100644 --- a/include/Engine/Rendering/BlendTree.h +++ b/include/Engine/Rendering/BlendTree.h @@ -60,8 +60,7 @@ public: { std::string NodeName; double progress; - bool Restart; - double AnimationSpeed; + bool Start; std::unordered_map StartWeights; }; @@ -78,6 +77,11 @@ public: void PrintTree(); BlendTree::AutoBlendInfo AutoBlendStep(AutoBlendInfo blendInfo); + BlendTree::Node* GetCommonParent(std::string NodeName1, std::string NodeName2); + BlendTree::Node* FirstCommonParent(Node* node1, Node* node2); + + EntityWrapper GetSubTreeRoot(std::string nodeName); + private: Skeleton* m_Skeleton = nullptr; Node* m_Root = nullptr; diff --git a/include/Engine/Rendering/EAnimationBlend.h b/include/Engine/Rendering/EAnimationBlend.h deleted file mode 100644 index 880a2fd0..00000000 --- a/include/Engine/Rendering/EAnimationBlend.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef Events_AnimationBlend_h__ -#define Events_AnimationBlend_h__ - -#include "../Core/EventBroker.h" -#include "../Core/EntityWrapper.h" - -namespace Events -{ - -struct AnimationBlend : Event -{ - EntityWrapper BlendEntity = EntityWrapper::Invalid; - double GoalWeight; - double Duration; - - EntityWrapper AnimationEntity = EntityWrapper::Invalid; -}; - -} - -#endif diff --git a/include/Engine/Rendering/EAutoAnimationBlend.h b/include/Engine/Rendering/EAutoAnimationBlend.h index edd8e0bc..08c49191 100644 --- a/include/Engine/Rendering/EAutoAnimationBlend.h +++ b/include/Engine/Rendering/EAutoAnimationBlend.h @@ -13,9 +13,9 @@ struct AutoAnimationBlend : Event std::string NodeName; double Duration = 0.0; double Delay = 0.0; - - - double AnimationSpeed = 1.0; + + bool Start = false; + bool Reverse = false; bool Restart = false; EntityWrapper AnimationEntity = EntityWrapper::Invalid; diff --git a/resources/Schema/Components/Animation.xml b/resources/Schema/Components/Animation.xml index 45ee8428..05de9f9f 100644 --- a/resources/Schema/Components/Animation.xml +++ b/resources/Schema/Components/Animation.xml @@ -2,6 +2,8 @@ + false + false 0 true false diff --git a/resources/Schema/Components/Animation.xsd b/resources/Schema/Components/Animation.xsd index 5e82c333..1090c4c7 100644 --- a/resources/Schema/Components/Animation.xsd +++ b/resources/Schema/Components/Animation.xsd @@ -8,6 +8,8 @@ + + diff --git a/resources/Schema/Entities/BlendTreeTest.xml b/resources/Schema/Entities/BlendTreeTest.xml index 3457fc5e..69590ceb 100644 --- a/resources/Schema/Entities/BlendTreeTest.xml +++ b/resources/Schema/Entities/BlendTreeTest.xml @@ -68,9 +68,9 @@ Models/Weapons/Blue/AssaultWeaponBlue.mesh - + + - @@ -85,11 +85,11 @@ - + - AimRifleA - + AimSecWepA + false true @@ -97,11 +97,11 @@ - + - AimSecWepA - + AimRifleA + false true @@ -125,7 +125,7 @@ StandCrouchBlend JumpDashBlend - 0 + 0.00067602147306955462 @@ -183,8 +183,9 @@ RunF - + 1 + true @@ -317,7 +318,7 @@ Jump DashBlend - 1 + 0.01016461050458084 @@ -327,6 +328,8 @@ JumpF + 1 + false @@ -337,7 +340,7 @@ DashFBBlend DashLRBlend - 0 + 0.99999999999984523 @@ -347,7 +350,7 @@ DashForward DashBackward - 1 + 0.98238059685988577 @@ -356,6 +359,8 @@ DashForwardF + + 1 false @@ -367,6 +372,7 @@ DashBackwardF + 1 false @@ -380,7 +386,7 @@ DashLeft DashRight - 0 + 0.96547196574235861 @@ -390,6 +396,7 @@ DashLeftF + 1 false @@ -400,6 +407,8 @@ DashRightF + + 1 false diff --git a/src/Engine/Rendering/AnimationSystem.cpp b/src/Engine/Rendering/AnimationSystem.cpp index 4e7f15f6..166ecb47 100644 --- a/src/Engine/Rendering/AnimationSystem.cpp +++ b/src/Engine/Rendering/AnimationSystem.cpp @@ -3,21 +3,21 @@ AnimationSystem::AnimationSystem(SystemParams params) : System(params) { - EVENT_SUBSCRIBE_MEMBER(m_EAnimationBlend, &AnimationSystem::OnAnimationBlend); EVENT_SUBSCRIBE_MEMBER(m_EAutoAnimationBlend, &AnimationSystem::OnAutoAnimationBlend); EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &AnimationSystem::OnInputCommand); } void AnimationSystem::Update(double dt) { - ImGui::InputText("AnimationName1", &m_AnimationName1[0], sizeof(m_AnimationName1)); - ImGui::SliderFloat("Blendtime1", &m_BlendTime1, 0.f, 10.f); - ImGui::InputText("AnimationName2", &m_AnimationName2[0], sizeof(m_AnimationName2)); - ImGui::SliderFloat("Blendtime2", &m_BlendTime2, 0.f, 10.f); - UpdateAnimations(dt); CreateBlendTrees(); UpdateWeights(dt); + + + for(auto& autoBlendQueue : m_AutoBlendQueues) { + autoBlendQueue.second.UpdateTime(dt); + // autoBlendQueue.second.PrintQueue(); + } } void AnimationSystem::CreateBlendTrees() @@ -91,66 +91,29 @@ void AnimationSystem::UpdateAnimations(double dt) double animationSpeed = (double)animationC["Speed"]; - if (animationSpeed != 0.0) { + if((bool)animationC["Reverse"]) { + animationSpeed *= -1; + } + + + if ((bool)animationC["Play"]) { double nextTime = (double)animationC["Time"] + animationSpeed * dt; - - - //Pre animation end blend - if (m_QueuedAutoBlendJobs.find(entity) != m_QueuedAutoBlendJobs.end()) { - if (glm::sign(m_QueuedAutoBlendJobs.at(entity).Delay) < 0) { - if (!(bool)animationC["Loop"]) { - if (nextTime > animation->Duration + m_QueuedAutoBlendJobs.at(entity).Delay && glm::sign(animationSpeed) > 0) { - AnimationComplete(entity); - } else if (nextTime < 0 - m_QueuedAutoBlendJobs.at(entity).Delay && glm::sign(animationSpeed) < 0) { - AnimationComplete(entity); - } - } else { - if (nextTime > animation->Duration + m_QueuedAutoBlendJobs.at(entity).Delay && glm::sign(animationSpeed) > 0) { - AnimationComplete(entity); - } else if (nextTime < 0 - m_QueuedAutoBlendJobs.at(entity).Delay && glm::sign(animationSpeed) < 0) { - AnimationComplete(entity); - } - } - } - } - - if (!(bool)animationC["Loop"]) { if (nextTime > animation->Duration) { nextTime = animation->Duration; - Events::AnimationComplete e; - e.Entity = entity; - e.Name = (std::string)animationC["AnimationName"]; - m_EventBroker->Publish(e); - AnimationComplete(entity); - (double&)animationC["Speed"] = 0.0; + (bool&)animationC["Play"] = false; } else if (nextTime < 0) { - Events::AnimationComplete e; - e.Entity = entity; - e.Name = (std::string)animationC["AnimationName"]; - m_EventBroker->Publish(e); - AnimationComplete(entity); nextTime = 0; - (double&)animationC["Speed"] = 0.0; + (bool&)animationC["Play"] = false; } } else { if (nextTime > animation->Duration) { - Events::AnimationComplete e; - e.Entity = entity; - e.Name = (std::string)animationC["AnimationName"]; - m_EventBroker->Publish(e); - AnimationComplete(entity); while (nextTime > animation->Duration) { nextTime -= animation->Duration; } } else if (nextTime < 0) { - Events::AnimationComplete e; - e.Entity = entity; - e.Name = (std::string)animationC["AnimationName"]; - m_EventBroker->Publish(e); - AnimationComplete(entity); while (nextTime < 0) { nextTime += animation->Duration; } @@ -164,154 +127,27 @@ void AnimationSystem::UpdateAnimations(double dt) void AnimationSystem::UpdateWeights(double dt) { - for (auto it = m_BlendJobs.begin(); it != m_BlendJobs.end();) { - if (!it->BlendEntity.Valid()) { - it = m_BlendJobs.erase(it); - continue; - } + for (auto& autoBlendQueue : m_AutoBlendQueues) { - if (it->BlendEntity.HasComponent("Blend")) { - it->CurrentTime += dt; - double progress = it->CurrentTime / it->Duration; - progress = glm::clamp(progress, 0.0, 1.0); + if(autoBlendQueue.second.HasActiveBlendJob()) { + AutoBlendQueue::AutoBlendJob& blendJob = autoBlendQueue.second.GetActiveBlendJob(); - double weight = ((it->GoalWeight - it->StartWeight) * progress) + it->StartWeight; - (double&)it->BlendEntity["Blend"]["Weight"] = weight; + std::shared_ptr blendTree = autoBlendQueue.second.GetBlendTree(); - if(weight == it->GoalWeight) { - it = m_BlendJobs.erase(it); + if (blendTree != nullptr) { + blendJob.BlendInfo.progress = glm::clamp(blendJob.CurrentTime / blendJob.Duration, 0.0, 1.0); + LOG_INFO("Progress: %f, %s", blendJob.BlendInfo.progress, blendJob.BlendInfo.NodeName.c_str()); + blendJob.BlendInfo = blendTree->AutoBlendStep(blendJob.BlendInfo); } + } - ++it; - } - - - for (auto it = m_AutoBlendJobs.begin(); it != m_AutoBlendJobs.end();) { - it->CurrentTime += dt; - - if (!it->RootNode.Valid()) { - it = m_AutoBlendJobs.erase(it); - continue; - } - - if (!it->RootNode.HasComponent("Model")) { - it = m_AutoBlendJobs.erase(it); - continue; - } - - Model* model; - try { - model = ResourceManager::Load<::Model, true>(it->RootNode["Model"]["Resource"]); - } catch (const std::exception&) { - continue; - } - - Skeleton* skeleton = model->m_RawModel->m_Skeleton; - if (skeleton == nullptr) { - continue; - } - - std::shared_ptr blendTree; - if(skeleton->BlendTrees.find(it->RootNode) != skeleton->BlendTrees.end()) { - blendTree = skeleton->BlendTrees.at(it->RootNode); - } else { - it = m_AutoBlendJobs.erase(it); - continue; - } - - - it->BlendInfo.progress = glm::clamp(it->CurrentTime / it->Duration, 0.0, 1.0); - it->BlendInfo = blendTree->AutoBlendStep(it->BlendInfo); - - - if (it->CurrentTime >= it->Duration) { - it = m_AutoBlendJobs.erase(it); - continue; - } - - ++it; } } - -void AnimationSystem::AnimationComplete(EntityWrapper animationEntity) -{ - for (auto it = m_QueuedBlendJobs.begin(); it != m_QueuedBlendJobs.end();) { - if (!it->BlendEntity.Valid() || !it->AnimationEntity.Valid()) { - it = m_QueuedBlendJobs.erase(it); - continue; - } - - if(animationEntity == it->AnimationEntity) { - BlendJob bj; - bj.BlendEntity = it->BlendEntity; - bj.StartWeight = it->StartWeight; - bj.GoalWeight = it->GoalWeight; - bj.Duration = it->Duration; - bj.CurrentTime = 0.0; - m_BlendJobs.push_back(bj); - it = m_QueuedBlendJobs.erase(it); - continue; - } - - ++it; - } - - - if (m_QueuedAutoBlendJobs.find(animationEntity) != m_QueuedAutoBlendJobs.end()) { - AutoBlendJob abj = m_QueuedAutoBlendJobs.at(animationEntity); - - if (!abj.RootNode.Valid() || !animationEntity.Valid()) { - m_QueuedAutoBlendJobs.erase(animationEntity); - } else { - m_AutoBlendJobs.push_back(abj); - m_QueuedAutoBlendJobs.erase(animationEntity); - } - - - - } - - -} - -bool AnimationSystem::OnAnimationBlend(Events::AnimationBlend& e) -{ - if(!e.BlendEntity.Valid()) { - return false; - } - if(!e.BlendEntity.HasComponent("Blend")){ - return false; - } - - if (e.AnimationEntity.Valid()) { - if (e.AnimationEntity.HasComponent("Animation")) { - QueuedBlendJob qbj; - qbj.BlendEntity = e.BlendEntity; - qbj.StartWeight = (double)e.BlendEntity["Blend"]["Weight"]; - qbj.GoalWeight = e.GoalWeight; - qbj.Duration = e.Duration; - qbj.CurrentTime = 0.0; - qbj.AnimationEntity = e.AnimationEntity; - m_QueuedBlendJobs.push_back(qbj); - return true; - } - } else { - BlendJob bj; - bj.BlendEntity = e.BlendEntity; - bj.StartWeight = (double)e.BlendEntity["Blend"]["Weight"]; - bj.GoalWeight = e.GoalWeight; - bj.Duration = e.Duration; - bj.CurrentTime = 0.0; - m_BlendJobs.push_back(bj); - return true; - } -} - - bool AnimationSystem::OnAutoAnimationBlend(Events::AutoAnimationBlend& e) { + if(!e.RootNode.Valid()) { return false; } @@ -320,108 +156,80 @@ bool AnimationSystem::OnAutoAnimationBlend(Events::AutoAnimationBlend& e) return false; } - if (e.AnimationEntity.Valid()) { - AutoBlendJob abj; - abj.RootNode = e.RootNode; - abj.CurrentTime = 0.0; - abj.Duration = e.Duration; - abj.Delay = e.Delay; + Model* model; + try { + model = ResourceManager::Load<::Model, true>((std::string)e.RootNode["Model"]["Resource"]); + } catch (const std::exception&) { + return false; + } - BlendTree::AutoBlendInfo abInfo; - abInfo.NodeName = e.NodeName; - abInfo.progress = 0.0; - abInfo.Restart = e.Restart; - abInfo.AnimationSpeed = e.AnimationSpeed; - abj.BlendInfo = abInfo; + Skeleton* skeleton = model->m_RawModel->m_Skeleton; + if (skeleton == nullptr) { + return false; + } - m_QueuedAutoBlendJobs[e.AnimationEntity] = abj; - return true; + std::shared_ptr blendTree; + if (skeleton->BlendTrees.find(e.RootNode) != skeleton->BlendTrees.end()) { + blendTree = skeleton->BlendTrees.at(e.RootNode); } else { - AutoBlendJob abj; - abj.RootNode = e.RootNode; - abj.CurrentTime = 0.0; - abj.Duration = e.Duration; - - BlendTree::AutoBlendInfo abInfo; - abInfo.NodeName = e.NodeName; - abInfo.progress = 0.0; - abInfo.Restart = e.Restart; - abInfo.AnimationSpeed = e.AnimationSpeed; - - abj.BlendInfo = abInfo; - - m_AutoBlendJobs.push_back(abj); - return true; + return false; } + + EntityWrapper subTreeRoot = blendTree->GetSubTreeRoot(e.NodeName); + + if(!subTreeRoot.Valid()) { + return false; + } + + AutoBlendQueue::AutoBlendJob abj; + abj.AnimationEntity = e.AnimationEntity; + abj.CurrentTime = 0.0; + abj.Delay = e.Delay; + abj.Duration = e.Duration; + abj.RootNode = e.RootNode; + + abj.BlendInfo.NodeName = e.NodeName; + abj.BlendInfo.progress = 0.0; + abj.BlendInfo.Start = e.Start; + + if (e.Restart) { + EntityWrapper nodeEntity = subTreeRoot.FirstChildByName(e.NodeName); + if (nodeEntity.Valid()) { + if (nodeEntity.HasComponent("Animation")) { + const Skeleton::Animation* animation = skeleton->GetAnimation(nodeEntity["Animation"]["AnimationName"]); + + if (animation != nullptr) { + if (e.Restart) { + (bool&)nodeEntity["Animation"]["Reverse"] = e.Reverse; + if (e.Reverse) { + (double&)nodeEntity["Animation"]["Time"] = animation->Duration; + } else { + (double&)nodeEntity["Animation"]["Time"] = 0.0; + } + } + } + } + } + } + + + LOG_INFO("Inserting %s blendJob into %s subtree", e.NodeName.c_str(), subTreeRoot.Name().c_str()); + m_AutoBlendQueues[subTreeRoot].Insert(abj); + + LOG_INFO("\n"); + m_AutoBlendQueues.at(subTreeRoot).PrintQueue(); + LOG_INFO("\n"); + + + return true; } bool AnimationSystem::OnInputCommand(const Events::InputCommand& e) { if (e.Value == 1.f) { - if (e.Command == "BlendTest0") { - auto blendComponents = m_World->GetComponents("BlendAdditive"); - - if (blendComponents == nullptr) { - return false; - } - - - for (auto& bc : *blendComponents) { - EntityWrapper entity = EntityWrapper(m_World, bc.EntityID); - - if (entity.Name() == "Assault") { - Events::AutoAnimationBlend aeb; - aeb.Duration = m_BlendTime1; - aeb.NodeName = m_AnimationName1; - aeb.RootNode = entity; - aeb.Restart = true; - - m_EventBroker->Publish(aeb); - - } - } - - } else if (e.Command == "BlendTest1") { - - auto blendComponents = m_World->GetComponents("BlendAdditive"); - - if (blendComponents == nullptr) { - return false; - } - - - for (auto& bc : *blendComponents) { - EntityWrapper entity = EntityWrapper(m_World, bc.EntityID); - - if (entity.Name() == "Assault") { - - { - Events::AutoAnimationBlend aeb; - aeb.Duration = m_BlendTime2; - aeb.NodeName = m_AnimationName2; - aeb.RootNode = entity; - aeb.Restart = true; - m_EventBroker->Publish(aeb); - } - - { - Events::AutoAnimationBlend aeb; - aeb.Duration = m_BlendTime2; - aeb.NodeName = "Run"; - aeb.RootNode = entity; - aeb.Restart = true; - aeb.AnimationEntity = entity.FirstChildByName("DashLeft"); - m_EventBroker->Publish(aeb); - } - - } - } - } - - if(e.Command == "DashForward") { auto blendComponents = m_World->GetComponents("BlendAdditive"); @@ -434,19 +242,21 @@ bool AnimationSystem::OnInputCommand(const Events::InputCommand& e) if (entity.Name() == "Assault") { { Events::AutoAnimationBlend aeb; - aeb.Duration = 0.1; + aeb.Duration = 0.2; aeb.NodeName = "DashForward"; aeb.RootNode = entity; aeb.Restart = true; + aeb.Start = true; m_EventBroker->Publish(aeb); } { Events::AutoAnimationBlend aeb; aeb.Duration = 0.3; - aeb.NodeName = "Run"; + aeb.NodeName = "StandCrouchBlend"; aeb.RootNode = entity; - aeb.Restart = true; - aeb.Delay = 0; + aeb.Delay = -0.3; + aeb.Start = true; + aeb.Restart = false; aeb.AnimationEntity = entity.FirstChildByName("DashForward"); m_EventBroker->Publish(aeb); } @@ -469,14 +279,16 @@ bool AnimationSystem::OnInputCommand(const Events::InputCommand& e) aeb.NodeName = "DashBackward"; aeb.RootNode = entity; aeb.Restart = true; + aeb.Start = true; m_EventBroker->Publish(aeb); } { Events::AutoAnimationBlend aeb; aeb.Duration = 0.3; - aeb.NodeName = "Run"; + aeb.NodeName = "StandCrouchBlend"; aeb.RootNode = entity; - aeb.Restart = true; + aeb.Start = true; + aeb.Restart = false; aeb.Delay = -0.3; aeb.AnimationEntity = entity.FirstChildByName("DashBackward"); m_EventBroker->Publish(aeb); @@ -499,15 +311,17 @@ bool AnimationSystem::OnInputCommand(const Events::InputCommand& e) aeb.NodeName = "DashLeft"; aeb.RootNode = entity; aeb.Restart = true; + aeb.Start = true; m_EventBroker->Publish(aeb); } { Events::AutoAnimationBlend aeb; aeb.Duration = 0.3; - aeb.NodeName = "Run"; + aeb.NodeName = "StandCrouchBlend"; aeb.RootNode = entity; - aeb.Restart = true; aeb.Delay = -0.3; + aeb.Start = true; + aeb.Restart = false; aeb.AnimationEntity = entity.FirstChildByName("DashLeft"); m_EventBroker->Publish(aeb); } @@ -529,14 +343,16 @@ bool AnimationSystem::OnInputCommand(const Events::InputCommand& e) aeb.NodeName = "DashRight"; aeb.RootNode = entity; aeb.Restart = true; + aeb.Start = true; m_EventBroker->Publish(aeb); } { Events::AutoAnimationBlend aeb; aeb.Duration = 0.3; - aeb.NodeName = "Run"; + aeb.NodeName = "StandCrouchBlend"; aeb.RootNode = entity; - aeb.Restart = true; + aeb.Start = true; + aeb.Restart = false; aeb.AnimationEntity = entity.FirstChildByName("DashRight"); aeb.Delay = -0.3; m_EventBroker->Publish(aeb); @@ -558,20 +374,128 @@ bool AnimationSystem::OnInputCommand(const Events::InputCommand& e) aeb.Duration = 0.35; aeb.NodeName = "Jump"; aeb.RootNode = entity; + aeb.Start = true; aeb.Restart = true; m_EventBroker->Publish(aeb); } { Events::AutoAnimationBlend aeb; - aeb.Duration = 0.35; - aeb.NodeName = "Run"; + aeb.Duration = 0.6; + aeb.NodeName = "StandCrouchBlend"; aeb.RootNode = entity; + aeb.Start = true; aeb.Restart = false; aeb.AnimationEntity = entity.FirstChildByName("Jump"); m_EventBroker->Publish(aeb); } } } + } else if (e.Command == "Reload") { + auto blendComponents = m_World->GetComponents("BlendAdditive"); + + if (blendComponents == nullptr) { + return false; + } + for (auto& bc : *blendComponents) { + EntityWrapper entity = EntityWrapper(m_World, bc.EntityID); + + if (entity.Name() == "Assault") { + { + Events::AutoAnimationBlend aeb; + aeb.Duration = 0.2; + aeb.NodeName = "ReloadSwitch"; + aeb.RootNode = entity; + aeb.Start = true; + aeb.Restart = true; + m_EventBroker->Publish(aeb); + } + { + Events::AutoAnimationBlend aeb; + aeb.Duration = 0.2; + aeb.NodeName = "IdlePrimary"; + aeb.RootNode = entity; + aeb.Delay = -0.1; + aeb.Start = true; + aeb.Restart = false; + aeb.AnimationEntity = entity.FirstChildByName("ReloadSwitch"); + m_EventBroker->Publish(aeb); + } + } + } + } else if (e.Command == "Crouch") { + auto blendComponents = m_World->GetComponents("BlendAdditive"); + + if (blendComponents == nullptr) { + return false; + } + for (auto& bc : *blendComponents) { + EntityWrapper entity = EntityWrapper(m_World, bc.EntityID); + + if (entity.Name() == "Assault") { + { + Events::AutoAnimationBlend aeb; + aeb.Duration = 0.3; + aeb.NodeName = "CrouchMovement"; + aeb.RootNode = entity; + aeb.Start = true; + aeb.Restart = true; + m_EventBroker->Publish(aeb); + } + } + } + } else if (e.Command == "Stand") { + auto blendComponents = m_World->GetComponents("BlendAdditive"); + + if (blendComponents == nullptr) { + return false; + } + for (auto& bc : *blendComponents) { + EntityWrapper entity = EntityWrapper(m_World, bc.EntityID); + + if (entity.Name() == "Assault") { + { + Events::AutoAnimationBlend aeb; + aeb.Duration = 0.3; + aeb.NodeName = "StandMovement"; + aeb.RootNode = entity; + aeb.Start = true; + aeb.Restart = true; + m_EventBroker->Publish(aeb); + } + } + } + } else if (e.Command == "Shoot") { + auto blendComponents = m_World->GetComponents("BlendAdditive"); + + if (blendComponents == nullptr) { + return false; + } + for (auto& bc : *blendComponents) { + EntityWrapper entity = EntityWrapper(m_World, bc.EntityID); + + if (entity.Name() == "Assault") { + { + Events::AutoAnimationBlend aeb; + aeb.Duration = 0.1; + aeb.NodeName = "ShootPrimary"; + aeb.RootNode = entity; + aeb.Start = true; + aeb.Restart = true; + m_EventBroker->Publish(aeb); + } + { + Events::AutoAnimationBlend aeb; + aeb.Duration = 0.1; + aeb.NodeName = "IdlePrimary"; + aeb.RootNode = entity; + aeb.Delay = 0.0; + aeb.Start = true; + aeb.Restart = false; + aeb.AnimationEntity = entity.FirstChildByName("ShootPrimary"); + m_EventBroker->Publish(aeb); + } + } + } } diff --git a/src/Engine/Rendering/AutoBlendQueue.cpp b/src/Engine/Rendering/AutoBlendQueue.cpp index e69de29b..9f0a7366 100644 --- a/src/Engine/Rendering/AutoBlendQueue.cpp +++ b/src/Engine/Rendering/AutoBlendQueue.cpp @@ -0,0 +1,195 @@ +#include "Rendering/AutoBlendQueue.h" + +void AutoBlendQueue::Insert(AutoBlendJob autoBlendJob) +{ + if(!autoBlendJob.RootNode.HasComponent("Model")) { + return; + } + + AutoblendNode blendNode; + blendNode.BlendJob = autoBlendJob; + blendNode.StartTime = autoBlendJob.Delay; + blendNode.EndTime = autoBlendJob.Delay + autoBlendJob.Duration; + + + + if (autoBlendJob.AnimationEntity.Valid()) { + if (autoBlendJob.AnimationEntity.HasComponent("Animation")) { + Model* model; + try { + model = ResourceManager::Load<::Model, true>((std::string)autoBlendJob.RootNode["Model"]["Resource"]); + } catch (const std::exception&) { + return; + } + + Skeleton* skeleton = model->m_RawModel->m_Skeleton; + if (skeleton == nullptr) { + return; + } + + const Skeleton::Animation* animation = skeleton->GetAnimation((std::string)autoBlendJob.AnimationEntity["Animation"]["AnimationName"]); + + if (animation == nullptr) { + return; + } + + double AnimationDuration = 0.0; + + double animationSpeed = (double)autoBlendJob.AnimationEntity["Animation"]["Speed"]; + double animationTime = (double)autoBlendJob.AnimationEntity["Animation"]["Time"]; + + + if ((bool)autoBlendJob.AnimationEntity["Animation"]["Reverse"]) { + AnimationDuration = (animation->Duration * animationSpeed) - (animation->Duration - animationTime); + } else { + AnimationDuration = (animation->Duration * animationSpeed) - animationTime; + } + + LOG_INFO("Animation Duration %f", AnimationDuration); + blendNode.StartTime += AnimationDuration; + blendNode.EndTime += AnimationDuration; + if (m_BlendQueue.size() == 0) { + m_BlendQueue.push_back(blendNode); + } else { + for (auto it = m_BlendQueue.begin(); it != m_BlendQueue.end(); it++) { + auto next = std::next(it, 1); + + if (next != m_BlendQueue.end()) { + if (it->StartTime >= blendNode.StartTime && next->StartTime <= blendNode.StartTime) { + LOG_INFO("Inserted %s between %s and %s", blendNode.BlendJob.BlendInfo.NodeName.c_str(), it->BlendJob.BlendInfo.NodeName.c_str(), next->BlendJob.BlendInfo.NodeName.c_str()); + m_BlendQueue.insert(next, blendNode); + return; + } + } else if(it->StartTime > blendNode.StartTime){ + LOG_INFO("Inserted %s after %s", blendNode.BlendJob.BlendInfo.NodeName.c_str(), it->BlendJob.BlendInfo.NodeName.c_str()); + m_BlendQueue.push_front(blendNode); + return; + } else if (it->StartTime <= blendNode.StartTime) { + LOG_INFO("Inserted %s after %s", blendNode.BlendJob.BlendInfo.NodeName.c_str(), it->BlendJob.BlendInfo.NodeName.c_str()); + m_BlendQueue.push_back(blendNode); + return; + } + } + } + } + } + + + LOG_INFO("Cleared BlendQueue and inserted %s", blendNode.BlendJob.BlendInfo.NodeName.c_str()); + m_BlendQueue.clear(); + m_BlendQueue.push_back(blendNode); +} + +void AutoBlendQueue::UpdateTime(double dt) +{ + for (auto it = m_BlendQueue.begin(); it != m_BlendQueue.end();) { + it->EndTime -= dt; + it->StartTime -= dt; + if (it->EndTime < 0) { + it = m_BlendQueue.erase(it); + } else { + it++; + } + } +} + +void AutoBlendQueue::PrintQueue() +{ + for (auto it = m_BlendQueue.begin(); it != m_BlendQueue.end(); it++) { + LOG_INFO("Start: %f End: %f \t %s", it->StartTime, it->EndTime, it->BlendJob.BlendInfo.NodeName.c_str()); + } +} + + +bool AutoBlendQueue::HasActiveBlendJob() +{ + if(m_BlendQueue.empty()) { + return false; + } else { + AutoblendNode blendNode = m_BlendQueue.front(); + if (blendNode.StartTime <= 0) { + AutoBlendJob blendJob = blendNode.BlendJob; + + if (!blendJob.RootNode.Valid()) { + m_BlendQueue.pop_front(); + return false; + } + + if (!blendJob.RootNode.HasComponent("Model")) { + m_BlendQueue.pop_front(); + return HasActiveBlendJob(); + } + + Model* model; + try { + model = ResourceManager::Load<::Model, true>(blendJob.RootNode["Model"]["Resource"]); + } catch (const std::exception&) { + m_BlendQueue.pop_front(); + return HasActiveBlendJob(); + } + + Skeleton* skeleton = model->m_RawModel->m_Skeleton; + if (skeleton == nullptr) { + m_BlendQueue.pop_front(); + return HasActiveBlendJob(); + } + + + if (skeleton->BlendTrees.find(blendJob.RootNode) != skeleton->BlendTrees.end()) { + return true; + } else { + m_BlendQueue.pop_front(); + return HasActiveBlendJob(); + } + + + } else { + return false; + } + } +} + + +std::shared_ptr AutoBlendQueue::GetBlendTree() +{ + AutoblendNode blendNode = m_BlendQueue.front(); + AutoBlendJob blendJob = blendNode.BlendJob; + + if (!blendJob.RootNode.Valid()) { + m_BlendQueue.pop_front(); + return false; + } + + if (!blendJob.RootNode.HasComponent("Model")) { + return nullptr; + } + + Model* model; + try { + model = ResourceManager::Load<::Model, true>(blendJob.RootNode["Model"]["Resource"]); + } catch (const std::exception&) { + return nullptr; + } + + Skeleton* skeleton = model->m_RawModel->m_Skeleton; + if (skeleton == nullptr) { + return nullptr; + } + + + if (skeleton->BlendTrees.find(blendJob.RootNode) != skeleton->BlendTrees.end()) { + return skeleton->BlendTrees.at(blendJob.RootNode); + } else { + return nullptr; + } + + + +} + +AutoBlendQueue::AutoBlendJob& AutoBlendQueue::GetActiveBlendJob() +{ + AutoblendNode& blendNode = m_BlendQueue.front(); + blendNode.BlendJob.CurrentTime = -blendNode.StartTime; + return blendNode.BlendJob; +} diff --git a/src/Engine/Rendering/BlendTree.cpp b/src/Engine/Rendering/BlendTree.cpp index f7381d4d..036c3f49 100644 --- a/src/Engine/Rendering/BlendTree.cpp +++ b/src/Engine/Rendering/BlendTree.cpp @@ -51,8 +51,6 @@ BlendTree::BlendTree(EntityWrapper ModelEntity, Skeleton* skeleton) } m_FinalPose = AccumulateFinalPose(); - - // PrintTree(); } @@ -207,18 +205,16 @@ BlendTree::AutoBlendInfo BlendTree::AutoBlendStep(AutoBlendInfo blendInfo) { std::vector goalNodes = FindNodesByName(blendInfo.NodeName); - if (blendInfo.Restart) { + if (blendInfo.Start) { for (auto it = goalNodes.begin(); it != goalNodes.end(); it++) { EntityWrapper entity = (*it)->Entity; if (entity.Valid()) { if (entity.HasComponent("Animation")) { - (double&)entity["Animation"]["Time"] = 0.0; - (double&)entity["Animation"]["Speed"] = blendInfo.AnimationSpeed; + (bool&)entity["Animation"]["Play"] = true; } } } - blendInfo.Restart = false; } @@ -230,8 +226,6 @@ BlendTree::AutoBlendInfo BlendTree::AutoBlendStep(AutoBlendInfo blendInfo) while (currentNode != nullptr) { - - if(!currentNode->Entity.HasComponent("Blend")) { return blendInfo; } @@ -267,6 +261,91 @@ BlendTree::AutoBlendInfo BlendTree::AutoBlendStep(AutoBlendInfo blendInfo) return blendInfo; } + +BlendTree::Node* BlendTree::GetCommonParent(std::string NodeName1, std::string NodeName2) +{ + std::vector nodes1 = FindNodesByName(NodeName1); + std::vector nodes2 = FindNodesByName(NodeName2); + + for (auto it = nodes1.begin(); it != nodes1.end(); it++) { + auto next = std::next(it, 1); + + if(next != nodes1.end()) { + Node* commonParent = FirstCommonParent((*it), (*next)); + (*next) = commonParent; + nodes1.erase(it); + it = nodes1.begin(); + } + } + + for (auto it = nodes2.begin(); it != nodes2.end(); it++) { + auto next = std::next(it, 1); + + if (next != nodes2.end()) { + Node* commonParent = FirstCommonParent((*it), (*next)); + (*next) = commonParent; + nodes2.erase(it); + it = nodes2.begin(); + } + } + + return FirstCommonParent(nodes1.front(), nodes2.front());; +} + + +BlendTree::Node* BlendTree::FirstCommonParent(Node* node1, Node* node2) +{ + std::list node1Parents; + + Node* currentNode = node1; + while (currentNode != nullptr) { + node1Parents.push_back(currentNode); + currentNode = currentNode->Parent; + } + + currentNode = node2; + while (currentNode != nullptr) { + for (auto it = node1Parents.begin(); it != node1Parents.end(); it++) { + if (currentNode == (*it)) { + return currentNode; + } + } + currentNode = currentNode->Parent; + } + + return nullptr; +} + + +EntityWrapper BlendTree::GetSubTreeRoot(std::string nodeName) +{ + std::vector nodes = FindNodesByName(nodeName); + + std::vector subTreeRoots; + + for (auto it = nodes.begin(); it != nodes.end(); it++) { + Node* currentNode = (*it); + while (currentNode->Parent->Type == NodeType::Blend) { + currentNode = currentNode->Parent; + } + subTreeRoots.push_back(currentNode); + } + + + for (auto it = subTreeRoots.begin(); it != subTreeRoots.end(); it++) { + auto next = std::next(it, 1); + + if (next != subTreeRoots.end()) { + Node* commonParent = FirstCommonParent((*it), (*next)); + (*next) = commonParent; + subTreeRoots.erase(it); + it = subTreeRoots.begin(); + } + } + + return subTreeRoots.front()->Entity; +} + void BlendTree::Blend(std::map& pose) { Node* currentNode;