2024-04-05 00:18:07 +02:00
|
|
|
#pragma clang diagnostic push
|
|
|
|
#pragma ide diagnostic ignored "misc-no-recursion"
|
2024-03-17 22:06:27 +01:00
|
|
|
//
|
|
|
|
// Created by martin on 17.03.24.
|
|
|
|
//
|
|
|
|
|
|
|
|
#include "AnimGraphBlendTree.h"
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
bool AnimGraphBlendTree::Init(AnimGraphContext& context) {
|
|
|
|
for (size_t i = 2; i < m_nodes.size(); i++) {
|
|
|
|
if (!m_nodes[i]->Init(context)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t i = 0; i < m_animdata_blocks.size(); i++) {
|
|
|
|
int num_soa_joints = context.m_skeleton->num_soa_joints();
|
|
|
|
m_animdata_blocks[i]->m_local_matrices.resize(num_soa_joints);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimGraphBlendTree::UpdateOrderedNodes() {
|
|
|
|
m_eval_ordered_nodes.clear();
|
|
|
|
UpdateOrderedNodesRecursive(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimGraphBlendTree::UpdateOrderedNodesRecursive(int node_index) {
|
|
|
|
AnimNode* node = m_nodes[node_index];
|
|
|
|
const std::vector<AnimGraphConnection>& node_input_connections =
|
|
|
|
m_node_input_connections[node_index];
|
|
|
|
for (size_t i = 0, n = node_input_connections.size(); i < n; i++) {
|
2024-04-01 12:33:23 +02:00
|
|
|
if (node_input_connections[i].m_crosses_hierarchy) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2024-03-17 22:06:27 +01:00
|
|
|
int input_node_index =
|
2024-04-01 12:33:23 +02:00
|
|
|
GetAnimNodeIndex(node_input_connections[i].m_source_node);
|
2024-03-17 22:06:27 +01:00
|
|
|
|
|
|
|
if (input_node_index == 1) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
UpdateOrderedNodesRecursive(input_node_index);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (node_index != 0) {
|
|
|
|
// In case we have multiple output connections from the node we here
|
|
|
|
// ensure that use the node evaluation that is the furthest away from
|
|
|
|
// the output.
|
|
|
|
std::vector<AnimNode*>::iterator find_iter = std::find(
|
|
|
|
m_eval_ordered_nodes.begin(),
|
|
|
|
m_eval_ordered_nodes.end(),
|
|
|
|
node);
|
|
|
|
if (find_iter != m_eval_ordered_nodes.end()) {
|
|
|
|
m_eval_ordered_nodes.erase(find_iter);
|
|
|
|
}
|
|
|
|
|
|
|
|
m_eval_ordered_nodes.push_back(node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-01 21:18:26 +02:00
|
|
|
void AnimGraphBlendTree::MarkActiveInputs(
|
|
|
|
const std::vector<AnimGraphConnection>& input_connections) {
|
2024-04-05 00:18:07 +02:00
|
|
|
for (AnimNode* node : m_nodes) {
|
|
|
|
if (node->m_tick_number != m_tick_number) {
|
|
|
|
node->m_state = AnimNodeEvalState::Deactivated;
|
2024-04-01 12:33:23 +02:00
|
|
|
}
|
2024-03-17 22:06:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
const std::vector<AnimGraphConnection>& graph_output_inputs =
|
|
|
|
m_node_input_connections[0];
|
|
|
|
for (size_t i = 0, n = graph_output_inputs.size(); i < n; i++) {
|
|
|
|
const AnimGraphConnection& graph_input = graph_output_inputs[i];
|
|
|
|
AnimNode* node = graph_input.m_source_node;
|
|
|
|
if (node != nullptr) {
|
2024-04-01 12:33:23 +02:00
|
|
|
node->m_tick_number = m_tick_number;
|
2024-03-17 22:06:27 +01:00
|
|
|
node->m_state = AnimNodeEvalState::Activated;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-01 12:33:23 +02:00
|
|
|
for (int i = m_eval_ordered_nodes.size() - 1; i >= 0; i--) {
|
2024-03-17 22:06:27 +01:00
|
|
|
AnimNode* node = m_eval_ordered_nodes[i];
|
2024-04-01 12:33:23 +02:00
|
|
|
if (CheckIsNodeActive(node)) {
|
2024-03-17 22:06:27 +01:00
|
|
|
size_t node_index = GetAnimNodeIndex(node);
|
2024-04-01 12:33:23 +02:00
|
|
|
node->MarkActiveInputs(m_node_input_connections[node_index]);
|
2024-03-17 22:06:27 +01:00
|
|
|
|
|
|
|
// Non-animation data inputs are always active.
|
|
|
|
for (size_t j = 0, nj = m_node_input_connections[node_index].size();
|
|
|
|
j < nj;
|
|
|
|
j++) {
|
|
|
|
const AnimGraphConnection& input =
|
|
|
|
m_node_input_connections[node_index][j];
|
|
|
|
if (input.m_source_node != nullptr
|
2024-04-01 21:18:26 +02:00
|
|
|
&& input.m_socket.m_type != SocketType::SocketTypeAnimation) {
|
2024-03-17 22:06:27 +01:00
|
|
|
input.m_source_node->m_state = AnimNodeEvalState::Activated;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-01 21:18:26 +02:00
|
|
|
void AnimGraphBlendTree::CalcSyncTrack(
|
|
|
|
const std::vector<AnimGraphConnection>& input_connections) {
|
2024-04-05 00:18:07 +02:00
|
|
|
for (int i = m_eval_ordered_nodes.size() - 1; i >= 0; i--) {
|
2024-03-17 22:06:27 +01:00
|
|
|
AnimNode* node = m_eval_ordered_nodes[i];
|
|
|
|
if (node->m_state == AnimNodeEvalState::Deactivated) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2024-04-01 12:33:23 +02:00
|
|
|
node->CalcSyncTrack(m_node_input_connections[GetAnimNodeIndex(node)]);
|
2024-03-17 22:06:27 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AnimGraphBlendTree::UpdateTime(float time_last, float time_now) {
|
|
|
|
const std::vector<AnimGraphConnection>& graph_output_inputs =
|
|
|
|
m_node_input_connections[0];
|
2024-04-05 00:18:07 +02:00
|
|
|
for (const AnimGraphConnection& graph_output_input : graph_output_inputs) {
|
|
|
|
AnimNode* node = graph_output_input.m_source_node;
|
2024-04-01 12:33:23 +02:00
|
|
|
if (node != nullptr && node->m_state != AnimNodeEvalState::TimeUpdated) {
|
|
|
|
node->UpdateTime(time_last, time_now);
|
2024-03-17 22:06:27 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-01 12:33:23 +02:00
|
|
|
for (int i = m_eval_ordered_nodes.size() - 1; i >= 0; --i) {
|
2024-03-17 22:06:27 +01:00
|
|
|
AnimNode* node = m_eval_ordered_nodes[i];
|
|
|
|
if (node->m_state != AnimNodeEvalState::TimeUpdated) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2024-04-01 12:33:23 +02:00
|
|
|
PropagateTimeToNodeInputs(node);
|
2024-03-17 22:06:27 +01:00
|
|
|
}
|
2024-04-01 12:33:23 +02:00
|
|
|
|
|
|
|
m_state = AnimNodeEvalState::TimeUpdated;
|
2024-03-17 22:06:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void AnimGraphBlendTree::Evaluate(AnimGraphContext& context) {
|
|
|
|
for (int i = 0, n = m_eval_ordered_nodes.size(); i < n; i++) {
|
|
|
|
AnimNode* node = m_eval_ordered_nodes[i];
|
|
|
|
|
|
|
|
if (node->m_state == AnimNodeEvalState::Deactivated) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
node->Evaluate(context);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-01 12:33:23 +02:00
|
|
|
void AnimGraphBlendTree::PropagateTimeToNodeInputs(const AnimNode* node) {
|
|
|
|
size_t node_index = GetAnimNodeIndex(node);
|
|
|
|
|
|
|
|
float node_time_now = node->m_time_now;
|
|
|
|
float node_time_last = node->m_time_last;
|
|
|
|
|
|
|
|
const std::vector<AnimGraphConnection>& node_input_connections =
|
|
|
|
m_node_input_connections[node_index];
|
2024-04-05 00:18:07 +02:00
|
|
|
for (const AnimGraphConnection& node_input_connection :
|
|
|
|
node_input_connections) {
|
|
|
|
AnimNode* input_node = node_input_connection.m_source_node;
|
2024-04-01 12:33:23 +02:00
|
|
|
|
|
|
|
// Only propagate time updates via animation sockets.
|
|
|
|
if (input_node != nullptr
|
2024-04-05 00:18:07 +02:00
|
|
|
&& node_input_connection.m_socket.m_type
|
2024-04-01 12:33:23 +02:00
|
|
|
== SocketType::SocketTypeAnimation
|
|
|
|
&& input_node->m_state == AnimNodeEvalState::Activated) {
|
|
|
|
input_node->UpdateTime(node_time_last, node_time_now);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-04-05 00:18:07 +02:00
|
|
|
|
|
|
|
#pragma clang diagnostic pop
|