Created a panel system and began moving everything over to it.

This commit is contained in:
Peter Slattery 2019-12-26 12:42:55 -08:00
parent f491988c90
commit 9b9fe2f5e1
12 changed files with 1030 additions and 265 deletions

View File

@ -15,147 +15,3 @@ FOLDHAUS_INPUT_COMMAND_PROC(DeleteAnimationBlock)
State->SelectedAnimationBlockHandle = {0}; State->SelectedAnimationBlockHandle = {0};
} }
} }
internal animation_block_handle
DrawAnimationTimeline (animation_system* AnimationSystem, v2 PanelMin, v2 PanelMax, animation_block_handle SelectedBlockHandle, render_command_buffer* RenderBuffer, interface_config Interface, mouse_state Mouse)
{
animation_block_handle Result = SelectedBlockHandle;
r32 AnimationPanelHeight = PanelMax.y - PanelMin.y;
r32 AnimationPanelWidth = PanelMax.x - PanelMin.x;
panel_result AnimationPanel = EvaluatePanel(RenderBuffer, PanelMin, PanelMax,
0, Interface);
b32 MouseDownAndNotHandled = MouseButtonTransitionedDown(Mouse.LeftButtonState);
for (u32 i = 0; i < AnimationSystem->BlocksCount; i++)
{
animation_block_entry AnimationBlockEntry = AnimationSystem->Blocks[i];
if (AnimationBlockIsFree(AnimationBlockEntry)) { continue; }
animation_block_handle CurrentBlockHandle = {};
CurrentBlockHandle.Index = i;
CurrentBlockHandle.Generation = AnimationBlockEntry.Generation;
animation_block AnimationBlockAt = AnimationBlockEntry.Block;
r32 StartTimePercent = AnimationBlockAt.StartTime / AnimationSystem->AnimationEnd;
r32 StartPosition = AnimationPanelWidth * StartTimePercent;
r32 EndTimePercent = AnimationBlockAt.EndTime / AnimationSystem->AnimationEnd;
r32 EndPosition = AnimationPanelWidth * EndTimePercent;
v2 Min = v2{StartPosition, 25};
v2 Max = v2{EndPosition, 75};
v4 BlockColor = BlackV4;
if (AnimationBlockHandlesAreEqual(SelectedBlockHandle, CurrentBlockHandle))
{
BlockColor = PinkV4;
}
PushRenderQuad2D(RenderBuffer, Min, Max, BlockColor);
PushRenderBoundingBox2D(RenderBuffer, Min, Max, 1, WhiteV4);
if (PointIsInRange(Mouse.Pos, Min, Max)
&& MouseButtonTransitionedDown(Mouse.LeftButtonState))
{
MouseDownAndNotHandled = false;
if (AnimationBlockHandlesAreEqual(SelectedBlockHandle, CurrentBlockHandle))
{
// If the block is already selected, deselect it.
Result = {0};
}
else
{
Result = CurrentBlockHandle;
}
}
}
r32 TimePercent = AnimationSystem->Time / AnimationSystem->AnimationEnd;
r32 SliderPosition = AnimationPanelWidth * TimePercent;
PushRenderQuad2D(RenderBuffer, v2{SliderPosition, AnimationPanelHeight},
v2{SliderPosition + 1, 0}, WhiteV4);
if (MouseDownAndNotHandled && PointIsInRange(Mouse.Pos, PanelMin, PanelMax))
{
r32 MouseDownPositionPercent = (Mouse.Pos.x - PanelMin.x) / AnimationPanelWidth;
r32 NewBlockTimeStart = MouseDownPositionPercent * AnimationSystem->AnimationEnd;
#define NEW_BLOCK_DURATION 1
r32 NewBlockTimeEnd = NewBlockTimeStart + NEW_BLOCK_DURATION;
animation_block Block = {0};
Block.StartTime = NewBlockTimeStart;
Block.EndTime = NewBlockTimeEnd;
Block.Proc = TestPatternThree;
animation_block_handle NewBlockHandle = AddAnimationBlock(Block, AnimationSystem);
Result = NewBlockHandle;
}
return Result;
}
internal animation_block_handle
DrawAnimationPanel (animation_system* AnimationSystem,
v2 PanelMin, v2 PanelMax,
animation_block_handle SelectedBlockHandle,
render_command_buffer* RenderBuffer,
interface_config Interface, mouse_state Mouse)
{
animation_block_handle Result = SelectedBlockHandle;
r32 OptionsRowHeight = 25;
v2 TimelineMin = PanelMin;
v2 TimelineMax = v2{PanelMax.x, PanelMax.y - OptionsRowHeight};
if (TimelineMax.y - TimelineMin.y > 0)
{
Result = DrawAnimationTimeline(AnimationSystem,
TimelineMin, TimelineMax,
SelectedBlockHandle,
RenderBuffer, Interface, Mouse);
}
v2 OptionsRowMin = v2{ PanelMin.x, TimelineMax.y };
v2 OptionsRowMax = PanelMax;
panel_result AnimationPanel = EvaluatePanel(RenderBuffer, OptionsRowMin, OptionsRowMax,
0, Interface);
r32 ButtonWidth = 35;
v2 ButtonMin = v2{0, 0};
v2 ButtonMax = v2{35, OptionsRowHeight - 2};
v2 ButtonAt = v2{OptionsRowMin.x + 1, OptionsRowMin.y + 1};
button_result PauseResult = EvaluateButton(RenderBuffer,
ButtonAt + ButtonMin, ButtonAt + ButtonMax,
MakeStringLiteral("Pause"),
Interface, Mouse);
ButtonAt.x += ButtonWidth + 2;
button_result PlayResult = EvaluateButton(RenderBuffer,
ButtonAt + ButtonMin, ButtonAt + ButtonMax,
MakeStringLiteral("Play"),
Interface, Mouse);
ButtonAt.x += ButtonWidth + 2;
button_result StopResult = EvaluateButton(RenderBuffer,
ButtonAt + ButtonMin, ButtonAt + ButtonMax,
MakeStringLiteral("Stop"),
Interface, Mouse);
if (PauseResult.Pressed)
{
AnimationSystem->TimelineShouldAdvance = false;
}
if (PlayResult.Pressed)
{
AnimationSystem->TimelineShouldAdvance = true;
}
if (StopResult.Pressed)
{
AnimationSystem->TimelineShouldAdvance = false;
AnimationSystem->Time = 0;
}
return Result;
}

View File

