Added NodeConnectionDebug tool.
This commit is contained in:
		
							parent
							
								
									55bcd9cd99
								
							
						
					
					
						commit
						a2e8de0b70
					
				| @ -24,9 +24,29 @@ struct EditorState { | ||||
| 
 | ||||
|   bool isGraphLoadedThisFrame = false; | ||||
|   ImVec2 mousePopupStart = {}; | ||||
|   char statusLine[1024] = {}; | ||||
| }; | ||||
| 
 | ||||
| struct NodeConnectionDebugState { | ||||
|   struct SocketInfo { | ||||
|     ax::NodeEditor::PinId pin = {}; | ||||
|     int nodeId = {}; | ||||
|     const AnimNodeResource* nodeResource = {}; | ||||
|     int socketId = {}; | ||||
|     const Socket* socket = {}; | ||||
|   }; | ||||
| 
 | ||||
|   SocketInfo sourceSocket = {}; | ||||
|   SocketInfo targetSocket = {}; | ||||
| 
 | ||||
|   void Reset() { | ||||
|     sourceSocket = {}; | ||||
|     targetSocket = {}; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| static EditorState sEditorState; | ||||
| static NodeConnectionDebugState sNodeConnectionDebugState; | ||||
| 
 | ||||
| constexpr int cPinIconSize = 24; | ||||
| 
 | ||||
| @ -503,56 +523,98 @@ void AnimGraphEditorBreadcrumbNavigation() { | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void HandleConnectionCreation( | ||||
|     BlendTreeResource& current_blend_tree) {  // Create Connections
 | ||||
| void HandleConnectionCreation(BlendTreeResource& current_blend_tree) { | ||||
|   if (ax::NodeEditor::BeginCreate()) { | ||||
|     ax::NodeEditor::PinId input_pin_id, output_pin_id; | ||||
|     if (ax::NodeEditor::QueryNewLink(&input_pin_id, &output_pin_id)) { | ||||
|       int source_node_index; | ||||
|       int source_node_socket_index; | ||||
|       ax::NodeEditor::PinId source_pin = input_pin_id; | ||||
|       ax::NodeEditor::PinId target_pin = output_pin_id; | ||||
| 
 | ||||
|       int source_node_index = -1; | ||||
|       int source_node_socket_index = -1; | ||||
|       const AnimNodeResource* source_node = nullptr; | ||||
|       const Socket* source_socket = nullptr; | ||||
| 
 | ||||
|       if (input_pin_id) { | ||||
|         if (IsPinInput(input_pin_id.Get())) { | ||||
|           source_pin = input_pin_id; | ||||
|           target_pin = output_pin_id; | ||||
|         } else { | ||||
|           target_pin = input_pin_id; | ||||
|           source_pin = output_pin_id; | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       if (output_pin_id) { | ||||
|         if (IsPinOutput(output_pin_id.Get())) { | ||||
|           target_pin = output_pin_id; | ||||
|           source_pin = input_pin_id; | ||||
|         } else { | ||||
|           source_pin = output_pin_id; | ||||
|           target_pin = input_pin_id; | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       if (source_pin) { | ||||
|         OutputPinIdToNodeIndexAndSocketIndex( | ||||
|             input_pin_id.Get(), | ||||
|             source_pin.Get(), | ||||
|             &source_node_index, | ||||
|             &source_node_socket_index); | ||||
| 
 | ||||
|         source_node = current_blend_tree.GetNode(source_node_index); | ||||
|         if (source_node->m_virtual_socket_accessor->m_outputs.size() | ||||
|             < source_node_socket_index) { | ||||
|           source_node_socket_index = -1; | ||||
|         } else { | ||||
|           source_socket = current_blend_tree.GetNodeOutputSocketByIndex( | ||||
|               source_node, | ||||
|               source_node_socket_index); | ||||
| 
 | ||||
|         if (source_node != nullptr) { | ||||
|           if (source_node->m_virtual_socket_accessor->m_outputs.size() | ||||
|               < source_node_socket_index) { | ||||
|             source_node_socket_index = -1; | ||||
|           } else { | ||||
|             source_socket = current_blend_tree.GetNodeOutputSocketByIndex( | ||||
|                 source_node, | ||||
|                 source_node_socket_index); | ||||
|           } | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       int target_node_index; | ||||
|       int target_node_socket_index; | ||||
|       int target_node_index = -1; | ||||
|       int target_node_socket_index = -1; | ||||
|       const AnimNodeResource* target_node = nullptr; | ||||
|       const Socket* target_socket = nullptr; | ||||
| 
 | ||||
|       if (output_pin_id) { | ||||
|       if (target_pin) { | ||||
|         InputPinIdToNodeIndexAndSocketIndex( | ||||
|             output_pin_id.Get(), | ||||
|             target_pin.Get(), | ||||
|             &target_node_index, | ||||
|             &target_node_socket_index); | ||||
| 
 | ||||
|         target_node = current_blend_tree.GetNode(target_node_index); | ||||
|         if (target_node->m_virtual_socket_accessor->m_inputs.size() | ||||
|             < target_node_socket_index) { | ||||
|           target_node_socket_index = -1; | ||||
|         } else { | ||||
|           target_socket = current_blend_tree.GetNodeInputSocketByIndex( | ||||
|               target_node, | ||||
|               target_node_socket_index); | ||||
| 
 | ||||
|         if (target_node != nullptr) { | ||||
|           if (target_node->m_virtual_socket_accessor->m_inputs.size() | ||||
|               < target_node_socket_index) { | ||||
|             target_node_socket_index = -1; | ||||
|           } else { | ||||
|             target_socket = current_blend_tree.GetNodeInputSocketByIndex( | ||||
|                 target_node, | ||||
|                 target_node_socket_index); | ||||
|           } | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       if (input_pin_id && output_pin_id) { | ||||
|       sNodeConnectionDebugState.sourceSocket.pin = source_pin; | ||||
|       sNodeConnectionDebugState.sourceSocket.nodeId = source_node_index; | ||||
|       sNodeConnectionDebugState.sourceSocket.nodeResource = source_node; | ||||
|       sNodeConnectionDebugState.sourceSocket.socketId = | ||||
|           source_node_socket_index; | ||||
|       sNodeConnectionDebugState.sourceSocket.socket = source_socket; | ||||
| 
 | ||||
|       sNodeConnectionDebugState.targetSocket.pin = target_pin; | ||||
|       sNodeConnectionDebugState.targetSocket.nodeId = target_node_index; | ||||
|       sNodeConnectionDebugState.targetSocket.nodeResource = target_node; | ||||
|       sNodeConnectionDebugState.targetSocket.socketId = | ||||
|           target_node_socket_index; | ||||
|       sNodeConnectionDebugState.targetSocket.socket = target_socket; | ||||
| 
 | ||||
|       if (source_pin && target_pin) { | ||||
|         if (source_socket == nullptr || target_socket == nullptr | ||||
|             || !current_blend_tree.IsConnectionValid( | ||||
|                 source_node, | ||||
| @ -605,9 +667,12 @@ void BlendTreeRenderNodes( | ||||
|         current_blend_tree.GetNodeInputSockets(node_resource); | ||||
|     for (size_t j = 0, ni = node_inputs.size(); j < ni; j++) { | ||||
|       Socket& socket = node_inputs[j]; | ||||
|       builder.Input(NodeIndexAndSocketIndexToInputPinId( | ||||
|       ax::NodeEditor::PinId input_pin = NodeIndexAndSocketIndexToInputPinId( | ||||
|           static_cast<int>(node_index), | ||||
|           static_cast<int>(j))); | ||||
|           static_cast<int>(j)); | ||||
|       builder.Input(input_pin); | ||||
| 
 | ||||
|       assert(!input_pin.Invalid); | ||||
| 
 | ||||
|       DrawSocketIcon( | ||||
|           socket.m_type, | ||||
| @ -679,19 +744,101 @@ void BlendTreeRenderConnections(BlendTreeResource& current_blend_tree) { | ||||
|         target_socket_pin_id); | ||||
|   } | ||||
| } | ||||
| void AnimGraphEditorDebugWidget() { | ||||
|   ImGui::Begin("Connection Debug Panel"); | ||||
|   ImGui::BeginTable("Connection", 3); | ||||
|   ImGui::TableNextRow(); | ||||
|   ImGui::TableSetColumnIndex(0); | ||||
|   ImGui::Text("Pin"); | ||||
|   ImGui::TableNextColumn(); | ||||
|   ImGui::Text("%x", sNodeConnectionDebugState.sourceSocket.pin.AsPointer()); | ||||
|   ImGui::TableNextColumn(); | ||||
|   ImGui::Text("%x", sNodeConnectionDebugState.targetSocket.pin.AsPointer()); | ||||
| 
 | ||||
|   ImGui::TableNextRow(); | ||||
|   ImGui::TableSetColumnIndex(0); | ||||
|   ImGui::Text("Node"); | ||||
|   ImGui::TableNextColumn(); | ||||
|   if (sNodeConnectionDebugState.sourceSocket.nodeResource) { | ||||
|     ImGui::Text( | ||||
|         "%s (%p)", | ||||
|         sNodeConnectionDebugState.sourceSocket.nodeResource->m_node_type_name | ||||
|             .c_str(), | ||||
|         sNodeConnectionDebugState.sourceSocket.nodeResource); | ||||
|   } | ||||
|   ImGui::TableNextColumn(); | ||||
|   if (sNodeConnectionDebugState.targetSocket.nodeResource) { | ||||
|     ImGui::Text( | ||||
|         "%s (%p)", | ||||
|         sNodeConnectionDebugState.targetSocket.nodeResource->m_node_type_name | ||||
|             .c_str(), | ||||
|         sNodeConnectionDebugState.targetSocket.nodeResource); | ||||
|   } | ||||
| 
 | ||||
|   ImGui::TableNextRow(); | ||||
|   ImGui::TableSetColumnIndex(0); | ||||
|   ImGui::Text("NodeId"); | ||||
|   ImGui::TableNextColumn(); | ||||
|   ImGui::Text("%d", sNodeConnectionDebugState.sourceSocket.nodeId); | ||||
|   ImGui::TableNextColumn(); | ||||
|   ImGui::Text("%d", sNodeConnectionDebugState.targetSocket.nodeId); | ||||
| 
 | ||||
|   ImGui::TableNextRow(); | ||||
|   ImGui::TableSetColumnIndex(0); | ||||
|   ImGui::Text("Socket"); | ||||
|   ImGui::TableNextColumn(); | ||||
|   if (sNodeConnectionDebugState.sourceSocket.socket) { | ||||
|     ImGui::Text( | ||||
|         "%s (%p)", | ||||
|         sNodeConnectionDebugState.sourceSocket.socket->m_name.c_str(), | ||||
|         sNodeConnectionDebugState.sourceSocket.socket); | ||||
|   } | ||||
| 
 | ||||
|   ImGui::TableNextColumn(); | ||||
|   if (sNodeConnectionDebugState.targetSocket.socket) { | ||||
|     ImGui::Text( | ||||
|         "%s (%p)", | ||||
|         sNodeConnectionDebugState.targetSocket.socket->m_name.c_str(), | ||||
|         sNodeConnectionDebugState.targetSocket.socket); | ||||
|   } | ||||
| 
 | ||||
|   ImGui::TableNextRow(); | ||||
|   ImGui::TableSetColumnIndex(0); | ||||
|   ImGui::Text("SocketId"); | ||||
|   ImGui::TableNextColumn(); | ||||
|   ImGui::Text("%x", sNodeConnectionDebugState.sourceSocket.socketId); | ||||
|   ImGui::TableNextColumn(); | ||||
|   ImGui::Text("%x", sNodeConnectionDebugState.targetSocket.socketId); | ||||
| 
 | ||||
|   ImGui::EndTable(); | ||||
| 
 | ||||
|   ImGui::End(); | ||||
| } | ||||
| 
 | ||||
| void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) { | ||||
|   sEditorState.statusLine[0] = '\0'; | ||||
|   sEditorState.statusLine[sizeof(sEditorState.statusLine) - 1] = '\0'; | ||||
| 
 | ||||
|   sNodeConnectionDebugState.Reset(); | ||||
| 
 | ||||
|   ax::NodeEditor::SetCurrentEditor(context); | ||||
| 
 | ||||
|   AnimGraphEditorMenuBar(); | ||||
| 
 | ||||
|   AnimGraphEditorBreadcrumbNavigation(); | ||||
| 
 | ||||
|   ImGui::Columns(2); | ||||
|   static ImGuiTableFlags flags = | ||||
|       ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_Resizable; | ||||
|   ImGui::BeginTable("GraphEditorWithSidebar", 2, flags); | ||||
|   ImGui::TableNextRow(); | ||||
|   ImGui::TableSetColumnIndex(0); | ||||
| 
 | ||||
|   //
 | ||||
|   // Node editor canvas
 | ||||
|   //
 | ||||
|   ax::NodeEditor::Begin("Graph Editor"); | ||||
|   ImVec2 graph_size = ImGui::GetContentRegionAvail(); | ||||
|   graph_size.y -= 20; | ||||
|   ax::NodeEditor::Begin("Graph Editor", graph_size); | ||||
| 
 | ||||
|   AnimGraphResource* current_graph = | ||||
|       sEditorState.hierarchyStack[sEditorState.hierarchyStackIndex]; | ||||
| @ -700,19 +847,19 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) { | ||||
|   ax::NodeEditor::Utilities::BlueprintNodeBuilder builder; | ||||
| 
 | ||||
|   BlendTreeRenderNodes(current_blend_tree, builder); | ||||
| 
 | ||||
|   BlendTreeRenderConnections(current_blend_tree); | ||||
| 
 | ||||
|   HandleConnectionCreation(current_blend_tree); | ||||
| 
 | ||||
|   BlendTreeEditorNodePopup(); | ||||
| 
 | ||||
|   ax::NodeEditor::End(); | ||||
| 
 | ||||
|   ImGui::Text("Status: %s", sEditorState.statusLine); | ||||
| 
 | ||||
|   //
 | ||||
|   // Sidebar
 | ||||
|   //
 | ||||
|   ImGui::NextColumn(); | ||||
|   ImGui::TableSetColumnIndex(1); | ||||
| 
 | ||||
|   if (ax::NodeEditor::GetSelectedObjectCount() > 0) { | ||||
|     ax::NodeEditor::NodeId selected_node_id = 0; | ||||
| @ -727,7 +874,9 @@ void AnimGraphEditorUpdate(ax::NodeEditor::EditorContext* context) { | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   ImGui::Columns(1); | ||||
|   ImGui::EndTable(); | ||||
| 
 | ||||
|   AnimGraphEditorDebugWidget(); | ||||
| 
 | ||||
|   // Clear flag, however it may be re-set further down when handling double
 | ||||
|   // clicking into subgraphs.
 | ||||
|  | ||||
| @ -13,6 +13,9 @@ struct SkinnedMesh; | ||||
| struct AnimGraphBlendTree; | ||||
| struct SyncTrack; | ||||
| 
 | ||||
| constexpr int cMaxSocketsPerNode = 500; | ||||
| constexpr int cMaxNodesPerGraph = 1000; | ||||
| 
 | ||||
| inline int GenerateInputAttributeId(int node_id, int input_index) { | ||||
|   return ((input_index + 1) << 14) + node_id; | ||||
| } | ||||
| @ -36,31 +39,42 @@ SplitOutputAttributeId(int attribute_id, int* node_id, int* output_index) { | ||||
| inline int NodeIndexAndSocketIndexToInputPinId( | ||||
|     int node_index, | ||||
|     int input_socket_index) { | ||||
|   return node_index * 1000 + input_socket_index; | ||||
|   return node_index * cMaxNodesPerGraph + input_socket_index; | ||||
| } | ||||
| 
 | ||||
| inline int NodeIndexAndSocketIndexToOutputPinId( | ||||
|     int node_index, | ||||
|     int output_socket_index) { | ||||
|   return node_index * 1000 + 500 + output_socket_index; | ||||
|   return node_index * cMaxNodesPerGraph + cMaxSocketsPerNode | ||||
|          + output_socket_index; | ||||
| } | ||||
| 
 | ||||
| inline void InputPinIdToNodeIndexAndSocketIndex( | ||||
|     unsigned long input_pin_id, | ||||
|     int* node_index, | ||||
|     int* socket_index) { | ||||
|   *socket_index = input_pin_id % 1000; | ||||
|   *node_index = (input_pin_id - *socket_index) / 1000; | ||||
|   *socket_index = static_cast<int>(input_pin_id) % cMaxNodesPerGraph; | ||||
|   *node_index = | ||||
|       (static_cast<int>(input_pin_id) - *socket_index) / cMaxNodesPerGraph; | ||||
| } | ||||
| 
 | ||||
| inline void OutputPinIdToNodeIndexAndSocketIndex( | ||||
|     unsigned long output_pin_id, | ||||
|     int* node_index, | ||||
|     int* socket_index) { | ||||
|   *socket_index = ((output_pin_id - 500) % 1000); | ||||
|   *node_index = (output_pin_id - *socket_index) / 1000; | ||||
|   *socket_index = | ||||
|       ((static_cast<int>(output_pin_id) - cMaxSocketsPerNode) | ||||
|        % cMaxNodesPerGraph); | ||||
|   *node_index = | ||||
|       (static_cast<int>(output_pin_id) - *socket_index) / cMaxNodesPerGraph; | ||||
| } | ||||
| 
 | ||||
| inline bool IsPinInput(unsigned long pin_id) { | ||||
|   return ((pin_id % cMaxNodesPerGraph) >= cMaxSocketsPerNode); | ||||
| } | ||||
| 
 | ||||
| inline bool IsPinOutput(unsigned long pin_id) { return !IsPinInput(pin_id); } | ||||
| 
 | ||||
| void SyncTrackEditor(SyncTrack* sync_track); | ||||
| 
 | ||||
| void SkinnedMeshWidget(SkinnedMesh* skinned_mesh); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Martin Felis
						Martin Felis