Made nodes selectable
This commit is contained in:
parent
e9a6bdd376
commit
6d893433c4
|
@ -625,7 +625,8 @@ UPDATE_AND_RENDER(UpdateAndRender)
|
||||||
|
|
||||||
DEBUG_IF(GlobalDebugServices->Interface.RenderSculpture) // DebugServices RenderSculpture Toggle
|
DEBUG_IF(GlobalDebugServices->Interface.RenderSculpture) // DebugServices RenderSculpture Toggle
|
||||||
{
|
{
|
||||||
s32 JobsNeeded = IntegerDivideRoundUp(State->TotalLEDsCount, LED_BUFFER_SIZE);
|
s32 JobsNeeded = PLATFORM_THREAD_COUNT;
|
||||||
|
s32 LEDBufferSize = IntegerDivideRoundUp(State->TotalLEDsCount, JobsNeeded);
|
||||||
|
|
||||||
draw_leds_job_data* JobDataBank = PushArray(State->Transient, draw_leds_job_data, JobsNeeded);
|
draw_leds_job_data* JobDataBank = PushArray(State->Transient, draw_leds_job_data, JobsNeeded);
|
||||||
s32 JobDataBankUsed = 0;
|
s32 JobDataBankUsed = 0;
|
||||||
|
@ -645,7 +646,7 @@ UPDATE_AND_RENDER(UpdateAndRender)
|
||||||
JobData->LEDs = LEDBuffer->LEDs;
|
JobData->LEDs = LEDBuffer->LEDs;
|
||||||
JobData->Colors = LEDBuffer->Colors;
|
JobData->Colors = LEDBuffer->Colors;
|
||||||
JobData->StartIndex = LEDBufferLEDsAssignedToJobs;
|
JobData->StartIndex = LEDBufferLEDsAssignedToJobs;
|
||||||
JobData->OnePastLastIndex = GSMin(JobData->StartIndex + LED_BUFFER_SIZE, LEDBuffer->Count);
|
JobData->OnePastLastIndex = GSMin(JobData->StartIndex + LEDBufferSize, LEDBuffer->Count);
|
||||||
|
|
||||||
LEDBufferLEDsAssignedToJobs += JobData->OnePastLastIndex - JobData->StartIndex;
|
LEDBufferLEDsAssignedToJobs += JobData->OnePastLastIndex - JobData->StartIndex;
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
#include "foldhaus_network_ordering.h"
|
#include "foldhaus_network_ordering.h"
|
||||||
#include "foldhaus_sacn.h"
|
#include "foldhaus_sacn.h"
|
||||||
|
|
||||||
#define LED_BUFFER_SIZE 256
|
|
||||||
struct led
|
struct led
|
||||||
{
|
{
|
||||||
s32 Index;
|
s32 Index;
|
||||||
|
|
|
@ -48,7 +48,9 @@ struct debug_services
|
||||||
|
|
||||||
debug_timing_proc* GetWallClock;
|
debug_timing_proc* GetWallClock;
|
||||||
|
|
||||||
debug_histogram_entry ScopeHistogram[SCOPE_HISTOGRAM_SIZE];
|
debug_histogram_entry* ScopeHistogramUnsorted;
|
||||||
|
debug_histogram_entry* ScopeHistogramSorted;
|
||||||
|
|
||||||
s32 ScopeHistogramUsed;
|
s32 ScopeHistogramUsed;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -70,6 +72,9 @@ InitDebugServices (debug_services* Services, u8* Memory, s32 MemorySize, s32 Tra
|
||||||
Services->Interface.RenderSculpture = true;
|
Services->Interface.RenderSculpture = true;
|
||||||
Services->Interface.SendSACNData = false;
|
Services->Interface.SendSACNData = false;
|
||||||
|
|
||||||
|
Services->ScopeHistogramUnsorted = PushArray(&Services->DebugStorage, debug_histogram_entry, SCOPE_HISTOGRAM_SIZE);
|
||||||
|
Services->ScopeHistogramSorted = PushArray(&Services->DebugStorage, debug_histogram_entry, SCOPE_HISTOGRAM_SIZE);
|
||||||
|
|
||||||
Services->ScopeHistogramUsed = 0;
|
Services->ScopeHistogramUsed = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +84,7 @@ DEBUGFindScopeHistogram (debug_services* Services, string Name)
|
||||||
s32 Result = -1;
|
s32 Result = -1;
|
||||||
for (s32 i = 0; i < SCOPE_HISTOGRAM_SIZE; i++)
|
for (s32 i = 0; i < SCOPE_HISTOGRAM_SIZE; i++)
|
||||||
{
|
{
|
||||||
if (StringsEqual(Services->ScopeHistogram[i].ScopeName, Name))
|
if (StringsEqual(Services->ScopeHistogramUnsorted[i].ScopeName, Name))
|
||||||
{
|
{
|
||||||
Result = i;
|
Result = i;
|
||||||
break;
|
break;
|
||||||
|
@ -95,7 +100,7 @@ DEBUGAddScopeHistogram (debug_services* Services, scope_time_record Record)
|
||||||
|
|
||||||
s32 Result = Services->ScopeHistogramUsed++;
|
s32 Result = Services->ScopeHistogramUsed++;
|
||||||
|
|
||||||
debug_histogram_entry* Entry = Services->ScopeHistogram + Result;
|
debug_histogram_entry* Entry = Services->ScopeHistogramUnsorted + Result;
|
||||||
Entry->ScopeName = MakeString(Entry->ScopeName_, 256);
|
Entry->ScopeName = MakeString(Entry->ScopeName_, 256);
|
||||||
|
|
||||||
Entry->CurrentFrame = 0;
|
Entry->CurrentFrame = 0;
|
||||||
|
@ -112,7 +117,7 @@ DEBUGAddScopeHistogram (debug_services* Services, scope_time_record Record)
|
||||||
internal void
|
internal void
|
||||||
DEBUGRecordScopeInHistogram (debug_services* Services, s32 Index, scope_time_record Record)
|
DEBUGRecordScopeInHistogram (debug_services* Services, s32 Index, scope_time_record Record)
|
||||||
{
|
{
|
||||||
debug_histogram_entry* Entry = Services->ScopeHistogram + Index;
|
debug_histogram_entry* Entry = Services->ScopeHistogramUnsorted + Index;
|
||||||
s32 FrameIndex = Entry->CurrentFrame;
|
s32 FrameIndex = Entry->CurrentFrame;
|
||||||
if (FrameIndex >= 0 && FrameIndex < HISTOGRAM_DEPTH)
|
if (FrameIndex >= 0 && FrameIndex < HISTOGRAM_DEPTH)
|
||||||
{
|
{
|
||||||
|
@ -138,6 +143,43 @@ DEBUGCacheScopeHistogramValues (debug_histogram_entry* Histogram)
|
||||||
Histogram->Average_CallCount = (Histogram->Total_CallCount / HISTOGRAM_DEPTH);
|
Histogram->Average_CallCount = (Histogram->Total_CallCount / HISTOGRAM_DEPTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
DEBUGSortedHistogramInsert(debug_histogram_entry Source, debug_histogram_entry* DestList, s32 DestCount, s32 Max)
|
||||||
|
{
|
||||||
|
s32 CurrentFrame0 = Source.CurrentFrame;
|
||||||
|
s32 V0 = Source.Average_Cycles; //PerFrame_Cycles[CurrentFrame0];
|
||||||
|
if (DestCount > 0)
|
||||||
|
{
|
||||||
|
for (s32 i = DestCount - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
s32 CurrentFrame1 = DestList[i].CurrentFrame;
|
||||||
|
s32 V1 = DestList[i].Average_Cycles; //PerFrame_Cycles[CurrentFrame1];
|
||||||
|
if (V0 < V1)
|
||||||
|
{
|
||||||
|
DestList[i + 1] = Source;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DestList[i + 1] = DestList[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DestList[0] = Source;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
DEBUGSortHistogram(debug_histogram_entry* Source, debug_histogram_entry* Dest, s32 Count, s32 Max)
|
||||||
|
{
|
||||||
|
for (s32 i = 0; i < Count; i++)
|
||||||
|
{
|
||||||
|
DEBUGSortedHistogramInsert(Source[i], Dest, i, Max);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
DEBUGCollateScopeRecords (debug_services* Services)
|
DEBUGCollateScopeRecords (debug_services* Services)
|
||||||
{
|
{
|
||||||
|
@ -155,8 +197,13 @@ DEBUGCollateScopeRecords (debug_services* Services)
|
||||||
|
|
||||||
for (s32 h = 0; h < Services->ScopeHistogramUsed; h++)
|
for (s32 h = 0; h < Services->ScopeHistogramUsed; h++)
|
||||||
{
|
{
|
||||||
DEBUGCacheScopeHistogramValues(Services->ScopeHistogram + h);
|
DEBUGCacheScopeHistogramValues(Services->ScopeHistogramUnsorted + h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEBUGSortHistogram(Services->ScopeHistogramUnsorted,
|
||||||
|
Services->ScopeHistogramSorted,
|
||||||
|
Services->ScopeHistogramUsed,
|
||||||
|
SCOPE_HISTOGRAM_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
|
@ -169,14 +216,14 @@ EndDebugFrame (debug_services* Services)
|
||||||
|
|
||||||
for (s32 i = 0; i < Services->ScopeHistogramUsed; i++)
|
for (s32 i = 0; i < Services->ScopeHistogramUsed; i++)
|
||||||
{
|
{
|
||||||
s32 NewFrame = Services->ScopeHistogram[i].CurrentFrame + 1;
|
s32 NewFrame = Services->ScopeHistogramUnsorted[i].CurrentFrame + 1;
|
||||||
if (NewFrame >= HISTOGRAM_DEPTH)
|
if (NewFrame >= HISTOGRAM_DEPTH)
|
||||||
{
|
{
|
||||||
NewFrame = 0;
|
NewFrame = 0;
|
||||||
}
|
}
|
||||||
Services->ScopeHistogram[i].CurrentFrame = NewFrame;
|
Services->ScopeHistogramUnsorted[i].CurrentFrame = NewFrame;
|
||||||
Services->ScopeHistogram[i].PerFrame_Cycles[NewFrame] = 0;
|
Services->ScopeHistogramUnsorted[i].PerFrame_Cycles[NewFrame] = 0;
|
||||||
Services->ScopeHistogram[i].PerFrame_CallCount[NewFrame] = 0;
|
Services->ScopeHistogramUnsorted[i].PerFrame_CallCount[NewFrame] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -119,22 +119,22 @@ DrawDebugInterface (render_command_buffer* RenderBuffer, r32 StartX, interface_c
|
||||||
{
|
{
|
||||||
v2 Register = v2{ColumnsStartX, TopOfScreenLinePos.y};
|
v2 Register = v2{ColumnsStartX, TopOfScreenLinePos.y};
|
||||||
|
|
||||||
s32 CurrentFrame = GlobalDebugServices->ScopeHistogram[i].CurrentFrame - 1;
|
s32 CurrentFrame = GlobalDebugServices->ScopeHistogramSorted[i].CurrentFrame - 1;
|
||||||
if (CurrentFrame < 0) { CurrentFrame = HISTOGRAM_DEPTH - 1; }
|
if (CurrentFrame < 0) { CurrentFrame = HISTOGRAM_DEPTH - 1; }
|
||||||
|
|
||||||
u64 CyclesPerHit = GlobalDebugServices->ScopeHistogram[i].PerFrame_Cycles[CurrentFrame];
|
u64 CyclesPerHit = GlobalDebugServices->ScopeHistogramSorted[i].PerFrame_Cycles[CurrentFrame];
|
||||||
r32 SecondsPerHit = (r32)CyclesPerHit / (r32)GlobalDebugServices->PerformanceCountFrequency;
|
r32 SecondsPerHit = (r32)CyclesPerHit / (r32)GlobalDebugServices->PerformanceCountFrequency;
|
||||||
|
|
||||||
// Column 1
|
// Column 1
|
||||||
PrintF(&DebugString, "%.*s",
|
PrintF(&DebugString, "%.*s",
|
||||||
GlobalDebugServices->ScopeHistogram[i].ScopeName.Length,
|
GlobalDebugServices->ScopeHistogramSorted[i].ScopeName.Length,
|
||||||
GlobalDebugServices->ScopeHistogram[i].ScopeName.Memory);
|
GlobalDebugServices->ScopeHistogramSorted[i].ScopeName.Memory);
|
||||||
r32 ColumnOneX = DrawString(RenderBuffer, DebugString, Interface.Font, Interface.FontSize,
|
r32 ColumnOneX = DrawString(RenderBuffer, DebugString, Interface.Font, Interface.FontSize,
|
||||||
Register, WhiteV4).x;
|
Register, WhiteV4).x;
|
||||||
Register.x += GSMax(ColumnOneX - Register.x, 250.f);
|
Register.x += GSMax(ColumnOneX - Register.x, 250.f);
|
||||||
|
|
||||||
// Column 2
|
// Column 2
|
||||||
PrintF(&DebugString, "%d hits", GlobalDebugServices->ScopeHistogram[i].PerFrame_CallCount[CurrentFrame]);
|
PrintF(&DebugString, "%d hits", GlobalDebugServices->ScopeHistogramSorted[i].PerFrame_CallCount[CurrentFrame]);
|
||||||
r32 ColumnTwoX = DrawString(RenderBuffer, DebugString, Interface.Font, Interface.FontSize,
|
r32 ColumnTwoX = DrawString(RenderBuffer, DebugString, Interface.Font, Interface.FontSize,
|
||||||
Register, WhiteV4).x;
|
Register, WhiteV4).x;
|
||||||
Register.x += GSMax(ColumnTwoX - Register.x, 150.f);
|
Register.x += GSMax(ColumnTwoX - Register.x, 150.f);
|
||||||
|
|
|
@ -413,17 +413,18 @@ BeginDraggingNode(app_state* State, node_interaction Interaction)
|
||||||
|
|
||||||
struct node_view_operation_state
|
struct node_view_operation_state
|
||||||
{
|
{
|
||||||
|
node_offset SelectedNodeOffset;
|
||||||
};
|
};
|
||||||
|
|
||||||
FOLDHAUS_INPUT_COMMAND_PROC(NodeViewBeginMouseDragInteraction)
|
FOLDHAUS_INPUT_COMMAND_PROC(NodeViewBeginMouseDragInteraction)
|
||||||
{
|
{
|
||||||
node_view_operation_state* OpState = GetCurrentOperationState(State->Modes, node_view_operation_state);
|
node_view_operation_state* OpState = GetCurrentOperationState(State->Modes, node_view_operation_state);
|
||||||
|
|
||||||
node_offset Node = GetNodeUnderPoint(State->NodeList, Mouse.DownPos, State->NodeRenderSettings);
|
node_offset NodeOffset = GetNodeUnderPoint(State->NodeList, Mouse.DownPos, State->NodeRenderSettings);
|
||||||
if (Node.Node)
|
if (NodeOffset.Node)
|
||||||
{
|
{
|
||||||
node_interaction NewInteraction = GetNodeInteractionType(Node.Node,
|
node_interaction NewInteraction = GetNodeInteractionType(NodeOffset.Node,
|
||||||
Node.Offset,
|
NodeOffset.Offset,
|
||||||
Mouse.Pos,
|
Mouse.Pos,
|
||||||
State->NodeRenderSettings);
|
State->NodeRenderSettings);
|
||||||
if (IsDraggingNodePort(NewInteraction))
|
if (IsDraggingNodePort(NewInteraction))
|
||||||
|
@ -439,9 +440,14 @@ FOLDHAUS_INPUT_COMMAND_PROC(NodeViewBeginMouseDragInteraction)
|
||||||
}
|
}
|
||||||
else // IsDraggingNode
|
else // IsDraggingNode
|
||||||
{
|
{
|
||||||
|
OpState->SelectedNodeOffset = NodeOffset;
|
||||||
BeginDraggingNode(State, NewInteraction);
|
BeginDraggingNode(State, NewInteraction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OpState->SelectedNodeOffset = InvalidNodeOffset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FOLDHAUS_INPUT_COMMAND_PROC(NodeViewBeginMouseSelectInteraction)
|
FOLDHAUS_INPUT_COMMAND_PROC(NodeViewBeginMouseSelectInteraction)
|
||||||
|
@ -475,7 +481,108 @@ FOLDHAUS_INPUT_COMMAND_PROC(NodeViewBeginMouseSelectInteraction)
|
||||||
OPERATION_RENDER_PROC(RenderNodeView)
|
OPERATION_RENDER_PROC(RenderNodeView)
|
||||||
{
|
{
|
||||||
node_view_operation_state* OpState = (node_view_operation_state*)Operation.OpStateMemory;
|
node_view_operation_state* OpState = (node_view_operation_state*)Operation.OpStateMemory;
|
||||||
RenderNodeList(State->NodeList, State->NodeRenderSettings, RenderBuffer);
|
|
||||||
|
DEBUG_TRACK_FUNCTION;
|
||||||
|
|
||||||
|
node_list_iterator NodeIter = GetNodeListIterator(*State->NodeList);
|
||||||
|
while (NodeIteratorIsValid(NodeIter))
|
||||||
|
{
|
||||||
|
interface_node* Node = NodeIter.At;
|
||||||
|
Node->Min = Node->MinAfterUpdate;
|
||||||
|
|
||||||
|
rect NodeBounds = CalculateNodeBounds(Node, State->NodeRenderSettings);
|
||||||
|
b32 DrawFields = PointIsInRect(Mouse.Pos, NodeBounds);
|
||||||
|
|
||||||
|
if (Node == OpState->SelectedNodeOffset.Node)
|
||||||
|
{
|
||||||
|
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});
|
||||||
|
|
||||||
|
DrawString(RenderBuffer, Node->Name, State->NodeRenderSettings.Font, State->NodeRenderSettings.Font->PixelHeight,
|
||||||
|
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 - 1];
|
||||||
|
node_struct_member Member = Spec.MemberList[Connection];
|
||||||
|
DrawString(RenderBuffer, MakeString(Member.Name),
|
||||||
|
State->NodeRenderSettings.Font, State->NodeRenderSettings.Font->PixelHeight,
|
||||||
|
v2{PortBounds.Min.x - 32, PortBounds.Min.y}, WhiteV4);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 - 1];
|
||||||
|
node_struct_member Member = Spec.MemberList[Connection];
|
||||||
|
DrawString(RenderBuffer, MakeString(Member.Name),
|
||||||
|
State->NodeRenderSettings.Font, State->NodeRenderSettings.Font->PixelHeight,
|
||||||
|
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 = (node_view_operation_state*)Operation.OpStateMemory;
|
||||||
|
if (IsValidOffset(OpState->SelectedNodeOffset))
|
||||||
|
{
|
||||||
|
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
FOLDHAUS_INPUT_COMMAND_PROC(CloseNodeView)
|
FOLDHAUS_INPUT_COMMAND_PROC(CloseNodeView)
|
||||||
|
@ -488,6 +595,7 @@ input_command NodeViewCommands [] = {
|
||||||
{ KeyCode_A, KeyCode_Invalid, Command_Began, OpenNodeLister},
|
{ KeyCode_A, KeyCode_Invalid, Command_Began, OpenNodeLister},
|
||||||
{ KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Began, NodeViewBeginMouseDragInteraction},
|
{ KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Began, NodeViewBeginMouseDragInteraction},
|
||||||
{ KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, NodeViewBeginMouseSelectInteraction},
|
{ KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, NodeViewBeginMouseSelectInteraction},
|
||||||
|
{ KeyCode_X, KeyCode_Invalid, Command_Began, NodeViewDeleteNode},
|
||||||
};
|
};
|
||||||
|
|
||||||
FOLDHAUS_INPUT_COMMAND_PROC(OpenNodeView)
|
FOLDHAUS_INPUT_COMMAND_PROC(OpenNodeView)
|
||||||
|
@ -498,6 +606,7 @@ FOLDHAUS_INPUT_COMMAND_PROC(OpenNodeView)
|
||||||
node_view_operation_state* OpState = CreateOperationState(NodeViewMode,
|
node_view_operation_state* OpState = CreateOperationState(NodeViewMode,
|
||||||
&State->Modes,
|
&State->Modes,
|
||||||
node_view_operation_state);
|
node_view_operation_state);
|
||||||
|
OpState->SelectedNodeOffset = InvalidNodeOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////
|
////////////////////////////////////////
|
||||||
|
|
|
@ -1,3 +1,20 @@
|
||||||
|
inline node_offset
|
||||||
|
InvalidNodeOffset()
|
||||||
|
{
|
||||||
|
node_offset Result = {};
|
||||||
|
|
||||||
|
// NOTE(Peter): I'm not sure this is actually invalid. Should be.
|
||||||
|
// If it is valid, it implies you can have offset from somewhere other than the beginning of
|
||||||
|
// the array, but where that point is isn't captured here so it seems like that shouldn't be
|
||||||
|
// correct
|
||||||
|
Result.Offset = -1;
|
||||||
|
Result.Node = 0; // NOTE(Peter): Pretty sure this is invalid tho ;)
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define IsValidOffset(off) ((off.Node != 0) && (off.Offset >= 0))
|
||||||
|
#define IsInvalidOffset(off) ((off.Node == 0) && (off.Offset < 0))
|
||||||
|
|
||||||
inline s32
|
inline s32
|
||||||
GetNodeMemorySize (interface_node Node)
|
GetNodeMemorySize (interface_node Node)
|
||||||
|
@ -136,6 +153,7 @@ CalculateNodeHeight (s32 Members)
|
||||||
internal void
|
internal void
|
||||||
PushNodeOnListFromSpecification (node_list* List, node_specification Spec, v2 Min, memory_arena* Storage)
|
PushNodeOnListFromSpecification (node_list* List, node_specification Spec, v2 Min, memory_arena* Storage)
|
||||||
{
|
{
|
||||||
|
// :NodesDontNeedToKnowTheirBounds
|
||||||
r32 NodeHeight = CalculateNodeHeight (Spec.MemberListLength);
|
r32 NodeHeight = CalculateNodeHeight (Spec.MemberListLength);
|
||||||
interface_node* Node = PushNodeOnList(List,
|
interface_node* Node = PushNodeOnList(List,
|
||||||
Spec.NameLength,
|
Spec.NameLength,
|
||||||
|
@ -1045,72 +1063,6 @@ DrawPort (render_command_buffer* RenderBuffer, rect Bounds, v4 Color)
|
||||||
PushRenderQuad2D(RenderBuffer, Bounds.Min, Bounds.Max, Color);
|
PushRenderQuad2D(RenderBuffer, Bounds.Min, Bounds.Max, Color);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
|
||||||
RenderNodeList (node_list* NodeList, node_render_settings RenderSettings, render_command_buffer* RenderBuffer)
|
|
||||||
{
|
|
||||||
DEBUG_TRACK_FUNCTION;
|
|
||||||
|
|
||||||
node_list_iterator NodeIter = GetNodeListIterator(*NodeList);
|
|
||||||
while (NodeIteratorIsValid(NodeIter))
|
|
||||||
{
|
|
||||||
interface_node* Node = NodeIter.At;
|
|
||||||
Node->Min = Node->MinAfterUpdate;
|
|
||||||
|
|
||||||
rect NodeBounds = CalculateNodeBounds(Node, RenderSettings);
|
|
||||||
|
|
||||||
PushRenderQuad2D(RenderBuffer, NodeBounds.Min, NodeBounds.Max, v4{.5f, .5f, .5f, 1.f});
|
|
||||||
|
|
||||||
DrawString(RenderBuffer, Node->Name, RenderSettings.Font, RenderSettings.Font->PixelHeight,
|
|
||||||
v2{NodeBounds.Min.x + 5, NodeBounds.Max.y - (RenderSettings.Font->PixelHeight + NODE_HEADER_HEIGHT + 5)},
|
|
||||||
WhiteV4);
|
|
||||||
|
|
||||||
for (s32 Connection = 0; Connection < Node->ConnectionsCount; Connection++)
|
|
||||||
{
|
|
||||||
// Inputs
|
|
||||||
if (ConnectionIsInput(Node, Connection))
|
|
||||||
{
|
|
||||||
rect PortBounds = CalculateNodeInputPortBounds(Node, Connection, RenderSettings);
|
|
||||||
v4 PortColor = RenderSettings.PortColors[Node->Connections[Connection].Type];
|
|
||||||
DrawPort(RenderBuffer, PortBounds, PortColor);
|
|
||||||
|
|
||||||
rect ValueBounds = CalculateNodeInputValueBounds(Node, Connection, RenderSettings);
|
|
||||||
DrawValueDisplay(RenderBuffer, ValueBounds, Node->Connections[Connection], RenderSettings.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, NodeList, RenderSettings);
|
|
||||||
v2 InputCenter = CalculateRectCenter(PortBounds);
|
|
||||||
v2 OutputCenter = CalculateRectCenter(ConnectedPortBounds);
|
|
||||||
PushRenderLine2D(RenderBuffer, OutputCenter, InputCenter, 1, WhiteV4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Outputs
|
|
||||||
if (ConnectionIsOutput(Node, Connection))
|
|
||||||
{
|
|
||||||
rect PortBounds = CalculateNodeOutputPortBounds(Node, Connection, RenderSettings);
|
|
||||||
v4 PortColor = RenderSettings.PortColors[Node->Connections[Connection].Type];
|
|
||||||
DrawPort(RenderBuffer, PortBounds, PortColor);
|
|
||||||
|
|
||||||
rect ValueBounds = CalculateNodeOutputValueBounds(Node, Connection, RenderSettings);
|
|
||||||
DrawValueDisplay(RenderBuffer, ValueBounds, Node->Connections[Connection], RenderSettings.Font);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (s32 Button = 0; Button < 3; Button++)
|
|
||||||
{
|
|
||||||
rect ButtonRect = CalculateNodeDragHandleBounds(NodeBounds, Button, RenderSettings);
|
|
||||||
PushRenderQuad2D(RenderBuffer, ButtonRect.Min, ButtonRect.Max, DragButtonColors[Button]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Next(&NodeIter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
ResetNodesUpdateState (node_list* NodeList)
|
ResetNodesUpdateState (node_list* NodeList)
|
||||||
{
|
{
|
||||||
|
|
|
@ -57,6 +57,8 @@ typedef DRAW_FONT_CODEPOINT(platform_draw_font_codepoint);
|
||||||
|
|
||||||
// Worker Threads
|
// Worker Threads
|
||||||
|
|
||||||
|
#define PLATFORM_THREAD_COUNT 4
|
||||||
|
|
||||||
#define THREADED_WORK_PROC(name) void name(s32 ThreadID, void* Data)
|
#define THREADED_WORK_PROC(name) void name(s32 ThreadID, void* Data)
|
||||||
typedef THREADED_WORK_PROC(threaded_work_proc);
|
typedef THREADED_WORK_PROC(threaded_work_proc);
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,8 @@ DrawCharacter (render_quad_batch_constructor* BatchConstructor, char C, bitmap_f
|
||||||
return v2{Position.x + CodepointInfo.Width * FontScale, Position.y};
|
return v2{Position.x + CodepointInfo.Width * FontScale, Position.y};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(Peter): Why are we passing in both the bitmap_font and the point size when everywhere, we just
|
||||||
|
// use the native point size of the font???
|
||||||
internal v2
|
internal v2
|
||||||
DrawString (render_command_buffer* RenderBuffer, string String, bitmap_font* Font, s32 PointSize, v2 Position, v4 Color)
|
DrawString (render_command_buffer* RenderBuffer, string String, bitmap_font* Font, s32 PointSize, v2 Position, v4 Color)
|
||||||
{
|
{
|
||||||
|
|
|
@ -533,22 +533,22 @@ INT NCmdShow
|
||||||
// Set up worker threads
|
// Set up worker threads
|
||||||
//
|
//
|
||||||
|
|
||||||
const s32 WorkerThreadCount = 2;
|
const s32 WorkerThreadCount = PLATFORM_THREAD_COUNT;
|
||||||
worker_thread_info* WorkerThreads = 0;
|
worker_thread_info* WorkerThreads = 0;
|
||||||
if (WorkerThreadCount > 0)
|
if (PLATFORM_THREAD_COUNT > 0)
|
||||||
{
|
{
|
||||||
WorkerThreads = (worker_thread_info*)malloc(sizeof(worker_thread_info) * WorkerThreadCount);
|
WorkerThreads = (worker_thread_info*)malloc(sizeof(worker_thread_info) * PLATFORM_THREAD_COUNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
work_queue WorkQueue = {};
|
work_queue WorkQueue = {};
|
||||||
WorkQueue.SemaphoreHandle = CreateSemaphoreEx(0, 0, WorkerThreadCount, 0, 0, SEMAPHORE_ALL_ACCESS);
|
WorkQueue.SemaphoreHandle = CreateSemaphoreEx(0, 0, PLATFORM_THREAD_COUNT, 0, 0, SEMAPHORE_ALL_ACCESS);
|
||||||
WorkQueue.JobsMax = 256;
|
WorkQueue.JobsMax = 256;
|
||||||
WorkQueue.NextJobIndex = 0;
|
WorkQueue.NextJobIndex = 0;
|
||||||
WorkQueue.PushWorkOnQueue = Win32PushWorkOnQueue;
|
WorkQueue.PushWorkOnQueue = Win32PushWorkOnQueue;
|
||||||
WorkQueue.DoQueueWorkUntilDone = Win32DoQueueWorkUntilDone;
|
WorkQueue.DoQueueWorkUntilDone = Win32DoQueueWorkUntilDone;
|
||||||
WorkQueue.ResetWorkQueue = ResetWorkQueue;
|
WorkQueue.ResetWorkQueue = ResetWorkQueue;
|
||||||
|
|
||||||
for (s32 i = 0; i < WorkerThreadCount; i++)
|
for (s32 i = 0; i < PLATFORM_THREAD_COUNT; i++)
|
||||||
{
|
{
|
||||||
// ID = 0 is reserved for this thread
|
// ID = 0 is reserved for this thread
|
||||||
WorkerThreads[i].ID = i + 1;
|
WorkerThreads[i].ID = i + 1;
|
||||||
|
@ -670,7 +670,7 @@ INT NCmdShow
|
||||||
CleanupResult = WSACleanup();
|
CleanupResult = WSACleanup();
|
||||||
}while(CleanupResult == SOCKET_ERROR);
|
}while(CleanupResult == SOCKET_ERROR);
|
||||||
|
|
||||||
for (s32 Thread = 0; Thread < WorkerThreadCount; Thread++)
|
for (s32 Thread = 0; Thread < PLATFORM_THREAD_COUNT; Thread++)
|
||||||
{
|
{
|
||||||
TerminateThread(WorkerThreads[Thread].Handle, 0);
|
TerminateThread(WorkerThreads[Thread].Handle, 0);
|
||||||
}
|
}
|
||||||
|
|
22
todo.txt
22
todo.txt
|
@ -8,27 +8,32 @@ Hardening
|
||||||
- Then we want to think about separating out mode render functions from mode update functions. Not sure its necessary but having something that operates like an update funciton but is called render is weird. Might want some sort of coroutine functionality in place, where modes can add and remove optional, parallel
|
- Then we want to think about separating out mode render functions from mode update functions. Not sure its necessary but having something that operates like an update funciton but is called render is weird. Might want some sort of coroutine functionality in place, where modes can add and remove optional, parallel
|
||||||
update functions
|
update functions
|
||||||
- memory visualization
|
- memory visualization
|
||||||
|
- - Log memory allocations
|
||||||
- separate rendering thread
|
- separate rendering thread
|
||||||
- cache led positions. Only update if they are moving
|
- cache led positions. Only update if they are moving
|
||||||
- - shift drag to 10x drag speed
|
- - shift drag to 10x drag speed
|
||||||
- select nodes -> delete nodes
|
|
||||||
- remove node connections
|
|
||||||
|
|
||||||
UI Improvements
|
UI Improvements
|
||||||
- highlight node field under active edit
|
- highlight node field under active edit
|
||||||
- print node field names on hover or on the node
|
- draw cursor in node field under active edit
|
||||||
|
x print node field names on hover or on the node
|
||||||
|
- Mouse Held Commands
|
||||||
|
- Actual cursor states
|
||||||
|
|
||||||
|
API Improvements
|
||||||
|
- Clean up DrawString... good lord
|
||||||
|
- Add Text Alignment to DrawString
|
||||||
|
- Investigate why we're giving nodes bounds :NodesDontNeedToKnowTheirBounds
|
||||||
|
- - Cant we just calculate this at render time?
|
||||||
|
|
||||||
Application
|
Application
|
||||||
- More efficient HSV <-> RGB
|
- More efficient HSV <-> RGB
|
||||||
|
|
||||||
- Save and load a session
|
- Save and load a session
|
||||||
- - Serialize Nodes
|
|
||||||
- Don't render if the window isn't visible
|
- Don't render if the window isn't visible
|
||||||
|
|
||||||
Development
|
Development
|
||||||
- Fix your scope time tracker to account for threads.
|
- Fix your scope time tracker to account for threads.
|
||||||
- Nest scope times so you can see totals/dig in
|
- Nest scope times so you can see totals/dig in
|
||||||
- Log memory allocations
|
|
||||||
|
|
||||||
Interface
|
Interface
|
||||||
- fullscreen
|
- fullscreen
|
||||||
|
@ -40,10 +45,11 @@ Interface
|
||||||
- Update the text system - use system fonts
|
- Update the text system - use system fonts
|
||||||
|
|
||||||
Switch To Nodes
|
Switch To Nodes
|
||||||
- evaluation step (one node at a time)
|
|
||||||
- selector node (has a list of connections that it can switch between)
|
- selector node (has a list of connections that it can switch between)
|
||||||
- serialize
|
|
||||||
- delete nodes
|
- delete nodes
|
||||||
|
- remove node connections
|
||||||
|
- Serialize Nodes
|
||||||
|
- evaluation step (one node at a time)
|
||||||
|
|
||||||
Structure
|
Structure
|
||||||
- motion
|
- motion
|
||||||
|
|
|
@ -20,6 +20,7 @@ x decided I don't like storing NodeRenderSettings in each operation mode. Probab
|
||||||
/Debug
|
/Debug
|
||||||
x Make debug scope tracking thread safe - was throwing an error in stringsequal but that stopped.
|
x Make debug scope tracking thread safe - was throwing an error in stringsequal but that stopped.
|
||||||
x Keep an eye out.
|
x Keep an eye out.
|
||||||
|
x Sort Scope Tracking
|
||||||
|
|
||||||
Switch To Nodes
|
Switch To Nodes
|
||||||
x basic node elements
|
x basic node elements
|
||||||
|
|
Loading…
Reference in New Issue