Implemented Animation Clip asset and animation controller #410
|
@ -23,7 +23,8 @@ of DigiPen Institute of Technology is prohibited.
|
||||||
#include "Animation/SHAnimationController.h"
|
#include "Animation/SHAnimationController.h"
|
||||||
#include "Editor/SHEditorUI.h"
|
#include "Editor/SHEditorUI.h"
|
||||||
#include "Editor/SHEditorWidgets.hpp"
|
#include "Editor/SHEditorWidgets.hpp"
|
||||||
#include "../../Command/SHCommand.hpp"
|
#include "Editor/Command/SHCommand.hpp"
|
||||||
|
#include "Input/SHInputManager.h"
|
||||||
|
|
||||||
namespace SHADE
|
namespace SHADE
|
||||||
{
|
{
|
||||||
|
@ -144,8 +145,9 @@ namespace SHADE
|
||||||
SHEditorWindow::Exit();
|
SHEditorWindow::Exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SHAnimationControllerEditor::Open(const SHAnimationController& controller)
|
void SHAnimationControllerEditor::Open(SHAnimationController& controllerHandle)
|
||||||
{
|
{
|
||||||
|
controller = controllerHandle;
|
||||||
controllerData = deserialise(controller);
|
controllerData = deserialise(controller);
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
@ -158,12 +160,12 @@ namespace SHADE
|
||||||
// Save Button
|
// Save Button
|
||||||
if (ImGui::Button(std::format("{} Save", ICON_MD_SAVE).data()))
|
if (ImGui::Button(std::format("{} Save", ICON_MD_SAVE).data()))
|
||||||
{
|
{
|
||||||
// TODO
|
// TODO: Actually save the resource
|
||||||
}
|
}
|
||||||
// Discard Button
|
// Discard Button
|
||||||
if (ImGui::Button(std::format("{} Discard Changes", ICON_MD_CANCEL).data()))
|
if (ImGui::Button(std::format("{} Discard Changes", ICON_MD_CANCEL).data()))
|
||||||
{
|
{
|
||||||
// TODO
|
Open(controller); // TODO: Actually load the resource
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::EndMenuBar();
|
ImGui::EndMenuBar();
|
||||||
|
@ -211,7 +213,6 @@ namespace SHADE
|
||||||
// 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
|
// Update all links
|
||||||
for (auto& link : controllerData->Links)
|
for (auto& link : controllerData->Links)
|
||||||
{
|
{
|
||||||
|
@ -293,10 +294,11 @@ namespace SHADE
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
||||||
// Delete Node Button
|
// Delete Node Button
|
||||||
ImGui::BeginDisabled(ImNodes::NumSelectedNodes() < 1);
|
ImGui::BeginDisabled((ImNodes::NumSelectedNodes() + ImNodes::NumSelectedLinks()) < 1);
|
||||||
if (ImGui::Button(std::format("{} Delete Nodes", ICON_MD_ADD).data()))
|
if (ImGui::Button(std::format("{} Delete Objects", ICON_MD_DELETE).data()))
|
||||||
{
|
{
|
||||||
|
deleteSelectedLinks();
|
||||||
|
deleteSelectedNodes();
|
||||||
}
|
}
|
||||||
ImGui::EndDisabled();
|
ImGui::EndDisabled();
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
@ -423,6 +425,13 @@ namespace SHADE
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delete
|
||||||
|
if (SHInputManager::GetKeyUp(SHInputManager::SH_KEYCODE::DEL))
|
||||||
|
{
|
||||||
|
deleteSelectedLinks();
|
||||||
|
deleteSelectedNodes();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SHAnimationControllerEditor::drawPropertiesMenuBar()
|
void SHAnimationControllerEditor::drawPropertiesMenuBar()
|
||||||
|
@ -674,6 +683,34 @@ namespace SHADE
|
||||||
ImGui::Text(TITLE);
|
ImGui::Text(TITLE);
|
||||||
ImNodes::EndOutputAttribute();
|
ImNodes::EndOutputAttribute();
|
||||||
}
|
}
|
||||||
|
void SHAnimationControllerEditor::deleteSelectedNodes()
|
||||||
|
{
|
||||||
|
const int NUM_SELECTED_NODES= ImNodes::NumSelectedNodes();
|
||||||
|
if (NUM_SELECTED_NODES > 0)
|
||||||
|
{
|
||||||
|
std::vector<int> selectedNodes(NUM_SELECTED_NODES);
|
||||||
|
ImNodes::GetSelectedNodes(selectedNodes.data());
|
||||||
|
|
||||||
|
for (auto nodeId : selectedNodes)
|
||||||
|
{
|
||||||
|
deleteNode(controllerData.value(), nodeId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void SHAnimationControllerEditor::deleteSelectedLinks()
|
||||||
|
{
|
||||||
|
const int NUM_SELECTED_LINKS = ImNodes::NumSelectedLinks();
|
||||||
|
if (NUM_SELECTED_LINKS > 0)
|
||||||
|
{
|
||||||
|
std::vector<int> selectedLinks(NUM_SELECTED_LINKS);
|
||||||
|
ImNodes::GetSelectedLinks(selectedLinks.data());
|
||||||
|
|
||||||
|
for (auto linkId : selectedLinks)
|
||||||
|
{
|
||||||
|
deleteLink(controllerData.value(), linkId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
std::list<SHAnimationControllerEditor::Node>::iterator SHAnimationControllerEditor::createNode(AnimControllerData& data)
|
std::list<SHAnimationControllerEditor::Node>::iterator SHAnimationControllerEditor::createNode(AnimControllerData& data)
|
||||||
{
|
{
|
||||||
const NodeIndex NEW_NODE_IDX = data.NextNodeIndex++;
|
const NodeIndex NEW_NODE_IDX = data.NextNodeIndex++;
|
||||||
|
@ -716,6 +753,62 @@ namespace SHADE
|
||||||
|
|
||||||
return EMPLACE_DATA.first;
|
return EMPLACE_DATA.first;
|
||||||
}
|
}
|
||||||
|
void SHAnimationControllerEditor::deleteLink(AnimControllerData& data, LinkIndex link)
|
||||||
|
{
|
||||||
|
const NodeLinkIndex LINK_IDX { link };
|
||||||
|
|
||||||
|
// Error check, don't do anything if they don't exist
|
||||||
|
if (!data.IndexToNodeMap.contains(LINK_IDX.SourceAttribute.OwnerNodeIndex) ||
|
||||||
|
!data.IndexToNodeMap.contains(LINK_IDX.DestinationAttribute.OwnerNodeIndex))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Get source node and attributes
|
||||||
|
auto& sourceNode = *data.IndexToNodeMap[LINK_IDX.SourceAttribute.OwnerNodeIndex];
|
||||||
|
auto& destNode = *data.IndexToNodeMap[LINK_IDX.DestinationAttribute.OwnerNodeIndex];
|
||||||
|
|
||||||
|
// Remove attributes
|
||||||
|
std::erase(sourceNode.OutputAttribs, LINK_IDX.SourceAttribute);
|
||||||
|
std::erase(destNode.InputAttribs, LINK_IDX.DestinationAttribute);
|
||||||
|
|
||||||
|
// Remove link
|
||||||
|
std::erase(sourceNode.Transitions, LINK_IDX);
|
||||||
|
data.Links.erase(link);
|
||||||
|
}
|
||||||
|
void SHAnimationControllerEditor::deleteNode(AnimControllerData& data, NodeIndex nodeIndex)
|
||||||
|
{
|
||||||
|
// Get node to delete
|
||||||
|
if (!data.IndexToNodeMap.contains(nodeIndex))
|
||||||
|
return;
|
||||||
|
auto nodeToDeleteIter = data.IndexToNodeMap[nodeIndex];
|
||||||
|
|
||||||
|
// Remove all links to other nodes
|
||||||
|
for (auto link : nodeToDeleteIter->Transitions)
|
||||||
|
{
|
||||||
|
deleteLink(data, link.Raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove all links from other nodes
|
||||||
|
for (auto node : data.Nodes)
|
||||||
|
{
|
||||||
|
for (NodeLinkIndex link : node.Transitions)
|
||||||
|
{
|
||||||
|
if (link.DestinationAttribute.OwnerNodeIndex == nodeIndex)
|
||||||
|
{
|
||||||
|
deleteLink(data, link.Raw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then finally, delete this node
|
||||||
|
data.IndexToNodeMap.erase(nodeIndex);
|
||||||
|
data.Nodes.erase(nodeToDeleteIter);
|
||||||
|
|
||||||
|
// If the starting node was this node, we need to reassign
|
||||||
|
if (data.StartingNode == nodeIndex)
|
||||||
|
{
|
||||||
|
data.StartingNode = data.Nodes.empty() ? data.NextNodeIndex : data.Nodes.front().Index;
|
||||||
|
}
|
||||||
|
}
|
||||||
/*-----------------------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------------------*/
|
||||||
/* Static Helper Functions */
|
/* Static Helper Functions */
|
||||||
/*-----------------------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
|
|
@ -45,7 +45,7 @@ namespace SHADE
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
/* Usage Functions */
|
/* Usage Functions */
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
void Open(const SHAnimationController& controller);
|
void Open(SHAnimationController& controller);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
@ -61,6 +61,8 @@ namespace SHADE
|
||||||
NodeIndex OwnerNodeIndex;
|
NodeIndex OwnerNodeIndex;
|
||||||
int8_t AttributeIndex; // Negative is input, positive is output
|
int8_t AttributeIndex; // Negative is input, positive is output
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool operator==(NodeAttributeIndex rhs) const noexcept { return Raw == rhs.Raw; }
|
||||||
};
|
};
|
||||||
union NodeLinkIndex
|
union NodeLinkIndex
|
||||||
{
|
{
|
||||||
|
@ -70,6 +72,8 @@ namespace SHADE
|
||||||
NodeAttributeIndex SourceAttribute;
|
NodeAttributeIndex SourceAttribute;
|
||||||
NodeAttributeIndex DestinationAttribute;
|
NodeAttributeIndex DestinationAttribute;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool operator==(NodeLinkIndex rhs) const noexcept { return Raw != rhs.Raw; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Node
|
struct Node
|
||||||
|
@ -111,6 +115,7 @@ namespace SHADE
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
/* Data Members */
|
/* Data Members */
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
SHAnimationController controller;
|
||||||
std::optional<AnimControllerData> controllerData;
|
std::optional<AnimControllerData> controllerData;
|
||||||
// Persistent Cached Data
|
// Persistent Cached Data
|
||||||
std::vector<std::string> conditionsList;
|
std::vector<std::string> conditionsList;
|
||||||
|
@ -130,12 +135,16 @@ namespace SHADE
|
||||||
NodeAttributeIndex getExtraOutputAttrib(uint32_t nodeIndex);
|
NodeAttributeIndex getExtraOutputAttrib(uint32_t nodeIndex);
|
||||||
void drawInputNode(int id, ImNodesPinShape_ pinShape);
|
void drawInputNode(int id, ImNodesPinShape_ pinShape);
|
||||||
void drawOutputNode(int id, int parentNodeId, ImNodesPinShape_ pinShape);
|
void drawOutputNode(int id, int parentNodeId, ImNodesPinShape_ pinShape);
|
||||||
|
void deleteSelectedNodes();
|
||||||
|
void deleteSelectedLinks();
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
/* Static Helper Functions */
|
/* Static Helper Functions */
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
static std::list<Node>::iterator createNode(AnimControllerData& data);
|
static std::list<Node>::iterator createNode(AnimControllerData& data);
|
||||||
static LinkMap::iterator createLink(AnimControllerData& data, std::list<Node>::iterator sourceNode, std::list<Node>::iterator destNode);
|
static LinkMap::iterator createLink(AnimControllerData& data, std::list<Node>::iterator sourceNode, std::list<Node>::iterator destNode);
|
||||||
|
static void deleteLink(AnimControllerData& data, LinkIndex link);
|
||||||
|
static void deleteNode(AnimControllerData& data, NodeIndex nodeIndex);
|
||||||
static AnimControllerData deserialise(const SHAnimationController& controller);
|
static AnimControllerData deserialise(const SHAnimationController& controller);
|
||||||
static SHAnimationController serialise(const AnimControllerData& data);
|
static SHAnimationController serialise(const AnimControllerData& data);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue