Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e8ef7924d2 | ||
|
|
0a45497de9 | ||
|
|
7c8b44247b | ||
|
|
abf44a875a | ||
|
|
42303d5f47 |
@@ -23,6 +23,7 @@ struct AnimGraph {
|
|||||||
char* m_input_buffer = nullptr;
|
char* m_input_buffer = nullptr;
|
||||||
char* m_output_buffer = nullptr;
|
char* m_output_buffer = nullptr;
|
||||||
char* m_connection_data_storage = nullptr;
|
char* m_connection_data_storage = nullptr;
|
||||||
|
char* m_const_node_inputs = nullptr;
|
||||||
|
|
||||||
std::vector<Socket>& getGraphOutputs() { return m_node_descriptor->m_inputs; }
|
std::vector<Socket>& getGraphOutputs() { return m_node_descriptor->m_inputs; }
|
||||||
std::vector<Socket>& getGraphInputs() { return m_node_descriptor->m_outputs; }
|
std::vector<Socket>& getGraphInputs() { return m_node_descriptor->m_outputs; }
|
||||||
@@ -44,6 +45,7 @@ struct AnimGraph {
|
|||||||
delete[] m_input_buffer;
|
delete[] m_input_buffer;
|
||||||
delete[] m_output_buffer;
|
delete[] m_output_buffer;
|
||||||
delete[] m_connection_data_storage;
|
delete[] m_connection_data_storage;
|
||||||
|
delete[] m_const_node_inputs;
|
||||||
|
|
||||||
for (int i = 0; i < m_nodes.size(); i++) {
|
for (int i = 0; i < m_nodes.size(); i++) {
|
||||||
delete m_nodes[i];
|
delete m_nodes[i];
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ enum class SocketType {
|
|||||||
SocketTypeUndefined = 0,
|
SocketTypeUndefined = 0,
|
||||||
SocketTypeBool,
|
SocketTypeBool,
|
||||||
SocketTypeAnimation,
|
SocketTypeAnimation,
|
||||||
|
SocketTypeInt,
|
||||||
SocketTypeFloat,
|
SocketTypeFloat,
|
||||||
SocketTypeVec3,
|
SocketTypeVec3,
|
||||||
SocketTypeQuat,
|
SocketTypeQuat,
|
||||||
@@ -143,7 +144,7 @@ enum class SocketType {
|
|||||||
constexpr size_t cSocketStringValueMaxLength = 256;
|
constexpr size_t cSocketStringValueMaxLength = 256;
|
||||||
|
|
||||||
static const char* SocketTypeNames[] =
|
static const char* SocketTypeNames[] =
|
||||||
{"", "Bool", "Animation", "Float", "Vec3", "Quat", "String"};
|
{"", "Bool", "Animation", "Int", "Float", "Vec3", "Quat", "String"};
|
||||||
|
|
||||||
enum SocketFlags { SocketFlagNone = 0, SocketFlagAffectsTime = 1 };
|
enum SocketFlags { SocketFlagNone = 0, SocketFlagAffectsTime = 1 };
|
||||||
|
|
||||||
@@ -152,6 +153,7 @@ struct Socket {
|
|||||||
SocketType m_type = SocketType::SocketTypeUndefined;
|
SocketType m_type = SocketType::SocketTypeUndefined;
|
||||||
union SocketValue {
|
union SocketValue {
|
||||||
bool flag;
|
bool flag;
|
||||||
|
int int_value;
|
||||||
float float_value;
|
float float_value;
|
||||||
Vec3 vec3;
|
Vec3 vec3;
|
||||||
Quat quat;
|
Quat quat;
|
||||||
@@ -165,6 +167,62 @@ struct Socket {
|
|||||||
SocketReference m_reference = {0};
|
SocketReference m_reference = {0};
|
||||||
SocketFlags m_flags = SocketFlagNone;
|
SocketFlags m_flags = SocketFlagNone;
|
||||||
size_t m_type_size = 0;
|
size_t m_type_size = 0;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void SetValue(const T value) {
|
||||||
|
if constexpr (std::is_same<T, bool>::value) {
|
||||||
|
m_value.flag = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if constexpr (std::is_same<T, int>::value) {
|
||||||
|
m_value.int_value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if constexpr (std::is_same<T, float>::value) {
|
||||||
|
m_value.float_value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if constexpr (std::is_same<T, Vec3>::value) {
|
||||||
|
m_value.vec3 = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if constexpr (std::is_same<T, Quat>::value) {
|
||||||
|
m_value.quat = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if constexpr (std::is_same<T, std::string>::value) {
|
||||||
|
m_value_string = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T GetValue() const {
|
||||||
|
if constexpr (std::is_same<T, bool>::value) {
|
||||||
|
return m_value.flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
if constexpr (std::is_same<T, int>::value) {
|
||||||
|
return m_value.int_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if constexpr (std::is_same<T, float>::value) {
|
||||||
|
return m_value.float_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if constexpr (std::is_same<T, Vec3>::value) {
|
||||||
|
return m_value.vec3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if constexpr (std::is_same<T, Quat>::value) {
|
||||||
|
return m_value.quat;
|
||||||
|
}
|
||||||
|
|
||||||
|
if constexpr (std::is_same<T, std::string>::value) {
|
||||||
|
return m_value_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
return T();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@@ -177,6 +235,10 @@ SocketType GetSocketType() {
|
|||||||
return SocketType::SocketTypeAnimation;
|
return SocketType::SocketTypeAnimation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if constexpr (std::is_same<T, int>::value) {
|
||||||
|
return SocketType::SocketTypeInt;
|
||||||
|
}
|
||||||
|
|
||||||
if constexpr (std::is_same<T, float>::value) {
|
if constexpr (std::is_same<T, float>::value) {
|
||||||
return SocketType::SocketTypeFloat;
|
return SocketType::SocketTypeFloat;
|
||||||
}
|
}
|
||||||
@@ -256,6 +318,13 @@ struct NodeDescriptorBase {
|
|||||||
*socket->m_reference.ptr_ptr = value_ptr;
|
*socket->m_reference.ptr_ptr = value_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void SetInputValue(const char* name, T value) {
|
||||||
|
Socket* socket = FindSocket(name, m_inputs);
|
||||||
|
assert(GetSocketType<T>() == socket->m_type);
|
||||||
|
socket->SetValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
void SetInputUnchecked(const char* name, void* value_ptr) {
|
void SetInputUnchecked(const char* name, void* value_ptr) {
|
||||||
Socket* socket = FindSocket(name, m_inputs);
|
Socket* socket = FindSocket(name, m_inputs);
|
||||||
*socket->m_reference.ptr_ptr = value_ptr;
|
*socket->m_reference.ptr_ptr = value_ptr;
|
||||||
@@ -316,21 +385,7 @@ struct NodeDescriptorBase {
|
|||||||
void SetPropertyValue(const char* name, const T& value) {
|
void SetPropertyValue(const char* name, const T& value) {
|
||||||
Socket* socket = FindSocket(name, m_properties);
|
Socket* socket = FindSocket(name, m_properties);
|
||||||
assert(GetSocketType<T>() == socket->m_type);
|
assert(GetSocketType<T>() == socket->m_type);
|
||||||
if constexpr (std::is_same<T, bool>::value) {
|
socket->SetValue(value);
|
||||||
socket->m_value.flag = *value;
|
|
||||||
}
|
|
||||||
if constexpr (std::is_same<T, float>::value) {
|
|
||||||
socket->m_value.float_value = *value;
|
|
||||||
}
|
|
||||||
if constexpr (std::is_same<T, Vec3>::value) {
|
|
||||||
socket->m_value.vec3 = *value;
|
|
||||||
}
|
|
||||||
if constexpr (std::is_same<T, Quat>::value) {
|
|
||||||
socket->m_value.quat = *value;
|
|
||||||
}
|
|
||||||
if constexpr (std::is_same<T, std::string>::value) {
|
|
||||||
socket->m_value_string = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@@ -340,6 +395,13 @@ struct NodeDescriptorBase {
|
|||||||
return *static_cast<T*>(socket->m_reference.ptr);
|
return *static_cast<T*>(socket->m_reference.ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T GetPropertyValue(const char* name) {
|
||||||
|
Socket* socket = FindSocket(name, m_properties);
|
||||||
|
assert(GetSocketType<T>() == socket->m_type);
|
||||||
|
return socket->GetValue<T>();
|
||||||
|
}
|
||||||
|
|
||||||
virtual void UpdateFlags(){};
|
virtual void UpdateFlags(){};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ ImNodesPinShape sGetSocketShapeFromSocketType(const SocketType& socket_type) {
|
|||||||
switch (socket_type) {
|
switch (socket_type) {
|
||||||
case SocketType::SocketTypeAnimation:
|
case SocketType::SocketTypeAnimation:
|
||||||
return ImNodesPinShape_QuadFilled;
|
return ImNodesPinShape_QuadFilled;
|
||||||
|
case SocketType::SocketTypeInt:
|
||||||
|
return ImNodesPinShape_CircleFilled;
|
||||||
case SocketType::SocketTypeFloat:
|
case SocketType::SocketTypeFloat:
|
||||||
return ImNodesPinShape_CircleFilled;
|
return ImNodesPinShape_CircleFilled;
|
||||||
case SocketType::SocketTypeVec3:
|
case SocketType::SocketTypeVec3:
|
||||||
@@ -165,16 +167,24 @@ void AnimGraphEditorRenderSidebar(
|
|||||||
int num_properties = node_resource.m_socket_accessor->m_properties.size();
|
int num_properties = node_resource.m_socket_accessor->m_properties.size();
|
||||||
for (int i = 0; i < num_properties; i++) {
|
for (int i = 0; i < num_properties; i++) {
|
||||||
Socket& property = node_resource.m_socket_accessor->m_properties[i];
|
Socket& property = node_resource.m_socket_accessor->m_properties[i];
|
||||||
if (property.m_type == SocketType::SocketTypeFloat) {
|
if (property.m_type == SocketType::SocketTypeInt) {
|
||||||
|
ImGui::InputInt(
|
||||||
|
property.m_name.c_str(),
|
||||||
|
reinterpret_cast<int*>(&property.m_value.int_value),
|
||||||
|
1);
|
||||||
|
} else if (property.m_type == SocketType::SocketTypeFloat) {
|
||||||
ImGui::SliderFloat(
|
ImGui::SliderFloat(
|
||||||
property.m_name.c_str(),
|
property.m_name.c_str(),
|
||||||
reinterpret_cast<float*>(&property.m_value.float_value),
|
reinterpret_cast<float*>(&property.m_value.float_value),
|
||||||
-100.f,
|
-100.f,
|
||||||
100.f);
|
100.f);
|
||||||
} else if (property.m_type == SocketType::SocketTypeBool) {
|
} else if (property.m_type == SocketType::SocketTypeBool) {
|
||||||
ImGui::Checkbox(
|
bool flag_value = property.GetValue<bool>();
|
||||||
|
if (ImGui::Checkbox(
|
||||||
property.m_name.c_str(),
|
property.m_name.c_str(),
|
||||||
reinterpret_cast<bool*>(property.m_reference.ptr));
|
&flag_value)) {
|
||||||
|
property.SetValue(flag_value);
|
||||||
|
}
|
||||||
} else if (property.m_type == SocketType::SocketTypeString) {
|
} else if (property.m_type == SocketType::SocketTypeString) {
|
||||||
char string_buf[1024];
|
char string_buf[1024];
|
||||||
memset(string_buf, '\0', sizeof(string_buf));
|
memset(string_buf, '\0', sizeof(string_buf));
|
||||||
@@ -300,6 +310,10 @@ void AnimGraphEditorUpdate() {
|
|||||||
node_type_name = "SpeedScale";
|
node_type_name = "SpeedScale";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ImGui::MenuItem("LockTranslationNode")) {
|
||||||
|
node_type_name = "LockTranslationNode";
|
||||||
|
}
|
||||||
|
|
||||||
if (ImGui::MenuItem("MathAddNode")) {
|
if (ImGui::MenuItem("MathAddNode")) {
|
||||||
node_type_name = "MathAddNode";
|
node_type_name = "MathAddNode";
|
||||||
}
|
}
|
||||||
@@ -344,10 +358,10 @@ void AnimGraphEditorUpdate() {
|
|||||||
ImNodes::EndNodeTitleBar();
|
ImNodes::EndNodeTitleBar();
|
||||||
|
|
||||||
// Inputs
|
// Inputs
|
||||||
const std::vector<Socket>& node_inputs =
|
std::vector<Socket>& node_inputs =
|
||||||
node_resource.m_socket_accessor->m_inputs;
|
node_resource.m_socket_accessor->m_inputs;
|
||||||
for (size_t j = 0, ni = node_inputs.size(); j < ni; j++) {
|
for (size_t j = 0, ni = node_inputs.size(); j < ni; j++) {
|
||||||
const Socket& socket = node_inputs[j];
|
Socket& socket = node_inputs[j];
|
||||||
|
|
||||||
ImColor socket_color = ImColor(255, 255, 255, 255);
|
ImColor socket_color = ImColor(255, 255, 255, 255);
|
||||||
if (socket.m_flags & SocketFlagAffectsTime) {
|
if (socket.m_flags & SocketFlagAffectsTime) {
|
||||||
@@ -364,10 +378,23 @@ void AnimGraphEditorUpdate() {
|
|||||||
sGraphGresource.isSocketConnected(node_resource, socket.m_name);
|
sGraphGresource.isSocketConnected(node_resource, socket.m_name);
|
||||||
if (!socket_connected && (socket.m_type == SocketType::SocketTypeFloat)) {
|
if (!socket_connected && (socket.m_type == SocketType::SocketTypeFloat)) {
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
float socket_value = 0.f;
|
float socket_value = socket.m_value.float_value;
|
||||||
ImGui::PushItemWidth(
|
ImGui::PushItemWidth(
|
||||||
130.0f - ImGui::CalcTextSize(socket.m_name.c_str()).x);
|
130.0f - ImGui::CalcTextSize(socket.m_name.c_str()).x);
|
||||||
ImGui::DragFloat("##hidelabel", &socket_value, 0.01f);
|
if (ImGui::DragFloat("##hidelabel", &socket_value, 0.01f)) {
|
||||||
|
socket.SetValue(socket_value);
|
||||||
|
}
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!socket_connected && (socket.m_type == SocketType::SocketTypeInt)) {
|
||||||
|
ImGui::SameLine();
|
||||||
|
int socket_value = socket.m_value.int_value;
|
||||||
|
ImGui::PushItemWidth(
|
||||||
|
130.0f - ImGui::CalcTextSize(socket.m_name.c_str()).x);
|
||||||
|
if (ImGui::InputInt("##hidelabel", &socket_value, 1)) {
|
||||||
|
socket.SetValue(socket_value);
|
||||||
|
}
|
||||||
ImGui::PopItemWidth();
|
ImGui::PopItemWidth();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -82,10 +82,40 @@ void AnimSamplerNode::Evaluate(AnimGraphContext& context) {
|
|||||||
ozz::animation::SamplingJob sampling_job;
|
ozz::animation::SamplingJob sampling_job;
|
||||||
sampling_job.animation = m_animation;
|
sampling_job.animation = m_animation;
|
||||||
sampling_job.context = &m_sampling_context;
|
sampling_job.context = &m_sampling_context;
|
||||||
sampling_job.ratio = m_time_now;
|
sampling_job.ratio = fmodf(m_time_now, m_animation->duration());
|
||||||
sampling_job.output = make_span(o_output->m_local_matrices);
|
sampling_job.output = make_span(o_output->m_local_matrices);
|
||||||
|
|
||||||
if (!sampling_job.Run()) {
|
if (!sampling_job.Run()) {
|
||||||
ozz::log::Err() << "Error sampling animation." << std::endl;
|
ozz::log::Err() << "Error sampling animation." << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LockTranslationNode::Evaluate(AnimGraphContext& context) {
|
||||||
|
o_output->m_local_matrices = i_input->m_local_matrices;
|
||||||
|
ozz::math::SoaFloat3 translation =
|
||||||
|
o_output->m_local_matrices[m_locked_bone_index].translation;
|
||||||
|
float x[4];
|
||||||
|
float y[4];
|
||||||
|
float z[4];
|
||||||
|
_mm_store_ps(x, translation.x);
|
||||||
|
_mm_store_ps(y, translation.y);
|
||||||
|
_mm_store_ps(z, translation.z);
|
||||||
|
|
||||||
|
if (m_lock_x) {
|
||||||
|
x[0] = 0.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_lock_y) {
|
||||||
|
y[0] = 0.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_lock_z) {
|
||||||
|
z[0] = 0.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
translation.x = _mm_load_ps(x);
|
||||||
|
translation.y = _mm_load_ps(y);
|
||||||
|
translation.z = _mm_load_ps(z);
|
||||||
|
|
||||||
|
o_output->m_local_matrices[m_locked_bone_index].translation = translation;
|
||||||
|
}
|
||||||
@@ -156,8 +156,8 @@ struct SpeedScaleNode : public AnimNode {
|
|||||||
float* i_speed_scale = nullptr;
|
float* i_speed_scale = nullptr;
|
||||||
|
|
||||||
void UpdateTime(float time_last, float time_now) override {
|
void UpdateTime(float time_last, float time_now) override {
|
||||||
m_time_last = time_last;
|
m_time_last = m_time_now;
|
||||||
m_time_now = time_last + (time_now - time_last) * (*i_speed_scale);
|
m_time_now = m_time_last + (time_now - time_last) * (*i_speed_scale);
|
||||||
m_state = AnimNodeEvalState::TimeUpdated;
|
m_state = AnimNodeEvalState::TimeUpdated;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,7 +196,7 @@ struct AnimSamplerNode : public AnimNode {
|
|||||||
virtual bool Init(AnimGraphContext& context) override;
|
virtual bool Init(AnimGraphContext& context) override;
|
||||||
void UpdateTime(float time_last, float time_now) override {
|
void UpdateTime(float time_last, float time_now) override {
|
||||||
m_time_last = time_last;
|
m_time_last = time_last;
|
||||||
m_time_now = fmodf(time_last + (time_now - time_last), m_animation->duration());
|
m_time_now = time_now;
|
||||||
m_state = AnimNodeEvalState::TimeUpdated;
|
m_state = AnimNodeEvalState::TimeUpdated;
|
||||||
}
|
}
|
||||||
virtual void Evaluate(AnimGraphContext& context) override;
|
virtual void Evaluate(AnimGraphContext& context) override;
|
||||||
@@ -211,6 +211,34 @@ struct NodeDescriptor<AnimSamplerNode> : public NodeDescriptorBase {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// ConstScalarNode
|
// ConstScalarNode
|
||||||
//
|
//
|
||||||
@@ -296,6 +324,8 @@ static inline AnimNode* AnimNodeFactory(const std::string& name) {
|
|||||||
result = new SpeedScaleNode;
|
result = new SpeedScaleNode;
|
||||||
} else if (name == "AnimSampler") {
|
} else if (name == "AnimSampler") {
|
||||||
result = new AnimSamplerNode;
|
result = new AnimSamplerNode;
|
||||||
|
} else if (name == "LockTranslationNode") {
|
||||||
|
result = new LockTranslationNode;
|
||||||
} else if (name == "BlendTree") {
|
} else if (name == "BlendTree") {
|
||||||
result = new BlendTreeNode;
|
result = new BlendTreeNode;
|
||||||
} else if (name == "MathAddNode") {
|
} else if (name == "MathAddNode") {
|
||||||
@@ -324,6 +354,8 @@ static inline NodeDescriptorBase* AnimNodeDescriptorFactory(
|
|||||||
return CreateNodeDescriptor<SpeedScaleNode>(node);
|
return CreateNodeDescriptor<SpeedScaleNode>(node);
|
||||||
} else if (node_type_name == "AnimSampler") {
|
} else if (node_type_name == "AnimSampler") {
|
||||||
return CreateNodeDescriptor<AnimSamplerNode>(node);
|
return CreateNodeDescriptor<AnimSamplerNode>(node);
|
||||||
|
} else if (node_type_name == "LockTranslationNode") {
|
||||||
|
return CreateNodeDescriptor<LockTranslationNode>(node);
|
||||||
} else if (node_type_name == "BlendTree") {
|
} else if (node_type_name == "BlendTree") {
|
||||||
return CreateNodeDescriptor<BlendTreeNode>(node);
|
return CreateNodeDescriptor<BlendTreeNode>(node);
|
||||||
} else if (node_type_name == "MathAddNode") {
|
} else if (node_type_name == "MathAddNode") {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "AnimGraphResource.h"
|
#include "AnimGraphResource.h"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
#include "3rdparty/json/json.hpp"
|
#include "3rdparty/json/json.hpp"
|
||||||
@@ -27,10 +28,15 @@ json sSocketToJson(const Socket& socket) {
|
|||||||
result["name"] = socket.m_name;
|
result["name"] = socket.m_name;
|
||||||
result["type"] = sSocketTypeToStr(socket.m_type);
|
result["type"] = sSocketTypeToStr(socket.m_type);
|
||||||
|
|
||||||
if (socket.m_reference.ptr != nullptr) {
|
if (socket.m_type == SocketType::SocketTypeString
|
||||||
|
&& socket.m_value_string.size() > 0) {
|
||||||
|
result["value"] = socket.m_value_string;
|
||||||
|
} else if (socket.m_value.flag) {
|
||||||
if (socket.m_type == SocketType::SocketTypeBool) {
|
if (socket.m_type == SocketType::SocketTypeBool) {
|
||||||
result["value"] = socket.m_value.flag;
|
result["value"] = socket.m_value.flag;
|
||||||
} else if (socket.m_type == SocketType::SocketTypeAnimation) {
|
} else if (socket.m_type == SocketType::SocketTypeAnimation) {
|
||||||
|
} else if (socket.m_type == SocketType::SocketTypeInt) {
|
||||||
|
result["value"] = socket.m_value.int_value;
|
||||||
} else if (socket.m_type == SocketType::SocketTypeFloat) {
|
} else if (socket.m_type == SocketType::SocketTypeFloat) {
|
||||||
result["value"] = socket.m_value.float_value;
|
result["value"] = socket.m_value.float_value;
|
||||||
} else if (socket.m_type == SocketType::SocketTypeVec3) {
|
} else if (socket.m_type == SocketType::SocketTypeVec3) {
|
||||||
@@ -42,8 +48,6 @@ json sSocketToJson(const Socket& socket) {
|
|||||||
result["value"][1] = socket.m_value.quat.v[1];
|
result["value"][1] = socket.m_value.quat.v[1];
|
||||||
result["value"][2] = socket.m_value.quat.v[2];
|
result["value"][2] = socket.m_value.quat.v[2];
|
||||||
result["value"][3] = socket.m_value.quat.v[3];
|
result["value"][3] = socket.m_value.quat.v[3];
|
||||||
} else if (socket.m_type == SocketType::SocketTypeString) {
|
|
||||||
result["value"] = socket.m_value_string;
|
|
||||||
} else {
|
} else {
|
||||||
std::cerr << "Invalid socket type '" << static_cast<int>(socket.m_type)
|
std::cerr << "Invalid socket type '" << static_cast<int>(socket.m_type)
|
||||||
<< "'." << std::endl;
|
<< "'." << std::endl;
|
||||||
@@ -59,25 +63,52 @@ Socket sJsonToSocket(const json& json_data) {
|
|||||||
result.m_name = json_data["name"];
|
result.m_name = json_data["name"];
|
||||||
|
|
||||||
std::string type_string = json_data["type"];
|
std::string type_string = json_data["type"];
|
||||||
|
bool have_value = json_data.contains("value");
|
||||||
|
|
||||||
if (type_string == "Bool") {
|
if (type_string == "Bool") {
|
||||||
result.m_type = SocketType::SocketTypeBool;
|
result.m_type = SocketType::SocketTypeBool;
|
||||||
result.m_type_size = sizeof(bool);
|
result.m_type_size = sizeof(bool);
|
||||||
|
if (have_value) {
|
||||||
|
result.m_value.flag = json_data["value"];
|
||||||
|
}
|
||||||
} else if (type_string == "Animation") {
|
} else if (type_string == "Animation") {
|
||||||
result.m_type = SocketType::SocketTypeAnimation;
|
result.m_type = SocketType::SocketTypeAnimation;
|
||||||
result.m_type_size = sizeof(AnimData);
|
result.m_type_size = sizeof(AnimData);
|
||||||
|
} else if (type_string == "Int") {
|
||||||
|
result.m_type = SocketType::SocketTypeInt;
|
||||||
|
result.m_type_size = sizeof(int);
|
||||||
|
if (have_value) {
|
||||||
|
result.m_value.int_value = json_data["value"];
|
||||||
|
}
|
||||||
} else if (type_string == "Float") {
|
} else if (type_string == "Float") {
|
||||||
result.m_type = SocketType::SocketTypeFloat;
|
result.m_type = SocketType::SocketTypeFloat;
|
||||||
result.m_type_size = sizeof(float);
|
result.m_type_size = sizeof(float);
|
||||||
|
if (have_value) {
|
||||||
|
result.m_value.float_value = json_data["value"];
|
||||||
|
}
|
||||||
} else if (type_string == "Vec3") {
|
} else if (type_string == "Vec3") {
|
||||||
result.m_type = SocketType::SocketTypeVec3;
|
result.m_type = SocketType::SocketTypeVec3;
|
||||||
result.m_type_size = sizeof(Vec3);
|
result.m_type_size = sizeof(Vec3);
|
||||||
|
if (have_value) {
|
||||||
|
result.m_value.vec3.x = json_data["value"][0];
|
||||||
|
result.m_value.vec3.y = json_data["value"][1];
|
||||||
|
result.m_value.vec3.z = json_data["value"][2];
|
||||||
|
}
|
||||||
} else if (type_string == "Quat") {
|
} else if (type_string == "Quat") {
|
||||||
result.m_type = SocketType::SocketTypeQuat;
|
result.m_type = SocketType::SocketTypeQuat;
|
||||||
result.m_type_size = sizeof(Quat);
|
result.m_type_size = sizeof(Quat);
|
||||||
|
if (have_value) {
|
||||||
|
result.m_value.quat.x = json_data["value"][0];
|
||||||
|
result.m_value.quat.y = json_data["value"][1];
|
||||||
|
result.m_value.quat.z = json_data["value"][2];
|
||||||
|
result.m_value.quat.w = json_data["value"][3];
|
||||||
|
}
|
||||||
} else if (type_string == "String") {
|
} else if (type_string == "String") {
|
||||||
result.m_type = SocketType::SocketTypeString;
|
result.m_type = SocketType::SocketTypeString;
|
||||||
result.m_type_size = sizeof(std::string);
|
result.m_type_size = sizeof(std::string);
|
||||||
|
if (have_value) {
|
||||||
|
result.m_value_string = json_data["value"];
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
std::cerr << "Invalid socket type '" << type_string << "'." << std::endl;
|
std::cerr << "Invalid socket type '" << type_string << "'." << std::endl;
|
||||||
}
|
}
|
||||||
@@ -88,7 +119,10 @@ Socket sJsonToSocket(const json& json_data) {
|
|||||||
//
|
//
|
||||||
// AnimGraphNode <-> json
|
// AnimGraphNode <-> json
|
||||||
//
|
//
|
||||||
json sAnimGraphNodeToJson(const AnimNodeResource& node) {
|
json sAnimGraphNodeToJson(
|
||||||
|
const AnimNodeResource& node,
|
||||||
|
int node_index,
|
||||||
|
const std::vector<AnimGraphConnectionResource>& connections) {
|
||||||
json result;
|
json result;
|
||||||
|
|
||||||
result["name"] = node.m_name;
|
result["name"] = node.m_name;
|
||||||
@@ -99,6 +133,27 @@ json sAnimGraphNodeToJson(const AnimNodeResource& node) {
|
|||||||
result["position"][j] = node.m_position[j];
|
result["position"][j] = node.m_position[j];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (size_t j = 0, n = node.m_socket_accessor->m_inputs.size(); j < n; j++) {
|
||||||
|
const Socket& socket = node.m_socket_accessor->m_inputs[j];
|
||||||
|
|
||||||
|
if (socket.m_type == SocketType::SocketTypeAnimation) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool socket_connected = false;
|
||||||
|
for (size_t k = 0, m = connections.size(); k < m; k++) {
|
||||||
|
if (connections[k].source_node_index == node_index
|
||||||
|
&& connections[k].source_socket_name == socket.m_name) {
|
||||||
|
socket_connected = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!socket_connected) {
|
||||||
|
result["inputs"].push_back(sSocketToJson(socket));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t j = 0, n = node.m_socket_accessor->m_properties.size(); j < n;
|
for (size_t j = 0, n = node.m_socket_accessor->m_properties.size(); j < n;
|
||||||
j++) {
|
j++) {
|
||||||
Socket& property = node.m_socket_accessor->m_properties[j];
|
Socket& property = node.m_socket_accessor->m_properties[j];
|
||||||
@@ -108,7 +163,7 @@ json sAnimGraphNodeToJson(const AnimNodeResource& node) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
AnimNodeResource sAnimGraphNodeFromJson(const json& json_node) {
|
AnimNodeResource sAnimGraphNodeFromJson(const json& json_node, int node_index) {
|
||||||
AnimNodeResource result;
|
AnimNodeResource result;
|
||||||
|
|
||||||
result.m_name = json_node["name"];
|
result.m_name = json_node["name"];
|
||||||
@@ -123,36 +178,21 @@ AnimNodeResource sAnimGraphNodeFromJson(const json& json_node) {
|
|||||||
for (size_t j = 0, n = result.m_socket_accessor->m_properties.size(); j < n;
|
for (size_t j = 0, n = result.m_socket_accessor->m_properties.size(); j < n;
|
||||||
j++) {
|
j++) {
|
||||||
Socket& property = result.m_socket_accessor->m_properties[j];
|
Socket& property = result.m_socket_accessor->m_properties[j];
|
||||||
json json_property = json_node["properties"][property.m_name];
|
property = sJsonToSocket(json_node["properties"][property.m_name]);
|
||||||
|
|
||||||
if (sSocketTypeToStr(property.m_type) == json_property["type"]) {
|
|
||||||
if (property.m_type == SocketType::SocketTypeBool) {
|
|
||||||
property.m_value.flag = json_property["value"];
|
|
||||||
} else if (property.m_type == SocketType::SocketTypeAnimation) {
|
|
||||||
} else if (property.m_type == SocketType::SocketTypeFloat) {
|
|
||||||
property.m_value.float_value = json_property["value"];
|
|
||||||
} else if (property.m_type == SocketType::SocketTypeVec3) {
|
|
||||||
property.m_value.vec3.v[0] = json_property["value"][0];
|
|
||||||
property.m_value.vec3.v[1] = json_property["value"][1];
|
|
||||||
property.m_value.vec3.v[2] = json_property["value"][2];
|
|
||||||
} else if (property.m_type == SocketType::SocketTypeQuat) {
|
|
||||||
Quat* property_quat = reinterpret_cast<Quat*>(property.m_reference.ptr);
|
|
||||||
property.m_value.quat.v[0] = json_property["value"][0];
|
|
||||||
property.m_value.quat.v[1] = json_property["value"][1];
|
|
||||||
property.m_value.quat.v[2] = json_property["value"][2];
|
|
||||||
property.m_value.quat.v[3] = json_property["value"][3];
|
|
||||||
} else if (property.m_type == SocketType::SocketTypeString) {
|
|
||||||
property.m_value_string = json_property["value"].get<std::string>();
|
|
||||||
} else {
|
|
||||||
std::cerr << "Invalid type for property '" << property.m_name
|
|
||||||
<< "'. Cannot parse json to type '"
|
|
||||||
<< static_cast<int>(property.m_type) << std::endl;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
std::cerr << "Invalid type for property '" << property.m_name
|
if (node_index != 0 && node_index != 1 && json_node.contains("inputs")) {
|
||||||
<< "': expected " << sSocketTypeToStr(property.m_type)
|
for (size_t j = 0, n = json_node["inputs"].size(); j < n; j++) {
|
||||||
<< " but got " << json_property["type"] << std::endl;
|
assert(json_node["inputs"][j].contains("name"));
|
||||||
|
std::string input_name = json_node["inputs"][j]["name"];
|
||||||
|
Socket* input_socket =
|
||||||
|
result.m_socket_accessor->GetInputSocket(input_name.c_str());
|
||||||
|
if (input_socket == nullptr) {
|
||||||
|
std::cerr << "Could not find input socket with name " << input_name
|
||||||
|
<< " for node type " << result.m_type_name << std::endl;
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
*input_socket = sJsonToSocket(json_node["inputs"][j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,7 +266,7 @@ bool AnimGraphResource::saveToFile(const char* filename) const {
|
|||||||
|
|
||||||
for (size_t i = 0; i < m_nodes.size(); i++) {
|
for (size_t i = 0; i < m_nodes.size(); i++) {
|
||||||
const AnimNodeResource& node = m_nodes[i];
|
const AnimNodeResource& node = m_nodes[i];
|
||||||
result["nodes"][i] = sAnimGraphNodeToJson(node);
|
result["nodes"][i] = sAnimGraphNodeToJson(node, i, m_connections);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < m_connections.size(); i++) {
|
for (size_t i = 0; i < m_connections.size(); i++) {
|
||||||
@@ -283,7 +323,7 @@ bool AnimGraphResource::loadFromFile(const char* filename) {
|
|||||||
m_name = json_data["name"];
|
m_name = json_data["name"];
|
||||||
|
|
||||||
// Load nodes
|
// Load nodes
|
||||||
for (size_t i = 0; i < json_data["nodes"].size(); i++) {
|
for (size_t i = 0, n = json_data["nodes"].size(); i < n; i++) {
|
||||||
const json& json_node = json_data["nodes"][i];
|
const json& json_node = json_data["nodes"][i];
|
||||||
if (json_node["type"] != "AnimNodeResource") {
|
if (json_node["type"] != "AnimNodeResource") {
|
||||||
std::cerr
|
std::cerr
|
||||||
@@ -292,20 +332,20 @@ bool AnimGraphResource::loadFromFile(const char* filename) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
AnimNodeResource node = sAnimGraphNodeFromJson(json_node);
|
AnimNodeResource node = sAnimGraphNodeFromJson(json_node, i);
|
||||||
m_nodes.push_back(node);
|
m_nodes.push_back(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup graph inputs and outputs
|
// Setup graph inputs and outputs
|
||||||
const json& graph_outputs = json_data["nodes"][0]["inputs"];
|
const json& graph_outputs = json_data["nodes"][0]["inputs"];
|
||||||
for (size_t i = 0; i < graph_outputs.size(); i++) {
|
for (size_t i = 0, n = graph_outputs.size(); i < n; i++) {
|
||||||
AnimNodeResource& graph_node = m_nodes[0];
|
AnimNodeResource& graph_node = m_nodes[0];
|
||||||
graph_node.m_socket_accessor->m_inputs.push_back(
|
graph_node.m_socket_accessor->m_inputs.push_back(
|
||||||
sJsonToSocket(graph_outputs[i]));
|
sJsonToSocket(graph_outputs[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
const json& graph_inputs = json_data["nodes"][1]["outputs"];
|
const json& graph_inputs = json_data["nodes"][1]["outputs"];
|
||||||
for (size_t i = 0; i < graph_inputs.size(); i++) {
|
for (size_t i = 0, n = graph_inputs.size(); i < n; i++) {
|
||||||
AnimNodeResource& graph_node = m_nodes[1];
|
AnimNodeResource& graph_node = m_nodes[1];
|
||||||
graph_node.m_socket_accessor->m_outputs.push_back(
|
graph_node.m_socket_accessor->m_outputs.push_back(
|
||||||
sJsonToSocket(graph_inputs[i]));
|
sJsonToSocket(graph_inputs[i]));
|
||||||
@@ -363,7 +403,9 @@ void AnimGraphResource::prepareGraphIOData(AnimGraph& instance) const {
|
|||||||
m_nodes[1].m_socket_accessor->m_outputs;
|
m_nodes[1].m_socket_accessor->m_outputs;
|
||||||
instance.m_node_descriptor->m_inputs = m_nodes[0].m_socket_accessor->m_inputs;
|
instance.m_node_descriptor->m_inputs = m_nodes[0].m_socket_accessor->m_inputs;
|
||||||
|
|
||||||
// inputs
|
//
|
||||||
|
// graph inputs
|
||||||
|
//
|
||||||
int input_block_size = 0;
|
int input_block_size = 0;
|
||||||
std::vector<Socket>& graph_inputs = instance.getGraphInputs();
|
std::vector<Socket>& graph_inputs = instance.getGraphInputs();
|
||||||
for (int i = 0; i < graph_inputs.size(); i++) {
|
for (int i = 0; i < graph_inputs.size(); i++) {
|
||||||
@@ -384,7 +426,9 @@ void AnimGraphResource::prepareGraphIOData(AnimGraph& instance) const {
|
|||||||
input_block_offset += sizeof(void*);
|
input_block_offset += sizeof(void*);
|
||||||
}
|
}
|
||||||
|
|
||||||
// outputs
|
//
|
||||||
|
// graph outputs
|
||||||
|
//
|
||||||
int output_block_size = 0;
|
int output_block_size = 0;
|
||||||
std::vector<Socket>& graph_outputs = instance.getGraphOutputs();
|
std::vector<Socket>& graph_outputs = instance.getGraphOutputs();
|
||||||
for (int i = 0; i < graph_outputs.size(); i++) {
|
for (int i = 0; i < graph_outputs.size(); i++) {
|
||||||
@@ -476,6 +520,41 @@ void AnimGraphResource::prepareGraphIOData(AnimGraph& instance) const {
|
|||||||
connection_data_offset += source_socket->m_type_size;
|
connection_data_offset += source_socket->m_type_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// const node inputs
|
||||||
|
//
|
||||||
|
std::vector<Socket*> const_inputs =
|
||||||
|
getConstNodeInputs(instance, instance_node_descriptors);
|
||||||
|
int const_node_inputs_buffer_size = 0;
|
||||||
|
for (int i = 0, n = const_inputs.size(); i < n; i++) {
|
||||||
|
if (const_inputs[i]->m_type == SocketType::SocketTypeString) {
|
||||||
|
// TODO: implement string const node input support
|
||||||
|
std::cerr << "Error: const inputs for strings not yet implemented!"
|
||||||
|
<< std::endl;
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
const_node_inputs_buffer_size += const_inputs[i]->m_type_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const_node_inputs_buffer_size > 0) {
|
||||||
|
instance.m_const_node_inputs = new char[const_node_inputs_buffer_size];
|
||||||
|
memset(instance.m_const_node_inputs, '\0', const_node_inputs_buffer_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int const_input_buffer_offset = 0;
|
||||||
|
for (int i = 0, n = const_inputs.size(); i < n; i++) {
|
||||||
|
Socket* const_input = const_inputs[i];
|
||||||
|
|
||||||
|
// TODO: implement string const node input support
|
||||||
|
assert(const_input->m_type != SocketType::SocketTypeString);
|
||||||
|
|
||||||
|
*const_input->m_reference.ptr_ptr =
|
||||||
|
&instance.m_const_node_inputs[const_input_buffer_offset];
|
||||||
|
memcpy (*const_input->m_reference.ptr_ptr, &const_input->m_value, const_inputs[i]->m_type_size);
|
||||||
|
|
||||||
|
const_input_buffer_offset += const_inputs[i]->m_type_size;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < m_nodes.size(); i++) {
|
for (int i = 0; i < m_nodes.size(); i++) {
|
||||||
delete instance_node_descriptors[i];
|
delete instance_node_descriptors[i];
|
||||||
}
|
}
|
||||||
@@ -501,6 +580,11 @@ void AnimGraphResource::setRuntimeNodeProperties(AnimGraph& instance) const {
|
|||||||
name.c_str(),
|
name.c_str(),
|
||||||
property.m_value.flag);
|
property.m_value.flag);
|
||||||
break;
|
break;
|
||||||
|
case SocketType::SocketTypeInt:
|
||||||
|
node_instance_accessor->SetProperty(
|
||||||
|
name.c_str(),
|
||||||
|
property.m_value.int_value);
|
||||||
|
break;
|
||||||
case SocketType::SocketTypeFloat:
|
case SocketType::SocketTypeFloat:
|
||||||
node_instance_accessor->SetProperty(
|
node_instance_accessor->SetProperty(
|
||||||
name.c_str(),
|
name.c_str(),
|
||||||
@@ -530,3 +614,24 @@ void AnimGraphResource::setRuntimeNodeProperties(AnimGraph& instance) const {
|
|||||||
delete node_instance_accessor;
|
delete node_instance_accessor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<Socket*> AnimGraphResource::getConstNodeInputs(
|
||||||
|
AnimGraph& instance,
|
||||||
|
std::vector<NodeDescriptorBase*>& instance_node_descriptors) const {
|
||||||
|
std::vector<Socket*> result;
|
||||||
|
|
||||||
|
for (int i = 0; i < m_nodes.size(); i++) {
|
||||||
|
for (int j = 0, num_inputs = instance_node_descriptors[i]->m_inputs.size();
|
||||||
|
j < num_inputs;
|
||||||
|
j++) {
|
||||||
|
Socket& input = instance_node_descriptors[i]->m_inputs[j];
|
||||||
|
|
||||||
|
if (*input.m_reference.ptr_ptr == nullptr) {
|
||||||
|
memcpy(&input.m_value, &m_nodes[i].m_socket_accessor->m_inputs[j].m_value, sizeof(Socket::SocketValue));
|
||||||
|
result.push_back(&input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|||||||
@@ -146,6 +146,7 @@ struct AnimGraphResource {
|
|||||||
void prepareGraphIOData(AnimGraph& instance) const;
|
void prepareGraphIOData(AnimGraph& instance) const;
|
||||||
void connectRuntimeNodes(AnimGraph& instance) const;
|
void connectRuntimeNodes(AnimGraph& instance) const;
|
||||||
void setRuntimeNodeProperties(AnimGraph& instance) const;
|
void setRuntimeNodeProperties(AnimGraph& instance) const;
|
||||||
|
std::vector<Socket*> getConstNodeInputs(AnimGraph& instance, std::vector<NodeDescriptorBase*>& instance_node_descriptors) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //ANIMTESTBED_ANIMGRAPHRESOURCE_H
|
#endif //ANIMTESTBED_ANIMGRAPHRESOURCE_H
|
||||||
|
|||||||
+8
-3
@@ -76,6 +76,7 @@ static struct {
|
|||||||
} loaded;
|
} loaded;
|
||||||
struct {
|
struct {
|
||||||
double frame;
|
double frame;
|
||||||
|
double anim_update_time;
|
||||||
float absolute;
|
float absolute;
|
||||||
uint64_t laptime;
|
uint64_t laptime;
|
||||||
float factor;
|
float factor;
|
||||||
@@ -511,7 +512,10 @@ int main() {
|
|||||||
stm_round_to_common_refresh_rate(stm_laptime(&state.time.laptime)));
|
stm_round_to_common_refresh_rate(stm_laptime(&state.time.laptime)));
|
||||||
|
|
||||||
if (!state.time.paused) {
|
if (!state.time.paused) {
|
||||||
|
state.time.anim_update_time = state.time.frame;
|
||||||
state.time.absolute += state.time.frame * state.time.factor;
|
state.time.absolute += state.time.frame * state.time.factor;
|
||||||
|
} else {
|
||||||
|
state.time.anim_update_time = 0.;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.ozz.animation != nullptr) {
|
if (state.ozz.animation != nullptr) {
|
||||||
@@ -725,7 +729,8 @@ int main() {
|
|||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (ImGui::Button("Step")) {
|
if (ImGui::Button("Step")) {
|
||||||
state.time.absolute += state.time.frame;
|
state.time.anim_update_time = 1. / 30.f;
|
||||||
|
state.time.absolute += state.time.anim_update_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.ozz.animation != nullptr) {
|
if (state.ozz.animation != nullptr) {
|
||||||
@@ -758,9 +763,9 @@ int main() {
|
|||||||
skinned_mesh.CalcModelMatrices();
|
skinned_mesh.CalcModelMatrices();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state.time.use_graph && anim_graph.m_nodes.size() > 0) {
|
if (state.time.use_graph && anim_graph.m_nodes.size() > 0 && state.time.anim_update_time > 0.) {
|
||||||
anim_graph.markActiveNodes();
|
anim_graph.markActiveNodes();
|
||||||
anim_graph.updateTime(state.time.frame);
|
anim_graph.updateTime(state.time.anim_update_time);
|
||||||
anim_graph.evaluate(anim_graph_context);
|
anim_graph.evaluate(anim_graph_context);
|
||||||
skinned_mesh.m_local_matrices = anim_graph_output.m_local_matrices;
|
skinned_mesh.m_local_matrices = anim_graph_output.m_local_matrices;
|
||||||
|
|
||||||
|
|||||||
@@ -2,14 +2,13 @@
|
|||||||
// Created by martin on 04.02.22.
|
// Created by martin on 04.02.22.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "ozz/base/io/archive.h"
|
|
||||||
#include "ozz/base/io/stream.h"
|
|
||||||
#include "ozz/base/log.h"
|
|
||||||
|
|
||||||
#include "AnimGraph/AnimGraph.h"
|
#include "AnimGraph/AnimGraph.h"
|
||||||
#include "AnimGraph/AnimGraphEditor.h"
|
#include "AnimGraph/AnimGraphEditor.h"
|
||||||
#include "AnimGraph/AnimGraphResource.h"
|
#include "AnimGraph/AnimGraphResource.h"
|
||||||
#include "catch.hpp"
|
#include "catch.hpp"
|
||||||
|
#include "ozz/base/io/archive.h"
|
||||||
|
#include "ozz/base/io/stream.h"
|
||||||
|
#include "ozz/base/log.h"
|
||||||
|
|
||||||
bool load_skeleton(ozz::animation::Skeleton& skeleton, const char* filename) {
|
bool load_skeleton(ozz::animation::Skeleton& skeleton, const char* filename) {
|
||||||
assert(filename);
|
assert(filename);
|
||||||
@@ -32,12 +31,11 @@ bool load_skeleton (ozz::animation::Skeleton& skeleton, const char* filename) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("AnimSamplerGraph", "[AnimGraphResource]") {
|
||||||
TEST_CASE("BasicGraph", "[AnimGraphResource]") {
|
|
||||||
AnimGraphResource graph_resource;
|
AnimGraphResource graph_resource;
|
||||||
|
|
||||||
graph_resource.clear();
|
graph_resource.clear();
|
||||||
graph_resource.m_name = "WalkRunBlendGraph";
|
graph_resource.m_name = "AnimSamplerGraph";
|
||||||
|
|
||||||
// Prepare graph inputs and outputs
|
// Prepare graph inputs and outputs
|
||||||
size_t walk_node_index =
|
size_t walk_node_index =
|
||||||
@@ -45,7 +43,9 @@ TEST_CASE("BasicGraph", "[AnimGraphResource]") {
|
|||||||
|
|
||||||
AnimNodeResource& walk_node = graph_resource.m_nodes[walk_node_index];
|
AnimNodeResource& walk_node = graph_resource.m_nodes[walk_node_index];
|
||||||
walk_node.m_name = "WalkAnim";
|
walk_node.m_name = "WalkAnim";
|
||||||
walk_node.m_socket_accessor->SetPropertyValue("Filename", std::string("data/walk.anim.ozz"));
|
walk_node.m_socket_accessor->SetPropertyValue(
|
||||||
|
"Filename",
|
||||||
|
std::string("data/walk.anim.ozz"));
|
||||||
|
|
||||||
AnimNodeResource& graph_node = graph_resource.m_nodes[0];
|
AnimNodeResource& graph_node = graph_resource.m_nodes[0];
|
||||||
graph_node.m_socket_accessor->RegisterInput<AnimData>("GraphOutput", nullptr);
|
graph_node.m_socket_accessor->RegisterInput<AnimData>("GraphOutput", nullptr);
|
||||||
@@ -56,9 +56,9 @@ TEST_CASE("BasicGraph", "[AnimGraphResource]") {
|
|||||||
graph_resource.getGraphOutputNode(),
|
graph_resource.getGraphOutputNode(),
|
||||||
"GraphOutput");
|
"GraphOutput");
|
||||||
|
|
||||||
graph_resource.saveToFile("WalkGraph.animgraph.json");
|
graph_resource.saveToFile("AnimSamplerGraph.animgraph.json");
|
||||||
AnimGraphResource graph_resource_loaded;
|
AnimGraphResource graph_resource_loaded;
|
||||||
graph_resource_loaded.loadFromFile("WalkGraph.animgraph.json");
|
graph_resource_loaded.loadFromFile("AnimSamplerGraph.animgraph.json");
|
||||||
|
|
||||||
AnimGraph graph;
|
AnimGraph graph;
|
||||||
graph_resource_loaded.createInstance(graph);
|
graph_resource_loaded.createInstance(graph);
|
||||||
@@ -108,6 +108,67 @@ TEST_CASE("BasicGraph", "[AnimGraphResource]") {
|
|||||||
graph_context.freeAnimations();
|
graph_context.freeAnimations();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Checks that node const inputs are properly set.
|
||||||
|
*/
|
||||||
|
TEST_CASE("AnimSamplerSpeedScaleGraph", "[AnimGraphResource]") {
|
||||||
|
AnimGraphResource graph_resource;
|
||||||
|
|
||||||
|
graph_resource.clear();
|
||||||
|
graph_resource.m_name = "AnimSamplerSpeedScaleGraph";
|
||||||
|
|
||||||
|
// Prepare graph inputs and outputs
|
||||||
|
size_t walk_node_index =
|
||||||
|
graph_resource.addNode(AnimNodeResourceFactory("AnimSampler"));
|
||||||
|
|
||||||
|
size_t speed_scale_node_index =
|
||||||
|
graph_resource.addNode(AnimNodeResourceFactory("SpeedScale"));
|
||||||
|
|
||||||
|
AnimNodeResource& walk_node = graph_resource.m_nodes[walk_node_index];
|
||||||
|
walk_node.m_name = "WalkAnim";
|
||||||
|
walk_node.m_socket_accessor->SetPropertyValue(
|
||||||
|
"Filename",
|
||||||
|
std::string("data/walk.anim.ozz"));
|
||||||
|
|
||||||
|
AnimNodeResource& speed_scale_node =
|
||||||
|
graph_resource.m_nodes[speed_scale_node_index];
|
||||||
|
speed_scale_node.m_name = "SpeedScale";
|
||||||
|
float speed_scale_value = 1.35f;
|
||||||
|
speed_scale_node.m_socket_accessor->SetInputValue(
|
||||||
|
"SpeedScale",
|
||||||
|
speed_scale_value);
|
||||||
|
|
||||||
|
AnimNodeResource& graph_node = graph_resource.m_nodes[0];
|
||||||
|
graph_node.m_socket_accessor->RegisterInput<AnimData>("GraphOutput", nullptr);
|
||||||
|
|
||||||
|
graph_resource.connectSockets(walk_node, "Output", speed_scale_node, "Input");
|
||||||
|
|
||||||
|
graph_resource.connectSockets(
|
||||||
|
speed_scale_node,
|
||||||
|
"Output",
|
||||||
|
graph_resource.getGraphOutputNode(),
|
||||||
|
"GraphOutput");
|
||||||
|
|
||||||
|
graph_resource.saveToFile("AnimSamplerSpeedScaleGraph.animgraph.json");
|
||||||
|
AnimGraphResource graph_resource_loaded;
|
||||||
|
graph_resource_loaded.loadFromFile(
|
||||||
|
"AnimSamplerSpeedScaleGraph.animgraph.json");
|
||||||
|
|
||||||
|
Socket* speed_scale_resource_loaded_input =
|
||||||
|
graph_resource_loaded.m_nodes[speed_scale_node_index]
|
||||||
|
.m_socket_accessor->GetInputSocket("SpeedScale");
|
||||||
|
REQUIRE(speed_scale_resource_loaded_input != nullptr);
|
||||||
|
|
||||||
|
REQUIRE_THAT(
|
||||||
|
speed_scale_resource_loaded_input->m_value.float_value,
|
||||||
|
Catch::Matchers::WithinAbs(speed_scale_value, 0.1));
|
||||||
|
|
||||||
|
AnimGraph graph;
|
||||||
|
graph_resource_loaded.createInstance(graph);
|
||||||
|
|
||||||
|
REQUIRE_THAT(*dynamic_cast<SpeedScaleNode*>(graph.m_nodes[speed_scale_node_index])->i_speed_scale,
|
||||||
|
Catch::Matchers::WithinAbs(speed_scale_value, 0.1));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST_CASE("Blend2Graph", "[AnimGraphResource]") {
|
TEST_CASE("Blend2Graph", "[AnimGraphResource]") {
|
||||||
@@ -126,9 +187,13 @@ TEST_CASE("Blend2Graph", "[AnimGraphResource]") {
|
|||||||
|
|
||||||
AnimNodeResource& walk_node = graph_resource.m_nodes[walk_node_index];
|
AnimNodeResource& walk_node = graph_resource.m_nodes[walk_node_index];
|
||||||
walk_node.m_name = "WalkAnim";
|
walk_node.m_name = "WalkAnim";
|
||||||
walk_node.m_socket_accessor->SetPropertyValue("Filename", std::string("data/walk.anim.ozz"));
|
walk_node.m_socket_accessor->SetPropertyValue(
|
||||||
|
"Filename",
|
||||||
|
std::string("data/walk.anim.ozz"));
|
||||||
AnimNodeResource& run_node = graph_resource.m_nodes[run_node_index];
|
AnimNodeResource& run_node = graph_resource.m_nodes[run_node_index];
|
||||||
run_node.m_socket_accessor->SetPropertyValue("Filename", std::string("data/run.anim.ozz"));
|
run_node.m_socket_accessor->SetPropertyValue(
|
||||||
|
"Filename",
|
||||||
|
std::string("data/run.anim.ozz"));
|
||||||
run_node.m_name = "RunAnim";
|
run_node.m_name = "RunAnim";
|
||||||
AnimNodeResource& blend_node = graph_resource.m_nodes[blend_node_index];
|
AnimNodeResource& blend_node = graph_resource.m_nodes[blend_node_index];
|
||||||
blend_node.m_name = "BlendWalkRun";
|
blend_node.m_name = "BlendWalkRun";
|
||||||
@@ -215,15 +280,17 @@ TEST_CASE("Blend2Graph", "[AnimGraphResource]") {
|
|||||||
AnimData* graph_output =
|
AnimData* graph_output =
|
||||||
static_cast<AnimData*>(*graph_output_socket->m_reference.ptr_ptr);
|
static_cast<AnimData*>(*graph_output_socket->m_reference.ptr_ptr);
|
||||||
|
|
||||||
CHECK(graph_output->m_local_matrices.size() == graph_context.m_skeleton->num_soa_joints());
|
CHECK(
|
||||||
|
graph_output->m_local_matrices.size()
|
||||||
|
== graph_context.m_skeleton->num_soa_joints());
|
||||||
|
|
||||||
CHECK(blend2_instance->o_output == *graph_output_socket->m_reference.ptr_ptr);
|
CHECK(
|
||||||
|
blend2_instance->o_output == *graph_output_socket->m_reference.ptr_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
graph_context.freeAnimations();
|
graph_context.freeAnimations();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST_CASE("InputAttributeConversion", "[AnimGraphResource]") {
|
TEST_CASE("InputAttributeConversion", "[AnimGraphResource]") {
|
||||||
int node_id = 3321;
|
int node_id = 3321;
|
||||||
int input_index = 221;
|
int input_index = 221;
|
||||||
@@ -243,7 +310,6 @@ TEST_CASE("InputAttributeConversion", "[AnimGraphResource]") {
|
|||||||
CHECK(output_index == parsed_output_index);
|
CHECK(output_index == parsed_output_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST_CASE("ResourceSaveLoadMathGraphInputs", "[AnimGraphResource]") {
|
TEST_CASE("ResourceSaveLoadMathGraphInputs", "[AnimGraphResource]") {
|
||||||
AnimGraphResource graph_resource_origin;
|
AnimGraphResource graph_resource_origin;
|
||||||
|
|
||||||
@@ -504,7 +570,9 @@ TEST_CASE("SimpleMathEvaluations", "[AnimGraphResource]") {
|
|||||||
THEN("output vector components equal the graph input vaulues") {
|
THEN("output vector components equal the graph input vaulues") {
|
||||||
CHECK(*float0_output_ptr == Approx(graph_float_input));
|
CHECK(*float0_output_ptr == Approx(graph_float_input));
|
||||||
CHECK(float1_output == Approx(graph_float_input * 2.f));
|
CHECK(float1_output == Approx(graph_float_input * 2.f));
|
||||||
REQUIRE_THAT(float2_output, Catch::Matchers::WithinAbs(graph_float_input * 3.f, 10));
|
REQUIRE_THAT(
|
||||||
|
float2_output,
|
||||||
|
Catch::Matchers::WithinAbs(graph_float_input * 3.f, 10));
|
||||||
}
|
}
|
||||||
|
|
||||||
context.freeAnimations();
|
context.freeAnimations();
|
||||||
|
|||||||
Reference in New Issue
Block a user