mirror of
https://github.com/antopilo/Nuake.git
synced 2026-09-09 20:08:57 +03:00
Skinned Model Component now reflected
This commit is contained in:
@@ -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();
|
||||
}
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user