diff --git a/SHADE_Engine/src/Animation/SHAnimationController.cpp b/SHADE_Engine/src/Animation/SHAnimationController.cpp index 557bedb3..9da907bf 100644 --- a/SHADE_Engine/src/Animation/SHAnimationController.cpp +++ b/SHADE_Engine/src/Animation/SHAnimationController.cpp @@ -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(testParam.Value)); + return evaluateCondition(testParam.Value != 0.0f); case AnimParam::Type::Float: - return evaluateCondition(std::get(testParam.Value)); + return evaluateCondition(testParam.Value); break; case AnimParam::Type::Int: - return evaluateCondition(std::get(testParam.Value)); + return evaluateCondition(static_cast(testParam.Value)); break; } diff --git a/SHADE_Engine/src/Animation/SHAnimationController.h b/SHADE_Engine/src/Animation/SHAnimationController.h index a7acb772..64210481 100644 --- a/SHADE_Engine/src/Animation/SHAnimationController.h +++ b/SHADE_Engine/src/Animation/SHAnimationController.h @@ -59,7 +59,7 @@ namespace SHADE Float, Int }; - using ValueType = std::variant; + using ValueType = float; /*-------------------------------------------------------------------------------*/ /* Constructor */ @@ -104,7 +104,7 @@ namespace SHADE /* Data Members */ /*-------------------------------------------------------------------------------*/ Handle Target; - ConditionType Condition; + ConditionType Condition = ConditionType::None; AnimParam Param; std::string ParamName; diff --git a/SHADE_Engine/src/Animation/SHAnimationController.hpp b/SHADE_Engine/src/Animation/SHAnimationController.hpp index 054f066e..f040b8d4 100644 --- a/SHADE_Engine/src/Animation/SHAnimationController.hpp +++ b/SHADE_Engine/src/Animation/SHAnimationController.hpp @@ -17,12 +17,14 @@ namespace SHADE template bool SHAnimationController::Transition::evaluateCondition(T value) const noexcept { - // Early failure if invalid data - if (!std::holds_alternative(Param.Value)) - return false; - // Get the value - const T PARAM_VAL = std::get(Param.Value); + const T PARAM_VAL = [&]() + { + if constexpr (std::is_floating_point_v) + return Param.Value; + else + return Param.Value != 0.0f; + }(); // Handle condition type switch (Condition) diff --git a/SHADE_Engine/src/Editor/EditorWindow/Animation/SHAnimationControllerEditor.cpp b/SHADE_Engine/src/Editor/EditorWindow/Animation/SHAnimationControllerEditor.cpp index 8dd98057..33372760 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Animation/SHAnimationControllerEditor.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/Animation/SHAnimationControllerEditor.cpp @@ -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(typesList.size()); ++i) { if (ImGui::Selectable(typesList[i].c_str())) { - controllerData->Params.emplace("New", static_cast(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(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(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 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,72 +548,78 @@ namespace SHADE { const SHAnimationController::AnimParam::Type PARAM_TYPE = controllerData->Params[linkData.ParamName]; - // Comparison Type - const auto& CURR_COMPARISON = conditionsList[static_cast(linkData.Condition)]; - ImGui::Text("Condition Type"); - ImGui::SameLine(); - if (ImGui::BeginCombo("##ConditionType", CURR_COMPARISON.c_str(), ImGuiComboFlags_None)) + if (PARAM_TYPE != SHAnimationController::AnimParam::Type::Trigger) { - // We only show equal and not equal for bool - const int LAST_ELEM = PARAM_TYPE == SHAnimationController::AnimParam::Type::Bool ? static_cast(SHAnimationController::Transition::ConditionType::NotEquals) - : static_cast(conditionsList.size() - 1); - // Comparisons - for (int i = 0; i <= LAST_ELEM; ++i) + // Comparison Type + const auto& CURR_COMPARISON = conditionsList[static_cast(linkData.Condition)]; + ImGui::Text("Condition Type"); + ImGui::SameLine(); + if (ImGui::BeginCombo("##ConditionType", CURR_COMPARISON.c_str(), ImGuiComboFlags_None)) { - const bool IS_SELECTED = i == static_cast(linkData.Condition); - if (ImGui::Selectable(conditionsList[i].c_str(), IS_SELECTED)) + // We only show equal and not equal for bool + const int LAST_ELEM = PARAM_TYPE == SHAnimationController::AnimParam::Type::Bool ? static_cast(SHAnimationController::Transition::ConditionType::NotEquals) + : static_cast(conditionsList.size() - 1); + // Comparisons + for (int i = 0; i <= LAST_ELEM; ++i) { - SHCommandManager::PerformCommand - ( - std::reinterpret_pointer_cast + const bool IS_SELECTED = i == static_cast(linkData.Condition); + if (ImGui::Selectable(conditionsList[i].c_str(), IS_SELECTED)) + { + SHCommandManager::PerformCommand ( - std::make_shared> + std::reinterpret_pointer_cast ( - linkData.Condition, - static_cast(i), - [&](SHAnimationController::Transition::ConditionType val) { linkData.Condition = val; } - ) - ), - false - ); - } + std::make_shared> + ( + linkData.Condition, + static_cast(i), + [&](SHAnimationController::Transition::ConditionType val) { linkData.Condition = val; } + ) + ), + 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(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(linkData.ParamThresholdValue); }, + [&](int val) { linkData.ParamThresholdValue = static_cast(val); } + ); + break; } } - ImGui::EndCombo(); - } - - // Parameter Value - switch (PARAM_TYPE) - { - case SHAnimationController::AnimParam::Type::Bool: - SHEditorWidgets::CheckBox - ( - "Threshold", - [&](){ return std::get(linkData.ParamThresholdValue); }, - [&](bool val) { linkData.ParamThresholdValue = val; } - ); - break; - case SHAnimationController::AnimParam::Type::Float: - SHEditorWidgets::DragFloat - ( - "Threshold", - [&]() { return std::get(linkData.ParamThresholdValue); }, - [&](float val) { linkData.ParamThresholdValue = val; } - ); - break; - case SHAnimationController::AnimParam::Type::Int: - SHEditorWidgets::DragInt - ( - "Threshold", - [&]() { return std::get(linkData.ParamThresholdValue); }, - [&](int val) { linkData.ParamThresholdValue = val; } - ); - break; - } + } } } diff --git a/SHADE_Engine/src/Editor/EditorWindow/Animation/SHAnimationControllerEditor.h b/SHADE_Engine/src/Editor/EditorWindow/Animation/SHAnimationControllerEditor.h index adc0887d..bafbe4a9 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/Animation/SHAnimationControllerEditor.h +++ b/SHADE_Engine/src/Editor/EditorWindow/Animation/SHAnimationControllerEditor.h @@ -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);