@ -22,68 +22,6 @@ MouseToWorldRay(r32 MouseX, r32 MouseY, camera* Camera, r32 WindowWidth, r32 Win
return WorldPosition; return WorldPosition;
} }
struct draw_leds_job_data
{
led* LEDs;
pixel* Colors;
s32 StartIndex;
s32 OnePastLastIndex;
render_quad_batch_constructor* Batch;
m44 FaceCameraMatrix;
m44 ModelViewMatrix;
r32 LEDHalfWidth;
};
internal void
DrawLEDsInBufferRangeJob (s32 ThreadID, void* JobData)
{
DEBUG_TRACK_FUNCTION;
draw_leds_job_data* Data = (draw_leds_job_data*)JobData;
s32 LEDCount = Data->OnePastLastIndex - Data->StartIndex;
quad_batch_constructor_reserved_range BatchReservedRange = ThreadSafeReserveRangeInQuadConstructor(Data->Batch, LEDCount * 2);
s32 TrisUsed = 0;
r32 HalfWidth = Data->LEDHalfWidth;
v4 P0_In = v4{-HalfWidth, -HalfWidth, 0, 1};
v4 P1_In = v4{HalfWidth, -HalfWidth, 0, 1};
v4 P2_In = v4{HalfWidth, HalfWidth, 0, 1};
v4 P3_In = v4{-HalfWidth, HalfWidth, 0, 1};
v2 UV0 = v2{0, 0};
v2 UV1 = v2{1, 0};
v2 UV2 = v2{1, 1};
v2 UV3 = v2{0, 1};
led* LED = Data->LEDs + Data->StartIndex;
for (s32 LEDIdx = 0;
LEDIdx < LEDCount;
LEDIdx++)
{
pixel PixelColor = Data->Colors[LED->Index];
v4 Color = v4{PixelColor.R / 255.f, PixelColor.G / 255.f, PixelColor.B / 255.f, 1.0f};
v4 V4Position = LED->Position;
V4Position.w = 0;
v4 P0 = P0_In + V4Position;
v4 P1 = P1_In + V4Position;
v4 P2 = P2_In + V4Position;
v4 P3 = P3_In + V4Position;
SetTri3DInBatch(Data->Batch, BatchReservedRange.Start + TrisUsed++,
P0, P1, P2, UV0, UV1, UV2, Color, Color, Color);
SetTri3DInBatch(Data->Batch, BatchReservedRange.Start + TrisUsed++,
P0, P2, P3, UV0, UV2, UV3, Color, Color, Color);
LED++;
}
}
struct send_sacn_job_data struct send_sacn_job_data
{ {
@ -194,7 +132,7 @@ INITIALIZE_APPLICATION(InitializeApplication)
State->Permanent.Alloc = (gs_memory_alloc*)Context.PlatformAlloc; State->Permanent.Alloc = (gs_memory_alloc*)Context.PlatformAlloc;
State->Permanent.Realloc = (gs_memory_realloc*)Context.PlatformRealloc; State->Permanent.Realloc = (gs_memory_realloc*)Context.PlatformRealloc;
State->Transient = {}; State->Transient = {};
State->Transient.Alloc = (gs_memory_alloc*)Context.PlatformAlloc; State->Transient.Alloc = (gs_memory_alloc*)Context.PlatformAlloc;
State->Transient.Realloc = (gs_memory_realloc*)Context.PlatformRealloc; State->Transient.Realloc = (gs_memory_realloc*)Context.PlatformRealloc;
InitializeInputCommandRegistry(&State->DefaultInputCommandRegistry, 32, &State->Permanent); InitializeInputCommandRegistry(&State->DefaultInputCommandRegistry, 32, &State->Permanent);
@ -244,12 +182,12 @@ State->Transient.Alloc = (gs_memory_alloc*)Context.PlatformAlloc;
u32 CodepointW, CodepointH; u32 CodepointW, CodepointH;
Context.PlatformDrawFontCodepoint( Context.PlatformDrawFontCodepoint(
Font->BitmapMemory, Font->BitmapMemory,
Font->BitmapWidth, Font->BitmapWidth,
Font->BitmapHeight, Font->BitmapHeight,
CodepointX, CodepointY, CodepointX, CodepointY,
Codepoint, FontInfo, Codepoint, FontInfo,
&CodepointW, &CodepointH); &CodepointW, &CodepointH);
AddCodepointToFont(Font, Codepoint, 0, 0, CodepointW, CodepointH, CodepointX, CodepointY); AddCodepointToFont(Font, Codepoint, 0, 0, CodepointW, CodepointH, CodepointX, CodepointY);
} }
@ -299,35 +237,44 @@ State->Transient.Alloc = (gs_memory_alloc*)Context.PlatformAlloc;
ReloadStaticData(Context, GlobalDebugServices, Alloc, Free); ReloadStaticData(Context, GlobalDebugServices, Alloc, Free);
// Setup Operation Modes // Setup Operation Modes
State->Modes.ActiveModesCount = 0; State->Modes.ActiveModesCount = 0;
State->Modes.Arena = {}; State->Modes.Arena = {};
State->Modes.Arena.Alloc = (gs_memory_alloc*)Context.PlatformAlloc; State->Modes.Arena.Alloc = (gs_memory_alloc*)Context.PlatformAlloc;
State->Modes.Arena.Realloc = (gs_memory_realloc*)Context.PlatformRealloc; State->Modes.Arena.Realloc = (gs_memory_realloc*)Context.PlatformRealloc;
State->Modes.Arena.FindAddressRule = FindAddress_InLastBufferOnly; State->Modes.Arena.FindAddressRule = FindAddress_InLastBufferOnly;
{ // MODES PLAYGROUND { // MODES PLAYGROUND
InitializeAnimationSystem(&State->AnimationSystem); InitializeAnimationSystem(&State->AnimationSystem);
animation_block BlockZero = {0}; animation_block BlockZero = {0};
BlockZero.StartTime = 0; BlockZero.StartTime = 0;
BlockZero.EndTime = 2; BlockZero.EndTime = 2;
BlockZero.Proc = TestPatternOne; BlockZero.Proc = TestPatternOne;
AddAnimationBlock(BlockZero, &State->AnimationSystem); AddAnimationBlock(BlockZero, &State->AnimationSystem);
animation_block BlockOne = {0}; animation_block BlockOne = {0};
BlockOne.StartTime = 3; BlockOne.StartTime = 3;
BlockOne.EndTime = 5; BlockOne.EndTime = 5;
BlockOne.Proc = TestPatternTwo; BlockOne.Proc = TestPatternTwo;
AddAnimationBlock(BlockOne, &State->AnimationSystem); AddAnimationBlock(BlockOne, &State->AnimationSystem);
animation_block BlockTwo = {0}; animation_block BlockTwo = {0};
BlockTwo.StartTime = 5; BlockTwo.StartTime = 5;
BlockTwo.EndTime = 8; BlockTwo.EndTime = 8;
BlockTwo.Proc = TestPatternThree; BlockTwo.Proc = TestPatternThree;
AddAnimationBlock(BlockTwo, &State->AnimationSystem); AddAnimationBlock(BlockTwo, &State->AnimationSystem);
State->AnimationSystem.AnimationEnd = 10; State->AnimationSystem.AnimationEnd = 10;
} // End Animation Playground } // End Animation Playground
{ // Panels Playground
InitializePanelLayout(&State->PanelLayout);
panel* Panel = TakeNewPanel(&State->PanelLayout);
SetPanelDefinition(Panel, GlobalPanelDefs[0]);
SplitPanelVertically(Panel, .5f, v2{0, 0}, v2{Context.WindowWidth, Context.WindowHeight}, &State->PanelLayout);
SetPanelDefinition(&Panel->Right->Panel, GlobalPanelDefs[1]);
} // End Panels Playground
} }
internal void internal void
@ -433,25 +380,25 @@ UPDATE_AND_RENDER(UpdateAndRender)
HandleInput(State, InputQueue, Mouse); HandleInput(State, InputQueue, Mouse);
if (State->AnimationSystem.TimelineShouldAdvance) { if (State->AnimationSystem.TimelineShouldAdvance) {
State->AnimationSystem.Time += Context.DeltaTime; State->AnimationSystem.Time += Context.DeltaTime;
if (State->AnimationSystem.Time > State->AnimationSystem.AnimationEnd) if (State->AnimationSystem.Time > State->AnimationSystem.AnimationEnd)
{ {
State->AnimationSystem.Time -= State->AnimationSystem.AnimationEnd; State->AnimationSystem.Time -= State->AnimationSystem.AnimationEnd;
} }
for (u32 i = 0; i < State->AnimationSystem.BlocksCount; i++) for (u32 i = 0; i < State->AnimationSystem.BlocksCount; i++)
{ {
animation_block_entry BlockEntry = State->AnimationSystem.Blocks[i]; animation_block_entry BlockEntry = State->AnimationSystem.Blocks[i];
if (!AnimationBlockIsFree(BlockEntry)) if (!AnimationBlockIsFree(BlockEntry))
{ {
animation_block Block = BlockEntry.Block; animation_block Block = BlockEntry.Block;
if (State->AnimationSystem.Time >= Block.StartTime if (State->AnimationSystem.Time >= Block.StartTime
&& State->AnimationSystem.Time <= Block.EndTime) && State->AnimationSystem.Time <= Block.EndTime)
{ {
Block.Proc(State, State->AnimationSystem.Time - Block.StartTime); Block.Proc(State, State->AnimationSystem.Time - Block.StartTime);
} }
} }
} }
} }
s32 HeaderSize = State->NetworkProtocolHeaderSize; s32 HeaderSize = State->NetworkProtocolHeaderSize;
@ -486,20 +433,28 @@ UPDATE_AND_RENDER(UpdateAndRender)
Job->DMXBuffers = DMXBuffers; Job->DMXBuffers = DMXBuffers;
Context.GeneralWorkQueue->PushWorkOnQueue( Context.GeneralWorkQueue->PushWorkOnQueue(
Context.GeneralWorkQueue, Context.GeneralWorkQueue,
SACNSendDMXBufferListJob, SACNSendDMXBufferListJob,
Job); Job);
}break; }break;
InvalidDefaultCase; InvalidDefaultCase;
} }
} }
PushRenderOrthographic(RenderBuffer, 0, 0, Context.WindowWidth, Context.WindowHeight);
PushRenderClearScreen(RenderBuffer);
v2 WindowMin = v2{0, 0};
v2 WindowMax = v2{Context.WindowWidth, Context.WindowHeight};
HandleMousePanelInteraction(&State->PanelLayout, WindowMin, WindowMax, Mouse);
DrawAllPanels(State->PanelLayout, WindowMin, WindowMax, RenderBuffer, State->Interface, Mouse, State, Context);
//////////////////////////////// ////////////////////////////////
// Render Assembly // Render Assembly
/////////////////////////////// ///////////////////////////////
if (Context.WindowIsVisible) if (Context.WindowIsVisible)
{ {
#if 0
State->Camera.AspectRatio = (r32)Context.WindowWidth / (r32)Context.WindowHeight; State->Camera.AspectRatio = (r32)Context.WindowWidth / (r32)Context.WindowHeight;
m44 ModelViewMatrix = GetCameraModelViewMatrix(State->Camera); m44 ModelViewMatrix = GetCameraModelViewMatrix(State->Camera);
@ -507,7 +462,7 @@ UPDATE_AND_RENDER(UpdateAndRender)
r32 LEDHalfWidth = .5f; r32 LEDHalfWidth = .5f;
PushRenderPerspective(RenderBuffer, 0, 0, Context.WindowWidth, Context.WindowHeight, State->Camera); PushRenderPerspective(RenderBuffer, 0, 0, Context.WindowWidth / 2, Context.WindowHeight, State->Camera);
PushRenderClearScreen(RenderBuffer); PushRenderClearScreen(RenderBuffer);
// TODO(Peter): Pretty sure this isn't working right now // TODO(Peter): Pretty sure this isn't working right now
@ -540,9 +495,9 @@ UPDATE_AND_RENDER(UpdateAndRender)
JobData->LEDHalfWidth = LEDHalfWidth; JobData->LEDHalfWidth = LEDHalfWidth;
Context.GeneralWorkQueue->PushWorkOnQueue( Context.GeneralWorkQueue->PushWorkOnQueue(
Context.GeneralWorkQueue, Context.GeneralWorkQueue,
DrawLEDsInBufferRangeJob, DrawLEDsInBufferRangeJob,
JobData); JobData);
} }
} }
@ -561,7 +516,6 @@ UPDATE_AND_RENDER(UpdateAndRender)
/////////////////////////////////////// ///////////////////////////////////////
// Menu Bar // Menu Bar
////////////////////////////////////// //////////////////////////////////////
r32 TopBarHeight = 40; r32 TopBarHeight = 40;
{ {
panel_result TopBarPanel = EvaluatePanel(RenderBuffer, panel_result TopBarPanel = EvaluatePanel(RenderBuffer,
@ -606,11 +560,11 @@ UPDATE_AND_RENDER(UpdateAndRender)
v2 TimelineMin = v2{0, 0}; v2 TimelineMin = v2{0, 0};
v2 TimelineMax = v2{Context.WindowWidth, 125}; v2 TimelineMax = v2{Context.WindowWidth, 125};
animation_block_handle NewSelection = DrawAnimationPanel(&State->AnimationSystem, animation_block_handle NewSelection = DrawAnimationPanel(&State->AnimationSystem,
TimelineMin, TimelineMax, TimelineMin, TimelineMax,
State->SelectedAnimationBlockHandle, State->SelectedAnimationBlockHandle,
RenderBuffer, State->Interface, Mouse); RenderBuffer, State->Interface, Mouse);
State->SelectedAnimationBlockHandle = NewSelection; State->SelectedAnimationBlockHandle = NewSelection;
for (s32 m = 0; m < State->Modes.ActiveModesCount; m++) for (s32 m = 0; m < State->Modes.ActiveModesCount; m++)
{ {
operation_mode OperationMode = State->Modes.ActiveModes[m]; operation_mode OperationMode = State->Modes.ActiveModes[m];
@ -623,16 +577,17 @@ State->SelectedAnimationBlockHandle,
DrawDebugInterface(RenderBuffer, 25, DrawDebugInterface(RenderBuffer, 25,
State->Interface, Context.WindowWidth, Context.WindowHeight - TopBarHeight, State->Interface, Context.WindowWidth, Context.WindowHeight - TopBarHeight,
Context.DeltaTime, State, State->Camera, Mouse, &State->Transient); Context.DeltaTime, State, State->Camera, Mouse, &State->Transient);
#endif
} }
// Checking for overflows // Checking for overflows
{ {
DEBUG_TRACK_SCOPE(OverflowChecks); DEBUG_TRACK_SCOPE(OverflowChecks);
AssertAllocationsNoOverflow(State->Permanent); AssertAllocationsNoOverflow(State->Permanent);
for (s32 i = 0; i < State->AssemblyList.Used; i++) for (s32 i = 0; i < State->AssemblyList.Used; i++)
{ {
assembly* Assembly = GetElementAtIndex(i, State->AssemblyList); assembly* Assembly = GetElementAtIndex(i, State->AssemblyList);
AssertAllocationsNoOverflow(Assembly->Arena); AssertAllocationsNoOverflow(Assembly->Arena);
} }
} }
} }

View File

@ -17,6 +17,8 @@
typedef struct app_state app_state; typedef struct app_state app_state;
#include "foldhaus_panel.h"
#include "foldhaus_command_dispatch.h" #include "foldhaus_command_dispatch.h"
#include "foldhaus_command_dispatch.cpp" #include "foldhaus_command_dispatch.cpp"
#include "foldhaus_operation_mode.h" #include "foldhaus_operation_mode.h"
@ -40,7 +42,7 @@ struct app_state
memory_arena Permanent; memory_arena Permanent;
memory_arena Transient; memory_arena Transient;
s32 NetworkProtocolHeaderSize; s32 NetworkProtocolHeaderSize;
network_protocol NetworkProtocol; network_protocol NetworkProtocol;
streaming_acn SACN; streaming_acn SACN;
@ -63,6 +65,8 @@ struct app_state
animation_system AnimationSystem; animation_system AnimationSystem;
animation_block_handle SelectedAnimationBlockHandle; animation_block_handle SelectedAnimationBlockHandle;
panel_layout PanelLayout;
}; };
internal void OpenColorPicker(app_state* State, v4* Address); internal void OpenColorPicker(app_state* State, v4* Address);
@ -165,4 +169,12 @@ r32 GreenSize = 20.0f;
#include "foldhaus_search_lister.cpp" #include "foldhaus_search_lister.cpp"
#include "foldhaus_interface.cpp" #include "foldhaus_interface.cpp"
#include "animation/foldhaus_animation_interface.h" #include "animation/foldhaus_animation_interface.h"
#include "panels/foldhaus_panel_sculpture_view.h"
#include "panels/foldhaus_panel_profiler.h"
#include "panels/foldhaus_panel_dmx_view.h"
#include "panels/foldhaus_panel_animation_timeline.h"
#include "generated/foldhaus_panels_generated.h"
#include "foldhaus_panel.cpp"

