Implemented Animation Clip asset and animation controller #410
|
@ -22,20 +22,8 @@ namespace SHADE
|
|||
/*-----------------------------------------------------------------------------------*/
|
||||
SHAnimationController::AnimParam::AnimParam(Type type)
|
||||
: ParamType { type }
|
||||
{
|
||||
switch (ParamType)
|
||||
{
|
||||
case Type::Bool:
|
||||
Value = false;
|
||||
break;
|
||||
case Type::Float:
|
||||
Value = 0.0f;
|
||||
break;
|
||||
case Type::Int:
|
||||
Value = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
, Value { 0.0f }
|
||||
{}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Transition - Usage Functions */
|
||||
|
@ -51,12 +39,12 @@ namespace SHADE
|
|||
{
|
||||
case AnimParam::Type::Bool:
|
||||
case AnimParam::Type::Trigger:
|
||||
return evaluateCondition(std::get<bool>(testParam.Value));
|
||||
return evaluateCondition<bool>(testParam.Value != 0.0f);
|
||||
case AnimParam::Type::Float:
|
||||
return evaluateCondition(std::get<float>(testParam.Value));
|
||||
return evaluateCondition<float>(testParam.Value);
|
||||
break;
|
||||
case AnimParam::Type::Int:
|
||||
return evaluateCondition(std::get<int>(testParam.Value));
|
||||
return evaluateCondition<int>(static_cast<int>(testParam.Value));
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ namespace SHADE
|
|||
Float,
|
||||
Int
|
||||
};
|
||||
using ValueType = std::variant<bool, float, int>;
|
||||
using ValueType = float;
|
||||
|
||||
/*-------------------------------------------------------------------------------*/
|
||||
/* Constructor */
|
||||
|
@ -104,7 +104,7 @@ namespace SHADE
|
|||
/* Data Members */
|
||||
/*-------------------------------------------------------------------------------*/
|
||||
Handle<Node> Target;
|
||||
ConditionType Condition;
|
||||
ConditionType Condition = ConditionType::None;
|
||||
AnimParam Param;
|
||||
std::string ParamName;
|
||||
|
||||
|
|
|
@ -17,12 +17,14 @@ namespace SHADE
|
|||
template<typename T>
|
||||
bool SHAnimationController::Transition::evaluateCondition(T value) const noexcept
|
||||
{
|
||||
// Early failure if invalid data
|
||||
if (!std::holds_alternative<T>(Param.Value))
|
||||
return false;
|
||||
|
||||
// Get the value
|
||||
const T PARAM_VAL = std::get<T>(Param.Value);
|
||||
const T PARAM_VAL = [&]()
|
||||
{
|
||||
if constexpr (std::is_floating_point_v<T>)
|
||||
return Param.Value;
|
||||
else
|
||||
return Param.Value != 0.0f;
|
||||
}();
|
||||
|
||||
// Handle condition type
|
||||
switch (Condition)
|
||||
|
|
|
@ -97,12 +97,26 @@ namespace SHADE
|
|||
|
||||
// Draw
|
||||
drawActiveMenuBar();
|
||||
ImGui::BeginTable("base_table", 3, ImGuiTableFlags_Resizable);
|
||||
ImGui::BeginTable("base_table", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable);
|
||||
{
|
||||
// Set up Columns
|
||||
ImGui::TableSetupColumn("params_panel", ImGuiTableColumnFlags_WidthStretch, SIDE_PANELS_COLUMN_WIDTH);
|
||||
ImGui::TableSetupColumn("main_panel", ImGuiTableColumnFlags_WidthFixed, MAIN_PANEL_COLUMN_WIDTH);
|
||||
ImGui::TableSetupColumn("prop_panel", ImGuiTableColumnFlags_WidthStretch, SIDE_PANELS_COLUMN_WIDTH);
|
||||
ImGui::TableSetupColumn(" Parameters", ImGuiTableColumnFlags_WidthStretch, SIDE_PANELS_COLUMN_WIDTH);
|
||||
ImGui::TableSetupColumn("State Machine", ImGuiTableColumnFlags_WidthFixed, MAIN_PANEL_COLUMN_WIDTH);
|
||||
ImGui::TableSetupColumn("Properties", ImGuiTableColumnFlags_WidthStretch, SIDE_PANELS_COLUMN_WIDTH);
|
||||
|
||||
// Header
|
||||
ImGui::TableHeadersRow();
|
||||
|
||||
// Render menu bars
|
||||
ImGui::TableNextRow();
|
||||
{
|
||||
ImGui::TableSetColumnIndex(0);
|
||||
drawParamsMenuBar();
|
||||
ImGui::TableSetColumnIndex(1);
|
||||
drawNodeEditorMenuBar();
|
||||
ImGui::TableSetColumnIndex(2);
|
||||
drawPropertiesMenuBar();
|
||||
}
|
||||
|
||||
// Render contents
|
||||
ImGui::TableNextRow();
|
||||
|
@ -141,37 +155,48 @@ namespace SHADE
|
|||
{
|
||||
if (ImGui::BeginMenuBar())
|
||||
{
|
||||
// Save Button
|
||||
if (ImGui::Button(std::format("{} Save", ICON_MD_SAVE).data()))
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
if (ImGui::Button(std::format("{} Add", ICON_MD_ADD).data()))
|
||||
// Discard Button
|
||||
if (ImGui::Button(std::format("{} Discard Changes", ICON_MD_CANCEL).data()))
|
||||
{
|
||||
createNode(controllerData.value());
|
||||
// TODO
|
||||
}
|
||||
|
||||
ImGui::EndMenuBar();
|
||||
}
|
||||
}
|
||||
|
||||
void SHAnimationControllerEditor::drawParamsPanel()
|
||||
void SHAnimationControllerEditor::drawParamsMenuBar()
|
||||
{
|
||||
// Add Parameter Button
|
||||
if (ImGui::BeginCombo("##Type", "Add Parameter", ImGuiComboFlags_None))
|
||||
if (ImGui::BeginCombo("##Type", std::format("{} Add Parameter", ICON_MD_ADD).data(), ImGuiComboFlags_None))
|
||||
{
|
||||
// All other options
|
||||
for (int i = 0; i < static_cast<int>(typesList.size()); ++i)
|
||||
{
|
||||
if (ImGui::Selectable(typesList[i].c_str()))
|
||||
{
|
||||
controllerData->Params.emplace("New", static_cast<SHAnimationController::AnimParam::Type>(i));
|
||||
int count = 0;
|
||||
std::string paramName = "New Param";
|
||||
while (controllerData->Params.contains(paramName))
|
||||
{
|
||||
paramName = "New Param " + std::to_string(++count);
|
||||
}
|
||||
controllerData->Params.emplace(paramName, static_cast<SHAnimationController::AnimParam::Type>(i));
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
}
|
||||
|
||||
void SHAnimationControllerEditor::drawParamsPanel()
|
||||
{
|
||||
int paramId = 0;
|
||||
for (auto param : controllerData->Params)
|
||||
for (const auto& param : controllerData->Params)
|
||||
{
|
||||
ImGui::PushID(paramId++);
|
||||
if (SHEditorWidgets::InputText
|
||||
|
@ -185,7 +210,15 @@ namespace SHADE
|
|||
controllerData->Params.erase(param.first);
|
||||
// Put into the new
|
||||
controllerData->Params[val] = TYPE;
|
||||
|
||||
// TODO: This needs to be handled in a custom command
|
||||
// Update all links
|
||||
for (auto& link : controllerData->Links)
|
||||
{
|
||||
link.second.ParamName = val;
|
||||
}
|
||||
},
|
||||
{}, ImGuiInputTextFlags_EnterReturnsTrue
|
||||
))
|
||||
{
|
||||
ImGui::PopID();
|
||||
|
@ -209,7 +242,30 @@ namespace SHADE
|
|||
(
|
||||
param.second,
|
||||
static_cast<SHAnimationController::AnimParam::Type>(i),
|
||||
[&](SHAnimationController::AnimParam::Type val) { controllerData->Params[param.first] = val; }
|
||||
[&](SHAnimationController::AnimParam::Type val)
|
||||
{
|
||||
controllerData->Params[param.first] = val;
|
||||
|
||||
// TODO: This needs to be handled in a custom command
|
||||
// For changing to boolean, we need to change inequalities to not equal, etc.
|
||||
if (val == SHAnimationController::AnimParam::Type::Bool)
|
||||
{
|
||||
for (auto& link : controllerData->Links)
|
||||
{
|
||||
switch (link.second.Condition)
|
||||
{
|
||||
case SHAnimationController::Transition::ConditionType::GreaterThan:
|
||||
case SHAnimationController::Transition::ConditionType::LessThan:
|
||||
link.second.Condition = SHAnimationController::Transition::ConditionType::NotEquals;
|
||||
break;
|
||||
case SHAnimationController::Transition::ConditionType::GreaterThanOrEqual:
|
||||
case SHAnimationController::Transition::ConditionType::LessThanOrEqual:
|
||||
link.second.Condition = SHAnimationController::Transition::ConditionType::Equals;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
),
|
||||
false
|
||||
|
@ -227,6 +283,33 @@ namespace SHADE
|
|||
}
|
||||
}
|
||||
|
||||
void SHAnimationControllerEditor::drawNodeEditorMenuBar()
|
||||
{
|
||||
// Add Node Button
|
||||
if (ImGui::Button(std::format("{} Add Node", ICON_MD_ADD).data()))
|
||||
{
|
||||
createNode(controllerData.value());
|
||||
}
|
||||
ImGui::SameLine();
|
||||
|
||||
// Delete Node Button
|
||||
ImGui::BeginDisabled(ImNodes::NumSelectedNodes() < 1);
|
||||
if (ImGui::Button(std::format("{} Delete Nodes", ICON_MD_ADD).data()))
|
||||
{
|
||||
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
ImGui::SameLine();
|
||||
|
||||
// Set Starting Node Button
|
||||
ImGui::BeginDisabled(ImNodes::NumSelectedNodes() != 1);
|
||||
if (ImGui::Button(std::format("{} Set Starting Node", ICON_MD_HOME).data()))
|
||||
{
|
||||
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
|
||||
void SHAnimationControllerEditor::drawNodeEditor()
|
||||
{
|
||||
static constexpr float NODE_WIDTH = 80.0f;
|
||||
|
@ -330,6 +413,39 @@ namespace SHADE
|
|||
}
|
||||
}
|
||||
|
||||
void SHAnimationControllerEditor::drawPropertiesMenuBar()
|
||||
{
|
||||
// Set Starting Node Button
|
||||
const int SELECTED_LINKS_COUNT = ImNodes::NumSelectedLinks();
|
||||
ImGui::BeginDisabled(SELECTED_LINKS_COUNT < 1);
|
||||
if (ImGui::Button(std::format("{} Reset Conditions", ICON_MD_SETTINGS_BACKUP_RESTORE).data()))
|
||||
{
|
||||
std::vector<int> selectedLinks(SELECTED_LINKS_COUNT);
|
||||
ImNodes::GetSelectedLinks(selectedLinks.data());
|
||||
for (auto& link : selectedLinks)
|
||||
{
|
||||
// Get LinkData
|
||||
NodeLinkIndex nodeLinkIndex;
|
||||
nodeLinkIndex.Raw = link;
|
||||
if (!controllerData->Links.contains(nodeLinkIndex.Raw))
|
||||
continue;
|
||||
|
||||
LinkData& linkData = controllerData->Links[nodeLinkIndex.Raw];
|
||||
|
||||
// Ensure that the link is valid
|
||||
if (!controllerData->IndexToNodeMap.contains(nodeLinkIndex.SourceAttribute.OwnerNodeIndex) ||
|
||||
!controllerData->IndexToNodeMap.contains(nodeLinkIndex.DestinationAttribute.OwnerNodeIndex))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
linkData.ParamName = "";
|
||||
linkData.Condition = SHAnimationController::Transition::ConditionType::None;
|
||||
}
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
|
||||
void SHAnimationControllerEditor::drawPropertiesPanel()
|
||||
{
|
||||
const int SELECTED_LINKS_COUNT = ImNodes::NumSelectedLinks();
|
||||
|
@ -432,6 +548,8 @@ namespace SHADE
|
|||
{
|
||||
const SHAnimationController::AnimParam::Type PARAM_TYPE = controllerData->Params[linkData.ParamName];
|
||||
|
||||
if (PARAM_TYPE != SHAnimationController::AnimParam::Type::Trigger)
|
||||
{
|
||||
// Comparison Type
|
||||
const auto& CURR_COMPARISON = conditionsList[static_cast<int>(linkData.Condition)];
|
||||
ImGui::Text("Condition Type");
|
||||
|
@ -471,21 +589,23 @@ namespace SHADE
|
|||
}
|
||||
|
||||
// Parameter Value
|
||||
if (linkData.Condition != SHAnimationController::Transition::ConditionType::None)
|
||||
{
|
||||
switch (PARAM_TYPE)
|
||||
{
|
||||
case SHAnimationController::AnimParam::Type::Bool:
|
||||
SHEditorWidgets::CheckBox
|
||||
(
|
||||
"Threshold",
|
||||
[&](){ return std::get<bool>(linkData.ParamThresholdValue); },
|
||||
[&](bool val) { linkData.ParamThresholdValue = val; }
|
||||
"Required State",
|
||||
[&]() { return linkData.ParamThresholdValue != 0.0f; },
|
||||
[&](bool val) { linkData.ParamThresholdValue = static_cast<float>(val); }
|
||||
);
|
||||
break;
|
||||
case SHAnimationController::AnimParam::Type::Float:
|
||||
SHEditorWidgets::DragFloat
|
||||
(
|
||||
"Threshold",
|
||||
[&]() { return std::get<float>(linkData.ParamThresholdValue); },
|
||||
[&]() { return linkData.ParamThresholdValue; },
|
||||
[&](float val) { linkData.ParamThresholdValue = val; }
|
||||
);
|
||||
break;
|
||||
|
@ -493,13 +613,15 @@ namespace SHADE
|
|||
SHEditorWidgets::DragInt
|
||||
(
|
||||
"Threshold",
|
||||
[&]() { return std::get<int>(linkData.ParamThresholdValue); },
|
||||
[&](int val) { linkData.ParamThresholdValue = val; }
|
||||
[&]() { return static_cast<int>(linkData.ParamThresholdValue); },
|
||||
[&](int val) { linkData.ParamThresholdValue = static_cast<float>(val); }
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ namespace SHADE
|
|||
NodeAttributeIndex SourceAttrib;
|
||||
NodeAttributeIndex DestAttrib;
|
||||
// Conditional Data
|
||||
SHAnimationController::Transition::ConditionType Condition;
|
||||
SHAnimationController::Transition::ConditionType Condition = SHAnimationController::Transition::ConditionType::None;
|
||||
std::string ParamName;
|
||||
SHAnimationController::AnimParam::ValueType ParamThresholdValue;
|
||||
};
|
||||
|
@ -120,8 +120,11 @@ namespace SHADE
|
|||
/* Helper Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
void drawActiveMenuBar();
|
||||
void drawParamsMenuBar();
|
||||
void drawParamsPanel();
|
||||
void drawNodeEditorMenuBar();
|
||||
void drawNodeEditor();
|
||||
void drawPropertiesMenuBar();
|
||||
void drawPropertiesPanel();
|
||||
NodeAttributeIndex getExtraInputAttrib(uint32_t nodeIndex);
|
||||
NodeAttributeIndex getExtraOutputAttrib(uint32_t nodeIndex);
|
||||
|
|
Loading…
Reference in New Issue