// // Created by martin on 25.03.22. // #ifndef ANIMTESTBED_ANIMGRAPHNODES_H #define ANIMTESTBED_ANIMGRAPHNODES_H #include #include "AnimGraphData.h" #include "SyncTrack.h" struct AnimNode; struct NodeInput { AnimNode* m_node; SocketType m_type = SocketType::SocketTypeUndefined; std::string m_input_name; }; enum class AnimNodeEvalState { Undefined, Deactivated, Activated, SyncTrackUpdated, TimeUpdated, Evaluated }; struct AnimNode { std::string m_name; std::string m_node_type_name; float m_time_now = 0.f; float m_time_last = 0.f; size_t m_index = -1; AnimNodeEvalState m_state = AnimNodeEvalState::Undefined; SyncTrack m_sync_track; virtual ~AnimNode(){}; virtual void MarkActiveInputs(const std::vector& inputs) { for (size_t i = 0, n = inputs.size(); i < n; i++) { AnimNode* input_node = inputs[i].m_node; if (input_node != nullptr) { input_node->m_state = AnimNodeEvalState::Activated; } } } virtual void CalcSyncTrack(const std::vector& inputs) { for (size_t i = 0, n = inputs.size(); i < n; i++) { AnimNode* input_node = inputs[i].m_node; if (input_node != nullptr && inputs[i].m_type == SocketType::SocketTypeAnimation && input_node->m_state != AnimNodeEvalState::Deactivated) { m_sync_track = input_node->m_sync_track; return; } } } virtual void UpdateTime(float time_last, float time_now) { m_time_last = time_last; m_time_now = time_now; m_state = AnimNodeEvalState::TimeUpdated; } virtual void Evaluate(){}; }; // // BlendTreeNode // struct BlendTreeNode : public AnimNode {}; template <> struct NodeSocketAccessor : public NodeSocketAccessorBase { NodeSocketAccessor(AnimNode* node_) {} }; // // Blend2Node // struct Blend2Node : public AnimNode { AnimData m_input0; AnimData m_input1; AnimData* m_output = nullptr; float m_blend_weight = 0.f; bool m_sync_blend = false; virtual void MarkActiveInputs(const std::vector& inputs) override { for (size_t i = 0, n = inputs.size(); i < n; i++) { AnimNode* input_node = inputs[i].m_node; if (input_node == nullptr) { continue; } if (inputs[i].m_input_name == "Input0" && m_blend_weight < 0.999) { input_node->m_state = AnimNodeEvalState::Activated; continue; } if (inputs[i].m_input_name == "Input1" && m_blend_weight > 0.001) { input_node->m_state = AnimNodeEvalState::Activated; continue; } } } virtual void UpdateTime(float dt, std::vector& inputs) { if (!m_sync_blend) { m_time_now = m_time_now + dt; } for (size_t i = 0, n = inputs.size(); i < n; i++) { AnimNode* input_node = inputs[i].m_node; if (input_node == nullptr) { continue; } if (input_node->m_state != AnimNodeEvalState::Deactivated) { if (!m_sync_blend) { input_node->m_time_now = m_time_now; } input_node->m_state = AnimNodeEvalState::TimeUpdated; continue; } } } }; template <> struct NodeSocketAccessor : public NodeSocketAccessorBase { NodeSocketAccessor(AnimNode* node_) { Blend2Node* node = dynamic_cast(node_); RegisterInput("Input0", &node->m_input0); RegisterInput("Input1", &node->m_input1); RegisterInput( "Weight", &node->m_blend_weight, SocketFlags::SocketFlagAffectsTime); RegisterOutput("Output", &node->m_output); RegisterProperty("Sync", &node->m_sync_blend); } virtual void UpdateFlags() override { Socket* weight_input_socket = FindSocket(m_inputs, "Weight"); assert(weight_input_socket != nullptr); if (GetProperty("Sync", false) == true) { weight_input_socket->m_flags = SocketFlags::SocketFlagAffectsTime; } else { weight_input_socket->m_flags = 0; } } }; // // SpeedScaleNode // struct SpeedScaleNode : public AnimNode { AnimData m_input; AnimData* m_output = nullptr; float m_speed_scale = 0.f; virtual void UpdateTime(float time_last, float time_now) { m_time_last = time_last; m_time_now = time_last + (time_now - time_last) * m_speed_scale; m_state = AnimNodeEvalState::TimeUpdated; } }; template <> struct NodeSocketAccessor : public NodeSocketAccessorBase { NodeSocketAccessor(AnimNode* node_) { SpeedScaleNode* node = dynamic_cast(node_); RegisterInput( "SpeedScale", &node->m_speed_scale, SocketFlags::SocketFlagAffectsTime); RegisterInput("Input", &node->m_input); RegisterOutput("Output", &node->m_output); } }; // // AnimSamplerNode // struct AnimSamplerNode : public AnimNode { AnimData* m_output = nullptr; std::string m_filename; }; template <> struct NodeSocketAccessor : public NodeSocketAccessorBase { NodeSocketAccessor(AnimNode* node_) { AnimSamplerNode* node = dynamic_cast(node_); RegisterOutput("Output", &node->m_output); RegisterProperty("Filename", &node->m_filename); } }; static inline AnimNode* AnimNodeFactory(const std::string& name) { AnimNode* result; if (name == "Blend2") { result = new Blend2Node; } else if (name == "SpeedScale") { result = new SpeedScaleNode; } else if (name == "AnimSampler") { result = new AnimSamplerNode; } else if (name == "BlendTree") { result = new BlendTreeNode; } if (result != nullptr) { result->m_node_type_name = name; return result; } std::cerr << "Invalid node type: " << name << std::endl; return nullptr; } static inline NodeSocketAccessorBase* AnimNodeAccessorFactory( const std::string& node_type_name, AnimNode* node) { if (node_type_name == "Blend2") { return new NodeSocketAccessor(node); } else if (node_type_name == "SpeedScale") { return new NodeSocketAccessor(node); } else if (node_type_name == "AnimSampler") { return new NodeSocketAccessor(node); } else if (node_type_name == "BlendTree") { return new NodeSocketAccessor(node); } else { std::cerr << "Invalid node type name " << node_type_name << "." << std::endl; } return nullptr; } #endif //ANIMTESTBED_ANIMGRAPHNODES_H