Started working on graph initialization in ATP Editor.
parent
a1931185d8
commit
e38c0b4934
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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 "
|
||||
|
|
|
@ -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;
|
||||
|
|
46
src/main.cc
46
src/main.cc
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"));
|
||||
|
||||
|
|
Loading…
Reference in New Issue