From 6149907576775fce6311317be92f5e27debb2c80 Mon Sep 17 00:00:00 2001 From: WiggleWizard <1405402+WiggleWizard@users.noreply.github.com> Date: Sat, 14 Sep 2024 21:47:01 +0100 Subject: [PATCH] Skinned Model Component now reflected --- .../src/ComponentsPanel/SkinnedModelPanel.h | 288 +++++++++--------- .../Components/SkinnedModelComponent.cpp | 86 +++++- .../Scene/Components/SkinnedModelComponent.h | 53 ++-- Nuake/src/Scene/Systems/AnimationSystem.cpp | 11 +- 4 files changed, 260 insertions(+), 178 deletions(-) diff --git a/Editor/src/ComponentsPanel/SkinnedModelPanel.h b/Editor/src/ComponentsPanel/SkinnedModelPanel.h index 9083d2cd..482c2cbc 100644 --- a/Editor/src/ComponentsPanel/SkinnedModelPanel.h +++ b/Editor/src/ComponentsPanel/SkinnedModelPanel.h @@ -24,149 +24,149 @@ public: void Draw(Nuake::Entity entity) override { - using namespace Nuake; - if (!entity.HasComponent()) - return; - - SkinnedModelComponent& component = entity.GetComponent(); - BeginComponentTable(SKINNED MESH, SkinnedModelComponent); - { - ImGui::Text("Model"); - ImGui::TableNextColumn(); - - std::string label = "None"; - - const bool isModelNone = component.ModelResource == nullptr; - if (!isModelNone) - { - label = std::to_string(component.ModelResource->ID); - } - - if (ImGui::Button(label.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0))) - { - } - - if (m_Expanded) - { - m_ModelInspector->Draw(); - } - - if (ImGui::BeginDragDropTarget()) - { - if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Model")) - { - char* file = (char*)payload->Data; - std::string fullPath = std::string(file, 256); - fullPath = Nuake::FileSystem::AbsoluteToRelative(fullPath); - - if (Nuake::String::EndsWith(fullPath, ".model")) - { - - } - else - { - m_QueuedModelPath = fullPath; - ImGui::OpenPopup("Create Skeleton"); - } - } - ImGui::EndDragDropTarget(); - } - - if (ImGui::BeginPopupModal("Create Skeleton", NULL, ImGuiWindowFlags_AlwaysAutoResize)) - { - ImGui::SetItemDefaultFocus(); - ImGui::Text("Would you like to create the skeleton structure in the scene tree?"); - ImGui::Separator(); - - if (ImGui::Button("OK", ImVec2(120, 0))) - { - component.ModelPath = m_QueuedModelPath; - component.LoadModel(); - - Scene* scene = entity.GetScene(); - scene->CreateSkeleton(entity); - - ImGui::CloseCurrentPopup(); - } - - ImGui::SetItemDefaultFocus(); - ImGui::SameLine(); - - if (ImGui::Button("Cancel", ImVec2(120, 0))) - { - ImGui::CloseCurrentPopup(); - } - - ImGui::EndPopup(); - } - - ImGui::TableNextColumn(); - ComponentTableReset(component.ModelPath, ""); - - if (component.ModelResource) - { - auto& model = component.ModelResource; - ImGui::TableNextColumn(); - - { - ImGui::Text("Playing"); - ImGui::TableNextColumn(); - - ImGui::Checkbox("##playing", &model->IsPlaying); - - ImGui::TableNextColumn(); - ComponentTableReset(model->IsPlaying, true); - ImGui::TableNextColumn(); - } - - if(model->GetCurrentAnimation()) - { - ImGui::Text("Animation"); - ImGui::TableNextColumn(); - - uint32_t animIndex = model->GetCurrentAnimationIndex(); - uint32_t oldAnimIndex = animIndex; - auto animations = model->GetAnimations(); - if (ImGui::BeginCombo("Type", model->GetCurrentAnimation()->GetName().c_str())) - { - for (uint32_t n = 0; n < model->GetAnimationsCount(); n++) - { - bool is_selected = (animIndex == n); - std::string animName = animations[n]->GetName(); - - if (animName.empty()) - { - animName = "Empty"; - } - - if (ImGui::Selectable(animName.c_str(), is_selected)) - { - animIndex = n; - } - - if (is_selected) - ImGui::SetItemDefaultFocus(); - } - ImGui::EndCombo(); - } - - if (animIndex != oldAnimIndex) - { - model->PlayAnimation(animIndex); - } - - ImGui::TableNextColumn(); - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); - std::string resetLabel = std::string(ICON_FA_UNDO) + "##ResetAnimId"; - if (ImGui::Button(resetLabel.c_str())) - { - model->PlayAnimation(0); - } - ImGui::PopStyleColor(); - } - } - - } - EndComponentTable(); + // using namespace Nuake; + // if (!entity.HasComponent()) + // return; + // + // SkinnedModelComponent& component = entity.GetComponent(); + // BeginComponentTable(SKINNED MESH, SkinnedModelComponent); + // { + // ImGui::Text("Model"); + // ImGui::TableNextColumn(); + // + // std::string label = "None"; + // + // const bool isModelNone = component.ModelResource == nullptr; + // if (!isModelNone) + // { + // label = std::to_string(component.ModelResource->ID); + // } + // + // if (ImGui::Button(label.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0))) + // { + // } + // + // if (m_Expanded) + // { + // m_ModelInspector->Draw(); + // } + // + // if (ImGui::BeginDragDropTarget()) + // { + // if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Model")) + // { + // char* file = (char*)payload->Data; + // std::string fullPath = std::string(file, 256); + // fullPath = Nuake::FileSystem::AbsoluteToRelative(fullPath); + // + // if (Nuake::String::EndsWith(fullPath, ".model")) + // { + // + // } + // else + // { + // m_QueuedModelPath = fullPath; + // ImGui::OpenPopup("Create Skeleton"); + // } + // } + // ImGui::EndDragDropTarget(); + // } + // + // if (ImGui::BeginPopupModal("Create Skeleton", NULL, ImGuiWindowFlags_AlwaysAutoResize)) + // { + // ImGui::SetItemDefaultFocus(); + // ImGui::Text("Would you like to create the skeleton structure in the scene tree?"); + // ImGui::Separator(); + // + // if (ImGui::Button("OK", ImVec2(120, 0))) + // { + // component.ModelPath = m_QueuedModelPath; + // component.LoadModel(); + // + // Scene* scene = entity.GetScene(); + // scene->CreateSkeleton(entity); + // + // ImGui::CloseCurrentPopup(); + // } + // + // ImGui::SetItemDefaultFocus(); + // ImGui::SameLine(); + // + // if (ImGui::Button("Cancel", ImVec2(120, 0))) + // { + // ImGui::CloseCurrentPopup(); + // } + // + // ImGui::EndPopup(); + // } + // + // ImGui::TableNextColumn(); + // ComponentTableReset(component.ModelPath, ""); + // + // if (component.ModelResource) + // { + // auto& model = component.ModelResource; + // ImGui::TableNextColumn(); + // + // { + // ImGui::Text("Playing"); + // ImGui::TableNextColumn(); + // + // ImGui::Checkbox("##playing", &model->IsPlaying); + // + // ImGui::TableNextColumn(); + // ComponentTableReset(model->IsPlaying, true); + // ImGui::TableNextColumn(); + // } + // + // if(model->GetCurrentAnimation()) + // { + // ImGui::Text("Animation"); + // ImGui::TableNextColumn(); + // + // uint32_t animIndex = model->GetCurrentAnimationIndex(); + // uint32_t oldAnimIndex = animIndex; + // auto animations = model->GetAnimations(); + // if (ImGui::BeginCombo("Type", model->GetCurrentAnimation()->GetName().c_str())) + // { + // for (uint32_t n = 0; n < model->GetAnimationsCount(); n++) + // { + // bool is_selected = (animIndex == n); + // std::string animName = animations[n]->GetName(); + // + // if (animName.empty()) + // { + // animName = "Empty"; + // } + // + // if (ImGui::Selectable(animName.c_str(), is_selected)) + // { + // animIndex = n; + // } + // + // if (is_selected) + // ImGui::SetItemDefaultFocus(); + // } + // ImGui::EndCombo(); + // } + // + // if (animIndex != oldAnimIndex) + // { + // model->PlayAnimation(animIndex); + // } + // + // ImGui::TableNextColumn(); + // ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + // std::string resetLabel = std::string(ICON_FA_UNDO) + "##ResetAnimId"; + // if (ImGui::Button(resetLabel.c_str())) + // { + // model->PlayAnimation(0); + // } + // ImGui::PopStyleColor(); + // } + // } + // + // } + // EndComponentTable(); } }; \ No newline at end of file diff --git a/Nuake/src/Scene/Components/SkinnedModelComponent.cpp b/Nuake/src/Scene/Components/SkinnedModelComponent.cpp index 0dcee3f3..717ca80c 100644 --- a/Nuake/src/Scene/Components/SkinnedModelComponent.cpp +++ b/Nuake/src/Scene/Components/SkinnedModelComponent.cpp @@ -1,16 +1,92 @@ #include "SkinnedModelComponent.h" #include "src/Resource/ModelLoader.h" +#include "src/Scene/Entities/Entity.h" namespace Nuake { - SkinnedModelComponent::SkinnedModelComponent() + void SkinnedModelComponent::LoadModel(entt::entity e, Scene* scene) { + ModelLoader loader = ModelLoader(); + this->ModelResource = loader.LoadSkinnedModel(ModelPath.GetRelativePath()); + Entity entity = Entity{ e, scene }; + scene->CreateSkeleton(entity); + + RegenerateAnimationList(); } - void SkinnedModelComponent::LoadModel() + void SkinnedModelComponent::SetPlaying(bool play) { - auto loader = ModelLoader(); - this->ModelResource = loader.LoadSkinnedModel(ModelPath); + if (ModelResource == nullptr) + return; + ModelResource->IsPlaying = play; } -} \ No newline at end of file + + bool SkinnedModelComponent::GetIsPlaying() const + { + if (ModelResource == nullptr) + return false; + return ModelResource->IsPlaying; + } + + void SkinnedModelComponent::SetAnimationList(int i) + { + animationList.index = i; + + // If the model is valid then play the animation + if (ModelResource != nullptr) + { + ModelResource->PlayAnimation(animationList.index); + } + } + + void SkinnedModelComponent::RegenerateAnimationList() + { + if (ModelResource == nullptr) + { + return; + } + + // Regenerate the animation list + std::vector> animations = ModelResource->GetAnimations(); + for (uint32_t i = 0; i < animations.size(); i++) + { + Ref& animation = animations[i]; + if (animation == nullptr) + { + continue; + } + + animationList.items.push_back(animation->GetName()); + } + } + + json SkinnedModelComponent::Serialize() + { + BEGIN_SERIALIZE(); + SERIALIZE_RES_FILE(ModelPath); + + if (ModelResource) + { + SERIALIZE_OBJECT(ModelResource); + } + END_SERIALIZE(); + } + + bool SkinnedModelComponent::Deserialize(const json& j) + { + DESERIALIZE_RES_FILE(ModelPath); + + ModelResource = CreateRef(); + + if (j.contains("ModelResource")) + { + auto& res = j["ModelResource"]; + ModelResource->Deserialize(res); + } + + RegenerateAnimationList(); + + return true; + } +} diff --git a/Nuake/src/Scene/Components/SkinnedModelComponent.h b/Nuake/src/Scene/Components/SkinnedModelComponent.h index 14461f96..36444a81 100644 --- a/Nuake/src/Scene/Components/SkinnedModelComponent.h +++ b/Nuake/src/Scene/Components/SkinnedModelComponent.h @@ -1,7 +1,10 @@ #pragma once #include "Component.h" +#include "FieldTypes.h" +#include "src/FileSystem/File.h" +#include "src/FileSystem/FileSystem.h" #include "src/Resource/Serializable.h" #include "src/Resource/SkinnedModel.h" @@ -10,44 +13,38 @@ namespace Nuake { + class Scene; + class SkinnedModelComponent : public Component { NUAKECOMPONENT(SkinnedModelComponent, "Skinned Model") + static void InitializeComponentClass() + { + BindComponentField<&SkinnedModelComponent::ModelPath>("ModelPath", "Model Path"); + BindComponentProperty<&SkinnedModelComponent::SetPlaying, &SkinnedModelComponent::GetIsPlaying>("Playing", "Playing"); + SetFlags(ComponentFieldTrait::Transient); + + BindComponentProperty<&SkinnedModelComponent::SetAnimationList, &SkinnedModelComponent::GetAnimationList>("Animation", "Animation"); + SetFlags(ComponentFieldTrait::Transient); + } + Ref ModelResource; - std::string ModelPath; + ResourceFile ModelPath; + DynamicItemList animationList; - SkinnedModelComponent(); + void LoadModel(entt::entity e, Scene* scene); - void LoadModel(); + void SetPlaying(bool play); + bool GetIsPlaying() const; - std::string directory; + DynamicItemList& GetAnimationList() { return animationList; } + void SetAnimationList(int i); - json Serialize() - { - BEGIN_SERIALIZE(); - SERIALIZE_VAL(ModelPath); + void RegenerateAnimationList(); - if (ModelResource) - { - SERIALIZE_OBJECT(ModelResource); - } - END_SERIALIZE(); - } + json Serialize(); - bool Deserialize(const json& j) - { - ModelPath = j["ModelPath"]; - - ModelResource = CreateRef(); - - if (j.contains("ModelResource")) - { - auto& res = j["ModelResource"]; - ModelResource->Deserialize(res); - } - - return true; - } + bool Deserialize(const json& j); }; } diff --git a/Nuake/src/Scene/Systems/AnimationSystem.cpp b/Nuake/src/Scene/Systems/AnimationSystem.cpp index 61c1508a..8118684b 100644 --- a/Nuake/src/Scene/Systems/AnimationSystem.cpp +++ b/Nuake/src/Scene/Systems/AnimationSystem.cpp @@ -31,7 +31,16 @@ namespace Nuake { auto [transformComponent, skinnedComponent] = view.get(e); - auto& model = skinnedComponent.ModelResource; + Ref model = skinnedComponent.ModelResource; + + // Load the model if it's not already loaded + // TODO: [WiggleWizard] Needs some sort of flag to infer that we've tried loading it once already, so + // we don't try loading the model every frame if it's invalid. + if (skinnedComponent.ModelPath.Exist() && skinnedComponent.ModelResource == nullptr) + { + skinnedComponent.LoadModel(e, m_Scene); + } + if (!model) { continue;