Compare commits
No commits in common. "bd304bde4e2da15a4aebc3bedbee6ea0427df7e0" and "0d0b181ebb2446bea72704b7d43c308fb80b88f1" have entirely different histories.
bd304bde4e
...
0d0b181ebb
@ -7,8 +7,6 @@
|
|||||||
#include "AnimGraphResource.h"
|
#include "AnimGraphResource.h"
|
||||||
#include "imnodes.h"
|
#include "imnodes.h"
|
||||||
|
|
||||||
using namespace AnimGraphCode;
|
|
||||||
|
|
||||||
ImNodesPinShape sGetSocketShapeFromSocketType(const SocketType& socket_type) {
|
ImNodesPinShape sGetSocketShapeFromSocketType(const SocketType& socket_type) {
|
||||||
switch (socket_type) {
|
switch (socket_type) {
|
||||||
case SocketType::SocketTypeAnimation:
|
case SocketType::SocketTypeAnimation:
|
||||||
@ -28,52 +26,6 @@ ImNodesPinShape sGetSocketShapeFromSocketType(const SocketType& socket_type) {
|
|||||||
return ImNodesPinShape_Quad;
|
return ImNodesPinShape_Quad;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimGraphEditorRenderSidebar(AnimNodeResource& node_resource) {
|
|
||||||
ImGui::Text("[%s]", node_resource.m_type_name.c_str());
|
|
||||||
|
|
||||||
char node_name_buffer[256];
|
|
||||||
memset(node_name_buffer, 0, sizeof(node_name_buffer));
|
|
||||||
strncpy(
|
|
||||||
node_name_buffer,
|
|
||||||
node_resource.m_name.c_str(),
|
|
||||||
std::min(node_resource.m_name.size(), sizeof(node_name_buffer)));
|
|
||||||
|
|
||||||
if (ImGui::InputText("Name", node_name_buffer, sizeof(node_name_buffer))) {
|
|
||||||
node_resource.m_name = node_name_buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
int num_properties = node_resource.m_socket_accessor->m_properties.size();
|
|
||||||
for (int i = 0; i < num_properties; i++) {
|
|
||||||
Socket& property = node_resource.m_socket_accessor->m_properties[i];
|
|
||||||
if (property.m_type == SocketType::SocketTypeFloat) {
|
|
||||||
ImGui::SliderFloat(
|
|
||||||
property.m_name.c_str(),
|
|
||||||
reinterpret_cast<float*>(property.m_value.ptr),
|
|
||||||
-100.f,
|
|
||||||
100.f);
|
|
||||||
} else if (property.m_type == SocketType::SocketTypeBool) {
|
|
||||||
ImGui::Checkbox(
|
|
||||||
property.m_name.c_str(),
|
|
||||||
reinterpret_cast<bool*>(property.m_value.ptr));
|
|
||||||
} else if (property.m_type == SocketType::SocketTypeString) {
|
|
||||||
std::string* property_string =
|
|
||||||
reinterpret_cast<std::string*>(property.m_value.ptr);
|
|
||||||
char string_buf[256];
|
|
||||||
memset(string_buf, 0, sizeof(string_buf));
|
|
||||||
strncpy(
|
|
||||||
string_buf,
|
|
||||||
property_string->c_str(),
|
|
||||||
std::min(property_string->size(), sizeof(string_buf)));
|
|
||||||
if (ImGui::InputText(
|
|
||||||
property.m_name.c_str(),
|
|
||||||
string_buf,
|
|
||||||
sizeof(string_buf))) {
|
|
||||||
(*property_string) = string_buf;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AnimGraphEditorUpdate() {
|
void AnimGraphEditorUpdate() {
|
||||||
static AnimGraphResource graph_resource = AnimGraphResource();
|
static AnimGraphResource graph_resource = AnimGraphResource();
|
||||||
|
|
||||||
@ -106,11 +58,6 @@ void AnimGraphEditorUpdate() {
|
|||||||
|
|
||||||
ImGui::EndMenuBar();
|
ImGui::EndMenuBar();
|
||||||
|
|
||||||
ImGui::Columns(2);
|
|
||||||
|
|
||||||
//
|
|
||||||
// Node editor canvas
|
|
||||||
//
|
|
||||||
ImNodes::BeginNodeEditor();
|
ImNodes::BeginNodeEditor();
|
||||||
|
|
||||||
// Popup menu
|
// Popup menu
|
||||||
@ -175,20 +122,13 @@ void AnimGraphEditorUpdate() {
|
|||||||
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];
|
const Socket& socket = node_inputs[j];
|
||||||
|
|
||||||
ImColor socket_color = ImColor(255, 255, 255, 255);
|
|
||||||
if (socket.m_flags & SocketFlagAffectsTime) {
|
|
||||||
socket_color = ImColor(255, 128, 128, 255);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImNodes::BeginInputAttribute(
|
ImNodes::BeginInputAttribute(
|
||||||
GenerateInputAttributeId(i, j),
|
GenerateInputAttributeId(i, j),
|
||||||
sGetSocketShapeFromSocketType(socket.m_type),
|
sGetSocketShapeFromSocketType(socket.m_type),
|
||||||
socket_color);
|
ImColor(255, 255, 255, 255));
|
||||||
ImGui::Text(socket.m_name.c_str());
|
ImGui::Text(socket.m_name.c_str());
|
||||||
|
|
||||||
ImNodes::PushAttributeFlag(
|
ImNodes::PushAttributeFlag(ImNodesAttributeFlags_EnableLinkDetachWithDragClick);
|
||||||
ImNodesAttributeFlags_EnableLinkDetachWithDragClick);
|
|
||||||
ImNodes::EndInputAttribute();
|
ImNodes::EndInputAttribute();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,21 +142,19 @@ void AnimGraphEditorUpdate() {
|
|||||||
sGetSocketShapeFromSocketType(socket.m_type),
|
sGetSocketShapeFromSocketType(socket.m_type),
|
||||||
ImColor(255, 255, 255, 255));
|
ImColor(255, 255, 255, 255));
|
||||||
ImGui::Text(socket.m_name.c_str());
|
ImGui::Text(socket.m_name.c_str());
|
||||||
ImNodes::PushAttributeFlag(
|
ImNodes::PushAttributeFlag(ImNodesAttributeFlags_EnableLinkDetachWithDragClick);
|
||||||
ImNodesAttributeFlags_EnableLinkDetachWithDragClick);
|
|
||||||
ImNodes::EndInputAttribute();
|
ImNodes::EndInputAttribute();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Graph output node
|
// Graph output node
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
if (ImGui::Button("+Output")) {
|
if (ImGui::Button("+Output")) {
|
||||||
AnimNodeResource& graph_output_node =
|
AnimNodeResource& graph_output_node = graph_resource.getGraphOutputNode();
|
||||||
graph_resource.getGraphOutputNode();
|
|
||||||
|
|
||||||
static float bla = 0.f;
|
static float bla = 0.f;
|
||||||
std::string socket_name = "Output";
|
std::string socket_name = "Output";
|
||||||
socket_name += std::to_string(
|
socket_name +=
|
||||||
graph_output_node.m_socket_accessor->m_inputs.size());
|
std::to_string(graph_output_node.m_socket_accessor->m_inputs.size());
|
||||||
graph_output_node.m_socket_accessor->RegisterInput<float>(
|
graph_output_node.m_socket_accessor->RegisterInput<float>(
|
||||||
socket_name,
|
socket_name,
|
||||||
nullptr);
|
nullptr);
|
||||||
@ -227,8 +165,8 @@ void AnimGraphEditorUpdate() {
|
|||||||
|
|
||||||
static float bla = 0.f;
|
static float bla = 0.f;
|
||||||
std::string socket_name = "Input";
|
std::string socket_name = "Input";
|
||||||
socket_name += std::to_string(
|
socket_name +=
|
||||||
graph_input_node.m_socket_accessor->m_outputs.size());
|
std::to_string(graph_input_node.m_socket_accessor->m_outputs.size());
|
||||||
graph_input_node.m_socket_accessor->RegisterOutput<float>(
|
graph_input_node.m_socket_accessor->RegisterOutput<float>(
|
||||||
socket_name,
|
socket_name,
|
||||||
nullptr);
|
nullptr);
|
||||||
@ -240,9 +178,6 @@ void AnimGraphEditorUpdate() {
|
|||||||
node_resource.m_position[0] = node_pos[0];
|
node_resource.m_position[0] = node_pos[0];
|
||||||
node_resource.m_position[1] = node_pos[1];
|
node_resource.m_position[1] = node_pos[1];
|
||||||
ImNodes::EndNode();
|
ImNodes::EndNode();
|
||||||
|
|
||||||
// Ensure flags such as SocketFlagAffectsTime are properly set.
|
|
||||||
node_resource.m_socket_accessor->UpdateFlags();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0, n = graph_resource.m_connections.size(); i < n; i++) {
|
for (size_t i = 0, n = graph_resource.m_connections.size(); i < n; i++) {
|
||||||
@ -285,25 +220,6 @@ void AnimGraphEditorUpdate() {
|
|||||||
// Handle link detachements.
|
// Handle link detachements.
|
||||||
int link_id = 0;
|
int link_id = 0;
|
||||||
if (ImNodes::IsLinkDestroyed(&link_id)) {
|
if (ImNodes::IsLinkDestroyed(&link_id)) {
|
||||||
graph_resource.m_connections.erase(
|
graph_resource.m_connections.erase(graph_resource.m_connections.begin() + link_id);
|
||||||
graph_resource.m_connections.begin() + link_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
int selected_nodes[ImNodes::NumSelectedNodes()];
|
|
||||||
ImNodes::GetSelectedNodes(selected_nodes);
|
|
||||||
|
|
||||||
//
|
|
||||||
// Sidebar
|
|
||||||
//
|
|
||||||
ImGui::NextColumn();
|
|
||||||
|
|
||||||
if (ImNodes::NumSelectedNodes() == 1) {
|
|
||||||
if (selected_nodes[0] < graph_resource.m_nodes.size()) {
|
|
||||||
AnimNodeResource& selected_node =
|
|
||||||
graph_resource.m_nodes[selected_nodes[0]];
|
|
||||||
AnimGraphEditorRenderSidebar(selected_node);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Columns(1);
|
|
||||||
}
|
|
@ -8,8 +8,6 @@
|
|||||||
|
|
||||||
#include "3rdparty/json/json.hpp"
|
#include "3rdparty/json/json.hpp"
|
||||||
|
|
||||||
namespace AnimGraphCode {
|
|
||||||
|
|
||||||
using json = nlohmann::json;
|
using json = nlohmann::json;
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -47,31 +45,6 @@ json sSocketToJson(const Socket& socket) {
|
|||||||
json result;
|
json result;
|
||||||
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_value.ptr != nullptr) {
|
|
||||||
if (socket.m_type == SocketType::SocketTypeBool) {
|
|
||||||
result["value"] = *reinterpret_cast<bool*>(socket.m_value.ptr);
|
|
||||||
} else if (socket.m_type == SocketType::SocketTypeAnimation) {
|
|
||||||
} else if (socket.m_type == SocketType::SocketTypeFloat) {
|
|
||||||
result["value"] = *reinterpret_cast<float*>(socket.m_value.ptr);
|
|
||||||
} else if (socket.m_type == SocketType::SocketTypeVec3) {
|
|
||||||
Vec3& vec3 = *reinterpret_cast<Vec3*>(socket.m_value.ptr);
|
|
||||||
result["value"][0] = vec3[0];
|
|
||||||
result["value"][1] = vec3[1];
|
|
||||||
result["value"][2] = vec3[2];
|
|
||||||
} else if (socket.m_type == SocketType::SocketTypeQuat) {
|
|
||||||
Quat& quat = *reinterpret_cast<Quat*>(socket.m_value.ptr);
|
|
||||||
result["value"][0] = quat[0];
|
|
||||||
result["value"][1] = quat[1];
|
|
||||||
result["value"][2] = quat[2];
|
|
||||||
result["value"][3] = quat[3];
|
|
||||||
} else if (socket.m_type == SocketType::SocketTypeString) {
|
|
||||||
result["value"] = *reinterpret_cast<std::string*>(socket.m_value.ptr);
|
|
||||||
} else {
|
|
||||||
std::cerr << "Invalid socket type '" << static_cast<int>(socket.m_type)
|
|
||||||
<< "'." << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,12 +95,6 @@ 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_properties.size(); j < n;
|
|
||||||
j++) {
|
|
||||||
Socket& property = node.m_socket_accessor->m_properties[j];
|
|
||||||
result["properties"][property.m_name] = sSocketToJson(property);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,49 +110,6 @@ AnimNodeResource sAnimGraphNodeFromJson(const json& json_node) {
|
|||||||
result.m_socket_accessor =
|
result.m_socket_accessor =
|
||||||
AnimNodeAccessorFactory(result.m_type_name, result.m_anim_node);
|
AnimNodeAccessorFactory(result.m_type_name, result.m_anim_node);
|
||||||
|
|
||||||
for (size_t j = 0, n = result.m_socket_accessor->m_properties.size(); j < n;
|
|
||||||
j++) {
|
|
||||||
Socket& property = result.m_socket_accessor->m_properties[j];
|
|
||||||
json json_property = json_node["properties"][property.m_name];
|
|
||||||
|
|
||||||
if (sSocketTypeToStr(property.m_type) == json_property["type"]) {
|
|
||||||
if (property.m_type == SocketType::SocketTypeBool) {
|
|
||||||
result.m_socket_accessor->SetProperty<bool>(
|
|
||||||
property.m_name,
|
|
||||||
json_property["value"]);
|
|
||||||
} else if (property.m_type == SocketType::SocketTypeAnimation) {
|
|
||||||
} else if (property.m_type == SocketType::SocketTypeFloat) {
|
|
||||||
result.m_socket_accessor->SetProperty<float>(
|
|
||||||
property.m_name,
|
|
||||||
json_property["value"]);
|
|
||||||
} else if (property.m_type == SocketType::SocketTypeVec3) {
|
|
||||||
Vec3* property_vec3 = reinterpret_cast<Vec3*>(property.m_value.ptr);
|
|
||||||
(*property_vec3)[0] = json_property["value"][0];
|
|
||||||
(*property_vec3)[1] = json_property["value"][1];
|
|
||||||
(*property_vec3)[2] = json_property["value"][2];
|
|
||||||
} else if (property.m_type == SocketType::SocketTypeQuat) {
|
|
||||||
Quat* property_quat = reinterpret_cast<Quat*>(property.m_value.ptr);
|
|
||||||
(*property_quat)[0] = json_property["value"][0];
|
|
||||||
(*property_quat)[1] = json_property["value"][1];
|
|
||||||
(*property_quat)[2] = json_property["value"][2];
|
|
||||||
(*property_quat)[3] = json_property["value"][3];
|
|
||||||
} else if (property.m_type == SocketType::SocketTypeString) {
|
|
||||||
result.m_socket_accessor->SetProperty<std::string>(
|
|
||||||
property.m_name,
|
|
||||||
json_property["value"]);
|
|
||||||
} 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
|
|
||||||
<< "': expected " << sSocketTypeToStr(property.m_type)
|
|
||||||
<< " but got " << json_property["type"] << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,14 +144,6 @@ AnimGraphConnection sAnimGraphConnectionFromJson(const json& json_node) {
|
|||||||
|
|
||||||
void AnimGraphResource::clear() {
|
void AnimGraphResource::clear() {
|
||||||
m_name = "";
|
m_name = "";
|
||||||
|
|
||||||
clearNodes();
|
|
||||||
m_connections.clear();
|
|
||||||
|
|
||||||
initGraphConnectors();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AnimGraphResource::clearNodes() {
|
|
||||||
for (size_t i = 0; i < m_nodes.size(); i++) {
|
for (size_t i = 0; i < m_nodes.size(); i++) {
|
||||||
delete m_nodes[i].m_socket_accessor;
|
delete m_nodes[i].m_socket_accessor;
|
||||||
m_nodes[i].m_socket_accessor = nullptr;
|
m_nodes[i].m_socket_accessor = nullptr;
|
||||||
@ -235,13 +151,13 @@ void AnimGraphResource::clearNodes() {
|
|||||||
m_nodes[i].m_anim_node = nullptr;
|
m_nodes[i].m_anim_node = nullptr;
|
||||||
}
|
}
|
||||||
m_nodes.clear();
|
m_nodes.clear();
|
||||||
}
|
|
||||||
|
|
||||||
void AnimGraphResource::initGraphConnectors() {
|
|
||||||
m_nodes.push_back(AnimNodeResourceFactory("BlendTree"));
|
m_nodes.push_back(AnimNodeResourceFactory("BlendTree"));
|
||||||
m_nodes[0].m_name = "Outputs";
|
m_nodes[0].m_name = "Outputs";
|
||||||
m_nodes.push_back(AnimNodeResourceFactory("BlendTree"));
|
m_nodes.push_back(AnimNodeResourceFactory("BlendTree"));
|
||||||
m_nodes[1].m_name = "Inputs";
|
m_nodes[1].m_name = "Inputs";
|
||||||
|
|
||||||
|
m_connections.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AnimGraphResource::saveToFile(const char* filename) const {
|
bool AnimGraphResource::saveToFile(const char* filename) const {
|
||||||
@ -304,7 +220,6 @@ bool AnimGraphResource::loadFromFile(const char* filename) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
clearNodes();
|
|
||||||
|
|
||||||
m_name = json_data["name"];
|
m_name = json_data["name"];
|
||||||
for (size_t i = 0; i < json_data["nodes"].size(); i++) {
|
for (size_t i = 0; i < json_data["nodes"].size(); i++) {
|
||||||
@ -348,16 +263,10 @@ bool AnimGraphResource::loadFromFile(const char* filename) {
|
|||||||
sJsonToSocket(graph_inputs[i]));
|
sJsonToSocket(graph_inputs[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimGraph::MarkActiveNodes() {
|
void* AnimGraph::GetOutput(const std::string& name) {
|
||||||
m_frame_counter++;
|
|
||||||
|
|
||||||
// TODO: start from output and trigger updating of the frame counter.
|
|
||||||
}
|
|
||||||
|
|
||||||
void* AnimGraph::GetOutput(const std::string& name) const {
|
|
||||||
Socket* socket = m_socket_accessor->FindInputSocket(name);
|
Socket* socket = m_socket_accessor->FindInputSocket(name);
|
||||||
if (socket == nullptr) {
|
if (socket == nullptr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -366,7 +275,7 @@ void* AnimGraph::GetOutput(const std::string& name) const {
|
|||||||
return socket->m_value.ptr;
|
return socket->m_value.ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* AnimGraph::GetInput(const std::string& name) const {
|
void* AnimGraph::GetInput(const std::string& name) {
|
||||||
Socket* socket = m_socket_accessor->FindOutputSocket(name);
|
Socket* socket = m_socket_accessor->FindOutputSocket(name);
|
||||||
if (socket == nullptr) {
|
if (socket == nullptr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -374,5 +283,3 @@ void* AnimGraph::GetInput(const std::string& name) const {
|
|||||||
|
|
||||||
return *(socket->m_value.ptr_ptr);
|
return *(socket->m_value.ptr_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
@ -14,8 +14,6 @@
|
|||||||
|
|
||||||
#include "SyncTrack.h"
|
#include "SyncTrack.h"
|
||||||
|
|
||||||
namespace AnimGraphCode {
|
|
||||||
|
|
||||||
enum class SocketType {
|
enum class SocketType {
|
||||||
SocketTypeUndefined,
|
SocketTypeUndefined,
|
||||||
SocketTypeBool,
|
SocketTypeBool,
|
||||||
@ -26,8 +24,6 @@ enum class SocketType {
|
|||||||
SocketTypeString
|
SocketTypeString
|
||||||
};
|
};
|
||||||
|
|
||||||
enum SocketFlags { SocketFlagAffectsTime = 1 };
|
|
||||||
|
|
||||||
struct AnimData {
|
struct AnimData {
|
||||||
float m_bone_transforms[16];
|
float m_bone_transforms[16];
|
||||||
};
|
};
|
||||||
@ -65,7 +61,6 @@ struct Socket {
|
|||||||
void** ptr_ptr;
|
void** ptr_ptr;
|
||||||
};
|
};
|
||||||
SocketValue m_value = {nullptr};
|
SocketValue m_value = {nullptr};
|
||||||
int m_flags = 0;
|
|
||||||
size_t m_type_size = 0;
|
size_t m_type_size = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -89,21 +84,13 @@ struct AnimNode {
|
|||||||
bool m_is_time_synced;
|
bool m_is_time_synced;
|
||||||
float m_time_now;
|
float m_time_now;
|
||||||
float m_time_last;
|
float m_time_last;
|
||||||
int m_frame_counter = 0;
|
|
||||||
SyncTrack m_sync_track;
|
SyncTrack m_sync_track;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AnimNodeInput {
|
|
||||||
AnimNode* m_node;
|
|
||||||
std::string m_input_name;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct NodeSocketAccessorBase {
|
struct NodeSocketAccessorBase {
|
||||||
NodeSocketAccessorBase() {}
|
NodeSocketAccessorBase() {}
|
||||||
virtual ~NodeSocketAccessorBase() {}
|
virtual ~NodeSocketAccessorBase() {}
|
||||||
|
|
||||||
virtual void UpdateFlags(){};
|
|
||||||
|
|
||||||
Socket* FindSocket(std::vector<Socket>& sockets, const std::string& name) {
|
Socket* FindSocket(std::vector<Socket>& sockets, const std::string& name) {
|
||||||
Socket* result = nullptr;
|
Socket* result = nullptr;
|
||||||
for (size_t i = 0, n = sockets.size(); i < n; i++) {
|
for (size_t i = 0, n = sockets.size(); i < n; i++) {
|
||||||
@ -153,40 +140,11 @@ struct NodeSocketAccessorBase {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
T GetSocketValue(
|
|
||||||
const std::vector<Socket>& sockets,
|
|
||||||
const std::string& name,
|
|
||||||
T default_value) {
|
|
||||||
const Socket* socket = FindSocket(sockets, name);
|
|
||||||
if (socket == nullptr) {
|
|
||||||
return default_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return *static_cast<T*>(socket->m_value.ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void SetSocketValue(
|
|
||||||
const std::vector<Socket>& sockets,
|
|
||||||
const std::string& name,
|
|
||||||
const T& value) {
|
|
||||||
const Socket* socket = FindSocket(sockets, name);
|
|
||||||
if (socket == nullptr) {
|
|
||||||
std::cerr << "Error: could not set value of socket with name " << name
|
|
||||||
<< ": no socket found." << std::endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
*static_cast<T*>(socket->m_value.ptr) = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool RegisterSocket(
|
bool RegisterSocket(
|
||||||
std::vector<Socket>& sockets,
|
std::vector<Socket>& sockets,
|
||||||
const std::string& name,
|
const std::string& name,
|
||||||
T* value_ptr,
|
T* value_ptr) {
|
||||||
int flags = 0) {
|
|
||||||
Socket* socket = FindSocket(sockets, name);
|
Socket* socket = FindSocket(sockets, name);
|
||||||
if (socket != nullptr) {
|
if (socket != nullptr) {
|
||||||
std::cerr << "Socket " << name << " already registered." << std::endl;
|
std::cerr << "Socket " << name << " already registered." << std::endl;
|
||||||
@ -197,7 +155,6 @@ struct NodeSocketAccessorBase {
|
|||||||
socket = &sockets[sockets.size() - 1];
|
socket = &sockets[sockets.size() - 1];
|
||||||
socket->m_name = name;
|
socket->m_name = name;
|
||||||
socket->m_type_size = sizeof(T);
|
socket->m_type_size = sizeof(T);
|
||||||
socket->m_flags = flags;
|
|
||||||
|
|
||||||
if constexpr (std::is_same<T, float>::value) {
|
if constexpr (std::is_same<T, float>::value) {
|
||||||
socket->m_type = SocketType::SocketTypeFloat;
|
socket->m_type = SocketType::SocketTypeFloat;
|
||||||
@ -237,20 +194,20 @@ struct NodeSocketAccessorBase {
|
|||||||
return RegisterSocket(m_properties, name, value);
|
return RegisterSocket(m_properties, name, value);
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void SetProperty(const std::string& name, const T& value) {
|
bool SetProperty(const std::string& name, T value) {
|
||||||
SetSocketValue(m_properties, name, value);
|
return SetSocketValue(m_properties, name, value);
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T GetProperty(const std::string& name, T default_value) {
|
T GetProperty(const std::string& name, T value) {
|
||||||
return GetSocketValue(m_properties, name, default_value);
|
return GetSocketValue(m_properties, name, value);
|
||||||
}
|
}
|
||||||
SocketType GetPropertyType(const std::string& name) {
|
SocketType GetPropertyType(const std::string& name) {
|
||||||
return GetSocketType(m_properties, name);
|
return GetSocketType(m_properties, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool RegisterInput(const std::string& name, T* value, int flags = 0) {
|
bool RegisterInput(const std::string& name, T* value) {
|
||||||
return RegisterSocket(m_inputs, name, value, flags);
|
return RegisterSocket(m_inputs, name, value);
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T* GetInput(const std::string& name, T* value) {
|
T* GetInput(const std::string& name, T* value) {
|
||||||
@ -267,8 +224,8 @@ struct NodeSocketAccessorBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool RegisterOutput(const std::string& name, T** value, int flags = 0) {
|
bool RegisterOutput(const std::string& name, T** value) {
|
||||||
return RegisterSocket(m_outputs, name, value, flags);
|
return RegisterSocket(m_outputs, name, value);
|
||||||
}
|
}
|
||||||
SocketType GetOutputType(const std::string& name) {
|
SocketType GetOutputType(const std::string& name) {
|
||||||
return GetSocketType(m_outputs, name);
|
return GetSocketType(m_outputs, name);
|
||||||
@ -318,26 +275,12 @@ struct NodeSocketAccessor<Blend2Node> : public NodeSocketAccessorBase {
|
|||||||
Blend2Node* node = dynamic_cast<Blend2Node*>(node_);
|
Blend2Node* node = dynamic_cast<Blend2Node*>(node_);
|
||||||
RegisterInput("Input0", &node->m_input0);
|
RegisterInput("Input0", &node->m_input0);
|
||||||
RegisterInput("Input1", &node->m_input1);
|
RegisterInput("Input1", &node->m_input1);
|
||||||
RegisterInput(
|
RegisterInput("Weight", &node->m_blend_weight);
|
||||||
"Weight",
|
|
||||||
&node->m_blend_weight,
|
|
||||||
SocketFlags::SocketFlagAffectsTime);
|
|
||||||
|
|
||||||
RegisterOutput("Output", &node->m_output);
|
RegisterOutput("Output", &node->m_output);
|
||||||
|
|
||||||
RegisterProperty("Sync", &node->m_sync_blend);
|
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<bool>("Sync", false) == true) {
|
|
||||||
weight_input_socket->m_flags = SocketFlags::SocketFlagAffectsTime;
|
|
||||||
} else {
|
|
||||||
weight_input_socket->m_flags = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SpeedScaleNode : public AnimNode {
|
struct SpeedScaleNode : public AnimNode {
|
||||||
@ -350,10 +293,7 @@ template <>
|
|||||||
struct NodeSocketAccessor<SpeedScaleNode> : public NodeSocketAccessorBase {
|
struct NodeSocketAccessor<SpeedScaleNode> : public NodeSocketAccessorBase {
|
||||||
NodeSocketAccessor(AnimNode* node_) {
|
NodeSocketAccessor(AnimNode* node_) {
|
||||||
SpeedScaleNode* node = dynamic_cast<SpeedScaleNode*>(node_);
|
SpeedScaleNode* node = dynamic_cast<SpeedScaleNode*>(node_);
|
||||||
RegisterInput(
|
RegisterInput("SpeedScale", &node->m_speed_scale);
|
||||||
"SpeedScale",
|
|
||||||
&node->m_speed_scale,
|
|
||||||
SocketFlags::SocketFlagAffectsTime);
|
|
||||||
RegisterInput("Input", &node->m_input);
|
RegisterInput("Input", &node->m_input);
|
||||||
|
|
||||||
RegisterOutput("Output", &node->m_output);
|
RegisterOutput("Output", &node->m_output);
|
||||||
@ -397,14 +337,16 @@ struct AnimGraphResource {
|
|||||||
AnimGraphResource() { clear(); }
|
AnimGraphResource() { clear(); }
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
void clearNodes();
|
|
||||||
void initGraphConnectors();
|
|
||||||
bool saveToFile(const char* filename) const;
|
bool saveToFile(const char* filename) const;
|
||||||
bool loadFromFile(const char* filename);
|
bool loadFromFile(const char* filename);
|
||||||
|
|
||||||
AnimNodeResource& getGraphOutputNode() { return m_nodes[0]; }
|
AnimNodeResource& getGraphOutputNode() {
|
||||||
|
return m_nodes[0];
|
||||||
|
}
|
||||||
|
|
||||||
AnimNodeResource& getGraphInputNode() { return m_nodes[1]; }
|
AnimNodeResource& getGraphInputNode() {
|
||||||
|
return m_nodes[1];
|
||||||
|
}
|
||||||
|
|
||||||
size_t addNode(AnimNodeResource node_resource) {
|
size_t addNode(AnimNodeResource node_resource) {
|
||||||
m_nodes.push_back(node_resource);
|
m_nodes.push_back(node_resource);
|
||||||
@ -521,19 +463,12 @@ struct AnimGraph {
|
|||||||
delete m_socket_accessor;
|
delete m_socket_accessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MarkActiveNodes();
|
|
||||||
bool CheckNodeActive(int node_index) {
|
|
||||||
assert(node_index < m_nodes.size());
|
|
||||||
return m_nodes[node_index]->m_frame_counter == m_frame_counter;
|
|
||||||
}
|
|
||||||
void UpdateTime(float dt);
|
void UpdateTime(float dt);
|
||||||
void Evaluate();
|
void Evaluate();
|
||||||
|
|
||||||
int m_frame_counter;
|
|
||||||
AnimData m_local_transforms;
|
AnimData m_local_transforms;
|
||||||
|
|
||||||
std::vector<AnimNode*> m_nodes;
|
std::vector<AnimNode*> m_nodes;
|
||||||
std::vector<std::vector<AnimNodeInput> > m_node_inputs;
|
std::vector<std::vector<AnimNode*> > m_node_inputs;
|
||||||
NodeSocketAccessorBase* m_socket_accessor;
|
NodeSocketAccessorBase* m_socket_accessor;
|
||||||
char* m_input_buffer = nullptr;
|
char* m_input_buffer = nullptr;
|
||||||
char* m_output_buffer = nullptr;
|
char* m_output_buffer = nullptr;
|
||||||
@ -541,24 +476,8 @@ struct AnimGraph {
|
|||||||
std::vector<Socket>& GetGraphOutputs() { return m_socket_accessor->m_inputs; }
|
std::vector<Socket>& GetGraphOutputs() { return m_socket_accessor->m_inputs; }
|
||||||
std::vector<Socket>& GetGraphInputs() { return m_socket_accessor->m_outputs; }
|
std::vector<Socket>& GetGraphInputs() { return m_socket_accessor->m_outputs; }
|
||||||
|
|
||||||
void* GetOutput(const std::string& name) const;
|
void* GetOutput(const std::string& name);
|
||||||
void* GetInput(const std::string& name) const;
|
void* GetInput(const std::string& name);
|
||||||
|
|
||||||
AnimNode* getAnimNodeForInput(
|
|
||||||
size_t node_index,
|
|
||||||
const std::string& input_name) {
|
|
||||||
assert(node_index < m_nodes.size());
|
|
||||||
assert(node_index < m_node_inputs.size());
|
|
||||||
|
|
||||||
std::vector<AnimNodeInput>& node_inputs = m_node_inputs[node_index];
|
|
||||||
for (size_t i = 0, n = node_inputs.size(); i < n; i++) {
|
|
||||||
if (node_inputs[i].m_input_name == input_name) {
|
|
||||||
return node_inputs[i].m_node;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
AnimNode* getAnimNode(const char* name) {
|
AnimNode* getAnimNode(const char* name) {
|
||||||
for (size_t i = 0; i < m_nodes.size(); i++) {
|
for (size_t i = 0; i < m_nodes.size(); i++) {
|
||||||
@ -591,21 +510,7 @@ struct AnimGraph {
|
|||||||
node->m_name = node_resource.m_name;
|
node->m_name = node_resource.m_name;
|
||||||
node->m_node_type_name = node_resource.m_type_name;
|
node->m_node_type_name = node_resource.m_type_name;
|
||||||
result.m_nodes.push_back(node);
|
result.m_nodes.push_back(node);
|
||||||
|
result.m_node_inputs.push_back(std::vector<AnimNode*>());
|
||||||
assert(node_resource.m_socket_accessor != nullptr);
|
|
||||||
result.m_node_inputs.push_back(std::vector<AnimNodeInput>());
|
|
||||||
std::vector<AnimNodeInput>& node_inputs = result.m_node_inputs.back();
|
|
||||||
for (int j = 0, n = node_resource.m_socket_accessor->m_inputs.size();
|
|
||||||
j < n;
|
|
||||||
j++) {
|
|
||||||
const Socket& input_socket =
|
|
||||||
node_resource.m_socket_accessor->m_inputs[j];
|
|
||||||
AnimNodeInput input;
|
|
||||||
input.m_node = nullptr;
|
|
||||||
input.m_input_name = input_socket.m_name;
|
|
||||||
|
|
||||||
node_inputs.push_back(input);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare graph inputs
|
// Prepare graph inputs
|
||||||
@ -731,14 +636,7 @@ struct AnimGraph {
|
|||||||
(*source_socket->m_value.ptr_ptr) = target_socket->m_value.ptr;
|
(*source_socket->m_value.ptr_ptr) = target_socket->m_value.ptr;
|
||||||
|
|
||||||
size_t target_node_index = result.getAnimNodeIndex(target_node);
|
size_t target_node_index = result.getAnimNodeIndex(target_node);
|
||||||
|
result.m_node_inputs[target_node_index].push_back(source_node);
|
||||||
std::vector<AnimNodeInput>& node_inputs =
|
|
||||||
result.m_node_inputs[target_node_index];
|
|
||||||
for (int j = 0, n = node_inputs.size(); j < n; j++) {
|
|
||||||
if (node_inputs[j].m_input_name == target_socket->m_name) {
|
|
||||||
node_inputs[j].m_node = source_node;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (target_node_accessor != result.m_socket_accessor) {
|
if (target_node_accessor != result.m_socket_accessor) {
|
||||||
delete target_node_accessor;
|
delete target_node_accessor;
|
||||||
@ -753,6 +651,4 @@ struct AnimGraph {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace AnimGraphCode
|
|
||||||
|
|
||||||
#endif //ANIMTESTBED_ANIMGRAPHRESOURCE_H
|
#endif //ANIMTESTBED_ANIMGRAPHRESOURCE_H
|
||||||
|
@ -5,8 +5,6 @@
|
|||||||
#include "AnimGraphResource.h"
|
#include "AnimGraphResource.h"
|
||||||
#include "catch.hpp"
|
#include "catch.hpp"
|
||||||
|
|
||||||
using namespace AnimGraphCode;
|
|
||||||
|
|
||||||
TEST_CASE("BasicGraph", "[AnimGraphResource]") {
|
TEST_CASE("BasicGraph", "[AnimGraphResource]") {
|
||||||
AnimGraphResource graph_resource;
|
AnimGraphResource graph_resource;
|
||||||
|
|
||||||
@ -102,10 +100,9 @@ TEST_CASE("BasicGraph", "[AnimGraphResource]") {
|
|||||||
|
|
||||||
CHECK(graph.m_node_inputs[anim_sampler_index0].size() == 0);
|
CHECK(graph.m_node_inputs[anim_sampler_index0].size() == 0);
|
||||||
CHECK(graph.m_node_inputs[anim_sampler_index1].size() == 0);
|
CHECK(graph.m_node_inputs[anim_sampler_index1].size() == 0);
|
||||||
CHECK(graph.m_node_inputs[blend_index].size() == 3);
|
CHECK(graph.m_node_inputs[blend_index].size() == 2);
|
||||||
CHECK(graph.m_node_inputs[blend_index][0].m_node == anim_sampler_instance0);
|
CHECK(graph.m_node_inputs[blend_index][0] == anim_sampler_instance0);
|
||||||
CHECK(graph.m_node_inputs[blend_index][1].m_node == anim_sampler_instance1);
|
CHECK(graph.m_node_inputs[blend_index][1] == anim_sampler_instance1);
|
||||||
CHECK(graph.m_node_inputs[blend_index][2].m_node == nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("InputAttributeConversion", "[AnimGraphResource]") {
|
TEST_CASE("InputAttributeConversion", "[AnimGraphResource]") {
|
||||||
@ -327,15 +324,12 @@ TEST_CASE("GraphInputOutputConnectivity", "[AnimGraphResource]") {
|
|||||||
|
|
||||||
AnimData* graph_input0 = (AnimData*) anim_graph.GetInput("GraphAnimInput0");
|
AnimData* graph_input0 = (AnimData*) anim_graph.GetInput("GraphAnimInput0");
|
||||||
REQUIRE(graph_input0 == &blend2_node->m_input0);
|
REQUIRE(graph_input0 == &blend2_node->m_input0);
|
||||||
REQUIRE(anim_graph.m_nodes[1] == anim_graph.getAnimNodeForInput(blend2_node_index, "Input0"));
|
|
||||||
|
|
||||||
AnimData* graph_input1 = (AnimData*) anim_graph.GetInput("GraphAnimInput1");
|
AnimData* graph_input1 = (AnimData*) anim_graph.GetInput("GraphAnimInput1");
|
||||||
REQUIRE(graph_input1 == &blend2_node->m_input1);
|
REQUIRE(graph_input1 == &blend2_node->m_input1);
|
||||||
REQUIRE(anim_graph.m_nodes[1] == anim_graph.getAnimNodeForInput(blend2_node_index, "Input1"));
|
|
||||||
|
|
||||||
AnimData* graph_output = (AnimData*) anim_graph.GetOutput("GraphAnimOutput");
|
AnimData* graph_output = (AnimData*) anim_graph.GetOutput("GraphAnimOutput");
|
||||||
REQUIRE(graph_output == blend2_node->m_output);
|
REQUIRE(graph_output == blend2_node->m_output);
|
||||||
REQUIRE(anim_graph.m_nodes[blend2_node_index] == anim_graph.getAnimNodeForInput(0, "GraphAnimOutput"));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user