Fixed parameters panel for animation controller editor and added menu bar

This commit is contained in:
Kah Wei 2023-03-07 16:38:00 +08:00
parent 9a8114f5dd
commit 493f2c3cfe
5 changed files with 209 additions and 94 deletions

View File

@ -22,20 +22,8 @@ namespace SHADE
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
SHAnimationController::AnimParam::AnimParam(Type type) SHAnimationController::AnimParam::AnimParam(Type type)
: ParamType { type } : ParamType { type }
{ , Value { 0.0f }
switch (ParamType) {}
{
case Type::Bool:
Value = false;
break;
case Type::Float:
Value = 0.0f;
break;
case Type::Int:
Value = 0;
break;
}
}
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Transition - Usage Functions */ /* Transition - Usage Functions */
@ -51,12 +39,12 @@ namespace SHADE
{ {
case AnimParam::Type::Bool: case AnimParam::Type::Bool:
case AnimParam::Type::Trigger: case AnimParam::Type::Trigger:
return evaluateCondition(std::get<bool>(testParam.Value)); return evaluateCondition<bool>(testParam.Value != 0.0f);
case AnimParam::Type::Float: case AnimParam::Type::Float:
return evaluateCondition(std::get<float>(testParam.Value)); return evaluateCondition<float>(testParam.Value);
break; break;
case AnimParam::Type::Int: case AnimParam::Type::Int:
return evaluateCondition(std::get<int>(testParam.Value)); return evaluateCondition<int>(static_cast<int>(testParam.Value));
break; break;
} }

View File

@ -59,7 +59,7 @@ namespace SHADE
Float, Float,
Int Int
}; };
using ValueType = std::variant<bool, float, int>; using ValueType = float;
/*-------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------*/
/* Constructor */ /* Constructor */
@ -104,7 +104,7 @@ namespace SHADE
/* Data Members */ /* Data Members */
/*-------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------*/
Handle<Node> Target; Handle<Node> Target;
ConditionType Condition; ConditionType Condition = ConditionType::None;
AnimParam Param; AnimParam Param;
std::string ParamName; std::string ParamName;

View File

@ -17,12 +17,14 @@ namespace SHADE
template<typename T> template<typename T>
bool SHAnimationController::Transition::evaluateCondition(T value) const noexcept 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 // 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 // Handle condition type
switch (Condition) switch (Condition)

View File

