Implemented Animation Clip asset and animation controller #410
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue