Add batching the same function inputs in Anim Graph for better usability
This commit is contained in:
@@ -271,7 +271,7 @@ void AnimGraphExecutor::Update(AnimGraphInstanceData& data, float dt)
|
||||
case ValueType::Null:
|
||||
break;
|
||||
default:
|
||||
LOG(Warning, "Invalid animation update result type {0}", result.Type.ToString());
|
||||
//LOG(Warning, "Invalid animation update result type {0}", result.Type.ToString());
|
||||
break;
|
||||
}
|
||||
if (animResult == nullptr)
|
||||
|
||||
@@ -1545,22 +1545,12 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
|
||||
}
|
||||
// State Output
|
||||
case 21:
|
||||
{
|
||||
if (box->HasConnection())
|
||||
value = eatBox(nodeBase, box->FirstConnection());
|
||||
else
|
||||
value = Value::Null;
|
||||
value = box->HasConnection() ? eatBox(nodeBase, box->FirstConnection()) : Value::Null;
|
||||
break;
|
||||
}
|
||||
// Rule Output
|
||||
case 22:
|
||||
{
|
||||
if (box->HasConnection())
|
||||
value = eatBox(nodeBase, box->FirstConnection());
|
||||
else
|
||||
value = Value::False;
|
||||
value = box->HasConnection() ? eatBox(nodeBase, box->FirstConnection()) : Value::Null;
|
||||
break;
|
||||
}
|
||||
// Transition Source State Anim
|
||||
case 23:
|
||||
{
|
||||
@@ -1637,7 +1627,7 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
|
||||
|
||||
// Evaluate the function output
|
||||
context.GraphStack.Push((Graph*)data.Graph);
|
||||
value = tryGetValue(functionOutputBox, Value::Zero);
|
||||
value = functionOutputBox && functionOutputBox->HasConnection() ? eatBox(nodeBase, functionOutputBox->FirstConnection()) : Value::Zero;
|
||||
context.GraphStack.Pop();
|
||||
break;
|
||||
}
|
||||
@@ -1926,17 +1916,13 @@ void AnimGraphExecutor::ProcessGroupFunction(Box* boxBase, Node* node, Value& va
|
||||
|
||||
// Peek the input box to use
|
||||
int32 inputIndex = -1;
|
||||
const auto name = (StringView)node->Values[1];
|
||||
for (int32 i = 0; i < function->Inputs.Count(); i++)
|
||||
{
|
||||
auto& input = function->Inputs[i];
|
||||
|
||||
// Pick the any nested graph that uses this input
|
||||
AnimSubGraph* subGraph = data.Graph;
|
||||
for (auto& graphIndex : input.GraphIndices)
|
||||
subGraph = subGraph->SubGraphs[graphIndex];
|
||||
if (node->ID == subGraph->Nodes[input.NodeIndex].ID)
|
||||
if (input.Name == name)
|
||||
{
|
||||
inputIndex = i;
|
||||
inputIndex = input.InputIndex;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ Asset::LoadResult AnimationGraphFunction::load()
|
||||
|
||||
// Load function signature
|
||||
// Note: search also the nested state machines graphs (state output and transition rule)
|
||||
ProcessGraphForSignature(&graph, true, Array<int32, FixedAllocation<8>>());
|
||||
ProcessGraphForSignature(&graph, true);
|
||||
if (Inputs.Count() >= 16 || Outputs.Count() >= 16)
|
||||
{
|
||||
LOG(Error, "Too many function inputs/outputs in '{0}'. The limit is max 16 inputs and max 16 outputs.", ToString());
|
||||
@@ -65,11 +65,14 @@ void AnimationGraphFunction::GetSignature(Array<StringView, FixedAllocation<32>>
|
||||
{
|
||||
types.Resize(32);
|
||||
names.Resize(32);
|
||||
for (int32 i = 0; i < Inputs.Count(); i++)
|
||||
for (int32 i = 0, j = 0; i < Inputs.Count(); i++)
|
||||
{
|
||||
auto& input = Inputs[i];
|
||||
types[i] = input.Type;
|
||||
names[i] = input.Name;
|
||||
if (input.InputIndex != i)
|
||||
continue;
|
||||
types[j] = input.Type;
|
||||
names[j] = input.Name;
|
||||
j++;
|
||||
}
|
||||
for (int32 i = 0; i < Outputs.Count(); i++)
|
||||
{
|
||||
@@ -79,7 +82,7 @@ void AnimationGraphFunction::GetSignature(Array<StringView, FixedAllocation<32>>
|
||||
}
|
||||
}
|
||||
|
||||
bool AnimationGraphFunction::SaveSurface(BytesContainer& data)
|
||||
bool AnimationGraphFunction::SaveSurface(const BytesContainer& data)
|
||||
{
|
||||
// Wait for asset to be loaded or don't if last load failed
|
||||
if (LastLoadFailed())
|
||||
@@ -113,7 +116,7 @@ bool AnimationGraphFunction::SaveSurface(BytesContainer& data)
|
||||
|
||||
#endif
|
||||
|
||||
void AnimationGraphFunction::ProcessGraphForSignature(AnimGraphBase* graph, bool canUseOutputs, const Array<int32, FixedAllocation<8>>& graphIndices)
|
||||
void AnimationGraphFunction::ProcessGraphForSignature(AnimGraphBase* graph, bool canUseOutputs)
|
||||
{
|
||||
for (int32 i = 0; i < graph->Nodes.Count(); i++)
|
||||
{
|
||||
@@ -123,13 +126,26 @@ void AnimationGraphFunction::ProcessGraphForSignature(AnimGraphBase* graph, bool
|
||||
{
|
||||
if (Inputs.Count() < 16)
|
||||
{
|
||||
// If there already is an input with that name just batch them together
|
||||
int32 inputIndex = Inputs.Count();
|
||||
auto name = (StringView)node.Values[1];
|
||||
for (auto& e : Inputs)
|
||||
{
|
||||
if (e.Name == name)
|
||||
{
|
||||
inputIndex = e.InputIndex;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto& p = Inputs.AddOne();
|
||||
p.InputIndex = inputIndex;
|
||||
p.NodeIndex = i;
|
||||
p.GraphIndices = graphIndices;
|
||||
#if USE_EDITOR
|
||||
p.Type = GetGraphFunctionTypeName_Deprecated(node.Values[0]);
|
||||
p.Name = (StringView)node.Values[1];
|
||||
#endif
|
||||
p.Name = name;
|
||||
|
||||
}
|
||||
}
|
||||
else if (node.Type == GRAPH_NODE_MAKE_TYPE(16, 2)) // Function Output
|
||||
@@ -137,32 +153,26 @@ void AnimationGraphFunction::ProcessGraphForSignature(AnimGraphBase* graph, bool
|
||||
if (Outputs.Count() < 16 && canUseOutputs)
|
||||
{
|
||||
auto& p = Outputs.AddOne();
|
||||
p.InputIndex = i;
|
||||
p.NodeIndex = i;
|
||||
p.GraphIndices = graphIndices;
|
||||
#if USE_EDITOR
|
||||
p.Type = GetGraphFunctionTypeName_Deprecated(node.Values[0]);
|
||||
p.Name = (StringView)node.Values[1];
|
||||
#endif
|
||||
p.Name = (StringView)node.Values[1];
|
||||
}
|
||||
}
|
||||
else if (node.Type == GRAPH_NODE_MAKE_TYPE(9, 18)) // State Machine
|
||||
{
|
||||
if (node.Data.StateMachine.Graph)
|
||||
{
|
||||
auto subGraph = graphIndices;
|
||||
subGraph.Add(graph->SubGraphs.Find(node.Data.StateMachine.Graph));
|
||||
ASSERT(subGraph.Last() != -1);
|
||||
ProcessGraphForSignature(node.Data.StateMachine.Graph, false, subGraph);
|
||||
ProcessGraphForSignature(node.Data.StateMachine.Graph, false);
|
||||
}
|
||||
}
|
||||
else if (node.Type == GRAPH_NODE_MAKE_TYPE(9, 20)) // State
|
||||
{
|
||||
if (node.Data.State.Graph)
|
||||
{
|
||||
auto subGraph = graphIndices;
|
||||
subGraph.Add(graph->SubGraphs.Find(node.Data.State.Graph));
|
||||
ASSERT(subGraph.Last() != -1);
|
||||
ProcessGraphForSignature(node.Data.State.Graph, false, subGraph);
|
||||
ProcessGraphForSignature(node.Data.State.Graph, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -170,10 +180,7 @@ void AnimationGraphFunction::ProcessGraphForSignature(AnimGraphBase* graph, bool
|
||||
{
|
||||
if (stateTransition.RuleGraph)
|
||||
{
|
||||
auto subGraph = graphIndices;
|
||||
subGraph.Add(graph->SubGraphs.Find(stateTransition.RuleGraph));
|
||||
ASSERT(subGraph.Last() != -1);
|
||||
ProcessGraphForSignature(stateTransition.RuleGraph, false, subGraph);
|
||||
ProcessGraphForSignature(stateTransition.RuleGraph, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,12 +20,12 @@ public:
|
||||
|
||||
struct FunctionParameter
|
||||
{
|
||||
int32 InputIndex;
|
||||
int32 NodeIndex;
|
||||
Array<int32, FixedAllocation<8>> GraphIndices;
|
||||
#if USE_EDITOR
|
||||
String Type;
|
||||
String Name;
|
||||
#endif
|
||||
String Name;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
@@ -54,13 +54,13 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="data">The surface graph data.</param>
|
||||
/// <returns>True if cannot save it, otherwise false.</returns>
|
||||
API_FUNCTION() bool SaveSurface(BytesContainer& data);
|
||||
API_FUNCTION() bool SaveSurface(const BytesContainer& data);
|
||||
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
void ProcessGraphForSignature(AnimGraphBase* graph, bool canUseOutputs, const Array<int32, FixedAllocation<8>>& graphIndices);
|
||||
void ProcessGraphForSignature(AnimGraphBase* graph, bool canUseOutputs);
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user