@ -97,12 +97,26 @@ namespace SHADE
// Draw // Draw
drawActiveMenuBar(); drawActiveMenuBar();
ImGui::BeginTable("base_table", 3, ImGuiTableFlags_Resizable); ImGui::BeginTable("base_table", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable);
{ {
// Set up Columns // Set up Columns
ImGui::TableSetupColumn("params_panel", ImGuiTableColumnFlags_WidthStretch, SIDE_PANELS_COLUMN_WIDTH); ImGui::TableSetupColumn(" Parameters", ImGuiTableColumnFlags_WidthStretch, SIDE_PANELS_COLUMN_WIDTH);
ImGui::TableSetupColumn("main_panel", ImGuiTableColumnFlags_WidthFixed, MAIN_PANEL_COLUMN_WIDTH); ImGui::TableSetupColumn("State Machine", ImGuiTableColumnFlags_WidthFixed, MAIN_PANEL_COLUMN_WIDTH);
ImGui::TableSetupColumn("prop_panel", ImGuiTableColumnFlags_WidthStretch, SIDE_PANELS_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 // Render contents
ImGui::TableNextRow(); ImGui::TableNextRow();
@ -141,37 +155,48 @@ namespace SHADE
{ {
if (ImGui::BeginMenuBar()) if (ImGui::BeginMenuBar())
{ {
// Save Button
if (ImGui::Button(std::format("{} Save", ICON_MD_SAVE).data())) if (ImGui::Button(std::format("{} Save", ICON_MD_SAVE).data()))
{ {
// TODO // 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(); ImGui::EndMenuBar();
} }
} }
void SHAnimationControllerEditor::drawParamsPanel() void SHAnimationControllerEditor::drawParamsMenuBar()
{ {
// Add Parameter Button // 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 // All other options
for (int i = 0; i < static_cast<int>(typesList.size()); ++i) for (int i = 0; i < static_cast<int>(typesList.size()); ++i)
{ {
if (ImGui::Selectable(typesList[i].c_str())) 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(); ImGui::EndCombo();
} }
}
void SHAnimationControllerEditor::drawParamsPanel()
{
int paramId = 0; int paramId = 0;
for (auto param : controllerData->Params) for (const auto& param : controllerData->Params)
{ {
ImGui::PushID(paramId++); ImGui::PushID(paramId++);
if (SHEditorWidgets::InputText if (SHEditorWidgets::InputText
@ -185,7 +210,15 @@ namespace SHADE
controllerData->Params.erase(param.first); controllerData->Params.erase(param.first);
// Put into the new // Put into the new
controllerData->Params[val] = TYPE; 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(); ImGui::PopID();
@ -209,7 +242,30 @@ namespace SHADE
( (
param.second, param.second,
static_cast<SHAnimationController::AnimParam::Type>(i), 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 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() void SHAnimationControllerEditor::drawNodeEditor()
{ {
static constexpr float NODE_WIDTH = 80.0f; 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() void SHAnimationControllerEditor::drawPropertiesPanel()
{ {
const int SELECTED_LINKS_COUNT = ImNodes::NumSelectedLinks(); const int SELECTED_LINKS_COUNT = ImNodes::NumSelectedLinks();
@ -432,71 +548,77 @@ namespace SHADE
{ {
const SHAnimationController::AnimParam::Type PARAM_TYPE = controllerData->Params[linkData.ParamName]; const SHAnimationController::AnimParam::Type PARAM_TYPE = controllerData->Params[linkData.ParamName];
// Comparison Type if (PARAM_TYPE != SHAnimationController::AnimParam::Type::Trigger)
const auto& CURR_COMPARISON = conditionsList[static_cast<int>(linkData.Condition)];
ImGui::Text("Condition Type");
ImGui::SameLine();
if (ImGui::BeginCombo("##ConditionType", CURR_COMPARISON.c_str(), ImGuiComboFlags_None))
{ {
// We only show equal and not equal for bool // Comparison Type
const int LAST_ELEM = PARAM_TYPE == SHAnimationController::AnimParam::Type::Bool ? static_cast<int>(SHAnimationController::Transition::ConditionType::NotEquals) const auto& CURR_COMPARISON = conditionsList[static_cast<int>(linkData.Condition)];
: static_cast<int>(conditionsList.size() - 1); ImGui::Text("Condition Type");
// Comparisons ImGui::SameLine();
for (int i = 0; i <= LAST_ELEM; ++i) if (ImGui::BeginCombo("##ConditionType", CURR_COMPARISON.c_str(), ImGuiComboFlags_None))
{ {
const bool IS_SELECTED = i == static_cast<int>(linkData.Condition); // We only show equal and not equal for bool
if (ImGui::Selectable(conditionsList[i].c_str(), IS_SELECTED)) const int LAST_ELEM = PARAM_TYPE == SHAnimationController::AnimParam::Type::Bool ? static_cast<int>(SHAnimationController::Transition::ConditionType::NotEquals)
: static_cast<int>(conditionsList.size() - 1);
// Comparisons
for (int i = 0; i <= LAST_ELEM; ++i)
{ {
SHCommandManager::PerformCommand const bool IS_SELECTED = i == static_cast<int>(linkData.Condition);
( if (ImGui::Selectable(conditionsList[i].c_str(), IS_SELECTED))
std::reinterpret_pointer_cast<SHBaseCommand> {
SHCommandManager::PerformCommand
( (
std::make_shared<SHCommand<SHAnimationController::Transition::ConditionType>> std::reinterpret_pointer_cast<SHBaseCommand>
( (
linkData.Condition, std::make_shared<SHCommand<SHAnimationController::Transition::ConditionType>>
static_cast<SHAnimationController::Transition::ConditionType>(i), (
[&](SHAnimationController::Transition::ConditionType val) { linkData.Condition = val; } linkData.Condition,
) static_cast<SHAnimationController::Transition::ConditionType>(i),
), [&](SHAnimationController::Transition::ConditionType val) { linkData.Condition = val; }
false )
); ),
} false
);
}
if (IS_SELECTED) if (IS_SELECTED)
{
ImGui::SetItemDefaultFocus();
}
}
ImGui::EndCombo();
}
// Parameter Value
if (linkData.Condition != SHAnimationController::Transition::ConditionType::None)
{
switch (PARAM_TYPE)
{ {
ImGui::SetItemDefaultFocus(); case SHAnimationController::AnimParam::Type::Bool:
SHEditorWidgets::CheckBox
(
"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 linkData.ParamThresholdValue; },
[&](float val) { linkData.ParamThresholdValue = val; }
);
break;
case SHAnimationController::AnimParam::Type::Int:
SHEditorWidgets::DragInt
(
"Threshold",
[&]() { return static_cast<int>(linkData.ParamThresholdValue); },
[&](int val) { linkData.ParamThresholdValue = static_cast<float>(val); }
);
break;
} }
} }
ImGui::EndCombo();
}
// Parameter Value
switch (PARAM_TYPE)
{
case SHAnimationController::AnimParam::Type::Bool:
SHEditorWidgets::CheckBox
(
"Threshold",
[&](){ return std::get<bool>(linkData.ParamThresholdValue); },
[&](bool val) { linkData.ParamThresholdValue = val; }
);
break;
case SHAnimationController::AnimParam::Type::Float:
SHEditorWidgets::DragFloat
(
"Threshold",
[&]() { return std::get<float>(linkData.ParamThresholdValue); },
[&](float val) { linkData.ParamThresholdValue = val; }
);
break;
case SHAnimationController::AnimParam::Type::Int:
SHEditorWidgets::DragInt
(
"Threshold",
[&]() { return std::get<int>(linkData.ParamThresholdValue); },
[&](int val) { linkData.ParamThresholdValue = val; }
);
break;
} }
} }
} }

View File

@ -91,7 +91,7 @@ namespace SHADE
NodeAttributeIndex SourceAttrib; NodeAttributeIndex SourceAttrib;
NodeAttributeIndex DestAttrib; NodeAttributeIndex DestAttrib;
// Conditional Data // Conditional Data
SHAnimationController::Transition::ConditionType Condition; SHAnimationController::Transition::ConditionType Condition = SHAnimationController::Transition::ConditionType::None;
std::string ParamName; std::string ParamName;
SHAnimationController::AnimParam::ValueType ParamThresholdValue; SHAnimationController::AnimParam::ValueType ParamThresholdValue;
}; };
@ -120,8 +120,11 @@ namespace SHADE
/* Helper Functions */ /* Helper Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
void drawActiveMenuBar(); void drawActiveMenuBar();
void drawParamsMenuBar();
void drawParamsPanel(); void drawParamsPanel();
void drawNodeEditorMenuBar();
void drawNodeEditor(); void drawNodeEditor();
void drawPropertiesMenuBar();
void drawPropertiesPanel(); void drawPropertiesPanel();
NodeAttributeIndex getExtraInputAttrib(uint32_t nodeIndex); NodeAttributeIndex getExtraInputAttrib(uint32_t nodeIndex);
NodeAttributeIndex getExtraOutputAttrib(uint32_t nodeIndex); NodeAttributeIndex getExtraOutputAttrib(uint32_t nodeIndex);