Compare commits
	
		
			No commits in common. "bd304bde4e2da15a4aebc3bedbee6ea0427df7e0" and "0d0b181ebb2446bea72704b7d43c308fb80b88f1" have entirely different histories.
		
	
	
		
			bd304bde4e
			...
			0d0b181ebb
		
	
		
@ -7,8 +7,6 @@
 | 
			
		||||
#include "AnimGraphResource.h"
 | 
			
		||||
#include "imnodes.h"
 | 
			
		||||
 | 
			
		||||
using namespace AnimGraphCode;
 | 
			
		||||
 | 
			
		||||
ImNodesPinShape sGetSocketShapeFromSocketType(const SocketType& socket_type) {
 | 
			
		||||
  switch (socket_type) {
 | 
			
		||||
    case SocketType::SocketTypeAnimation:
 | 
			
		||||
@ -28,52 +26,6 @@ ImNodesPinShape sGetSocketShapeFromSocketType(const SocketType& socket_type) {
 | 
			
		||||
  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() {
 | 
			
		||||
  static AnimGraphResource graph_resource = AnimGraphResource();
 | 
			
		||||
 | 
			
		||||
@ -106,11 +58,6 @@ void AnimGraphEditorUpdate() {
 | 
			
		||||
 | 
			
		||||
  ImGui::EndMenuBar();
 | 
			
		||||
 | 
			
		||||
  ImGui::Columns(2);
 | 
			
		||||
 | 
			
		||||
  //
 | 
			
		||||
  // Node editor canvas
 | 
			
		||||
  //
 | 
			
		||||
  ImNodes::BeginNodeEditor();
 | 
			
		||||
 | 
			
		||||
  // Popup menu
 | 
			
		||||
@ -175,20 +122,13 @@ void AnimGraphEditorUpdate() {
 | 
			
		||||
        node_resource.m_socket_accessor->m_inputs;
 | 
			
		||||
    for (size_t j = 0, ni = node_inputs.size(); j < ni; 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(
 | 
			
		||||
          GenerateInputAttributeId(i, j),
 | 
			
		||||
          sGetSocketShapeFromSocketType(socket.m_type),
 | 
			
		||||
          socket_color);
 | 
			
		||||
          ImColor(255, 255, 255, 255));
 | 
			
		||||
      ImGui::Text(socket.m_name.c_str());
 | 
			
		||||
 | 
			
		||||
      ImNodes::PushAttributeFlag(
 | 
			
		||||
          ImNodesAttributeFlags_EnableLinkDetachWithDragClick);
 | 
			
		||||
      ImNodes::PushAttributeFlag(ImNodesAttributeFlags_EnableLinkDetachWithDragClick);
 | 
			
		||||
      ImNodes::EndInputAttribute();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -202,21 +142,19 @@ void AnimGraphEditorUpdate() {
 | 
			
		||||
          sGetSocketShapeFromSocketType(socket.m_type),
 | 
			
		||||
          ImColor(255, 255, 255, 255));
 | 
			
		||||
      ImGui::Text(socket.m_name.c_str());
 | 
			
		||||
      ImNodes::PushAttributeFlag(
 | 
			
		||||
          ImNodesAttributeFlags_EnableLinkDetachWithDragClick);
 | 
			
		||||
      ImNodes::PushAttributeFlag(ImNodesAttributeFlags_EnableLinkDetachWithDragClick);
 | 
			
		||||
      ImNodes::EndInputAttribute();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Graph output node
 | 
			
		||||
    if (i == 0) {
 | 
			
		||||
      if (ImGui::Button("+Output")) {
 | 
			
		||||
        AnimNodeResource& graph_output_node =
 | 
			
		||||
            graph_resource.getGraphOutputNode();
 | 
			
		||||
        AnimNodeResource& graph_output_node = graph_resource.getGraphOutputNode();
 | 
			
		||||
 | 
			
		||||
        static float bla = 0.f;
 | 
			
		||||
        std::string socket_name = "Output";
 | 
			
		||||
        socket_name += std::to_string(
 | 
			
		||||
            graph_output_node.m_socket_accessor->m_inputs.size());
 | 
			
		||||
        socket_name +=
 | 
			
		||||
            std::to_string(graph_output_node.m_socket_accessor->m_inputs.size());
 | 
			
		||||
        graph_output_node.m_socket_accessor->RegisterInput<float>(
 | 
			
		||||
            socket_name,
 | 
			
		||||
            nullptr);
 | 
			
		||||
@ -227,8 +165,8 @@ void AnimGraphEditorUpdate() {
 | 
			
		||||
 | 
			
		||||
        static float bla = 0.f;
 | 
			
		||||
        std::string socket_name = "Input";
 | 
			
		||||
        socket_name += std::to_string(
 | 
			
		||||
            graph_input_node.m_socket_accessor->m_outputs.size());
 | 
			
		||||
        socket_name +=
 | 
			
		||||
            std::to_string(graph_input_node.m_socket_accessor->m_outputs.size());
 | 
			
		||||
        graph_input_node.m_socket_accessor->RegisterOutput<float>(
 | 
			
		||||
            socket_name,
 | 
			
		||||
            nullptr);
 | 
			
		||||
@ -240,9 +178,6 @@ void AnimGraphEditorUpdate() {
 | 
			
		||||
    node_resource.m_position[0] = node_pos[0];
 | 
			
		||||
    node_resource.m_position[1] = node_pos[1];
 | 
			
		||||
    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++) {
 | 
			
		||||
@ -285,25 +220,6 @@ void AnimGraphEditorUpdate() {
 | 
			
		||||
  // Handle link detachements.
 | 
			
		||||
  int link_id = 0;
 | 
			
		||||
  if (ImNodes::IsLinkDestroyed(&link_id)) {
 | 
			
		||||
    graph_resource.m_connections.erase(
 | 
			
		||||
        graph_resource.m_connections.begin() + link_id);
 | 
			
		||||
    graph_resource.m_connections.erase(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"
 | 
			
		||||
 | 
			
		||||
namespace AnimGraphCode {
 | 
			
		||||
 | 
			
		||||
using json = nlohmann::json;
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
@ -47,31 +45,6 @@ json sSocketToJson(const Socket& socket) {
 | 
			
		||||
  json result;
 | 
			
		||||
  result["name"] = socket.m_name;
 | 
			
		||||
  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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -122,12 +95,6 @@ json sAnimGraphNodeToJson(const AnimNodeResource& node) {
 | 
			
		||||
    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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -143,49 +110,6 @@ AnimNodeResource sAnimGraphNodeFromJson(const json& json_node) {
 | 
			
		||||
  result.m_socket_accessor =
 | 
			
		||||
      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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -220,14 +144,6 @@ AnimGraphConnection sAnimGraphConnectionFromJson(const json& json_node) {
 | 
			
		||||
 | 
			
		||||
void AnimGraphResource::clear() {
 | 
			
		||||
  m_name = "";
 | 
			
		||||
 | 
			
		||||
  clearNodes();
 | 
			
		||||
  m_connections.clear();
 | 
			
		||||
 | 
			
		||||
  initGraphConnectors();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AnimGraphResource::clearNodes() {
 | 
			
		||||
  for (size_t i = 0; i < m_nodes.size(); i++) {
 | 
			
		||||
    delete m_nodes[i].m_socket_accessor;
 | 
			
		||||
    m_nodes[i].m_socket_accessor = nullptr;
 | 
			
		||||
@ -235,13 +151,13 @@ void AnimGraphResource::clearNodes() {
 | 
			
		||||
    m_nodes[i].m_anim_node = nullptr;
 | 
			
		||||
  }
 | 
			
		||||
  m_nodes.clear();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AnimGraphResource::initGraphConnectors() {
 | 
			
		||||
  m_nodes.push_back(AnimNodeResourceFactory("BlendTree"));
 | 
			
		||||
  m_nodes[0].m_name = "Outputs";
 | 
			
		||||
  m_nodes.push_back(AnimNodeResourceFactory("BlendTree"));
 | 
			
		||||
  m_nodes[1].m_name = "Inputs";
 | 
			
		||||
 | 
			
		||||
  m_connections.clear();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool AnimGraphResource::saveToFile(const char* filename) const {
 | 
			
		||||
@ -304,7 +220,6 @@ bool AnimGraphResource::loadFromFile(const char* filename) {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  clear();
 | 
			
		||||
  clearNodes();
 | 
			
		||||
 | 
			
		||||
  m_name = json_data["name"];
 | 
			
		||||
  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]));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
  return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AnimGraph::MarkActiveNodes() {
 | 
			
		||||
  m_frame_counter++;
 | 
			
		||||
 | 
			
		||||
  // TODO: start from output and trigger updating of the frame counter.
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* AnimGraph::GetOutput(const std::string& name) const {
 | 
			
		||||
void* AnimGraph::GetOutput(const std::string& name) {
 | 
			
		||||
  Socket* socket = m_socket_accessor->FindInputSocket(name);
 | 
			
		||||
  if (socket == nullptr) {
 | 
			
		||||
    return nullptr;
 | 
			
		||||
@ -366,13 +275,11 @@ void* AnimGraph::GetOutput(const std::string& name) const {
 | 
			
		||||
  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);
 | 
			
		||||
  if (socket == nullptr) {
 | 
			
		||||
    return nullptr;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return *(socket->m_value.ptr_ptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -14,8 +14,6 @@
 | 
			
		||||
 | 
			
		||||
#include "SyncTrack.h"
 | 
			
		||||
 | 
			
		||||
namespace AnimGraphCode {
 | 
			
		||||
 | 
			
		||||
enum class SocketType {
 | 
			
		||||
  SocketTypeUndefined,
 | 
			
		||||
  SocketTypeBool,
 | 
			
		||||
@ -26,8 +24,6 @@ enum class SocketType {
 | 
			
		||||
  SocketTypeString
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum SocketFlags { SocketFlagAffectsTime = 1 };
 | 
			
		||||
 | 
			
		||||
struct AnimData {
 | 
			
		||||
  float m_bone_transforms[16];
 | 
			
		||||
};
 | 
			
		||||
@ -65,7 +61,6 @@ struct Socket {
 | 
			
		||||
    void** ptr_ptr;
 | 
			
		||||
  };
 | 
			
		||||
  SocketValue m_value = {nullptr};
 | 
			
		||||
  int m_flags = 0;
 | 
			
		||||
  size_t m_type_size = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -89,21 +84,13 @@ struct AnimNode {
 | 
			
		||||
  bool m_is_time_synced;
 | 
			
		||||
  float m_time_now;
 | 
			
		||||
  float m_time_last;
 | 
			
		||||
  int m_frame_counter = 0;
 | 
			
		||||
  SyncTrack m_sync_track;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct AnimNodeInput {
 | 
			
		||||
  AnimNode* m_node;
 | 
			
		||||
  std::string m_input_name;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct NodeSocketAccessorBase {
 | 
			
		||||
  NodeSocketAccessorBase() {}
 | 
			
		||||
  virtual ~NodeSocketAccessorBase() {}
 | 
			
		||||
 | 
			
		||||
  virtual void UpdateFlags(){};
 | 
			
		||||
 | 
			
		||||
  Socket* FindSocket(std::vector<Socket>& sockets, const std::string& name) {
 | 
			
		||||
    Socket* result = nullptr;
 | 
			
		||||
    for (size_t i = 0, n = sockets.size(); i < n; i++) {
 | 
			
		||||
@ -153,40 +140,11 @@ struct NodeSocketAccessorBase {
 | 
			
		||||
    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>
 | 
			
		||||
  bool RegisterSocket(
 | 
			
		||||
      std::vector<Socket>& sockets,
 | 
			
		||||
      const std::string& name,
 | 
			
		||||
      T* value_ptr,
 | 
			
		||||
      int flags = 0) {
 | 
			
		||||
      T* value_ptr) {
 | 
			
		||||
    Socket* socket = FindSocket(sockets, name);
 | 
			
		||||
    if (socket != nullptr) {
 | 
			
		||||
      std::cerr << "Socket " << name << " already registered." << std::endl;
 | 
			
		||||
@ -197,7 +155,6 @@ struct NodeSocketAccessorBase {
 | 
			
		||||
    socket = &sockets[sockets.size() - 1];
 | 
			
		||||
    socket->m_name = name;
 | 
			
		||||
    socket->m_type_size = sizeof(T);
 | 
			
		||||
    socket->m_flags = flags;
 | 
			
		||||
 | 
			
		||||
    if constexpr (std::is_same<T, float>::value) {
 | 
			
		||||
      socket->m_type = SocketType::SocketTypeFloat;
 | 
			
		||||
@ -237,20 +194,20 @@ struct NodeSocketAccessorBase {
 | 
			
		||||
    return RegisterSocket(m_properties, name, value);
 | 
			
		||||
  }
 | 
			
		||||
  template <typename T>
 | 
			
		||||
  void SetProperty(const std::string& name, const T& value) {
 | 
			
		||||
    SetSocketValue(m_properties, name, value);
 | 
			
		||||
  bool SetProperty(const std::string& name, T value) {
 | 
			
		||||
    return SetSocketValue(m_properties, name, value);
 | 
			
		||||
  }
 | 
			
		||||
  template <typename T>
 | 
			
		||||
  T GetProperty(const std::string& name, T default_value) {
 | 
			
		||||
    return GetSocketValue(m_properties, name, default_value);
 | 
			
		||||
  T GetProperty(const std::string& name, T value) {
 | 
			
		||||
    return GetSocketValue(m_properties, name, value);
 | 
			
		||||
  }
 | 
			
		||||
  SocketType GetPropertyType(const std::string& name) {
 | 
			
		||||
    return GetSocketType(m_properties, name);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  template <typename T>
 | 
			
		||||
  bool RegisterInput(const std::string& name, T* value, int flags = 0) {
 | 
			
		||||
    return RegisterSocket(m_inputs, name, value, flags);
 | 
			
		||||
  bool RegisterInput(const std::string& name, T* value) {
 | 
			
		||||
    return RegisterSocket(m_inputs, name, value);
 | 
			
		||||
  }
 | 
			
		||||
  template <typename T>
 | 
			
		||||
  T* GetInput(const std::string& name, T* value) {
 | 
			
		||||
@ -267,8 +224,8 @@ struct NodeSocketAccessorBase {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  template <typename T>
 | 
			
		||||
  bool RegisterOutput(const std::string& name, T** value, int flags = 0) {
 | 
			
		||||
    return RegisterSocket(m_outputs, name, value, flags);
 | 
			
		||||
  bool RegisterOutput(const std::string& name, T** value) {
 | 
			
		||||
    return RegisterSocket(m_outputs, name, value);
 | 
			
		||||
  }
 | 
			
		||||
  SocketType GetOutputType(const std::string& name) {
 | 
			
		||||
    return GetSocketType(m_outputs, name);
 | 
			
		||||
@ -318,26 +275,12 @@ struct NodeSocketAccessor<Blend2Node> : public NodeSocketAccessorBase {
 | 
			
		||||
    Blend2Node* node = dynamic_cast<Blend2Node*>(node_);
 | 
			
		||||
    RegisterInput("Input0", &node->m_input0);
 | 
			
		||||
    RegisterInput("Input1", &node->m_input1);
 | 
			
		||||
    RegisterInput(
 | 
			
		||||
        "Weight",
 | 
			
		||||
        &node->m_blend_weight,
 | 
			
		||||
        SocketFlags::SocketFlagAffectsTime);
 | 
			
		||||
    RegisterInput("Weight", &node->m_blend_weight);
 | 
			
		||||
 | 
			
		||||
    RegisterOutput("Output", &node->m_output);
 | 
			
		||||
 | 
			
		||||
    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 {
 | 
			
		||||
@ -350,10 +293,7 @@ template <>
 | 
			
		||||
struct NodeSocketAccessor<SpeedScaleNode> : public NodeSocketAccessorBase {
 | 
			
		||||
  NodeSocketAccessor(AnimNode* node_) {
 | 
			
		||||
    SpeedScaleNode* node = dynamic_cast<SpeedScaleNode*>(node_);
 | 
			
		||||
    RegisterInput(
 | 
			
		||||
        "SpeedScale",
 | 
			
		||||
        &node->m_speed_scale,
 | 
			
		||||
        SocketFlags::SocketFlagAffectsTime);
 | 
			
		||||
    RegisterInput("SpeedScale", &node->m_speed_scale);
 | 
			
		||||
    RegisterInput("Input", &node->m_input);
 | 
			
		||||
 | 
			
		||||
    RegisterOutput("Output", &node->m_output);
 | 
			
		||||
@ -397,14 +337,16 @@ struct AnimGraphResource {
 | 
			
		||||
  AnimGraphResource() { clear(); }
 | 
			
		||||
 | 
			
		||||
  void clear();
 | 
			
		||||
  void clearNodes();
 | 
			
		||||
  void initGraphConnectors();
 | 
			
		||||
  bool saveToFile(const char* filename) const;
 | 
			
		||||
  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) {
 | 
			
		||||
    m_nodes.push_back(node_resource);
 | 
			
		||||
@ -521,19 +463,12 @@ struct AnimGraph {
 | 
			
		||||
    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 Evaluate();
 | 
			
		||||
 | 
			
		||||
  int m_frame_counter;
 | 
			
		||||
  AnimData m_local_transforms;
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
  char* m_input_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>& GetGraphInputs() { return m_socket_accessor->m_outputs; }
 | 
			
		||||
 | 
			
		||||
  void* GetOutput(const std::string& name) const;
 | 
			
		||||
  void* GetInput(const std::string& name) const;
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
  }
 | 
			
		||||
  void* GetOutput(const std::string& name);
 | 
			
		||||
  void* GetInput(const std::string& name);
 | 
			
		||||
 | 
			
		||||
  AnimNode* getAnimNode(const char* name) {
 | 
			
		||||
    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_node_type_name = node_resource.m_type_name;
 | 
			
		||||
      result.m_nodes.push_back(node);
 | 
			
		||||
 | 
			
		||||
      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);
 | 
			
		||||
      }
 | 
			
		||||
      result.m_node_inputs.push_back(std::vector<AnimNode*>());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Prepare graph inputs
 | 
			
		||||
@ -731,14 +636,7 @@ struct AnimGraph {
 | 
			
		||||
      (*source_socket->m_value.ptr_ptr) = target_socket->m_value.ptr;
 | 
			
		||||
 | 
			
		||||
      size_t target_node_index = result.getAnimNodeIndex(target_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;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      result.m_node_inputs[target_node_index].push_back(source_node);
 | 
			
		||||
 | 
			
		||||
      if (target_node_accessor != result.m_socket_accessor) {
 | 
			
		||||
        delete target_node_accessor;
 | 
			
		||||
@ -753,6 +651,4 @@ struct AnimGraph {
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace AnimGraphCode
 | 
			
		||||
 | 
			
		||||
#endif  //ANIMTESTBED_ANIMGRAPHRESOURCE_H
 | 
			
		||||
 | 
			
		||||
@ -5,8 +5,6 @@
 | 
			
		||||
#include "AnimGraphResource.h"
 | 
			
		||||
#include "catch.hpp"
 | 
			
		||||
 | 
			
		||||
using namespace AnimGraphCode;
 | 
			
		||||
 | 
			
		||||
TEST_CASE("BasicGraph", "[AnimGraphResource]") {
 | 
			
		||||
  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_index1].size() == 0);
 | 
			
		||||
  CHECK(graph.m_node_inputs[blend_index].size() == 3);
 | 
			
		||||
  CHECK(graph.m_node_inputs[blend_index][0].m_node == anim_sampler_instance0);
 | 
			
		||||
  CHECK(graph.m_node_inputs[blend_index][1].m_node == anim_sampler_instance1);
 | 
			
		||||
  CHECK(graph.m_node_inputs[blend_index][2].m_node == nullptr);
 | 
			
		||||
  CHECK(graph.m_node_inputs[blend_index].size() == 2);
 | 
			
		||||
  CHECK(graph.m_node_inputs[blend_index][0] == anim_sampler_instance0);
 | 
			
		||||
  CHECK(graph.m_node_inputs[blend_index][1] == anim_sampler_instance1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE("InputAttributeConversion", "[AnimGraphResource]") {
 | 
			
		||||
@ -327,15 +324,12 @@ TEST_CASE("GraphInputOutputConnectivity", "[AnimGraphResource]") {
 | 
			
		||||
 | 
			
		||||
        AnimData* graph_input0 = (AnimData*) anim_graph.GetInput("GraphAnimInput0");
 | 
			
		||||
        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");
 | 
			
		||||
        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");
 | 
			
		||||
        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