Started working on graph initialization in ATP Editor.

AnimGraphEditor
Martin Felis 2023-03-26 23:39:11 +02:00
parent a1931185d8
commit e38c0b4934
10 changed files with 193 additions and 155 deletions

View File

@ -7,6 +7,8 @@
#include <cstring>
bool AnimGraph::init(AnimGraphContext& context) {
context.m_graph = this;
for (size_t i = 2; i < m_nodes.size(); i++) {
if (!m_nodes[i]->Init(context)) {
return false;

View File

@ -27,19 +27,26 @@ struct AnimGraph {
AnimDataAllocator m_anim_data_allocator;
~AnimGraph() {
std::vector<AnimGraphConnection>& graph_outputs = m_node_input_connections[0];
~AnimGraph() { dealloc(); }
for (size_t i = 0, n = graph_outputs.size(); i < n; i++) {
AnimGraphConnection& connection = graph_outputs[i];
if (connection.m_target_socket.m_type == SocketType::SocketTypeAnimation) {
AnimData* graph_anim_output =
static_cast<AnimData*>(connection.m_target_socket.m_reference.ptr);
assert(graph_anim_output != nullptr);
bool init(AnimGraphContext& context);
void dealloc() {
if (m_node_input_connections.size() > 0) {
std::vector<AnimGraphConnection>& graph_outputs =
m_node_input_connections[0];
// we have to explicitly call the destructor as the AnimData* was
// initialized using a placement new operator.
graph_anim_output->m_local_matrices.vector::~vector();
for (size_t i = 0, n = graph_outputs.size(); i < n; i++) {
AnimGraphConnection& connection = graph_outputs[i];
if (connection.m_target_socket.m_type
== SocketType::SocketTypeAnimation) {
AnimData* graph_anim_output = static_cast<AnimData*>(
connection.m_target_socket.m_reference.ptr);
assert(graph_anim_output != nullptr);
// we have to explicitly call the destructor as the AnimData* was
// initialized using a placement new operator.
graph_anim_output->m_local_matrices.vector::~vector();
}
}
}
@ -53,8 +60,6 @@ struct AnimGraph {
delete m_socket_accessor;
}
bool init(AnimGraphContext& context);
void updateOrderedNodes();
void updateOrderedNodesRecursive(int node_index);
void markActiveNodes();
@ -70,7 +75,7 @@ struct AnimGraph {
void evalSyncTracks();
void updateTime(float dt);
void evaluate(AnimGraphContext& context);
void reset() {
void resetNodeStates() {
for (size_t i = 0, n = m_nodes.size(); i < n; i++) {
m_nodes[i]->m_time_now = 0.f;
m_nodes[i]->m_time_last = 0.f;
@ -102,7 +107,6 @@ struct AnimGraph {
return nullptr;
}
int getNodeEvalOrderIndex(const AnimNode* node) {
for (size_t i = 0, n = m_eval_ordered_nodes.size(); i < n; i++) {
if (m_eval_ordered_nodes[i] == node) {
@ -112,12 +116,13 @@ struct AnimGraph {
return -1;
}
const AnimNode* getAnimNodeForInput (
const AnimNode* getAnimNodeForInput(
size_t node_index,
const std::string& input_name) const {
assert(node_index < m_nodes.size());
const std::vector<AnimGraphConnection>& input_connection = m_node_input_connections[node_index];
const std::vector<AnimGraphConnection>& input_connection =
m_node_input_connections[node_index];
for (size_t i = 0, n = input_connection.size(); i < n; i++) {
if (input_connection[i].m_target_socket.m_name == input_name) {
return input_connection[i].m_source_node;
@ -137,7 +142,7 @@ struct AnimGraph {
return nullptr;
}
size_t getAnimNodeIndex (AnimNode* node) {
size_t getAnimNodeIndex(AnimNode* node) {
for (size_t i = 0; i < m_nodes.size(); i++) {
if (m_nodes[i] == node) {
return i;

View File

@ -9,10 +9,10 @@
#include <cstring>
#include <iostream>
#include <list>
#include <map>
#include <string>
#include <vector>
#include <list>
#include "SyncTrack.h"
#include "ozz/animation/runtime/animation.h"
@ -76,16 +76,15 @@ struct AnimDataAllocator {
void free(AnimData* anim_data) {
#ifdef ANIM_DATA_ALLOCATOR_DEBUG
std::cout << "Storing buffer with size " << anim_data->m_local_matrices.size()
<< " " << anim_data << std::endl;
std::cout << "Storing buffer with size "
<< anim_data->m_local_matrices.size() << " " << anim_data
<< std::endl;
#endif
m_anim_data_list.push_front(anim_data);
}
size_t size() {
return m_anim_data_list.size();
}
size_t size() { return m_anim_data_list.size(); }
};
struct AnimGraphContext {
@ -134,7 +133,7 @@ struct Socket {
float float_value;
float vec3[3];
float quat[4];
char str[cSocketStringValueMaxLength];
std::string* string_ptr;
};
SocketValue m_value = {0};
union SocketReference {
@ -265,6 +264,9 @@ struct NodeSocketAccessorBase {
socket->m_type = SocketType::SocketTypeAnimation;
} else if constexpr (std::is_same<T, std::string>::value) {
socket->m_type = SocketType::SocketTypeString;
socket->m_value.string_ptr = value_ptr;
socket->m_reference.ptr = value_ptr;
return true;
} else if constexpr (std::is_same<T, float*>::value) {
socket->m_type = SocketType::SocketTypeFloat;
} else if constexpr (std::is_same<T, bool*>::value) {
@ -381,6 +383,13 @@ inline void NodeSocketAccessorBase::SetSocketReferenceValue<const Quat&>(
static_cast<float*>(socket->m_reference.ptr)[3] = value[3];
}
template <>
inline void NodeSocketAccessorBase::SetSocketReferenceValue<const std::string*>(
Socket* socket,
const std::string* value) {
socket->m_value.string_ptr = const_cast<std::string*>(value);
}
template <>
inline void NodeSocketAccessorBase::SetSocketReferenceValue<const std::string&>(
Socket* socket,
@ -433,20 +442,17 @@ inline void NodeSocketAccessorBase::SetSocketValue<const Quat&>(
}
template <>
inline void NodeSocketAccessorBase::SetSocketValue<const std::string&>(
inline void NodeSocketAccessorBase::SetSocketValue<std::string>(
Socket* socket,
const std::string& value) {
constexpr size_t string_max_length = sizeof(socket->m_value.str) - 1;
strncpy(socket->m_value.str, value.data(), string_max_length);
socket->m_value.str
[value.size() > string_max_length ? string_max_length : value.size()] = 0;
std::string value) {
*socket->m_value.string_ptr = value;
}
template <>
inline void NodeSocketAccessorBase::SetSocketValue<const char*>(
Socket* socket,
const char* value) {
SetSocketValue<const std::string&>(socket, value);
SetSocketValue<std::string>(socket, value);
}
template <typename T>

View File

@ -9,6 +9,8 @@
#include "imnodes.h"
#include "misc/cpp/imgui_stdlib.h"
static AnimGraphResource sGraphGresource = AnimGraphResource();
ImNodesPinShape sGetSocketShapeFromSocketType(const SocketType& socket_type) {
switch (socket_type) {
case SocketType::SocketTypeAnimation:
@ -54,7 +56,7 @@ void RemoveConnectionsForSocket(
// AnimGraphConnectionResource& connection = *iter;
// if (connection.m_source_node == &node_resource
// && connection.m_source_socket == &socket) {
// iter = graph_resource.m_connections.erase(iter);
// iter = sGraphGresource.m_connections.erase(iter);
// } else {
// iter++;
// }
@ -91,19 +93,13 @@ void AnimGraphEditorRenderSidebar(
property.m_name.c_str(),
reinterpret_cast<bool*>(property.m_reference.ptr));
} else if (property.m_type == SocketType::SocketTypeString) {
std::string* property_string =
reinterpret_cast<std::string*>(property.m_reference.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)));
char string_buf[1024];
memcpy (string_buf, property.m_value.string_ptr->c_str(), property.m_value.string_ptr->size() + 1);
if (ImGui::InputText(
property.m_name.c_str(),
string_buf,
sizeof(string_buf))) {
(*property_string) = string_buf;
*property.m_value.string_ptr = string_buf;
}
}
}
@ -152,33 +148,31 @@ void AnimGraphEditorRenderSidebar(
}
void AnimGraphEditorUpdate() {
static AnimGraphResource graph_resource = AnimGraphResource();
ImGui::BeginMenuBar();
if (ImGui::Button("Save")) {
graph_resource.saveToFile("editor_graph.json");
sGraphGresource.saveToFile("editor_graph.json");
}
if (ImGui::Button("Load")) {
graph_resource.loadFromFile("editor_graph.json");
sGraphGresource.loadFromFile("editor_graph.json");
for (size_t i = 0, n = graph_resource.m_nodes.size(); i < n; i++) {
const AnimNodeResource& node_resource = graph_resource.m_nodes[i];
for (size_t i = 0, n = sGraphGresource.m_nodes.size(); i < n; i++) {
const AnimNodeResource& node_resource = sGraphGresource.m_nodes[i];
ImNodes::SetNodeGridSpacePos(
i,
ImVec2(node_resource.m_position[0], node_resource.m_position[1]));
}
}
if (ImGui::Button("Clear")) {
graph_resource.clear();
sGraphGresource.clear();
}
char graph_name_buffer[256];
memset(graph_name_buffer, 0, sizeof(graph_name_buffer));
strncpy(
graph_name_buffer,
graph_resource.m_name.c_str(),
sGraphGresource.m_name.c_str(),
sizeof(graph_name_buffer));
if (ImGui::InputText("Name", graph_name_buffer, sizeof(graph_name_buffer))) {
graph_resource.m_name = graph_name_buffer;
sGraphGresource.m_name = graph_name_buffer;
}
ImGui::EndMenuBar();
@ -228,9 +222,9 @@ void AnimGraphEditorUpdate() {
if (node_type_name != "") {
AnimNodeResource node_resource =
AnimNodeResourceFactory(node_type_name);
size_t node_id = graph_resource.m_nodes.size();
size_t node_id = sGraphGresource.m_nodes.size();
ImNodes::SetNodeScreenSpacePos(node_id, ImGui::GetMousePos());
graph_resource.m_nodes.push_back(node_resource);
sGraphGresource.m_nodes.push_back(node_resource);
}
ImGui::EndPopup();
@ -239,17 +233,17 @@ void AnimGraphEditorUpdate() {
ImGui::PopStyleVar(ImGuiStyleVar_WindowPadding);
}
for (size_t i = 0, n = graph_resource.m_nodes.size(); i < n; i++) {
AnimNodeResource& node_resource = graph_resource.m_nodes[i];
for (size_t i = 0, n = sGraphGresource.m_nodes.size(); i < n; i++) {
AnimNodeResource& node_resource = sGraphGresource.m_nodes[i];
ImNodes::BeginNode(i);
ImGui::PushItemWidth(110.0f);
// Header
ImNodes::BeginNodeTitleBar();
if (&node_resource == &graph_resource.getGraphOutputNode()) {
if (&node_resource == &sGraphGresource.getGraphOutputNode()) {
ImGui::TextUnformatted("Graph Outputs");
} else if (&node_resource == &graph_resource.getGraphInputNode()) {
} else if (&node_resource == &sGraphGresource.getGraphInputNode()) {
ImGui::TextUnformatted("Graph Inputs");
} else {
ImGui::TextUnformatted(node_resource.m_type_name.c_str());
@ -273,7 +267,8 @@ void AnimGraphEditorUpdate() {
socket_color);
ImGui::TextUnformatted(socket.m_name.c_str());
bool socket_connected = graph_resource.isSocketConnected(node_resource, socket.m_name);
bool socket_connected =
sGraphGresource.isSocketConnected(node_resource, socket.m_name);
if (!socket_connected &&
(socket.m_type == SocketType::SocketTypeFloat)) {
ImGui::SameLine();
@ -307,7 +302,7 @@ void AnimGraphEditorUpdate() {
if (i == 0) {
if (ImGui::Button("+Output")) {
AnimNodeResource& graph_output_node =
graph_resource.getGraphOutputNode();
sGraphGresource.getGraphOutputNode();
static float bla = 0.f;
std::string socket_name = "Output";
@ -319,7 +314,8 @@ void AnimGraphEditorUpdate() {
}
} else if (i == 1) {
if (ImGui::Button("+Input")) {
AnimNodeResource& graph_input_node = graph_resource.getGraphInputNode();
AnimNodeResource& graph_input_node =
sGraphGresource.getGraphInputNode();
static float bla = 0.f;
std::string socket_name = "Input";
@ -343,18 +339,18 @@ void AnimGraphEditorUpdate() {
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 = sGraphGresource.m_connections.size(); i < n; i++) {
const AnimGraphConnectionResource& connection =
graph_resource.m_connections[i];
sGraphGresource.m_connections[i];
int start_attr, end_attr;
const AnimNodeResource& source_node =
graph_resource.m_nodes[connection.source_node_index];
sGraphGresource.m_nodes[connection.source_node_index];
int source_socket_index = source_node.m_socket_accessor->GetOutputIndex(
connection.source_socket_name);
const AnimNodeResource& target_node =
graph_resource.m_nodes[connection.target_node_index];
sGraphGresource.m_nodes[connection.target_node_index];
int target_socket_index = target_node.m_socket_accessor->GetInputIndex(
connection.target_socket_name);
@ -386,24 +382,29 @@ void AnimGraphEditorUpdate() {
AnimGraphConnectionResource connection;
connection.source_node_index = node_start_id;
const AnimNodeResource& source_node = graph_resource.m_nodes[node_start_id];
const AnimNodeResource& source_node =
sGraphGresource.m_nodes[node_start_id];
connection.source_socket_name =
source_node.m_socket_accessor->m_outputs[node_start_output_index]
.m_name;
connection.target_node_index = node_end_id;
const AnimNodeResource& target_node = graph_resource.m_nodes[node_end_id];
const AnimNodeResource& target_node = sGraphGresource.m_nodes[node_end_id];
connection.target_socket_name =
target_node.m_socket_accessor->m_inputs[node_end_input_index].m_name;
graph_resource.m_connections.push_back(connection);
sGraphGresource.m_connections.push_back(connection);
}
if (ImGui::IsKeyPressed(ImGuiKey_Delete, false)) {
std::cerr << "Delete key!" << std::endl;
}
// Handle link detachements.
int link_id = 0;
if (ImNodes::IsLinkDestroyed(&link_id)) {
graph_resource.m_connections.erase(
graph_resource.m_connections.begin() + link_id);
sGraphGresource.m_connections.erase(
sGraphGresource.m_connections.begin() + link_id);
}
int selected_nodes[ImNodes::NumSelectedNodes()];
@ -415,12 +416,16 @@ void AnimGraphEditorUpdate() {
ImGui::NextColumn();
if (ImNodes::NumSelectedNodes() == 1) {
if (selected_nodes[0] < graph_resource.m_nodes.size()) {
if (selected_nodes[0] < sGraphGresource.m_nodes.size()) {
AnimNodeResource& selected_node =
graph_resource.m_nodes[selected_nodes[0]];
AnimGraphEditorRenderSidebar(graph_resource, selected_node);
sGraphGresource.m_nodes[selected_nodes[0]];
AnimGraphEditorRenderSidebar(sGraphGresource, selected_node);
}
}
ImGui::Columns(1);
}
void AnimGraphEditorGetRuntimeGraph(AnimGraph& anim_graph) {
sGraphGresource.createInstance(anim_graph);
}

View File

@ -5,6 +5,8 @@
#ifndef ANIMTESTBED_ANIMGRAPHEDITOR_H
#define ANIMTESTBED_ANIMGRAPHEDITOR_H
#include "AnimGraph.h"
inline int GenerateInputAttributeId(int node_id, int input_index) {
return ((input_index + 1) << 14) + node_id;
}
@ -27,4 +29,6 @@ SplitOutputAttributeId(int attribute_id, int* node_id, int* output_index) {
void AnimGraphEditorUpdate();
void AnimGraphEditorGetRuntimeGraph(AnimGraph& anim_graph);
#endif //ANIMTESTBED_ANIMGRAPHEDITOR_H

View File

@ -43,7 +43,7 @@ json sSocketToJson(const Socket& socket) {
result["value"][2] = socket.m_value.quat[2];
result["value"][3] = socket.m_value.quat[3];
} else if (socket.m_type == SocketType::SocketTypeString) {
result["value"] = std::string(socket.m_value.str);
result["value"] = *socket.m_value.string_ptr;
} else {
std::cerr << "Invalid socket type '" << static_cast<int>(socket.m_type)
<< "'." << std::endl;
@ -142,17 +142,7 @@ AnimNodeResource sAnimGraphNodeFromJson(const json& json_node) {
property.m_value.quat[2] = json_property["value"][2];
property.m_value.quat[3] = json_property["value"][3];
} else if (property.m_type == SocketType::SocketTypeString) {
std::string value_str = json_property["value"];
size_t string_length = value_str.size();
constexpr size_t string_max_length = sizeof(property.m_value.str) - 1;
if (string_length > string_max_length) {
std::cerr << "Warning: string '" << value_str
<< "' too long, truncating to " << string_max_length
<< " bytes." << std::endl;
string_length = string_max_length;
}
memcpy(property.m_value.str, value_str.data(), string_length);
property.m_value.str[string_length] = 0;
*(property.m_value.string_ptr) = json_property["value"].get<std::string>();
} else {
std::cerr << "Invalid type for property '" << property.m_name
<< "'. Cannot parse json to type '"
@ -263,7 +253,7 @@ bool AnimGraphResource::saveToFile(const char* filename) const {
std::ofstream output_file;
output_file.open(filename);
output_file << to_string(result) << std::endl;
output_file << result.dump(4, ' ') << std::endl;
output_file.close();
return true;
@ -340,18 +330,14 @@ bool AnimGraphResource::loadFromFile(const char* filename) {
return true;
}
AnimGraph AnimGraphResource::createInstance() const {
AnimGraph result;
void AnimGraphResource::createInstance(AnimGraph& result) const {
createRuntimeNodeInstances(result);
prepareGraphIOData(result);
connectRuntimeNodes(result);
setRuntimeNodeProperties(result);
result.updateOrderedNodes();
result.reset();
return result;
result.resetNodeStates();
}
void AnimGraphResource::createRuntimeNodeInstances(AnimGraph& instance) const {
@ -384,8 +370,11 @@ void AnimGraphResource::prepareGraphIOData(AnimGraph& instance) const {
for (int i = 0; i < graph_inputs.size(); i++) {
input_block_size += sizeof(void*);
}
instance.m_input_buffer = new char[input_block_size];
memset(instance.m_input_buffer, 0, input_block_size);
if (input_block_size > 0) {
instance.m_input_buffer = new char[input_block_size];
memset(instance.m_input_buffer, 0, input_block_size);
}
int input_block_offset = 0;
for (int i = 0; i < graph_inputs.size(); i++) {
@ -400,8 +389,11 @@ void AnimGraphResource::prepareGraphIOData(AnimGraph& instance) const {
for (int i = 0; i < graph_outputs.size(); i++) {
output_block_size += graph_outputs[i].m_type_size;
}
instance.m_output_buffer = new char[output_block_size];
memset(instance.m_output_buffer, 0, output_block_size);
if (output_block_size > 0) {
instance.m_output_buffer = new char[output_block_size];
memset(instance.m_output_buffer, 0, output_block_size);
}
int output_block_offset = 0;
for (int i = 0; i < graph_outputs.size(); i++) {
@ -557,9 +549,9 @@ void AnimGraphResource::setRuntimeNodeProperties(AnimGraph& instance) const {
property.m_value.quat);
break;
case SocketType::SocketTypeString:
node_instance_accessor->SetPropertyReferenceValue(
node_instance_accessor->SetPropertyValue(
name,
property.m_value.str);
*property.m_value.string_ptr);
break;
default:
std::cerr << "Invalid socket type "

View File

@ -140,7 +140,7 @@ struct AnimGraphResource {
return false;
}
AnimGraph createInstance() const;
void createInstance(AnimGraph& result) const;
void createRuntimeNodeInstances(AnimGraph& instance) const;
void prepareGraphIOData(AnimGraph& instance) const;

View File

@ -82,6 +82,7 @@ static struct {
float anim_ratio;
bool anim_ratio_ui_override;
bool paused;
bool use_graph = false;
} time;
} state;
@ -311,7 +312,7 @@ int main() {
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_FALSE);
glfwWindowHint(GLFW_SAMPLES, 16);
GLFWwindow* w = glfwCreateWindow(Width, Height, "AnimTestbed", 0, 0);
GLFWwindow* w = glfwCreateWindow(Width, Height, "ATP Editor", 0, 0);
glfwMakeContextCurrent(w);
glfwSwapInterval(1);
@ -378,9 +379,11 @@ int main() {
SkinnedMesh skinned_mesh;
skinned_mesh_resource.createInstance(skinned_mesh);
skinned_mesh.SetCurrentAnimation(0);
AnimGraph anim_graph;
AnimGraphContext anim_graph_context;
state.time.factor = 1.0f;
Camera_Init(&state.camera);
@ -611,6 +614,13 @@ int main() {
ImGui::EndMenu();
}
if (ImGui::Button("Update Runtime Graph")) {
anim_graph.dealloc();
AnimGraphEditorGetRuntimeGraph(anim_graph);
anim_graph_context.m_skeleton = &skinned_mesh.m_skeleton;
anim_graph.init(anim_graph_context);
}
ImGui::EndMainMenuBar();
}
@ -654,8 +664,8 @@ int main() {
}
if (gApplicationConfig.animation_player_widget.visible) {
ImGui::SetNextWindowPos(ImVec2(gApplicationConfig.animation_player_widget.position[0], gApplicationConfig.skinned_mesh_widget.position[1]), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(gApplicationConfig.animation_player_widget.size[0], gApplicationConfig.skinned_mesh_widget.size[1]), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowPos(ImVec2(gApplicationConfig.animation_player_widget.position[0], gApplicationConfig.animation_player_widget.position[1]), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(gApplicationConfig.animation_player_widget.size[0], gApplicationConfig.animation_player_widget.size[1]), ImGuiCond_FirstUseEver);
ImGui::Begin("Animation Player", &gApplicationConfig.animation_player_widget.visible);
@ -667,16 +677,28 @@ int main() {
gApplicationConfig.animation_player_widget.size[0] = animation_player_widget_size.x;
gApplicationConfig.animation_player_widget.size[1] = animation_player_widget_size.y;
ImGui::Text("Animation");
const char* items[255] = {0};
static int selected = -1;
for (int i = 0; i < skinned_mesh.m_animations.size(); i++) {
items[i] = skinned_mesh.m_animation_names[i].c_str();
if (anim_graph.m_nodes.size() > 0) {
ImGui::Checkbox("Use Graph", &state.time.use_graph);
} else {
state.time.use_graph = false;
}
if (ImGui::Combo("Animation", &selected, items, skinned_mesh.m_animations.size())) {
state.ozz.animation = skinned_mesh.m_animations[selected];
if (!state.time.use_graph) {
ImGui::Text("Animation");
const char* items[255] = {0};
static int selected = -1;
for (int i = 0; i < skinned_mesh.m_animations.size(); i++) {
items[i] = skinned_mesh.m_animation_names[i].c_str();
}
if (ImGui::Combo(
"Animation",
&selected,
items,
skinned_mesh.m_animations.size())) {
state.ozz.animation = skinned_mesh.m_animations[selected];
}
}
if (state.time.paused) {

View File

@ -190,8 +190,8 @@ TEST_CASE_METHOD(
graph_context.m_animation_map["trans_y"] = animation_translate_y.get();
// Instantiate graph
AnimGraph graph = graph_resource.createInstance();
graph_context.m_graph = &graph;
AnimGraph graph;
graph_resource.createInstance(graph);
graph.init(graph_context);
// Get runtime graph inputs and outputs

View File

@ -74,9 +74,9 @@ TEST_CASE("BasicGraph", "[AnimGraphResource]") {
AnimGraphResource graph_resource_loaded;
graph_resource_loaded.loadFromFile("WalkGraph.animgraph.json");
AnimGraph graph = graph_resource_loaded.createInstance();
AnimGraph graph;
graph_resource_loaded.createInstance(graph);
AnimGraphContext graph_context;
graph_context.m_graph = &graph;
ozz::animation::Skeleton skeleton;
REQUIRE(load_skeleton(skeleton, "data/skeleton.ozz"));
@ -283,7 +283,8 @@ TEST_CASE("ResourceSaveLoadMathGraphInputs", "[AnimGraphResource]") {
!= nullptr);
WHEN("Instantiating an AnimGraph") {
AnimGraph anim_graph = graph_resource_loaded.createInstance();
AnimGraph anim_graph;
graph_resource_loaded.createInstance(anim_graph);
REQUIRE(anim_graph.getInputSocket("GraphFloatInput") != nullptr);
REQUIRE(
@ -418,7 +419,8 @@ TEST_CASE("SimpleMathEvaluations", "[AnimGraphResource]") {
graph_resource_loaded.m_nodes[1];
WHEN("Instantiating an AnimGraph") {
AnimGraph anim_graph = graph_resource_loaded.createInstance();
AnimGraph anim_graph;
graph_resource_loaded.createInstance(anim_graph);
REQUIRE(anim_graph.getInputSocket("GraphFloatInput") != nullptr);
REQUIRE(
@ -495,12 +497,12 @@ TEST_CASE("SimpleMathEvaluations", "[AnimGraphResource]") {
}
TEST_CASE("GraphInputOutputConnectivity", "[AnimGraphResource]") {
AnimGraphResource graph_resource;
AnimGraphResource sGraphGresource;
graph_resource.clear();
graph_resource.m_name = "TestGraphInputOutputConnectivity";
sGraphGresource.clear();
sGraphGresource.m_name = "TestGraphInputOutputConnectivity";
AnimNodeResource& graph_output_node = graph_resource.m_nodes[0];
AnimNodeResource& graph_output_node = sGraphGresource.m_nodes[0];
graph_output_node.m_socket_accessor->RegisterInput<float>(
"GraphFloatOutput",
nullptr);
@ -508,7 +510,7 @@ TEST_CASE("GraphInputOutputConnectivity", "[AnimGraphResource]") {
"GraphAnimOutput",
nullptr);
AnimNodeResource& graph_input_node = graph_resource.m_nodes[1];
AnimNodeResource& graph_input_node = sGraphGresource.m_nodes[1];
graph_input_node.m_socket_accessor->RegisterOutput<float>(
"GraphFloatInput",
nullptr);
@ -523,13 +525,13 @@ TEST_CASE("GraphInputOutputConnectivity", "[AnimGraphResource]") {
nullptr);
WHEN("Connecting float input with float output") {
REQUIRE(graph_resource.connectSockets(
graph_resource.getGraphInputNode(),
REQUIRE(sGraphGresource.connectSockets(
sGraphGresource.getGraphInputNode(),
"GraphFloatInput",
graph_resource.getGraphOutputNode(),
sGraphGresource.getGraphOutputNode(),
"GraphFloatOutput"));
AnimGraph anim_graph = graph_resource.createInstance();
AnimGraph anim_graph = sGraphGresource.createInstance();
THEN("Writing to the input pointer changes the value of the output.") {
float* float_input_ptr = (float*)anim_graph.getInput("GraphFloatInput");
@ -545,18 +547,18 @@ TEST_CASE("GraphInputOutputConnectivity", "[AnimGraphResource]") {
WHEN("Connecting adding a Blend2 node") {
size_t blend2_node_index =
graph_resource.addNode(AnimNodeResourceFactory("Blend2"));
sGraphGresource.addNode(AnimNodeResourceFactory("Blend2"));
AnimNodeResource& blend2_node_resource =
graph_resource.m_nodes[blend2_node_index];
sGraphGresource.m_nodes[blend2_node_index];
REQUIRE(graph_resource.connectSockets(
graph_resource.getGraphInputNode(),
REQUIRE(sGraphGresource.connectSockets(
sGraphGresource.getGraphInputNode(),
"GraphFloatInput",
blend2_node_resource,
"Weight"));
THEN("Connected float input points to the blend weight.") {
AnimGraph anim_graph = graph_resource.createInstance();
AnimGraph anim_graph = sGraphGresource.createInstance();
Blend2Node* blend2_node =
dynamic_cast<Blend2Node*>(anim_graph.m_nodes[blend2_node_index]);
@ -571,28 +573,28 @@ TEST_CASE("GraphInputOutputConnectivity", "[AnimGraphResource]") {
WHEN(
"Connecting AnimData inputs to blend2 node and blend2 output to graph "
"output.") {
REQUIRE(graph_resource.connectSockets(
graph_resource.getGraphInputNode(),
REQUIRE(sGraphGresource.connectSockets(
sGraphGresource.getGraphInputNode(),
"GraphAnimInput0",
blend2_node_resource,
"Input0"));
REQUIRE(graph_resource.connectSockets(
graph_resource.getGraphInputNode(),
REQUIRE(sGraphGresource.connectSockets(
sGraphGresource.getGraphInputNode(),
"GraphAnimInput1",
blend2_node_resource,
"Input1"));
REQUIRE(graph_resource.connectSockets(
REQUIRE(sGraphGresource.connectSockets(
blend2_node_resource,
"Output",
graph_resource.getGraphOutputNode(),
sGraphGresource.getGraphOutputNode(),
"GraphAnimOutput"));
THEN(
"AnimData from output gets blended and result is written to "
"Output.") {
AnimGraph anim_graph = graph_resource.createInstance();
AnimGraph anim_graph = sGraphGresource.createInstance();
Blend2Node* blend2_node =
dynamic_cast<Blend2Node*>(anim_graph.m_nodes[blend2_node_index]);
@ -623,57 +625,57 @@ TEST_CASE("GraphInputOutputConnectivity", "[AnimGraphResource]") {
WHEN("Adding AnimSampler Nodes") {
size_t blend2_node_index =
graph_resource.addNode(AnimNodeResourceFactory("Blend2"));
sGraphGresource.addNode(AnimNodeResourceFactory("Blend2"));
size_t sampler_node_index =
graph_resource.addNode(AnimNodeResourceFactory("AnimSampler"));
sGraphGresource.addNode(AnimNodeResourceFactory("AnimSampler"));
size_t speed_scale_node_index =
graph_resource.addNode(AnimNodeResourceFactory("SpeedScale"));
sGraphGresource.addNode(AnimNodeResourceFactory("SpeedScale"));
AnimNodeResource& blend2_node_resource =
graph_resource.m_nodes[blend2_node_index];
sGraphGresource.m_nodes[blend2_node_index];
AnimNodeResource& sampler_node_resource =
graph_resource.m_nodes[sampler_node_index];
sGraphGresource.m_nodes[sampler_node_index];
AnimNodeResource& speed_scale_node_resource =
graph_resource.m_nodes[speed_scale_node_index];
sGraphGresource.m_nodes[speed_scale_node_index];
REQUIRE(graph_resource.connectSockets(
graph_resource.getGraphInputNode(),
REQUIRE(sGraphGresource.connectSockets(
sGraphGresource.getGraphInputNode(),
"GraphFloatInput",
blend2_node_resource,
"Weight"));
REQUIRE(graph_resource.connectSockets(
graph_resource.getGraphInputNode(),
REQUIRE(sGraphGresource.connectSockets(
sGraphGresource.getGraphInputNode(),
"SpeedScaleInput",
speed_scale_node_resource,
"SpeedScale"));
REQUIRE(graph_resource.connectSockets(
graph_resource.getGraphInputNode(),
REQUIRE(sGraphGresource.connectSockets(
sGraphGresource.getGraphInputNode(),
"GraphAnimInput0",
blend2_node_resource,
"Input0"));
REQUIRE(graph_resource.connectSockets(
REQUIRE(sGraphGresource.connectSockets(
sampler_node_resource,
"Output",
speed_scale_node_resource,
"Input"));
REQUIRE(graph_resource.connectSockets(
REQUIRE(sGraphGresource.connectSockets(
speed_scale_node_resource,
"Output",
blend2_node_resource,
"Input1"));
REQUIRE(graph_resource.connectSockets(
REQUIRE(sGraphGresource.connectSockets(
blend2_node_resource,
"Output",
graph_resource.getGraphOutputNode(),
sGraphGresource.getGraphOutputNode(),
"GraphAnimOutput"));
THEN("Data flow and node ordering must be correct.") {
AnimGraph anim_graph = graph_resource.createInstance();
AnimGraph anim_graph = sGraphGresource.createInstance();
Blend2Node* blend2_node =
dynamic_cast<Blend2Node*>(anim_graph.m_nodes[blend2_node_index]);
SpeedScaleNode* speed_scale_node = dynamic_cast<SpeedScaleNode*>(
@ -727,7 +729,7 @@ TEST_CASE("GraphInputOutputConnectivity", "[AnimGraphResource]") {
}
WHEN("Instantiating graph") {
AnimGraph anim_graph = graph_resource.createInstance();
AnimGraph anim_graph = sGraphGresource.createInstance();
float* blend_weight_input =
reinterpret_cast<float*>(anim_graph.getInput("GraphFloatInput"));