diff --git a/src/foldhaus_app.cpp b/src/foldhaus_app.cpp index a9f3f2b..b54eb35 100644 --- a/src/foldhaus_app.cpp +++ b/src/foldhaus_app.cpp @@ -186,7 +186,6 @@ RELOAD_STATIC_DATA(ReloadStaticData) RegisterKeyPressCommand(&State->DefaultInputCommandRegistry, KeyCode_MouseLeftButton, Command_Began, KeyCode_Invalid, Begin3DViewMouseRotate); RegisterKeyPressCommand(&State->DefaultInputCommandRegistry, KeyCode_U, Command_Began, KeyCode_Invalid, OpenUniverseView); - RegisterKeyPressCommand(&State->DefaultInputCommandRegistry, KeyCode_Tab, Command_Began, KeyCode_Invalid, OpenNodeView); } } @@ -297,14 +296,6 @@ INITIALIZE_APPLICATION(InitializeApplication) GlobalDebugServices->Interface.RenderSculpture = true; - State->NodeList = AllocateNodeList(State->Permanent, 128); - State->OutputNode = PushOutputNodeOnList(State->NodeList, v2{500, 250}, State->Permanent); - { - State->NodeRenderSettings.PortColors[MemberType_r32] = RedV4; - State->NodeRenderSettings.PortColors[MemberType_s32] = GreenV4; - State->NodeRenderSettings.PortColors[MemberType_v4] = BlueV4; - State->NodeRenderSettings.Font = State->Font; - } ReloadStaticData(Context, GlobalDebugServices, Alloc, Free); { // MODES PLAYGROUND @@ -414,18 +405,7 @@ UPDATE_AND_RENDER(UpdateAndRender) HandleInput(State, InputQueue, Mouse); - for (s32 AssemblyIndex = 0; AssemblyIndex < State->AssembliesCount; AssemblyIndex++) - { - assembly Assembly = State->AssemblyList[AssemblyIndex]; - UpdateOutputNodeCalculations(State->OutputNode, State->NodeList, - State->Permanent, State->Transient, - Assembly.LEDs, - Assembly.Colors, - Assembly.LEDCount, - Context.DeltaTime); - ResetNodesUpdateState(State->NodeList); - } - ClearTransientNodeColorBuffers(State->NodeList); + // Update Visuals Here s32 HeaderSize = State->NetworkProtocolHeaderSize; dmx_buffer_list* DMXBuffers = 0; diff --git a/src/foldhaus_app.h b/src/foldhaus_app.h index b8a723b..1874697 100644 --- a/src/foldhaus_app.h +++ b/src/foldhaus_app.h @@ -23,8 +23,6 @@ typedef struct app_state app_state; #include "foldhaus_text_entry.h" -#include "foldhaus_default_nodes.h" -#include "generated/foldhaus_nodes_generated.cpp" #include "foldhaus_search_lister.h" enum network_protocol @@ -63,10 +61,6 @@ struct app_state input_command_queue CommandQueue; text_entry ActiveTextEntry; - node_list* NodeList; - node_header* OutputNode; - - node_render_settings NodeRenderSettings; bitmap_font* Font; interface_config Interface; }; @@ -74,7 +68,7 @@ struct app_state internal void OpenColorPicker(app_state* State, v4* Address); #include "foldhaus_assembly.cpp" -#include "foldhaus_node.cpp" + #include "foldhaus_debug_visuals.h" //#include "foldhaus_sacn_view.cpp" #include "foldhaus_text_entry.cpp" diff --git a/src/foldhaus_debug_visuals.h b/src/foldhaus_debug_visuals.h index e9e313a..a98770e 100644 --- a/src/foldhaus_debug_visuals.h +++ b/src/foldhaus_debug_visuals.h @@ -298,13 +298,6 @@ DrawDebugInterface (render_command_buffer* RenderBuffer, r32 StartX, interface_c TopOfScreenLinePos, WhiteV4); TopOfScreenLinePos.y -= NewLineYOffset(*Interface.Font); - PrintF(&DebugString, "Nodes Memory: %d / %d", - State->NodeList->TotalUsed, - State->NodeList->TotalMax); - DrawString(RenderBuffer, DebugString, Interface.Font, - TopOfScreenLinePos, WhiteV4); - TopOfScreenLinePos.y -= NewLineYOffset(*Interface.Font); - PrintF(&DebugString, "Render Buffer: %d / %d (at this point)", RenderBuffer->CommandMemoryUsed, RenderBuffer->CommandMemorySize); diff --git a/src/foldhaus_interface.cpp b/src/foldhaus_interface.cpp index cc1c53a..efb720b 100644 --- a/src/foldhaus_interface.cpp +++ b/src/foldhaus_interface.cpp @@ -128,504 +128,6 @@ FOLDHAUS_INPUT_COMMAND_PROC(OpenUniverseView) OpState->Zoom = 1.0f; } -//////////////////////////////////////// -// -// Node Lister -// -/////////////////////////////////////// - -struct node_lister_operation_state -{ - search_lister SearchLister; - v2 ListPosition; -}; - -OPERATION_RENDER_PROC(RenderNodeLister) -{ - node_lister_operation_state* OpState = (node_lister_operation_state*)Operation.OpStateMemory; - - v2 TopLeft = OpState->ListPosition; - v2 Dimension = v2{300, 30}; - - // Filter the lister - OpState->SearchLister.Filter = State->ActiveTextEntry.Buffer; - FilterSearchLister(&OpState->SearchLister); - - // Display Search Lister - search_lister_result NodeListerResult = EvaluateSearchLister (RenderBuffer, TopLeft, Dimension, - MakeStringLiteral("Nodes List"), - OpState->SearchLister.SourceList, - OpState->SearchLister.FilteredIndexLUT, - OpState->SearchLister.FilteredListCount, - OpState->SearchLister.HotItem, - &State->ActiveTextEntry.Buffer, - State->ActiveTextEntry.CursorPosition, - State->Font, State->Interface, Mouse); -} - -FOLDHAUS_INPUT_COMMAND_PROC(NodeListerNextItem) -{ - node_lister_operation_state* OpState = GetCurrentOperationState(State->Modes, node_lister_operation_state); - OpState->SearchLister.HotItem = GetNextFilteredItem(OpState->SearchLister); -} - -FOLDHAUS_INPUT_COMMAND_PROC(NodeListerPrevItem) -{ - node_lister_operation_state* OpState = GetCurrentOperationState(State->Modes, node_lister_operation_state); - OpState->SearchLister.HotItem = GetPrevFilteredItem(OpState->SearchLister); -} - -FOLDHAUS_INPUT_COMMAND_PROC(CloseNodeLister) -{ - DeactivateCurrentOperationMode(&State->Modes); -} - -FOLDHAUS_INPUT_COMMAND_PROC(SelectAndCloseNodeLister) -{ - node_lister_operation_state* OpState = GetCurrentOperationState(State->Modes, node_lister_operation_state); - s32 FilteredNodeIndex = OpState->SearchLister.HotItem; - if (FilteredNodeIndex >= 0) - { - s32 NodeIndex = OpState->SearchLister.FilteredIndexLUT[FilteredNodeIndex]; - PushNodeOnListFromSpecification(State->NodeList, (node_type)NodeIndex, - Mouse.Pos, State->Permanent); - } - CloseNodeLister(State, Event, Mouse); -} - -input_command UniverseViewCommads [] = { - { KeyCode_DownArrow, KeyCode_Invalid, Command_Began, NodeListerNextItem }, - { KeyCode_UpArrow, KeyCode_Invalid, Command_Began, NodeListerPrevItem }, - { KeyCode_Enter, KeyCode_Invalid, Command_Began, SelectAndCloseNodeLister }, - { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Began, CloseNodeLister }, - { KeyCode_Esc, KeyCode_Invalid, Command_Began, CloseNodeLister }, - DEFAULT_TEXT_ENTRY_INPUT_COMMANDS_ARRAY_ENTRY, -}; - -FOLDHAUS_INPUT_COMMAND_PROC(OpenNodeLister) -{ - operation_mode* AddNodeOperation = ActivateOperationModeWithCommands(&State->Modes, UniverseViewCommads); - - AddNodeOperation->Render = RenderNodeLister; - - node_lister_operation_state* OpState = CreateOperationState(AddNodeOperation, - &State->Modes, - node_lister_operation_state); - { - OpState->SearchLister.SourceListCount = NodeSpecificationsCount; - OpState->SearchLister.SourceList = PushArray(&State->Modes.Arena, string, OpState->SearchLister.SourceListCount); - { - for (s32 i = 0; i < OpState->SearchLister.SourceListCount; i++) - { - OpState->SearchLister.SourceList[i] = MakeString( - NodeSpecifications[i].Name, - NodeSpecifications[i].NameLength); - } - } - OpState->SearchLister.Filter = MakeString(PushArray(&State->Modes.Arena, char, 64), 0, 64); - - OpState->SearchLister.FilteredListMax = OpState->SearchLister.SourceListCount; - OpState->SearchLister.FilteredListCount = 0; - OpState->SearchLister.FilteredIndexLUT = PushArray(&State->Modes.Arena, s32, OpState->SearchLister.SourceListCount); - } - - OpState->ListPosition = Mouse.Pos; - SetTextInputDestinationToString(&State->ActiveTextEntry, &OpState->SearchLister.Filter); -} - -//////////////////////////////////////// -// -// Node Color Picker -// -/////////////////////////////////////// - -struct color_picker_operation_state -{ - v4* ValueAddr; -}; - -internal void -CloseColorPicker(app_state* State) -{ - DeactivateCurrentOperationMode(&State->Modes); -} - -FOLDHAUS_INPUT_COMMAND_PROC(CloseColorPickerCommand) -{ - CloseColorPicker(State); -} - -OPERATION_RENDER_PROC(RenderColorPicker) -{ - color_picker_operation_state* OpState = (color_picker_operation_state*)Operation.OpStateMemory; - - - b32 ShouldClose = EvaluateColorPicker(RenderBuffer, OpState->ValueAddr, - v2{200, 200}, State->Interface, Mouse); - - if (ShouldClose) - { - CloseColorPicker(State); - } -} - -input_command ColorPickerCommands [] = { - { KeyCode_Esc, KeyCode_Invalid, Command_Began, CloseColorPickerCommand }, -}; - -internal void -OpenColorPicker(app_state* State, node_connection* Connection) -{ - operation_mode* ColorPickerMode = ActivateOperationModeWithCommands(&State->Modes, ColorPickerCommands); - ColorPickerMode->Render = RenderColorPicker; - - color_picker_operation_state* OpState = CreateOperationState(ColorPickerMode, - &State->Modes, - color_picker_operation_state); - OpState->ValueAddr = Connection->V4ValuePtr; -} - - -//////////////////////////////////////// -// -// Node Field Text Edit -// -/////////////////////////////////////// - -FOLDHAUS_INPUT_COMMAND_PROC(EndNodeFieldTextEdit) -{ - DeactivateCurrentOperationMode(&State->Modes); -} - -input_command NodeFieldTextEditCommands [] = { - { KeyCode_Enter, KeyCode_Invalid, Command_Began, EndNodeFieldTextEdit }, - { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Began, EndNodeFieldTextEdit }, - DEFAULT_TEXT_ENTRY_INPUT_COMMANDS_ARRAY_ENTRY, -}; - -internal void -BeginNodeFieldTextEdit(app_state* State, node_connection* Connection) -{ - operation_mode* NodeFieldTextEditMode = ActivateOperationModeWithCommands(&State->Modes, - NodeFieldTextEditCommands); - - SetTextInputDestinationToFloat(&State->ActiveTextEntry, Connection->R32ValuePtr); -} - -//////////////////////////////////////// -// -// Node Port Mouse Drag -// -/////////////////////////////////////// - -struct drag_node_port_operation_state -{ - node_interaction Interaction; -}; - -OPERATION_RENDER_PROC(RenderDraggingNodePort) -{ - drag_node_port_operation_state* OpState = (drag_node_port_operation_state*)Operation.OpStateMemory; - UpdateDraggingNodePort(Mouse.Pos, OpState->Interaction, State->NodeList, - State->NodeRenderSettings, RenderBuffer); -} - -FOLDHAUS_INPUT_COMMAND_PROC(EndDraggingNodePort) -{ - drag_node_port_operation_state* OpState = GetCurrentOperationState(State->Modes, drag_node_port_operation_state); - - TryConnectNodes(OpState->Interaction, Mouse.Pos, State->NodeList, State->NodeRenderSettings); - DeactivateCurrentOperationMode(&State->Modes); -} - -input_command DragNodePortInputCommands[] = { - { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, EndDraggingNodePort }, -}; - -internal void -BeginDraggingNodePort(app_state* State, node_interaction Interaction) -{ - operation_mode* DragNodePortMode = ActivateOperationModeWithCommands( - &State->Modes, - DragNodePortInputCommands); - DragNodePortMode->Render = RenderDraggingNodePort; - - drag_node_port_operation_state* OpState = CreateOperationState(DragNodePortMode, - &State->Modes, - drag_node_port_operation_state); - OpState->Interaction = Interaction; -} - -//////////////////////////////////////// -// -// Node Field Mouse Drag -// -/////////////////////////////////////// - -OPERATION_RENDER_PROC(RenderDragNodeField) -{ - // TODO(Peter): - //UpdateDraggingNodeValue(Mouse.Pos, Mouse.OldPos, OpState->Interaction, State->NodeList, State->NodeRenderSettings, State); -} - -internal void -BeginInteractWithNodeField(app_state* State, node_interaction Interaction) -{ - // TODO(Peter): -} - -//////////////////////////////////////// -// -// Node Mouse Drag -// -/////////////////////////////////////// - -struct drag_node_operation_state -{ - node_interaction Interaction; -}; - -OPERATION_RENDER_PROC(RenderDraggingNode) -{ - drag_node_operation_state* OpState = GetCurrentOperationState(State->Modes, drag_node_operation_state); - UpdateDraggingNode(Mouse.Pos, OpState->Interaction, State->NodeList, - State->NodeRenderSettings); -} - -FOLDHAUS_INPUT_COMMAND_PROC(EndDraggingNode) -{ - DeactivateCurrentOperationMode(&State->Modes); -} - -input_command DragNodeInputCommands[] = { - { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, EndDraggingNode }, -}; - -internal void -BeginDraggingNode(app_state* State, node_interaction Interaction) -{ - operation_mode* DragNodeMode = ActivateOperationModeWithCommands( - &State->Modes, - DragNodeInputCommands); - DragNodeMode->Render = RenderDraggingNode; - - drag_node_operation_state* OpState = CreateOperationState(DragNodeMode, - &State->Modes, - drag_node_operation_state); - OpState->Interaction = Interaction; -} - -//////////////////////////////////////// -// -// Node View -// -/////////////////////////////////////// - -struct node_view_operation_state -{ - s32 SelectedNodeHandle; -}; - -FOLDHAUS_INPUT_COMMAND_PROC(NodeViewBeginMouseDragInteraction) -{ - node_view_operation_state* OpState = GetCurrentOperationState(State->Modes, node_view_operation_state); - - node_header* Node = GetNodeUnderPoint(State->NodeList, Mouse.DownPos, State->NodeRenderSettings); - if (Node) - { - node_interaction NewInteraction = GetNodeInteractionType(Node, - Mouse.Pos, - State->NodeRenderSettings); - if (IsDraggingNodePort(NewInteraction)) - { - BeginDraggingNodePort(State, NewInteraction); - } - else if(IsDraggingNodeValue(NewInteraction)) - { - // TODO(Peter): This probably wants to live in a mouse held action - // the first frame we realize we're held over a field, just transition to - // drag node field - //BeginInteractWithNodeField(State, NewInteraction, State->NodeRenderSettings); - } - else // IsDraggingNode - { - OpState->SelectedNodeHandle = Node->Handle; - BeginDraggingNode(State, NewInteraction); - } - } - else - { - OpState->SelectedNodeHandle = 0; - } -} - -FOLDHAUS_INPUT_COMMAND_PROC(NodeViewBeginMouseSelectInteraction) -{ - node_view_operation_state* OpState = GetCurrentOperationState(State->Modes, node_view_operation_state); - - node_header* Node = GetNodeUnderPoint(State->NodeList, Mouse.Pos, State->NodeRenderSettings); - if (Node) - { - node_interaction NewInteraction = GetNodeInteractionType(Node, - Mouse.Pos, - State->NodeRenderSettings); - if(IsDraggingNodeValue(NewInteraction)) - { - node_connection* Connection = Node->Connections + NewInteraction.InputValue; - struct_member_type InputType = Connection->Type; - - if (InputType == MemberType_r32) - { - BeginNodeFieldTextEdit(State, Connection); - } - else if (InputType == MemberType_v4) - { - OpenColorPicker(State, Connection); - } - } - } -} - -OPERATION_RENDER_PROC(RenderNodeView) -{ - node_view_operation_state* OpState = (node_view_operation_state*)Operation.OpStateMemory; - - DEBUG_TRACK_FUNCTION; - - MakeStringBuffer(NodeHeaderBuffer, 128); - - node_header* SelectedNode = GetNodeWithHandle(State->NodeList, OpState->SelectedNodeHandle); - - node_list_iterator NodeIter = GetNodeListIterator(*State->NodeList); - while (NodeIteratorIsValid(NodeIter)) - { - node_header* Node = NodeIter.At; - - rect NodeBounds = CalculateNodeBounds(Node, State->NodeRenderSettings); - b32 DrawFields = PointIsInRect(Mouse.Pos, NodeBounds); - - if (Node == SelectedNode) - { - PushRenderQuad2D(RenderBuffer, NodeBounds.Min - v2{2, 2}, NodeBounds.Max + v2{2, 2}, WhiteV4); - } - - PushRenderQuad2D(RenderBuffer, NodeBounds.Min, NodeBounds.Max, v4{.5f, .5f, .5f, 1.f}); - - // TODO(Peter): This is just for debug purposes. We can remove and go back to just having - // Node->Name in DrawString - string NodeName = GetNodeName(*Node); - PrintF(&NodeHeaderBuffer, "%.*s: %d", NodeName.Length, NodeName.Memory, Node->Handle); - DrawString(RenderBuffer, NodeHeaderBuffer, State->NodeRenderSettings.Font, - v2{NodeBounds.Min.x + 5, NodeBounds.Max.y - (State->NodeRenderSettings.Font->PixelHeight + NODE_HEADER_HEIGHT + 5)}, - WhiteV4); - - for (s32 Connection = 0; Connection < Node->ConnectionsCount; Connection++) - { - v4 PortColor = State->NodeRenderSettings.PortColors[Node->Connections[Connection].Type]; - - // Inputs - if (ConnectionIsInput(Node, Connection)) - { - rect PortBounds = CalculateNodeInputPortBounds(Node, Connection, State->NodeRenderSettings); - DrawPort(RenderBuffer, PortBounds, PortColor); - - // - // TODO(Peter): I don't like excluding OutputNode, feels too much like a special case - // but I don't want to get in to the meta programming right now. - // We should just generate a spec and struct member types for NodeType_OutputNode - // - // :ExcludingOutputNodeSpecialCase - // - if (Node->Type != NodeType_OutputNode && DrawFields) - { - node_specification Spec = NodeSpecifications[Node->Type]; - node_struct_member Member = Spec.MemberList[Connection]; - DrawString(RenderBuffer, MakeString(Member.Name), - State->NodeRenderSettings.Font, - v2{PortBounds.Min.x - 8, PortBounds.Min.y}, WhiteV4, Align_Right); - } - - rect ValueBounds = CalculateNodeInputValueBounds(Node, Connection, State->NodeRenderSettings); - DrawValueDisplay(RenderBuffer, ValueBounds, Node->Connections[Connection], State->NodeRenderSettings.Font); - - // NOTE(Peter): its way easier to draw the connection on the input port b/c its a 1:1 relationship, - // whereas output ports might have many connections, they really only know about the most recent one - // Not sure if this is a problem. We mostly do everything backwards here, starting at the - // most downstream node and working back up to find dependencies. - if (ConnectionHasUpstreamConnection(Node, Connection)) - { - rect ConnectedPortBounds = GetBoundsOfPortConnectedToInput(Node, Connection, State->NodeList, State->NodeRenderSettings); - v2 InputCenter = CalculateRectCenter(PortBounds); - v2 OutputCenter = CalculateRectCenter(ConnectedPortBounds); - PushRenderLine2D(RenderBuffer, OutputCenter, InputCenter, 1, WhiteV4); - } - } - - // Outputs - if (ConnectionIsOutput(Node, Connection)) - { - rect PortBounds = CalculateNodeOutputPortBounds(Node, Connection, State->NodeRenderSettings); - DrawPort(RenderBuffer, PortBounds, PortColor); - - if (DrawFields) - { - node_specification Spec = NodeSpecifications[Node->Type]; - node_struct_member Member = Spec.MemberList[Connection]; - DrawString(RenderBuffer, MakeString(Member.Name), - State->NodeRenderSettings.Font, - v2{PortBounds.Max.x + 8, PortBounds.Min.y}, WhiteV4); - } - - rect ValueBounds = CalculateNodeOutputValueBounds(Node, Connection, State->NodeRenderSettings); - DrawValueDisplay(RenderBuffer, ValueBounds, Node->Connections[Connection], State->NodeRenderSettings.Font); - } - - for (s32 Button = 0; Button < 3; Button++) - { - rect ButtonRect = CalculateNodeDragHandleBounds(NodeBounds, Button, State->NodeRenderSettings); - PushRenderQuad2D(RenderBuffer, ButtonRect.Min, ButtonRect.Max, DragButtonColors[Button]); - } - } - - Next(&NodeIter); - } -} - -FOLDHAUS_INPUT_COMMAND_PROC(NodeViewDeleteNode) -{ - node_view_operation_state* OpState = GetCurrentOperationState(State->Modes, node_view_operation_state); - if (OpState->SelectedNodeHandle > 0) - { - node_header* SelectedNode = GetNodeWithHandle(State->NodeList, OpState->SelectedNodeHandle); - FreeNodeOnList(State->NodeList, SelectedNode); - } -} - -FOLDHAUS_INPUT_COMMAND_PROC(CloseNodeView) -{ - DeactivateCurrentOperationMode(&State->Modes); -} - -input_command NodeViewCommands [] = { - { KeyCode_Tab, KeyCode_Invalid, Command_Began, CloseNodeView}, - { KeyCode_A, KeyCode_Invalid, Command_Began, OpenNodeLister}, - { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Began, NodeViewBeginMouseDragInteraction}, - { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, NodeViewBeginMouseSelectInteraction}, - { KeyCode_X, KeyCode_Invalid, Command_Began, NodeViewDeleteNode}, -}; - -FOLDHAUS_INPUT_COMMAND_PROC(OpenNodeView) -{ - operation_mode* NodeViewMode = ActivateOperationModeWithCommands(&State->Modes, NodeViewCommands); - NodeViewMode->Render = RenderNodeView; - - node_view_operation_state* OpState = CreateOperationState(NodeViewMode, - &State->Modes, - node_view_operation_state); - - OpState->SelectedNodeHandle = 0; -} - //////////////////////////////////////// // // 3D View Mouse Rotate diff --git a/src/foldhaus_search_lister.cpp b/src/foldhaus_search_lister.cpp index 6e7ca98..ee42843 100644 --- a/src/foldhaus_search_lister.cpp +++ b/src/foldhaus_search_lister.cpp @@ -1,3 +1,9 @@ +internal b32 +NamePassesFilter (string Target, string Filter) +{ + return (Filter.Length == 0 || StringContainsStringCaseInsensitive(Target, Filter)); +} + internal void FilterSearchLister (search_lister* SearchLister) { @@ -9,7 +15,7 @@ FilterSearchLister (search_lister* SearchLister) for (s32 i = 0; i < SearchLister->SourceListCount; i++) { string* NameString = SearchLister->SourceList + i; - if (SpecificationPassesFilter(*NameString, SearchLister->Filter)) + if (NamePassesFilter(*NameString, SearchLister->Filter)) { SearchLister->FilteredIndexLUT[SearchLister->FilteredListCount++] = i; } diff --git a/src/node/foldhaus_node_interface.cpp b/src/node/foldhaus_node_interface.cpp new file mode 100644 index 0000000..2e44c67 --- /dev/null +++ b/src/node/foldhaus_node_interface.cpp @@ -0,0 +1,498 @@ + +//////////////////////////////////////// +// +// Node Lister +// +/////////////////////////////////////// + +struct node_lister_operation_state +{ + search_lister SearchLister; + v2 ListPosition; +}; + +OPERATION_RENDER_PROC(RenderNodeLister) +{ + node_lister_operation_state* OpState = (node_lister_operation_state*)Operation.OpStateMemory; + + v2 TopLeft = OpState->ListPosition; + v2 Dimension = v2{300, 30}; + + // Filter the lister + OpState->SearchLister.Filter = State->ActiveTextEntry.Buffer; + FilterSearchLister(&OpState->SearchLister); + + // Display Search Lister + search_lister_result NodeListerResult = EvaluateSearchLister (RenderBuffer, TopLeft, Dimension, + MakeStringLiteral("Nodes List"), + OpState->SearchLister.SourceList, + OpState->SearchLister.FilteredIndexLUT, + OpState->SearchLister.FilteredListCount, + OpState->SearchLister.HotItem, + &State->ActiveTextEntry.Buffer, + State->ActiveTextEntry.CursorPosition, + State->Font, State->Interface, Mouse); +} + +FOLDHAUS_INPUT_COMMAND_PROC(NodeListerNextItem) +{ + node_lister_operation_state* OpState = GetCurrentOperationState(State->Modes, node_lister_operation_state); + OpState->SearchLister.HotItem = GetNextFilteredItem(OpState->SearchLister); +} + +FOLDHAUS_INPUT_COMMAND_PROC(NodeListerPrevItem) +{ + node_lister_operation_state* OpState = GetCurrentOperationState(State->Modes, node_lister_operation_state); + OpState->SearchLister.HotItem = GetPrevFilteredItem(OpState->SearchLister); +} + +FOLDHAUS_INPUT_COMMAND_PROC(CloseNodeLister) +{ + DeactivateCurrentOperationMode(&State->Modes); +} + +FOLDHAUS_INPUT_COMMAND_PROC(SelectAndCloseNodeLister) +{ + node_lister_operation_state* OpState = GetCurrentOperationState(State->Modes, node_lister_operation_state); + s32 FilteredNodeIndex = OpState->SearchLister.HotItem; + if (FilteredNodeIndex >= 0) + { + s32 NodeIndex = OpState->SearchLister.FilteredIndexLUT[FilteredNodeIndex]; + PushNodeOnListFromSpecification(State->NodeList, (node_type)NodeIndex, + Mouse.Pos, State->Permanent); + } + CloseNodeLister(State, Event, Mouse); +} + +input_command UniverseViewCommads [] = { + { KeyCode_DownArrow, KeyCode_Invalid, Command_Began, NodeListerNextItem }, + { KeyCode_UpArrow, KeyCode_Invalid, Command_Began, NodeListerPrevItem }, + { KeyCode_Enter, KeyCode_Invalid, Command_Began, SelectAndCloseNodeLister }, + { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Began, CloseNodeLister }, + { KeyCode_Esc, KeyCode_Invalid, Command_Began, CloseNodeLister }, + DEFAULT_TEXT_ENTRY_INPUT_COMMANDS_ARRAY_ENTRY, +}; + +FOLDHAUS_INPUT_COMMAND_PROC(OpenNodeLister) +{ + operation_mode* AddNodeOperation = ActivateOperationModeWithCommands(&State->Modes, UniverseViewCommads); + + AddNodeOperation->Render = RenderNodeLister; + + node_lister_operation_state* OpState = CreateOperationState(AddNodeOperation, + &State->Modes, + node_lister_operation_state); + { + OpState->SearchLister.SourceListCount = NodeSpecificationsCount; + OpState->SearchLister.SourceList = PushArray(&State->Modes.Arena, string, OpState->SearchLister.SourceListCount); + { + for (s32 i = 0; i < OpState->SearchLister.SourceListCount; i++) + { + OpState->SearchLister.SourceList[i] = MakeString( + NodeSpecifications[i].Name, + NodeSpecifications[i].NameLength); + } + } + OpState->SearchLister.Filter = MakeString(PushArray(&State->Modes.Arena, char, 64), 0, 64); + + OpState->SearchLister.FilteredListMax = OpState->SearchLister.SourceListCount; + OpState->SearchLister.FilteredListCount = 0; + OpState->SearchLister.FilteredIndexLUT = PushArray(&State->Modes.Arena, s32, OpState->SearchLister.SourceListCount); + } + + OpState->ListPosition = Mouse.Pos; + SetTextInputDestinationToString(&State->ActiveTextEntry, &OpState->SearchLister.Filter); +} + +//////////////////////////////////////// +// +// Node Color Picker +// +/////////////////////////////////////// + +struct color_picker_operation_state +{ + v4* ValueAddr; +}; + +internal void +CloseColorPicker(app_state* State) +{ + DeactivateCurrentOperationMode(&State->Modes); +} + +FOLDHAUS_INPUT_COMMAND_PROC(CloseColorPickerCommand) +{ + CloseColorPicker(State); +} + +OPERATION_RENDER_PROC(RenderColorPicker) +{ + color_picker_operation_state* OpState = (color_picker_operation_state*)Operation.OpStateMemory; + + + b32 ShouldClose = EvaluateColorPicker(RenderBuffer, OpState->ValueAddr, + v2{200, 200}, State->Interface, Mouse); + + if (ShouldClose) + { + CloseColorPicker(State); + } +} + +input_command ColorPickerCommands [] = { + { KeyCode_Esc, KeyCode_Invalid, Command_Began, CloseColorPickerCommand }, +}; + +internal void +OpenColorPicker(app_state* State, node_connection* Connection) +{ + operation_mode* ColorPickerMode = ActivateOperationModeWithCommands(&State->Modes, ColorPickerCommands); + ColorPickerMode->Render = RenderColorPicker; + + color_picker_operation_state* OpState = CreateOperationState(ColorPickerMode, + &State->Modes, + color_picker_operation_state); + OpState->ValueAddr = Connection->V4ValuePtr; +} + + +//////////////////////////////////////// +// +// Node Field Text Edit +// +/////////////////////////////////////// + +FOLDHAUS_INPUT_COMMAND_PROC(EndNodeFieldTextEdit) +{ + DeactivateCurrentOperationMode(&State->Modes); +} + +input_command NodeFieldTextEditCommands [] = { + { KeyCode_Enter, KeyCode_Invalid, Command_Began, EndNodeFieldTextEdit }, + { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Began, EndNodeFieldTextEdit }, + DEFAULT_TEXT_ENTRY_INPUT_COMMANDS_ARRAY_ENTRY, +}; + +internal void +BeginNodeFieldTextEdit(app_state* State, node_connection* Connection) +{ + operation_mode* NodeFieldTextEditMode = ActivateOperationModeWithCommands(&State->Modes, + NodeFieldTextEditCommands); + + SetTextInputDestinationToFloat(&State->ActiveTextEntry, Connection->R32ValuePtr); +} + +//////////////////////////////////////// +// +// Node Port Mouse Drag +// +/////////////////////////////////////// + +struct drag_node_port_operation_state +{ + node_interaction Interaction; +}; + +OPERATION_RENDER_PROC(RenderDraggingNodePort) +{ + drag_node_port_operation_state* OpState = (drag_node_port_operation_state*)Operation.OpStateMemory; + UpdateDraggingNodePort(Mouse.Pos, OpState->Interaction, State->NodeList, + State->NodeRenderSettings, RenderBuffer); +} + +FOLDHAUS_INPUT_COMMAND_PROC(EndDraggingNodePort) +{ + drag_node_port_operation_state* OpState = GetCurrentOperationState(State->Modes, drag_node_port_operation_state); + + TryConnectNodes(OpState->Interaction, Mouse.Pos, State->NodeList, State->NodeRenderSettings); + DeactivateCurrentOperationMode(&State->Modes); +} + +input_command DragNodePortInputCommands[] = { + { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, EndDraggingNodePort }, +}; + +internal void +BeginDraggingNodePort(app_state* State, node_interaction Interaction) +{ + operation_mode* DragNodePortMode = ActivateOperationModeWithCommands( + &State->Modes, + DragNodePortInputCommands); + DragNodePortMode->Render = RenderDraggingNodePort; + + drag_node_port_operation_state* OpState = CreateOperationState(DragNodePortMode, + &State->Modes, + drag_node_port_operation_state); + OpState->Interaction = Interaction; +} + +//////////////////////////////////////// +// +// Node Field Mouse Drag +// +/////////////////////////////////////// + +OPERATION_RENDER_PROC(RenderDragNodeField) +{ + // TODO(Peter): + //UpdateDraggingNodeValue(Mouse.Pos, Mouse.OldPos, OpState->Interaction, State->NodeList, State->NodeRenderSettings, State); +} + +internal void +BeginInteractWithNodeField(app_state* State, node_interaction Interaction) +{ + // TODO(Peter): +} + +//////////////////////////////////////// +// +// Node Mouse Drag +// +/////////////////////////////////////// + +struct drag_node_operation_state +{ + node_interaction Interaction; +}; + +OPERATION_RENDER_PROC(RenderDraggingNode) +{ + drag_node_operation_state* OpState = GetCurrentOperationState(State->Modes, drag_node_operation_state); + UpdateDraggingNode(Mouse.Pos, OpState->Interaction, State->NodeList, + State->NodeRenderSettings); +} + +FOLDHAUS_INPUT_COMMAND_PROC(EndDraggingNode) +{ + DeactivateCurrentOperationMode(&State->Modes); +} + +input_command DragNodeInputCommands[] = { + { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, EndDraggingNode }, +}; + +internal void +BeginDraggingNode(app_state* State, node_interaction Interaction) +{ + operation_mode* DragNodeMode = ActivateOperationModeWithCommands( + &State->Modes, + DragNodeInputCommands); + DragNodeMode->Render = RenderDraggingNode; + + drag_node_operation_state* OpState = CreateOperationState(DragNodeMode, + &State->Modes, + drag_node_operation_state); + OpState->Interaction = Interaction; +} + +//////////////////////////////////////// +// +// Node View +// +/////////////////////////////////////// + +struct node_view_operation_state +{ + s32 SelectedNodeHandle; +}; + +FOLDHAUS_INPUT_COMMAND_PROC(NodeViewBeginMouseDragInteraction) +{ + node_view_operation_state* OpState = GetCurrentOperationState(State->Modes, node_view_operation_state); + + node_header* Node = GetNodeUnderPoint(State->NodeList, Mouse.DownPos, State->NodeRenderSettings); + if (Node) + { + node_interaction NewInteraction = GetNodeInteractionType(Node, + Mouse.Pos, + State->NodeRenderSettings); + if (IsDraggingNodePort(NewInteraction)) + { + BeginDraggingNodePort(State, NewInteraction); + } + else if(IsDraggingNodeValue(NewInteraction)) + { + // TODO(Peter): This probably wants to live in a mouse held action + // the first frame we realize we're held over a field, just transition to + // drag node field + //BeginInteractWithNodeField(State, NewInteraction, State->NodeRenderSettings); + } + else // IsDraggingNode + { + OpState->SelectedNodeHandle = Node->Handle; + BeginDraggingNode(State, NewInteraction); + } + } + else + { + OpState->SelectedNodeHandle = 0; + } +} + +FOLDHAUS_INPUT_COMMAND_PROC(NodeViewBeginMouseSelectInteraction) +{ + node_view_operation_state* OpState = GetCurrentOperationState(State->Modes, node_view_operation_state); + + node_header* Node = GetNodeUnderPoint(State->NodeList, Mouse.Pos, State->NodeRenderSettings); + if (Node) + { + node_interaction NewInteraction = GetNodeInteractionType(Node, + Mouse.Pos, + State->NodeRenderSettings); + if(IsDraggingNodeValue(NewInteraction)) + { + node_connection* Connection = Node->Connections + NewInteraction.InputValue; + struct_member_type InputType = Connection->Type; + + if (InputType == MemberType_r32) + { + BeginNodeFieldTextEdit(State, Connection); + } + else if (InputType == MemberType_v4) + { + OpenColorPicker(State, Connection); + } + } + } +} + +OPERATION_RENDER_PROC(RenderNodeView) +{ + node_view_operation_state* OpState = (node_view_operation_state*)Operation.OpStateMemory; + + DEBUG_TRACK_FUNCTION; + + MakeStringBuffer(NodeHeaderBuffer, 128); + + node_header* SelectedNode = GetNodeWithHandle(State->NodeList, OpState->SelectedNodeHandle); + + node_list_iterator NodeIter = GetNodeListIterator(*State->NodeList); + while (NodeIteratorIsValid(NodeIter)) + { + node_header* Node = NodeIter.At; + + rect NodeBounds = CalculateNodeBounds(Node, State->NodeRenderSettings); + b32 DrawFields = PointIsInRect(Mouse.Pos, NodeBounds); + + if (Node == SelectedNode) + { + PushRenderQuad2D(RenderBuffer, NodeBounds.Min - v2{2, 2}, NodeBounds.Max + v2{2, 2}, WhiteV4); + } + + PushRenderQuad2D(RenderBuffer, NodeBounds.Min, NodeBounds.Max, v4{.5f, .5f, .5f, 1.f}); + + // TODO(Peter): This is just for debug purposes. We can remove and go back to just having + // Node->Name in DrawString + string NodeName = GetNodeName(*Node); + PrintF(&NodeHeaderBuffer, "%.*s: %d", NodeName.Length, NodeName.Memory, Node->Handle); + DrawString(RenderBuffer, NodeHeaderBuffer, State->NodeRenderSettings.Font, + v2{NodeBounds.Min.x + 5, NodeBounds.Max.y - (State->NodeRenderSettings.Font->PixelHeight + NODE_HEADER_HEIGHT + 5)}, + WhiteV4); + + for (s32 Connection = 0; Connection < Node->ConnectionsCount; Connection++) + { + v4 PortColor = State->NodeRenderSettings.PortColors[Node->Connections[Connection].Type]; + + // Inputs + if (ConnectionIsInput(Node, Connection)) + { + rect PortBounds = CalculateNodeInputPortBounds(Node, Connection, State->NodeRenderSettings); + DrawPort(RenderBuffer, PortBounds, PortColor); + + // + // TODO(Peter): I don't like excluding OutputNode, feels too much like a special case + // but I don't want to get in to the meta programming right now. + // We should just generate a spec and struct member types for NodeType_OutputNode + // + // :ExcludingOutputNodeSpecialCase + // + if (Node->Type != NodeType_OutputNode && DrawFields) + { + node_specification Spec = NodeSpecifications[Node->Type]; + node_struct_member Member = Spec.MemberList[Connection]; + DrawString(RenderBuffer, MakeString(Member.Name), + State->NodeRenderSettings.Font, + v2{PortBounds.Min.x - 8, PortBounds.Min.y}, WhiteV4, Align_Right); + } + + rect ValueBounds = CalculateNodeInputValueBounds(Node, Connection, State->NodeRenderSettings); + DrawValueDisplay(RenderBuffer, ValueBounds, Node->Connections[Connection], State->NodeRenderSettings.Font); + + // NOTE(Peter): its way easier to draw the connection on the input port b/c its a 1:1 relationship, + // whereas output ports might have many connections, they really only know about the most recent one + // Not sure if this is a problem. We mostly do everything backwards here, starting at the + // most downstream node and working back up to find dependencies. + if (ConnectionHasUpstreamConnection(Node, Connection)) + { + rect ConnectedPortBounds = GetBoundsOfPortConnectedToInput(Node, Connection, State->NodeList, State->NodeRenderSettings); + v2 InputCenter = CalculateRectCenter(PortBounds); + v2 OutputCenter = CalculateRectCenter(ConnectedPortBounds); + PushRenderLine2D(RenderBuffer, OutputCenter, InputCenter, 1, WhiteV4); + } + } + + // Outputs + if (ConnectionIsOutput(Node, Connection)) + { + rect PortBounds = CalculateNodeOutputPortBounds(Node, Connection, State->NodeRenderSettings); + DrawPort(RenderBuffer, PortBounds, PortColor); + + if (DrawFields) + { + node_specification Spec = NodeSpecifications[Node->Type]; + node_struct_member Member = Spec.MemberList[Connection]; + DrawString(RenderBuffer, MakeString(Member.Name), + State->NodeRenderSettings.Font, + v2{PortBounds.Max.x + 8, PortBounds.Min.y}, WhiteV4); + } + + rect ValueBounds = CalculateNodeOutputValueBounds(Node, Connection, State->NodeRenderSettings); + DrawValueDisplay(RenderBuffer, ValueBounds, Node->Connections[Connection], State->NodeRenderSettings.Font); + } + + for (s32 Button = 0; Button < 3; Button++) + { + rect ButtonRect = CalculateNodeDragHandleBounds(NodeBounds, Button, State->NodeRenderSettings); + PushRenderQuad2D(RenderBuffer, ButtonRect.Min, ButtonRect.Max, DragButtonColors[Button]); + } + } + + Next(&NodeIter); + } +} + +FOLDHAUS_INPUT_COMMAND_PROC(NodeViewDeleteNode) +{ + node_view_operation_state* OpState = GetCurrentOperationState(State->Modes, node_view_operation_state); + if (OpState->SelectedNodeHandle > 0) + { + node_header* SelectedNode = GetNodeWithHandle(State->NodeList, OpState->SelectedNodeHandle); + FreeNodeOnList(State->NodeList, SelectedNode); + } +} + +FOLDHAUS_INPUT_COMMAND_PROC(CloseNodeView) +{ + DeactivateCurrentOperationMode(&State->Modes); +} + +input_command NodeViewCommands [] = { + { KeyCode_Tab, KeyCode_Invalid, Command_Began, CloseNodeView}, + { KeyCode_A, KeyCode_Invalid, Command_Began, OpenNodeLister}, + { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Began, NodeViewBeginMouseDragInteraction}, + { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, NodeViewBeginMouseSelectInteraction}, + { KeyCode_X, KeyCode_Invalid, Command_Began, NodeViewDeleteNode}, +}; + +FOLDHAUS_INPUT_COMMAND_PROC(OpenNodeView) +{ + operation_mode* NodeViewMode = ActivateOperationModeWithCommands(&State->Modes, NodeViewCommands); + NodeViewMode->Render = RenderNodeView; + + node_view_operation_state* OpState = CreateOperationState(NodeViewMode, + &State->Modes, + node_view_operation_state); + + OpState->SelectedNodeHandle = 0; +}