2022-03-25 11:46:44 +01:00
|
|
|
//
|
|
|
|
// Created by martin on 25.03.22.
|
|
|
|
//
|
|
|
|
|
|
|
|
#ifndef ANIMTESTBED_ANIMGRAPHNODES_H
|
|
|
|
#define ANIMTESTBED_ANIMGRAPHNODES_H
|
|
|
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
#include "AnimGraphData.h"
|
|
|
|
#include "SyncTrack.h"
|
2022-04-11 16:46:09 +02:00
|
|
|
#include "ozz/animation/runtime/sampling_job.h"
|
2022-03-25 11:46:44 +01:00
|
|
|
|
|
|
|
struct AnimNode;
|
|
|
|
|
|
|
|
struct NodeInput {
|
|
|
|
AnimNode* m_node;
|
|
|
|
SocketType m_type = SocketType::SocketTypeUndefined;
|
2022-04-01 13:19:54 +02:00
|
|
|
Socket* m_node_output_socket;
|
2022-03-25 11:46:44 +01:00
|
|
|
std::string m_input_name;
|
|
|
|
};
|
|
|
|
|
|
|
|
enum class AnimNodeEvalState {
|
|
|
|
Undefined,
|
|
|
|
Deactivated,
|
|
|
|
Activated,
|
|
|
|
SyncTrackUpdated,
|
|
|
|
TimeUpdated,
|
|
|
|
Evaluated
|
|
|
|
};
|
|
|
|
|
2022-04-01 13:19:54 +02:00
|
|
|
struct AnimGraphConnection {
|
|
|
|
AnimNode* m_source_node = nullptr;
|
|
|
|
Socket m_source_socket;
|
|
|
|
AnimNode* m_target_node = nullptr;
|
|
|
|
Socket m_target_socket;
|
|
|
|
};
|
|
|
|
|
2022-03-25 11:46:44 +01:00
|
|
|
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(){};
|
|
|
|
|
2022-04-11 16:46:09 +02:00
|
|
|
virtual bool Init(AnimGraphContext& context) { return true; };
|
|
|
|
|
2022-04-01 13:19:54 +02:00
|
|
|
virtual void MarkActiveInputs(const std::vector<AnimGraphConnection>& inputs) {
|
2022-03-25 11:46:44 +01:00
|
|
|
for (size_t i = 0, n = inputs.size(); i < n; i++) {
|
2022-04-01 13:19:54 +02:00
|
|
|
AnimNode* input_node = inputs[i].m_source_node;
|
2022-03-25 11:46:44 +01:00
|
|
|
if (input_node != nullptr) {
|
|
|
|
input_node->m_state = AnimNodeEvalState::Activated;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-01 13:19:54 +02:00
|
|
|
virtual void CalcSyncTrack(const std::vector<AnimGraphConnection>& inputs) {
|
2022-03-25 11:46:44 +01:00
|
|
|
for (size_t i = 0, n = inputs.size(); i < n; i++) {
|
2022-04-01 13:19:54 +02:00
|
|
|
AnimNode* input_node = inputs[i].m_source_node;
|
2022-03-25 11:46:44 +01:00
|
|
|
if (input_node != nullptr
|
2022-04-01 13:19:54 +02:00
|
|
|
&& inputs[i].m_source_socket.m_type == SocketType::SocketTypeAnimation
|
2022-03-25 11:46:44 +01:00
|
|
|
&& 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;
|
|
|
|
}
|
|
|
|
|
2022-04-11 16:46:09 +02:00
|
|
|
virtual void Evaluate(AnimGraphContext& context){};
|
2022-03-25 11:46:44 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// BlendTreeNode
|
|
|
|
//
|
|
|
|
struct BlendTreeNode : public AnimNode {};
|
|
|
|
|
|
|
|
template <>
|
2023-03-30 23:50:07 +02:00
|
|
|
struct NodeDescriptor<BlendTreeNode> : public NodeDescriptorBase {
|
|
|
|
NodeDescriptor(BlendTreeNode* node_) {}
|
2022-03-25 11:46:44 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
//
|
|
|
|
// Blend2Node
|
|
|
|
//
|
|
|
|
struct Blend2Node : public AnimNode {
|
2022-04-01 13:19:54 +02:00
|
|
|
AnimData* i_input0 = nullptr;
|
|
|
|
AnimData* i_input1 = nullptr;
|
|
|
|
AnimData* o_output = nullptr;
|
|
|
|
float* i_blend_weight = nullptr;
|
2022-03-25 11:46:44 +01:00
|
|
|
bool m_sync_blend = false;
|
|
|
|
|
2022-04-01 13:19:54 +02:00
|
|
|
virtual void MarkActiveInputs(const std::vector<AnimGraphConnection>& inputs) override {
|
2022-03-25 11:46:44 +01:00
|
|
|
for (size_t i = 0, n = inputs.size(); i < n; i++) {
|
2022-04-01 13:19:54 +02:00
|
|
|
AnimNode* input_node = inputs[i].m_source_node;
|
2022-03-25 11:46:44 +01:00
|
|
|
if (input_node == nullptr) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2022-04-01 13:19:54 +02:00
|
|
|
if (inputs[i].m_target_socket.m_name == "Input0" && *i_blend_weight < 0.999) {
|
2022-03-25 11:46:44 +01:00
|
|
|
input_node->m_state = AnimNodeEvalState::Activated;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2022-04-01 13:19:54 +02:00
|
|
|
if (inputs[i].m_target_socket.m_name == "Input1" && *i_blend_weight > 0.001) {
|
2022-03-25 11:46:44 +01:00
|
|
|
input_node->m_state = AnimNodeEvalState::Activated;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-11 16:46:09 +02:00
|
|
|
virtual void Evaluate(AnimGraphContext& context) override;
|
2022-03-25 11:46:44 +01:00
|
|
|
};
|
|
|
|
|
2023-03-29 22:25:09 +02:00
|
|
|
template <>
|
|
|
|
struct NodeDescriptor<Blend2Node> : public NodeDescriptorBase {
|
|
|
|
NodeDescriptor(Blend2Node* node) {
|
|
|
|
RegisterInput("Input0", &node->i_input0);
|
|
|
|
RegisterInput("Input1", &node->i_input1);
|
|
|
|
RegisterInput("Weight", &node->i_blend_weight);
|
|
|
|
|
|
|
|
RegisterOutput("Output", &node->o_output);
|
|
|
|
|
|
|
|
RegisterProperty("Sync", &node->m_sync_blend);
|
|
|
|
}
|
2023-03-30 16:53:09 +02:00
|
|
|
|
|
|
|
void UpdateFlags() override {
|
|
|
|
Socket* weight_input_socket = FindSocket("Weight", m_inputs);
|
|
|
|
assert(weight_input_socket != nullptr);
|
|
|
|
|
2023-04-03 19:31:09 +02:00
|
|
|
if (GetProperty<bool>("Sync") == true) {
|
2023-03-30 16:53:09 +02:00
|
|
|
weight_input_socket->m_flags = SocketFlags::SocketFlagAffectsTime;
|
|
|
|
} else {
|
|
|
|
weight_input_socket->m_flags = SocketFlags::SocketFlagNone;
|
|
|
|
}
|
|
|
|
}
|
2023-03-29 22:25:09 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2022-03-25 11:46:44 +01:00
|
|
|
//
|
|
|
|
// SpeedScaleNode
|
|
|
|
//
|
|
|
|
struct SpeedScaleNode : public AnimNode {
|
2022-04-01 13:19:54 +02:00
|
|
|
AnimData* i_input = nullptr;
|
2022-04-11 16:46:09 +02:00
|
|
|
AnimData* o_output = nullptr;
|
2022-04-01 13:19:54 +02:00
|
|
|
float* i_speed_scale = nullptr;
|
2022-03-25 11:46:44 +01:00
|
|
|
|
2022-04-11 16:46:09 +02:00
|
|
|
void UpdateTime(float time_last, float time_now) override {
|
2023-04-02 21:24:12 +02:00
|
|
|
m_time_last = m_time_now;
|
|
|
|
m_time_now = m_time_last + (time_now - time_last) * (*i_speed_scale);
|
2022-03-25 11:46:44 +01:00
|
|
|
m_state = AnimNodeEvalState::TimeUpdated;
|
|
|
|
}
|
2022-04-11 16:46:09 +02:00
|
|
|
|
|
|
|
void Evaluate(AnimGraphContext& context) override {
|
|
|
|
assert (i_input != nullptr);
|
|
|
|
assert (o_output != nullptr);
|
|
|
|
|
|
|
|
o_output->m_local_matrices = i_input->m_local_matrices;
|
|
|
|
};
|
2022-03-25 11:46:44 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
template <>
|
2023-03-30 23:50:07 +02:00
|
|
|
struct NodeDescriptor<SpeedScaleNode> : public NodeDescriptorBase {
|
|
|
|
NodeDescriptor(SpeedScaleNode* node) {
|
2022-03-25 11:46:44 +01:00
|
|
|
RegisterInput(
|
|
|
|
"SpeedScale",
|
2022-04-01 13:19:54 +02:00
|
|
|
&node->i_speed_scale,
|
2022-03-25 11:46:44 +01:00
|
|
|
SocketFlags::SocketFlagAffectsTime);
|
2022-04-01 13:19:54 +02:00
|
|
|
RegisterInput("Input", &node->i_input);
|
2022-03-25 11:46:44 +01:00
|
|
|
|
2022-04-11 16:46:09 +02:00
|
|
|
RegisterOutput("Output", &node->o_output);
|
2022-03-25 11:46:44 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-03-30 23:50:07 +02:00
|
|
|
|
2022-03-25 11:46:44 +01:00
|
|
|
//
|
|
|
|
// AnimSamplerNode
|
|
|
|
//
|
|
|
|
struct AnimSamplerNode : public AnimNode {
|
2022-04-01 13:19:54 +02:00
|
|
|
AnimData* o_output = nullptr;
|
2022-03-25 11:46:44 +01:00
|
|
|
std::string m_filename;
|
2023-03-26 11:44:29 +02:00
|
|
|
ozz::animation::SamplingJob::Context m_sampling_context;
|
2022-04-11 16:46:09 +02:00
|
|
|
ozz::animation::Animation* m_animation = nullptr;
|
|
|
|
|
|
|
|
virtual ~AnimSamplerNode();
|
|
|
|
virtual bool Init(AnimGraphContext& context) override;
|
2023-03-28 22:00:58 +02:00
|
|
|
void UpdateTime(float time_last, float time_now) override {
|
|
|
|
m_time_last = time_last;
|
2023-04-02 21:24:12 +02:00
|
|
|
m_time_now = time_now;
|
2023-03-28 22:00:58 +02:00
|
|
|
m_state = AnimNodeEvalState::TimeUpdated;
|
|
|
|
}
|
2022-04-11 16:46:09 +02:00
|
|
|
virtual void Evaluate(AnimGraphContext& context) override;
|
2022-03-25 11:46:44 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
template <>
|
2023-03-30 23:50:07 +02:00
|
|
|
struct NodeDescriptor<AnimSamplerNode> : public NodeDescriptorBase {
|
|
|
|
NodeDescriptor(AnimSamplerNode* node) {
|
2022-04-01 13:19:54 +02:00
|
|
|
RegisterOutput("Output", &node->o_output);
|
2022-03-25 11:46:44 +01:00
|
|
|
|
|
|
|
RegisterProperty("Filename", &node->m_filename);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-04-02 21:40:49 +02:00
|
|
|
//
|
|
|
|
// LockTranslationNode
|
|
|
|
//
|
|
|
|
struct LockTranslationNode : public AnimNode {
|
|
|
|
AnimData* i_input = nullptr;
|
|
|
|
AnimData* o_output = nullptr;
|
|
|
|
int m_locked_bone_index;
|
|
|
|
bool m_lock_x;
|
|
|
|
bool m_lock_y;
|
|
|
|
bool m_lock_z;
|
|
|
|
|
|
|
|
virtual void Evaluate(AnimGraphContext& context) override;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <>
|
|
|
|
struct NodeDescriptor<LockTranslationNode> : public NodeDescriptorBase {
|
|
|
|
NodeDescriptor(LockTranslationNode* node) {
|
|
|
|
RegisterInput("Input", &node->i_input);
|
|
|
|
RegisterOutput("Output", &node->o_output);
|
|
|
|
|
|
|
|
RegisterProperty("BoneIndex", &node->m_locked_bone_index);
|
|
|
|
RegisterProperty("LockAxisX", &node->m_lock_x);
|
|
|
|
RegisterProperty("LockAxisY", &node->m_lock_y);
|
|
|
|
RegisterProperty("LockAxisZ", &node->m_lock_z);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2023-03-28 22:00:58 +02:00
|
|
|
//
|
|
|
|
// ConstScalarNode
|
|
|
|
//
|
|
|
|
struct ConstScalarNode : public AnimNode {
|
|
|
|
float* o_value = nullptr;
|
|
|
|
float value = 0.f;
|
|
|
|
|
|
|
|
virtual void Evaluate(AnimGraphContext& context){
|
|
|
|
*o_value = value;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
template <>
|
2023-03-30 23:50:07 +02:00
|
|
|
struct NodeDescriptor<ConstScalarNode> : public NodeDescriptorBase {
|
|
|
|
NodeDescriptor(ConstScalarNode* node) {
|
2023-03-28 22:00:58 +02:00
|
|
|
RegisterOutput("ScalarOutput", &node->o_value);
|
|
|
|
RegisterProperty("ScalarValue", &node->value);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-03-30 23:50:07 +02:00
|
|
|
|
2022-04-01 13:19:54 +02:00
|
|
|
//
|
|
|
|
// MathAddNode
|
|
|
|
//
|
|
|
|
struct MathAddNode : public AnimNode {
|
|
|
|
float* i_input0 = nullptr;
|
|
|
|
float* i_input1 = nullptr;
|
2023-03-30 23:50:07 +02:00
|
|
|
float* o_output = nullptr;
|
2022-04-01 13:19:54 +02:00
|
|
|
|
2022-04-11 16:46:09 +02:00
|
|
|
void Evaluate(AnimGraphContext& context) override {
|
2022-04-01 13:19:54 +02:00
|
|
|
assert (i_input0 != nullptr);
|
|
|
|
assert (i_input1 != nullptr);
|
|
|
|
|
2023-03-30 23:50:07 +02:00
|
|
|
*o_output = *i_input0 + *i_input1;
|
2022-04-01 13:19:54 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <>
|
2023-03-30 23:50:07 +02:00
|
|
|
struct NodeDescriptor<MathAddNode> : public NodeDescriptorBase {
|
|
|
|
NodeDescriptor(MathAddNode* node) {
|
2022-04-01 13:19:54 +02:00
|
|
|
RegisterInput("Input0", &node->i_input0);
|
|
|
|
RegisterInput("Input1", &node->i_input1);
|
|
|
|
RegisterOutput("Output", &node->o_output);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-04-03 21:05:11 +02:00
|
|
|
//
|
|
|
|
// MathFloatToVec3Node
|
|
|
|
//
|
|
|
|
struct MathFloatToVec3Node : public AnimNode {
|
|
|
|
float* i_input0 = nullptr;
|
|
|
|
float* i_input1 = nullptr;
|
|
|
|
float* i_input2 = nullptr;
|
2023-03-30 23:50:07 +02:00
|
|
|
Vec3* o_output = nullptr;
|
2022-04-03 21:05:11 +02:00
|
|
|
|
2022-04-11 16:46:09 +02:00
|
|
|
void Evaluate(AnimGraphContext& context) override {
|
2022-04-03 21:05:11 +02:00
|
|
|
assert (i_input0 != nullptr);
|
|
|
|
assert (i_input1 != nullptr);
|
|
|
|
assert (i_input2 != nullptr);
|
|
|
|
|
2023-03-30 23:50:07 +02:00
|
|
|
o_output->v[0] = *i_input0;
|
|
|
|
o_output->v[1] = *i_input1;
|
|
|
|
o_output->v[2] = *i_input2;
|
2022-04-03 21:05:11 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <>
|
2023-03-30 23:50:07 +02:00
|
|
|
struct NodeDescriptor<MathFloatToVec3Node> : public NodeDescriptorBase {
|
|
|
|
NodeDescriptor(MathFloatToVec3Node* node) {
|
2022-04-03 21:05:11 +02:00
|
|
|
RegisterInput("Input0", &node->i_input0);
|
|
|
|
RegisterInput("Input1", &node->i_input1);
|
|
|
|
RegisterInput("Input2", &node->i_input2);
|
|
|
|
RegisterOutput("Output", &node->o_output);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-03-30 23:50:07 +02:00
|
|
|
|
2022-03-25 12:05:56 +01:00
|
|
|
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;
|
2023-04-02 21:40:49 +02:00
|
|
|
} else if (name == "LockTranslationNode") {
|
|
|
|
result = new LockTranslationNode;
|
2022-03-25 12:05:56 +01:00
|
|
|
} else if (name == "BlendTree") {
|
|
|
|
result = new BlendTreeNode;
|
2022-04-03 21:05:11 +02:00
|
|
|
} else if (name == "MathAddNode") {
|
|
|
|
result = new MathAddNode;
|
|
|
|
} else if (name == "MathFloatToVec3Node") {
|
|
|
|
result = new MathFloatToVec3Node;
|
2023-03-28 22:00:58 +02:00
|
|
|
} else if (name == "ConstScalarNode") {
|
|
|
|
result = new ConstScalarNode;
|
2022-03-25 12:05:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (result != nullptr) {
|
|
|
|
result->m_node_type_name = name;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::cerr << "Invalid node type: " << name << std::endl;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2023-03-30 23:50:07 +02:00
|
|
|
static inline NodeDescriptorBase* AnimNodeDescriptorFactory(
|
2022-03-25 12:05:56 +01:00
|
|
|
const std::string& node_type_name,
|
|
|
|
AnimNode* node) {
|
|
|
|
if (node_type_name == "Blend2") {
|
2023-03-30 23:50:07 +02:00
|
|
|
return CreateNodeDescriptor<Blend2Node>(node);
|
2022-03-25 12:05:56 +01:00
|
|
|
} else if (node_type_name == "SpeedScale") {
|
2023-03-30 23:50:07 +02:00
|
|
|
return CreateNodeDescriptor<SpeedScaleNode>(node);
|
2022-03-25 12:05:56 +01:00
|
|
|
} else if (node_type_name == "AnimSampler") {
|
2023-03-30 23:50:07 +02:00
|
|
|
return CreateNodeDescriptor<AnimSamplerNode>(node);
|
2023-04-02 21:40:49 +02:00
|
|
|
} else if (node_type_name == "LockTranslationNode") {
|
|
|
|
return CreateNodeDescriptor<LockTranslationNode>(node);
|
2022-03-25 12:05:56 +01:00
|
|
|
} else if (node_type_name == "BlendTree") {
|
2023-03-30 23:50:07 +02:00
|
|
|
return CreateNodeDescriptor<BlendTreeNode>(node);
|
2022-04-03 21:05:11 +02:00
|
|
|
} else if (node_type_name == "MathAddNode") {
|
2023-03-30 23:50:07 +02:00
|
|
|
return CreateNodeDescriptor<MathAddNode>(node);
|
2022-04-03 21:05:11 +02:00
|
|
|
} else if (node_type_name == "MathFloatToVec3Node") {
|
2023-03-30 23:50:07 +02:00
|
|
|
return CreateNodeDescriptor<MathFloatToVec3Node>(node);
|
2023-03-28 22:00:58 +02:00
|
|
|
} else if (node_type_name == "ConstScalarNode") {
|
2023-03-30 23:50:07 +02:00
|
|
|
return CreateNodeDescriptor<ConstScalarNode>(node);
|
2022-03-25 12:05:56 +01:00
|
|
|
} else {
|
|
|
|
std::cerr << "Invalid node type name " << node_type_name << "."
|
|
|
|
<< std::endl;
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2022-03-25 11:46:44 +01:00
|
|
|
#endif //ANIMTESTBED_ANIMGRAPHNODES_H
|