View File

@ -1,4 +1,4 @@
#if 0
internal void internal void
RenderProfiler_ScopeVisualization(render_command_buffer* RenderBuffer, RenderProfiler_ScopeVisualization(render_command_buffer* RenderBuffer,
interface_config Interface, mouse_state Mouse, interface_config Interface, mouse_state Mouse,
@ -188,6 +188,7 @@ DrawDebugFrameList (render_command_buffer* RenderBuffer, interface_config Interf
VisibleFrame, Memory); VisibleFrame, Memory);
} }
} }
#endif
internal void internal void
DrawDebugInterface (render_command_buffer* RenderBuffer, r32 StartX, interface_config Interface, r32 WindowWidth, r32 WindowHeight, r32 DeltaTime, app_state* State, camera Camera, mouse_state Mouse, memory_arena* Transient) DrawDebugInterface (render_command_buffer* RenderBuffer, r32 StartX, interface_config Interface, r32 WindowWidth, r32 WindowHeight, r32 DeltaTime, app_state* State, camera Camera, mouse_state Mouse, memory_arena* Transient)
@ -311,7 +312,7 @@ DrawDebugInterface (render_command_buffer* RenderBuffer, r32 StartX, interface_c
v2 ProfilerMin = v2{TopOfDebugView.x, TopOfDebugView.y - 500}; v2 ProfilerMin = v2{TopOfDebugView.x, TopOfDebugView.y - 500};
v2 ProfilerMax = v2{TopOfDebugView.x + 700, TopOfDebugView.y - 64}; v2 ProfilerMax = v2{TopOfDebugView.x + 700, TopOfDebugView.y - 64};
PushRenderQuad2D(RenderBuffer, ProfilerMin, ProfilerMax, v4{0, 0, 0, .8f}); PushRenderQuad2D(RenderBuffer, ProfilerMin, ProfilerMax, v4{0, 0, 0, .8f});
DrawDebugFrameList(RenderBuffer, Interface, Mouse, ProfilerMin, ProfilerMax, Transient); //DrawDebugFrameList(RenderBuffer, Interface, Mouse, ProfilerMin, ProfilerMax, Transient);
#if 0 #if 0
r32 ColumnsStartX = TopOfScreenLinePos.x; r32 ColumnsStartX = TopOfScreenLinePos.x;

313
src/foldhaus_panel.cpp Normal file
View File

@ -0,0 +1,313 @@
/////////////////////////////////
//
// Book-Keeping
//
/////////////////////////////////
internal void
InitializePanelLayout(panel_layout* Layout)
{
Layout->FreeList.Free.Next = &Layout->FreeList;
}
internal panel_entry*
TakeNewPanelEntry(panel_layout* Layout)
{
panel_entry* FreeEntry = 0;
if (Layout->FreeList.Free.Next != &Layout->FreeList)
{
FreeEntry = Layout->FreeList.Free.Next;
Layout->FreeList.Free.Next = FreeEntry->Free.Next;
}
else
{
Assert(Layout->PanelsUsed < PANELS_MAX);
FreeEntry = Layout->Panels + Layout->PanelsUsed++;
}
return FreeEntry;
}
internal panel*
TakeNewPanel(panel_layout* Layout)
{
panel* Result = 0;
panel_entry* FreeEntry = TakeNewPanelEntry(Layout);
Result = &FreeEntry->Panel;
*Result = {0};
return Result;
}
internal void
FreePanelEntry(panel_entry* Entry, panel_layout* Layout)
{
Assert(Entry >= Layout->Panels && Entry <= Layout->Panels + PANELS_MAX);
Entry->Panel = {0};
Entry->Free.Next = Layout->FreeList.Free.Next;
Layout->FreeList.Free.Next = Entry;
}
internal void
FreePanelAtIndex(s32 Index, panel_layout* Layout)
{
Assert(Index > 0 && Index < (s32)Layout->PanelsUsed);
panel_entry* EntryToFree = Layout->Panels + Index;
EntryToFree->Free.Next = Layout->FreeList.Free.Next;
Layout->FreeList.Free.Next = EntryToFree;
}
internal void
SplitPanelVertically(panel* Parent, r32 Percent, v2 ParentMin, v2 ParentMax, panel_layout* Layout)
{
r32 SplitX = GSLerp(ParentMin.x, ParentMax.x, Percent);
if (SplitX > ParentMin.x && SplitX < ParentMax.x)
{
Parent->SplitDirection = PanelSplit_Vertical;
Parent->SplitPercent = Percent;
Parent->Left = TakeNewPanelEntry(Layout);
Parent->Left->Panel.Render = Parent->Render;
Parent->Right = TakeNewPanelEntry(Layout);
Parent->Right->Panel.Render = Parent->Render;
}
}
internal void
SplitPanelHorizontally(panel* Parent, r32 Percent, v2 ParentMin, v2 ParentMax, panel_layout* Layout)
{
r32 SplitY = GSLerp(ParentMin.y, ParentMax.y, Percent);
if (SplitY > ParentMin.y && SplitY < ParentMax.y)
{
Parent->SplitDirection = PanelSplit_Horizontal;
Parent->SplitPercent = Percent;
Parent->Bottom = TakeNewPanelEntry(Layout);
Parent->Bottom->Panel.Render = Parent->Render;
Parent->Top = TakeNewPanelEntry(Layout);
Parent->Top->Panel.Render = Parent->Render;
}
}
internal void
ConsolidatePanelsKeepOne(panel* Parent, panel_entry* PanelEntryToKeep, panel_layout* Layout)
{
panel_entry* LeftChild = Parent->Left;
panel_entry* RightChild = Parent->Right;
*Parent = PanelEntryToKeep->Panel;
Parent->SplitDirection = PanelSplit_NoSplit;
FreePanelEntry(LeftChild, Layout);
FreePanelEntry(RightChild, Layout);
}
internal void
SetPanelDefinition(panel* Panel, panel_definition Def)
{
if(Panel->Cleanup)
{
Panel->Cleanup(Panel);
}
Panel->Cleanup = Def.Cleanup;
Panel->Render = Def.Render;
Def.Init(Panel);
}
/////////////////////////////////
//
// Rendering And Interaction
//
/////////////////////////////////
internal void
HandleMousePanelInteractionOrRecurse(panel* Panel, v2 PanelMin, v2 PanelMax, panel_layout* PanelLayout, mouse_state Mouse)
{
r32 PanelEdgeClickMaxDistance = 4;
// TODO(Peter): Need a way to calculate this button's position more systemically
if (Panel->SplitDirection == PanelSplit_NoSplit
&& PointIsInRange(Mouse.DownPos, PanelMin, PanelMin + v2{25, 25}))
{
r32 XDistance = GSAbs(Mouse.Pos.x - Mouse.DownPos.x);
r32 YDistance = GSAbs(Mouse.Pos.y - Mouse.DownPos.y);
if (XDistance > YDistance)
{
r32 XPercent = (Mouse.Pos.x - PanelMin.x) / (PanelMax.x - PanelMin.x);
SplitPanelVertically(Panel, XPercent, PanelMin, PanelMax, PanelLayout);
}
else
{
r32 YPercent = (Mouse.Pos.y - PanelMin.y) / (PanelMax.y - PanelMin.y);
SplitPanelHorizontally(Panel, YPercent, PanelMin, PanelMax, PanelLayout);
}
}
else if (Panel->SplitDirection == PanelSplit_Horizontal)
{
r32 SplitY = GSLerp(PanelMin.y, PanelMax.y, Panel->SplitPercent);
r32 ClickDistanceFromSplit = GSAbs(Mouse.DownPos.y - SplitY);
if (ClickDistanceFromSplit < PanelEdgeClickMaxDistance)
{
r32 NewSplitY = Mouse.Pos.y;
if (NewSplitY <= PanelMin.y)
{
ConsolidatePanelsKeepOne(Panel, Panel->Top, PanelLayout);
}
else if (NewSplitY >= PanelMax.y)
{
ConsolidatePanelsKeepOne(Panel, Panel->Bottom, PanelLayout);
}
else
{
Panel->SplitPercent = (NewSplitY - PanelMin.y) / (PanelMax.y - PanelMin.y);
}
}
else
{
HandleMousePanelInteractionOrRecurse(&Panel->Bottom->Panel, PanelMin, v2{PanelMax.x, SplitY}, PanelLayout, Mouse);
HandleMousePanelInteractionOrRecurse(&Panel->Top->Panel, v2{PanelMin.x, SplitY}, PanelMax, PanelLayout, Mouse);
}
}
else if (Panel->SplitDirection == PanelSplit_Vertical)
{
r32 SplitX = GSLerp(PanelMin.x, PanelMax.x, Panel->SplitPercent);
r32 ClickDistanceFromSplit = GSAbs(Mouse.DownPos.x - SplitX);
if (ClickDistanceFromSplit < PanelEdgeClickMaxDistance)
{
r32 NewSplitX = Mouse.Pos.x;
if (NewSplitX <= PanelMin.x)
{
ConsolidatePanelsKeepOne(Panel, Panel->Right, PanelLayout);
}
else if (NewSplitX >= PanelMax.x)
{
ConsolidatePanelsKeepOne(Panel, Panel->Left, PanelLayout);
}
else
{
Panel->SplitPercent = (NewSplitX - PanelMin.x) / (PanelMax.x - PanelMin.x);
}
}
else
{
HandleMousePanelInteractionOrRecurse(&Panel->Left->Panel, PanelMin, v2{SplitX, PanelMax.y}, PanelLayout, Mouse);
HandleMousePanelInteractionOrRecurse(&Panel->Right->Panel, v2{SplitX, PanelMin.y}, PanelMax, PanelLayout, Mouse);
}
}
}
internal void
HandleMousePanelInteraction(panel_layout* PanelLayout, v2 WindowMin, v2 WindowMax, mouse_state Mouse)
{
r32 PanelEdgeClickMaxDistance = 4;
if (MouseButtonTransitionedUp(Mouse.LeftButtonState))
{
Assert(PanelLayout->PanelsUsed > 0);
panel* FirstPanel = &PanelLayout->Panels[0].Panel;
HandleMousePanelInteractionOrRecurse(FirstPanel, WindowMin, WindowMax, PanelLayout, Mouse);
}
}
internal void
DrawPanelFooter(panel* Panel, render_command_buffer* RenderBuffer, v2 FooterMin, v2 FooterMax, interface_config Interface, mouse_state Mouse)
{
PushRenderQuad2D(RenderBuffer, FooterMin, v2{FooterMax.x, FooterMin.y + 25}, v4{.5f, .5f, .5f, 1.f});
PushRenderQuad2D(RenderBuffer, FooterMin, FooterMin + v2{25, 25}, WhiteV4);
v2 PanelSelectButtonMin = FooterMin + v2{30, 1};
v2 PanelSelectButtonMax = PanelSelectButtonMin + v2{100, 23};
if (Panel->PanelSelectionMenuOpen)
{
v2 ButtonDimension = v2{100, 25};
v2 ButtonMin = v2{PanelSelectButtonMin.x, FooterMax.y};
v2 MenuMin = ButtonMin;
v2 MenuMax = v2{ButtonMin.x + ButtonDimension.x, ButtonMin.y + (ButtonDimension.y * GlobalPanelDefsCount)};
if (MouseButtonTransitionedDown(Mouse.LeftButtonState)
&& !PointIsInRange(Mouse.DownPos, MenuMin, MenuMax))
{
Panel->PanelSelectionMenuOpen = false;
}
for (s32 i = 0; i < GlobalPanelDefsCount; i++)
{
panel_definition Def = GlobalPanelDefs[i];
string DefName = MakeString(Def.PanelName, Def.PanelNameLength);
button_result DefinitionButton = EvaluateButton(RenderBuffer,
ButtonMin, ButtonMin + ButtonDimension,
DefName, Interface, Mouse);
if (DefinitionButton.Pressed)
{
SetPanelDefinition(Panel, Def);
Panel->PanelSelectionMenuOpen = false;
}
ButtonMin.y += ButtonDimension.y;
}
}
button_result ButtonResult = EvaluateButton(RenderBuffer,
PanelSelectButtonMin,
PanelSelectButtonMax,
MakeStringLiteral("Select"), Interface, Mouse);
if (ButtonResult.Pressed)
{
Panel->PanelSelectionMenuOpen = !Panel->PanelSelectionMenuOpen;
}
}
internal void
DrawPanelBorder(panel Panel, v2 PanelMin, v2 PanelMax, v4 Color, render_command_buffer* RenderBuffer)
{
PushRenderBoundingBox2D(RenderBuffer, PanelMin, PanelMax, 1, Color);
}
internal void
DrawPanelOrRecurse(panel* Panel, v2 PanelMin, v2 PanelMax, v2 WindowMin, v2 WindowMax, render_command_buffer* RenderBuffer, interface_config Interface, mouse_state Mouse, app_state* State, context Context)
{
if (Panel->SplitDirection == PanelSplit_NoSplit)
{
v2 FooterMin = PanelMin;
v2 FooterMax = v2{PanelMax.x, PanelMin.y + 25};
v2 PanelViewMin = v2{PanelMin.x, FooterMax.y};
v2 PanelViewMax = PanelMax;
Panel->Render(*Panel, PanelViewMin, PanelViewMax, RenderBuffer, State, Context, Mouse);
v4 BorderColor = v4{0, 1, 1, 1};
if (PointIsInRange(Mouse.Pos, PanelMin, PanelMax))
{
BorderColor = v4{1, 0, 1, 1};
}
PushRenderOrthographic(RenderBuffer, WindowMin.x, WindowMin.y, WindowMax.x, WindowMax.y);
DrawPanelBorder(*Panel, PanelMin, PanelMax, BorderColor, RenderBuffer);
DrawPanelFooter(Panel, RenderBuffer, FooterMin, FooterMax, Interface, Mouse);
}
else if (Panel->SplitDirection == PanelSplit_Horizontal)
{
r32 SplitY = GSLerp(PanelMin.y, PanelMax.y, Panel->SplitPercent);
DrawPanelOrRecurse(&Panel->Bottom->Panel, PanelMin, v2{PanelMax.x, SplitY}, WindowMin, WindowMax, RenderBuffer, Interface, Mouse, State, Context);
DrawPanelOrRecurse(&Panel->Top->Panel, v2{PanelMin.x, SplitY}, PanelMax, WindowMin, WindowMax, RenderBuffer, Interface, Mouse, State, Context);
}
else if (Panel->SplitDirection == PanelSplit_Vertical)
{
r32 SplitX = GSLerp(PanelMin.x, PanelMax.x, Panel->SplitPercent);
DrawPanelOrRecurse(&Panel->Left->Panel, PanelMin, v2{SplitX, PanelMax.y}, WindowMin, WindowMax, RenderBuffer, Interface, Mouse, State, Context);
DrawPanelOrRecurse(&Panel->Right->Panel, v2{SplitX, PanelMin.y}, PanelMax, WindowMin, WindowMax, RenderBuffer, Interface, Mouse, State, Context);
}
}
internal void
DrawAllPanels(panel_layout PanelLayout, v2 WindowMin, v2 WindowMax, render_command_buffer* RenderBuffer, interface_config Interface, mouse_state Mouse, app_state* State, context Context)
{
Assert(PanelLayout.PanelsUsed > 0);
panel* FirstPanel = &PanelLayout.Panels[0].Panel;
DrawPanelOrRecurse(FirstPanel, WindowMin, WindowMax, WindowMin, WindowMax, RenderBuffer, Interface, Mouse, State, Context);
}

73
src/foldhaus_panel.h Normal file
View File

@ -0,0 +1,73 @@
typedef struct panel panel;
#define PANEL_INIT_PROC(name) void name(panel* Panel)
typedef PANEL_INIT_PROC(panel_init_proc);
#define PANEL_CLEANUP_PROC(name) void name(panel* Panel)
typedef PANEL_CLEANUP_PROC(panel_cleanup_proc);
#define PANEL_RENDER_PROC(name) void name(panel Panel, v2 PanelMin, v2 PanelMax, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse)
typedef PANEL_RENDER_PROC(panel_render_proc);
enum panel_split_direction
{
PanelSplit_NoSplit,
PanelSplit_Horizontal,
PanelSplit_Vertical,
PanelSplit_Count,
};
typedef struct panel_entry panel_entry;
struct panel
{
panel_render_proc* Render;
panel_cleanup_proc* Cleanup;
panel_split_direction SplitDirection;
r32 SplitPercent;
// TODO(Peter): This REALLY doesn't want to live here
// Probably belongs in a more generalized PanelInterfaceState or something
b32 PanelSelectionMenuOpen;
union{
panel_entry* Left;
panel_entry* Top;
};
union{
panel_entry* Right;
panel_entry* Bottom;
};
};
struct free_panel
{
panel_entry* Next;
};
struct panel_entry
{
panel Panel;
free_panel Free;
};
#define PANELS_MAX 16
struct panel_layout
{
panel_entry Panels[PANELS_MAX];
u32 PanelsUsed;
panel_entry FreeList;
};
struct panel_definition
{
char* PanelName;
s32 PanelNameLength;
panel_init_proc* Init;
panel_cleanup_proc* Cleanup;
panel_render_proc* Render;
};

View File

@ -0,0 +1,7 @@
global_variable s32 GlobalPanelDefsCount = 4;
global_variable panel_definition GlobalPanelDefs[] = {
{ "Sculpture View", 14, SculptureView_Init, SculptureView_Cleanup, SculptureView_Render },
{ "Animation Timeline", 18, AnimationTimeline_Init, AnimationTimeline_Cleanup, AnimationTimeline_Render },
{ "DMX View", 8, DMXView_Init, DMXView_Cleanup, DMXView_Render },
{ "Profiler", 8, ProfilerView_Init, ProfilerView_Cleanup, ProfilerView_Render },
};

View File

@ -191,7 +191,7 @@ enum gs_memory_find_address_rule
typedef void* gs_memory_alloc(gs_mem_u32 Size); typedef void* gs_memory_alloc(gs_mem_u32 Size);
typedef void* gs_memory_realloc(void* Address, gs_mem_u32 OldSize, gs_mem_u32 NewSize); typedef void* gs_memory_realloc(void* Address, gs_mem_u32 OldSize, gs_mem_u32 NewSize);
typedef void gs_memory_free(void* Address, gs_mem_u32 Size); typedef void gs_memory_free(void* Address, gs_mem_u32 Size);
#ifndef GS_MEMORY_BUFFER_SIZE #ifndef GS_MEMORY_BUFFER_SIZE
#define GS_MEMORY_BUFFER_SIZE 1024 #define GS_MEMORY_BUFFER_SIZE 1024

View File

@ -0,0 +1,149 @@
PANEL_INIT_PROC(AnimationTimeline_Init)
{
}
PANEL_CLEANUP_PROC(AnimationTimeline_Cleanup)
{
}
internal animation_block_handle
DrawAnimationTimeline (animation_system* AnimationSystem, v2 PanelMin, v2 PanelMax, animation_block_handle SelectedBlockHandle, render_command_buffer* RenderBuffer, interface_config Interface, mouse_state Mouse)
{
animation_block_handle Result = SelectedBlockHandle;
r32 AnimationPanelHeight = PanelMax.y - PanelMin.y;
r32 AnimationPanelWidth = PanelMax.x - PanelMin.x;
panel_result AnimationPanel = EvaluatePanel(RenderBuffer, PanelMin, PanelMax,
0, Interface);
b32 MouseDownAndNotHandled = MouseButtonTransitionedDown(Mouse.LeftButtonState);
for (u32 i = 0; i < AnimationSystem->BlocksCount; i++)
{
animation_block_entry AnimationBlockEntry = AnimationSystem->Blocks[i];
if (AnimationBlockIsFree(AnimationBlockEntry)) { continue; }
animation_block_handle CurrentBlockHandle = {};
CurrentBlockHandle.Index = i;
CurrentBlockHandle.Generation = AnimationBlockEntry.Generation;
animation_block AnimationBlockAt = AnimationBlockEntry.Block;
r32 StartTimePercent = AnimationBlockAt.StartTime / AnimationSystem->AnimationEnd;
r32 StartPosition = AnimationPanelWidth * StartTimePercent;
r32 EndTimePercent = AnimationBlockAt.EndTime / AnimationSystem->AnimationEnd;
r32 EndPosition = AnimationPanelWidth * EndTimePercent;
v2 Min = PanelMin + v2{StartPosition, 25};
v2 Max = PanelMin + v2{EndPosition, 75};
v4 BlockColor = BlackV4;
if (AnimationBlockHandlesAreEqual(SelectedBlockHandle, CurrentBlockHandle))
{
BlockColor = PinkV4;
}
PushRenderQuad2D(RenderBuffer, Min, Max, BlockColor);
PushRenderBoundingBox2D(RenderBuffer, Min, Max, 1, WhiteV4);
if (PointIsInRange(Mouse.Pos, Min, Max)
&& MouseButtonTransitionedDown(Mouse.LeftButtonState))
{
MouseDownAndNotHandled = false;
if (AnimationBlockHandlesAreEqual(SelectedBlockHandle, CurrentBlockHandle))
{
// If the block is already selected, deselect it.
Result = {0};
}
else
{
Result = CurrentBlockHandle;
}
}
}
r32 TimePercent = AnimationSystem->Time / AnimationSystem->AnimationEnd;
r32 SliderX = PanelMin.x + (AnimationPanelWidth * TimePercent);
v2 SliderMin = v2{SliderX, PanelMin.y};
v2 SliderMax = v2{SliderX + 1, PanelMax.y - 25};
PushRenderQuad2D(RenderBuffer, SliderMin, SliderMax, WhiteV4);
if (MouseDownAndNotHandled && PointIsInRange(Mouse.Pos, PanelMin, PanelMax))
{
r32 MouseDownPositionPercent = (Mouse.Pos.x - PanelMin.x) / AnimationPanelWidth;
r32 NewBlockTimeStart = MouseDownPositionPercent * AnimationSystem->AnimationEnd;
#define NEW_BLOCK_DURATION 1
r32 NewBlockTimeEnd = NewBlockTimeStart + NEW_BLOCK_DURATION;
animation_block Block = {0};
Block.StartTime = NewBlockTimeStart;
Block.EndTime = NewBlockTimeEnd;
Block.Proc = TestPatternThree;
animation_block_handle NewBlockHandle = AddAnimationBlock(Block, AnimationSystem);
Result = NewBlockHandle;
}
return Result;
}
PANEL_RENDER_PROC(AnimationTimeline_Render)
{
animation_block_handle SelectedBlockHandle = State->SelectedAnimationBlockHandle;
r32 OptionsRowHeight = 25;
v2 TimelineMin = PanelMin;
v2 TimelineMax = v2{PanelMax.x, PanelMax.y - OptionsRowHeight};
if (TimelineMax.y - TimelineMin.y > 0)
{
SelectedBlockHandle = DrawAnimationTimeline(&State->AnimationSystem,
TimelineMin, TimelineMax,
SelectedBlockHandle,
RenderBuffer, State->Interface, Mouse);
}
v2 OptionsRowMin = v2{ PanelMin.x, TimelineMax.y };
v2 OptionsRowMax = PanelMax;
panel_result AnimationPanel = EvaluatePanel(RenderBuffer, OptionsRowMin, OptionsRowMax,
0, State->Interface);
r32 ButtonWidth = 35;
v2 ButtonMin = v2{0, 0};
v2 ButtonMax = v2{35, OptionsRowHeight - 2};
v2 ButtonAt = v2{OptionsRowMin.x + 1, OptionsRowMin.y + 1};
button_result PauseResult = EvaluateButton(RenderBuffer,
ButtonAt + ButtonMin, ButtonAt + ButtonMax,
MakeStringLiteral("Pause"),
State->Interface, Mouse);
ButtonAt.x += ButtonWidth + 2;
button_result PlayResult = EvaluateButton(RenderBuffer,
ButtonAt + ButtonMin, ButtonAt + ButtonMax,
MakeStringLiteral("Play"),
State->Interface, Mouse);
ButtonAt.x += ButtonWidth + 2;
button_result StopResult = EvaluateButton(RenderBuffer,
ButtonAt + ButtonMin, ButtonAt + ButtonMax,
MakeStringLiteral("Stop"),
State->Interface, Mouse);
if (PauseResult.Pressed)
{
State->AnimationSystem.TimelineShouldAdvance = false;
}
if (PlayResult.Pressed)
{
State->AnimationSystem.TimelineShouldAdvance = true;
}
if (StopResult.Pressed)
{
State->AnimationSystem.TimelineShouldAdvance = false;
State->AnimationSystem.Time = 0;
}
State->SelectedAnimationBlockHandle = SelectedBlockHandle;
}

View File

@ -0,0 +1,77 @@
PANEL_INIT_PROC(DMXView_Init)
{
}
PANEL_CLEANUP_PROC(DMXView_Cleanup)
{
}
PANEL_RENDER_PROC(DMXView_Render)
{
#if 0
DEBUG_TRACK_SCOPE(DrawUniverseOutputDisplay);
universe_view_operation_state* OpState = (universe_view_operation_state*)Operation.OpStateMemory;
string TitleBarString = InitializeEmptyString(PushArray(State->Transient, char, 64), 64);
v2 DisplayArea_Dimension = v2{600, 600};
v2 DisplayContents_Offset = OpState->DisplayOffset;
//
// TODO(Peter): I don't like this. Dragging the Universe view should be an operation mode, just
// like rotating the 3D view, but modes don't have access to the state of modes above them in the stack
// (and attempting to cast those states to the appropriate type seems risky)
//
// :NeedToPassStateDownModeChain
//
if (OpState->MouseDown)
{
DisplayContents_Offset += (Mouse.Pos - Mouse.DownPos);
}
v2 DisplayArea_TopLeft = v2{300, (r32)RenderBuffer->ViewHeight - 50} + DisplayContents_Offset;
v2 UniverseDisplayDimension = v2{100, 100} * OpState->Zoom;
v2 Padding = v2{25, 50} * OpState->Zoom;
v2 UniverseDisplayTopLeft = DisplayArea_TopLeft;
sacn_universe_buffer* UniverseList = State->SACN.UniverseBuffer;
while(UniverseList)
{
for (s32 UniverseIdx = 0;
UniverseIdx < UniverseList->Used;
UniverseIdx++)
{
sacn_universe* Universe = UniverseList->Universes + UniverseIdx;
DrawSACNUniversePixels(RenderBuffer, Universe, UniverseDisplayTopLeft, UniverseDisplayDimension);
if (OpState->Zoom > .5f)
{
v2 TitleDisplayStart = UniverseDisplayTopLeft + v2{0, 12};
PrintF(&TitleBarString, "Universe %d", Universe->Universe);
DrawString(RenderBuffer, TitleBarString, State->Interface.Font,
TitleDisplayStart, WhiteV4);
}
UniverseDisplayTopLeft.x += UniverseDisplayDimension.x + Padding.x;
if (UniverseDisplayTopLeft.x > DisplayArea_TopLeft.x + DisplayArea_Dimension.x)
{
UniverseDisplayTopLeft.x = DisplayArea_TopLeft.x;
UniverseDisplayTopLeft.y -= UniverseDisplayDimension.y + Padding.y;
}
if (UniverseDisplayTopLeft.y < DisplayArea_TopLeft.y - DisplayArea_Dimension.y)
{
break;
}
}
UniverseList = UniverseList->Next;
}
#endif
}

View File

@ -0,0 +1,199 @@
PANEL_INIT_PROC(ProfilerView_Init)
{
}
PANEL_CLEANUP_PROC(ProfilerView_Cleanup)
{
}
internal void
RenderProfiler_ScopeVisualization(render_command_buffer* RenderBuffer,
interface_config Interface, mouse_state Mouse,
v2 Min, v2 Max,
debug_frame* VisibleFrame, memory_arena* Memory)
{
v4 ThreadColors[] = {
v4{.73f, .33f, .83f, 1},
v4{0, .50f, .50f, 1},
v4{.83f, 0, 0, 1},
v4{.33f, .49f, .83f, 1},
v4{.74f, .40f, .25f, 1},
};
r32 Width = Max.x - Min.x;
r32 DepthHeight = 64;
s64 FrameStartCycles = VisibleFrame->FrameStartCycles;
s64 FrameTotalCycles = VisibleFrame->FrameEndCycles - VisibleFrame->FrameStartCycles;
debug_scope_record_list* ThreadScopeCalls = GetScopeListForThreadInFrame(GlobalDebugServices,
VisibleFrame);
MakeStringBuffer(String, 256);
for (s32 i = 0; i < ThreadScopeCalls->Count; i++)
{
scope_record* Record = ThreadScopeCalls->Calls + i;
scope_name* Name = GetOrAddNameHashEntry(VisibleFrame, Record->NameHash);
r32 PercentStart = (r32)(Record->StartCycles - FrameStartCycles) / (r32)FrameTotalCycles;
r32 PercentEnd = (r32)(Record->EndCycles - FrameStartCycles) / (r32)FrameTotalCycles;
v2 ScopeMin = v2{Min.x + (Width * PercentStart), Max.y - ((Record->CallDepth + 1) * DepthHeight)};
v2 ScopeMax = v2{Min.x + (Width * PercentEnd), ScopeMin.y + (DepthHeight - 4)};
if ((ScopeMax.x - ScopeMin.x) >= 1)
{
v4 Color = ThreadColors[0];
if (PointIsInRange(Mouse.Pos, ScopeMin, ScopeMax))
{
Color = GreenV4;
}
PushRenderQuad2D(RenderBuffer, ScopeMin, ScopeMax, Color);
PushRenderBoundingBox2D(RenderBuffer, ScopeMin, ScopeMax, 1, BlackV4);
if (PointIsInRange(Mouse.Pos, ScopeMin, ScopeMax))
{
PushRenderQuad2D(RenderBuffer, Mouse.Pos, Mouse.Pos + v2{256, 32}, BlackV4);
PrintF(&String, "%.*s : %d - %d", Name->Name.Length, Name->Name.Memory, Record->StartCycles, Record->EndCycles);
DrawString(RenderBuffer, String, Interface.Font, Mouse.Pos, WhiteV4);
}
}
}
}
internal void
RenderProfiler_ListVisualization(render_command_buffer* RenderBuffer,
interface_config Interface, mouse_state Mouse,
v2 Min, v2 Max,
debug_frame* VisibleFrame, memory_arena* Memory)
{
MakeStringBuffer(String, 256);
r32 YAt = Max.y - Interface.Font->PixelHeight;
r32 Column0X = Min.x;
r32 Column1X = Column0X + 256;
r32 Column2X = Column1X + 128;
r32 Column3X = Column2X + 128;
r32 Column4X = Column3X + 100;
for (s32 n = 0; n < VisibleFrame->ScopeNamesMax; n++)
{
scope_name NameEntry = VisibleFrame->ScopeNamesHash[n];
if (NameEntry.Hash != 0)
{
collated_scope_record* CollatedRecord = VisibleFrame->CollatedScopes + n;
PrintF(&String, "%.*s", NameEntry.Name.Length, NameEntry.Name.Memory);
DrawString(RenderBuffer, String, Interface.Font, v2{Column0X, YAt}, WhiteV4);
PrintF(&String, "%f", CollatedRecord->PercentFrameTime);
DrawString(RenderBuffer, String, Interface.Font, v2{Column1X, YAt}, WhiteV4);
PrintF(&String, "%fs", CollatedRecord->TotalSeconds);
DrawString(RenderBuffer, String, Interface.Font, v2{Column2X, YAt}, WhiteV4);
PrintF(&String, "%dcy", CollatedRecord->TotalCycles);
DrawString(RenderBuffer, String, Interface.Font, v2{Column3X, YAt}, WhiteV4);
PrintF(&String, "%d calls", CollatedRecord->CallCount);
DrawString(RenderBuffer, String, Interface.Font, v2{Column4X, YAt}, WhiteV4);
YAt -= Interface.Font->PixelHeight + 4;
if (YAt < Min.y) { break; }
}
}
}
PANEL_RENDER_PROC(ProfilerView_Render)
{
memory_arena* Memory = &State->Transient;
string String = InitializeEmptyString(PushArray(Memory, char, 256), 256);
v4 FrameColors[] = { GreenV4, YellowV4, RedV4, WhiteV4 };
r32 FrameListHeight = 64;
v2 FrameListMin = v2{PanelMin.x + 16, PanelMax.y - (16 + FrameListHeight)};
v2 FrameListMax = v2{PanelMax.x - 16, PanelMax.y - 16};
r32 FrameListPadding = 4;
r32 FrameListInnerWidth = (FrameListMax.x - FrameListMin.x) - (FrameListPadding * 2);
r32 SingleFrameStep = FrameListInnerWidth / DEBUG_FRAME_COUNT;
r32 SingleFrameWidth = (r32)((s32)SingleFrameStep - 2);
PushRenderBoundingBox2D(RenderBuffer, FrameListMin, FrameListMax, 2, WhiteV4);
if (PointIsInRange(Mouse.Pos, FrameListMin, FrameListMax) &&
MouseButtonHeldDown(Mouse.LeftButtonState))
{
r32 LocalMouseX = (Mouse.Pos.x - FrameListMin.x) + FrameListPadding;
s32 ClosestFrameIndex = (LocalMouseX / SingleFrameStep);
if (ClosestFrameIndex >= 0 && ClosestFrameIndex < DEBUG_FRAME_COUNT)
{
GlobalDebugServices->RecordFrames = false;
GlobalDebugServices->CurrentDebugFrame = ClosestFrameIndex;
}
}
for (s32 F = 0; F < DEBUG_FRAME_COUNT; F++)
{
v2 Min = v2{FrameListMin.x + FrameListPadding + (F * SingleFrameStep), FrameListMin.y + 4};
v2 Max = v2{Min.x + SingleFrameWidth, FrameListMax.y - 4};
s32 FramesAgo = (GlobalDebugServices->CurrentDebugFrame - F);
if (FramesAgo < 0) { FramesAgo += DEBUG_FRAME_COUNT; }
v4 Color = FrameColors[GSClamp(0, FramesAgo, 3)];
PushRenderQuad2D(RenderBuffer, Min, Max, Color);
}
debug_frame* VisibleFrame = GetLastDebugFrame(GlobalDebugServices);
s64 FrameStartCycles = VisibleFrame->FrameStartCycles;
s64 FrameTotalCycles = VisibleFrame->FrameEndCycles - VisibleFrame->FrameStartCycles;
PrintF(&String, "Frame %d - Total Cycles: %lld",
GlobalDebugServices->CurrentDebugFrame - 1,
FrameTotalCycles);
DrawString(RenderBuffer, String, State->Interface.Font, FrameListMin - v2{0, 32}, WhiteV4);
v2 ButtonMin = v2{FrameListMax.x - 128, FrameListMin.y - 32};
v2 ButtonMax = ButtonMin + v2{128, 28};
button_result ShouldResumeRecording = EvaluateButton(RenderBuffer, ButtonMin, ButtonMax,
MakeString("Resume Recording"), State->Interface, Mouse);
if (ShouldResumeRecording.Pressed)
{
GlobalDebugServices->RecordFrames = true;
}
ButtonMin = v2{FrameListMin.x, FrameListMin.y - 60};
ButtonMax = v2{FrameListMin.x + 128, FrameListMin.y - 42};
button_result ActivateScopeView = EvaluateButton(RenderBuffer, ButtonMin, ButtonMax,
MakeString("Scope View"), State->Interface, Mouse);
ButtonMin.x += 152;
ButtonMax.x += 152;
button_result ActivateListView = EvaluateButton(RenderBuffer, ButtonMin, ButtonMax,
MakeString("List View"), State->Interface, Mouse);
if (ActivateScopeView.Pressed) { GlobalDebugServices->Interface.FrameView = FRAME_VIEW_PROFILER; }
if (ActivateListView.Pressed) { GlobalDebugServices->Interface.FrameView = FRAME_VIEW_SCOPE_LIST; }
v2 ViewModeMin = v2{FrameListMin.x, PanelMin.y};
v2 ViewModeMax = v2{FrameListMax.x, FrameListMin.y - 96};
if (GlobalDebugServices->Interface.FrameView == FRAME_VIEW_PROFILER)
{
RenderProfiler_ScopeVisualization(RenderBuffer, State->Interface, Mouse,
ViewModeMin, ViewModeMax,
VisibleFrame, Memory);
}
else
{
RenderProfiler_ListVisualization(RenderBuffer, State->Interface, Mouse,
ViewModeMin, ViewModeMax,
VisibleFrame, Memory);
}
}

View File

@ -0,0 +1,123 @@
PANEL_INIT_PROC(SculptureView_Init)
{
}
PANEL_CLEANUP_PROC(SculptureView_Cleanup)
{
}
struct draw_leds_job_data
{
led* LEDs;
pixel* Colors;
s32 StartIndex;
s32 OnePastLastIndex;
render_quad_batch_constructor* Batch;
m44 FaceCameraMatrix;
m44 ModelViewMatrix;
r32 LEDHalfWidth;
};
internal void
DrawLEDsInBufferRangeJob (s32 ThreadID, void* JobData)
{
DEBUG_TRACK_FUNCTION;
draw_leds_job_data* Data = (draw_leds_job_data*)JobData;
s32 LEDCount = Data->OnePastLastIndex - Data->StartIndex;
quad_batch_constructor_reserved_range BatchReservedRange = ThreadSafeReserveRangeInQuadConstructor(Data->Batch, LEDCount * 2);
s32 TrisUsed = 0;
r32 HalfWidth = Data->LEDHalfWidth;
v4 P0_In = v4{-HalfWidth, -HalfWidth, 0, 1};
v4 P1_In = v4{HalfWidth, -HalfWidth, 0, 1};
v4 P2_In = v4{HalfWidth, HalfWidth, 0, 1};
v4 P3_In = v4{-HalfWidth, HalfWidth, 0, 1};
v2 UV0 = v2{0, 0};
v2 UV1 = v2{1, 0};
v2 UV2 = v2{1, 1};
v2 UV3 = v2{0, 1};
led* LED = Data->LEDs + Data->StartIndex;
for (s32 LEDIdx = 0;
LEDIdx < LEDCount;
LEDIdx++)
{
pixel PixelColor = Data->Colors[LED->Index];
v4 Color = v4{PixelColor.R / 255.f, PixelColor.G / 255.f, PixelColor.B / 255.f, 1.0f};
v4 V4Position = LED->Position;
V4Position.w = 0;
v4 P0 = P0_In + V4Position;
v4 P1 = P1_In + V4Position;
v4 P2 = P2_In + V4Position;
v4 P3 = P3_In + V4Position;
SetTri3DInBatch(Data->Batch, BatchReservedRange.Start + TrisUsed++,
P0, P1, P2, UV0, UV1, UV2, Color, Color, Color);
SetTri3DInBatch(Data->Batch, BatchReservedRange.Start + TrisUsed++,
P0, P2, P3, UV0, UV2, UV3, Color, Color, Color);
LED++;
}
}
PANEL_RENDER_PROC(SculptureView_Render)
{
DEBUG_TRACK_SCOPE(RenderSculpture);
r32 PanelWidth = PanelMax.x - PanelMin.x;
r32 PanelHeight = PanelMax.y - PanelMin.y;
State->Camera.AspectRatio = PanelWidth / PanelHeight;
m44 ModelViewMatrix = GetCameraModelViewMatrix(State->Camera);
m44 ProjectionMatrix = GetCameraPerspectiveProjectionMatrix(State->Camera);
r32 LEDHalfWidth = .5f;
PushRenderPerspective(RenderBuffer, PanelMin.x, PanelMin.y, PanelWidth, PanelHeight, State->Camera);
// TODO(Peter): Pretty sure this isn't working right now
m44 FaceCameraMatrix = GetLookAtMatrix(v4{0, 0, 0, 1}, V4(State->Camera.Position, 1));
FaceCameraMatrix = FaceCameraMatrix;
s32 MaxLEDsPerJob = 2048;
render_quad_batch_constructor RenderLEDsBatch = PushRenderQuad3DBatch(RenderBuffer, State->TotalLEDsCount);
for (s32 i = 0; i < State->ActiveAssemblyIndecies.Used; i++)
{
array_entry_handle AssemblyHandle = *GetElementAtIndex(i, State->ActiveAssemblyIndecies);
assembly Assembly = *GetElementWithHandle(AssemblyHandle, State->AssemblyList);
s32 JobsNeeded = IntegerDivideRoundUp(Assembly.LEDCount, MaxLEDsPerJob);
for (s32 Job = 0; Job < JobsNeeded; Job++)
{
draw_leds_job_data* JobData = PushStruct(&State->Transient, draw_leds_job_data);
JobData->LEDs = Assembly.LEDs;
JobData->Colors = Assembly.Colors;
JobData->StartIndex = Job * MaxLEDsPerJob;
JobData->OnePastLastIndex = GSMin(JobData->StartIndex + MaxLEDsPerJob, Assembly.LEDCount);
JobData->Batch = &RenderLEDsBatch;
JobData->FaceCameraMatrix;
JobData->ModelViewMatrix = ModelViewMatrix;
JobData->LEDHalfWidth = LEDHalfWidth;
Context.GeneralWorkQueue->PushWorkOnQueue(
Context.GeneralWorkQueue,
DrawLEDsInBufferRangeJob,
JobData);
}
}
Context.GeneralWorkQueue->DoQueueWorkUntilDone(Context.GeneralWorkQueue, 0);
Context.GeneralWorkQueue->ResetWorkQueue(Context.GeneralWorkQueue);
}