Skinned Model Component now reflected

This commit is contained in:
WiggleWizard
2024-09-14 21:47:01 +01:00
parent d8d904b6ba
commit 6149907576
4 changed files with 260 additions and 178 deletions

View File

@@ -24,149 +24,149 @@ public:
void Draw(Nuake::Entity entity) override
{
using namespace Nuake;
if (!entity.HasComponent<SkinnedModelComponent>())
return;
SkinnedModelComponent& component = entity.GetComponent<SkinnedModelComponent>();
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<SkinnedModelComponent>())
// return;
//
// SkinnedModelComponent& component = entity.GetComponent<SkinnedModelComponent>();
// 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();
}
};

View File

@@ -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;
}
}
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<Ref<SkeletalAnimation>> animations = ModelResource->GetAnimations();
for (uint32_t i = 0; i < animations.size(); i++)
{
Ref<SkeletalAnimation>& 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<SkinnedModel>();
if (j.contains("ModelResource"))
{
auto& res = j["ModelResource"];
ModelResource->Deserialize(res);
}
RegenerateAnimationList();
return true;
}
}

View File

@@ -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<SkinnedModel> 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<SkinnedModel>();
if (j.contains("ModelResource"))
{
auto& res = j["ModelResource"];
ModelResource->Deserialize(res);
}
return true;
}
bool Deserialize(const json& j);
};
}

View File

@@ -31,7 +31,16 @@ namespace Nuake
{
auto [transformComponent, skinnedComponent] = view.get<TransformComponent, SkinnedModelComponent>(e);
auto& model = skinnedComponent.ModelResource;
Ref<SkinnedModel> 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;