From 57f144ea649aeb4101733afa720535f26ee531b4 Mon Sep 17 00:00:00 2001 From: PS Date: Sat, 24 Oct 2020 18:54:47 -0700 Subject: [PATCH 01/13] refactored panel sytstem --- src/app/editor/foldhaus_editor.cpp | 107 ++++++ src/app/editor/foldhaus_interface.cpp | 115 ++++--- src/app/editor/foldhaus_panel.h | 311 +++++++++--------- .../foldhaus_panel_animation_timeline.h | 6 +- .../editor/panels/foldhaus_panel_hierarchy.h | 2 +- src/app/foldhaus_app.cpp | 88 +---- src/app/foldhaus_app.h | 2 + src/gs_libs/gs_types.h | 2 +- 8 files changed, 327 insertions(+), 306 deletions(-) create mode 100644 src/app/editor/foldhaus_editor.cpp diff --git a/src/app/editor/foldhaus_editor.cpp b/src/app/editor/foldhaus_editor.cpp new file mode 100644 index 0000000..d2e1f6f --- /dev/null +++ b/src/app/editor/foldhaus_editor.cpp @@ -0,0 +1,107 @@ +// +// File: foldhaus_editor.cpp +// Author: Peter Slattery +// Creation Date: 2020-10-24 +// +#ifndef FOLDHAUS_EDITOR_CPP + +internal void +Editor_HandleInput (app_state* State, rect2 WindowBounds, input_queue InputQueue, mouse_state Mouse, context Context) +{ + DEBUG_TRACK_FUNCTION; + + b32 PanelSystemHandledInput = HandleMousePanelInteraction(&State->PanelSystem, State->WindowBounds, Mouse, State); + + if (!PanelSystemHandledInput) + { + input_command_registry ActiveCommands = {}; + if (State->Modes.ActiveModesCount > 0) + { + ActiveCommands = State->Modes.ActiveModes[State->Modes.ActiveModesCount - 1].Commands; + } + else + { + panel* PanelWithMouseOverIt = GetPanelContainingPoint(Mouse.Pos, State->PanelSystem.Panels + 0); + if (!PanelWithMouseOverIt) { return; } + State->HotPanel = PanelWithMouseOverIt; + + s32 PanelTypeIndex = PanelWithMouseOverIt->TypeIndex; + panel_definition PanelDefinition = GlobalPanelDefs[PanelTypeIndex]; + if (!PanelDefinition.InputCommands) { return; } + + ActiveCommands.Commands = PanelDefinition.InputCommands; + ActiveCommands.Size = sizeof(*PanelDefinition.InputCommands) / sizeof(PanelDefinition.InputCommands[0]); + ActiveCommands.Used = ActiveCommands.Size; + } + + for (s32 EventIdx = 0; EventIdx < InputQueue.QueueUsed; EventIdx++) + { + input_entry Event = InputQueue.Entries[EventIdx]; + + // NOTE(Peter): These are in the order Down, Up, Held because we want to privalege + // Down and Up over Held. In other words, we don't want to call a Held command on the + // frame when the button was released, even if the command is registered to both events + if (KeyTransitionedDown(Event)) + { + FindAndPushExistingCommand(ActiveCommands, Event, Command_Began, &State->CommandQueue); + } + else if (KeyTransitionedUp(Event)) + { + FindAndPushExistingCommand(ActiveCommands, Event, Command_Ended, &State->CommandQueue); + } + else if (KeyHeldDown(Event)) + { + FindAndPushExistingCommand(ActiveCommands, Event, Command_Held, &State->CommandQueue); + } + } + } + + // Execute all commands in CommandQueue + for (s32 CommandIdx = State->CommandQueue.Used - 1; CommandIdx >= 0; CommandIdx--) + { + command_queue_entry* Entry = &State->CommandQueue.Commands[CommandIdx]; + Entry->Command.Proc(State, Entry->Event, Mouse, Context); + } + + ClearCommandQueue(&State->CommandQueue); +} + +internal void +Editor_Update(app_state* State, context* Context, input_queue InputQueue) +{ + Context->Mouse.CursorType = CursorType_Arrow; + State->WindowBounds = Context->WindowBounds; + State->Interface.Mouse = Context->Mouse; + State->Camera.AspectRatio = RectAspectRatio(Context->WindowBounds); + + PanelSystem_UpdateLayout(&State->PanelSystem, State->WindowBounds); + Editor_HandleInput(State, State->WindowBounds, InputQueue, Context->Mouse, *Context); +} + +internal void +Editor_Render(app_state* State, context* Context, render_command_buffer* RenderBuffer) +{ + PushRenderOrthographic(RenderBuffer, State->WindowBounds); + PushRenderClearScreen(RenderBuffer); + + State->Interface.RenderBuffer = RenderBuffer; + + DrawAllPanels(State->PanelSystem, RenderBuffer, &Context->Mouse, State, *Context); + + for (s32 m = 0; m < State->Modes.ActiveModesCount; m++) + { + operation_mode OperationMode = State->Modes.ActiveModes[m]; + if (OperationMode.Render != 0) + { + OperationMode.Render(State, RenderBuffer, OperationMode, Context->Mouse, *Context); + } + } + + Context->GeneralWorkQueue->CompleteQueueWork(Context->GeneralWorkQueue, Context->ThreadContext); + Context->GeneralWorkQueue->ResetWorkQueue(Context->GeneralWorkQueue); + +} + + +#define FOLDHAUS_EDITOR_CPP +#endif // FOLDHAUS_EDITOR_CPP \ No newline at end of file diff --git a/src/app/editor/foldhaus_interface.cpp b/src/app/editor/foldhaus_interface.cpp index 28a24c2..8b7878c 100644 --- a/src/app/editor/foldhaus_interface.cpp +++ b/src/app/editor/foldhaus_interface.cpp @@ -13,6 +13,8 @@ enum panel_edit_mode { + PanelEdit_Invalid, + PanelEdit_Modify, PanelEdit_Destroy, @@ -111,6 +113,7 @@ FOLDHAUS_INPUT_COMMAND_PROC(EndDragPanelBorderOperation) else { Panel->SplitPercent = (NewSplitY - PanelBounds.Min.y) / Rect2Height(PanelBounds); + Panel_UpdateLayout(Panel, PanelBounds); } } else if (Panel->SplitDirection == PanelSplit_Vertical) @@ -127,6 +130,7 @@ FOLDHAUS_INPUT_COMMAND_PROC(EndDragPanelBorderOperation) else { Panel->SplitPercent = (NewSplitX - PanelBounds.Min.x) / Rect2Width(PanelBounds); + Panel_UpdateLayout(Panel, PanelBounds); } } } @@ -239,9 +243,9 @@ FOLDHAUS_INPUT_COMMAND_PROC(EndSplitPanelOperation) s32 PanelTypeIndex = Panel->TypeIndex; gs_data PanelStateMemory = Panel->StateMemory; - Panel_SetCurrentType(&Panel->Left->Panel, &State->PanelSystem, PanelTypeIndex, PanelStateMemory, State, Context); + Panel_SetCurrentType(Panel->Left, &State->PanelSystem, PanelTypeIndex, PanelStateMemory, State, Context); - SetAndInitPanelType(&Panel->Right->Panel, &State->PanelSystem, PanelTypeIndex, State, Context); + SetAndInitPanelType(Panel->Right, &State->PanelSystem, PanelTypeIndex, State, Context); DeactivateCurrentOperationMode(&State->Modes); } @@ -251,12 +255,12 @@ input_command SplitPanelCommands[] = { }; internal void -BeginSplitPanelOperation(panel* Panel, rect2 PanelBounds, mouse_state Mouse, app_state* State) +BeginSplitPanelOperation(panel* Panel, mouse_state Mouse, app_state* State) { operation_mode* SplitPanel = ActivateOperationModeWithCommands(&State->Modes, SplitPanelCommands, UpdateAndRenderSplitPanel); split_panel_operation_state* OpState = CreateOperationState(SplitPanel, &State->Modes, split_panel_operation_state); OpState->Panel = Panel; - OpState->InitialPanelBounds = PanelBounds; + OpState->InitialPanelBounds = Panel->Bounds; } @@ -265,61 +269,44 @@ BeginSplitPanelOperation(panel* Panel, rect2 PanelBounds, mouse_state Mouse, app #define PANEL_EDGE_CLICK_MAX_DISTANCE 6 internal b32 -HandleMouseDownPanelInteractionOrRecurse(panel* Panel, panel_edit_mode PanelEditMode, rect2 PanelBounds, mouse_state Mouse, app_state* State) +HandleMouseDownPanelInteractionOrRecurse(panel* Panel, panel_edit_mode PanelEditMode, mouse_state Mouse, app_state* State) { b32 HandledMouseInput = false; - rect2 PanelSplitButtonBounds = rect2{ PanelBounds.Min, PanelBounds.Min + v2{25, 25} }; + // TODO(pjs): this can probably live in panel_with_layout + rect2 PanelSplitButtonBounds = rect2{ Panel->Bounds.Min, Panel->Bounds.Min + v2{25, 25} }; if (Panel->SplitDirection == PanelSplit_NoSplit && PointIsInRect(PanelSplitButtonBounds, Mouse.DownPos)) { - BeginSplitPanelOperation(Panel, PanelBounds, Mouse, State); + BeginSplitPanelOperation(Panel, Mouse, State); HandledMouseInput = true; } - else if (Panel->SplitDirection == PanelSplit_Horizontal) + else if (Panel->SplitDirection != PanelSplit_NoSplit) { - r32 SplitY = LerpR32(Panel->SplitPercent, PanelBounds.Min.y, PanelBounds.Max.y); - r32 ClickDistanceFromSplit = Abs(Mouse.DownPos.y - SplitY); + u32 ElementIndex = 0; + switch(Panel->SplitDirection) + { + case PanelSplit_Vertical: { ElementIndex = 0; } break; + case PanelSplit_Horizontal: { ElementIndex = 1; } break; + InvalidDefaultCase; + } + + r32 SplitPosition = LerpR32(Panel->SplitPercent, Panel->Bounds.Min.E[ElementIndex], Panel->Bounds.Max.E[ElementIndex]); + r32 ClickDistanceFromSplit = Abs(Mouse.DownPos.E[ElementIndex] - SplitPosition); if (ClickDistanceFromSplit < PANEL_EDGE_CLICK_MAX_DISTANCE) { - BeginDragPanelBorder(Panel, PanelEditMode, PanelBounds, PanelSplit_Horizontal, Mouse, State); - HandledMouseInput = true; + BeginDragPanelBorder(Panel, PanelEditMode, Panel->Bounds, Panel->SplitDirection, Mouse, State); } else { - rect2 TopPanelBounds = GetTopPanelBounds(Panel, PanelBounds); - rect2 BottomPanelBounds = GetBottomPanelBounds(Panel, PanelBounds); - if (PointIsInRect(BottomPanelBounds, Mouse.DownPos)) + if (PointIsInRect(Panel->Bottom->Bounds, Mouse.DownPos)) { - HandleMouseDownPanelInteractionOrRecurse(&Panel->Bottom->Panel, PanelEditMode, BottomPanelBounds, Mouse, State); + HandleMouseDownPanelInteractionOrRecurse(Panel->Bottom, PanelEditMode, Mouse, State); } - if (PointIsInRect(TopPanelBounds, Mouse.DownPos)) + else if (PointIsInRect(Panel->Top->Bounds, Mouse.DownPos)) { - HandleMouseDownPanelInteractionOrRecurse(&Panel->Top->Panel, PanelEditMode, TopPanelBounds, Mouse, State); - } - } - } - else if (Panel->SplitDirection == PanelSplit_Vertical) - { - r32 SplitX = LerpR32(Panel->SplitPercent, PanelBounds.Min.x, PanelBounds.Max.x); - r32 ClickDistanceFromSplit = Abs(Mouse.DownPos.x - SplitX); - if (ClickDistanceFromSplit < PANEL_EDGE_CLICK_MAX_DISTANCE) - { - BeginDragPanelBorder(Panel, PanelEditMode, PanelBounds, PanelSplit_Vertical, Mouse, State); - HandledMouseInput = true; - } - else - { - rect2 LeftPanelBounds = GetLeftPanelBounds(Panel, PanelBounds); - rect2 RightPanelBounds = GetRightPanelBounds(Panel, PanelBounds); - if (PointIsInRect(LeftPanelBounds, Mouse.DownPos)) - { - HandleMouseDownPanelInteractionOrRecurse(&Panel->Left->Panel, PanelEditMode, LeftPanelBounds, Mouse, State); - } - if (PointIsInRect(RightPanelBounds, Mouse.DownPos)) - { - HandleMouseDownPanelInteractionOrRecurse(&Panel->Right->Panel, PanelEditMode, RightPanelBounds, Mouse, State); + HandleMouseDownPanelInteractionOrRecurse(Panel->Top, PanelEditMode, Mouse, State); } } } @@ -332,14 +319,21 @@ HandleMousePanelInteraction(panel_system* PanelSystem, rect2 WindowBounds, mouse { b32 HandledMouseInput = false; - panel* FirstPanel = &PanelSystem->Panels[0].Panel; + panel* FirstPanel = PanelSystem->Panels + 0; + panel_edit_mode EditMode = PanelEdit_Invalid; + if (MouseButtonTransitionedDown(Mouse.LeftButtonState)) { - HandledMouseInput = HandleMouseDownPanelInteractionOrRecurse(FirstPanel, PanelEdit_Modify, WindowBounds, Mouse, State); + EditMode = PanelEdit_Modify; } else if (MouseButtonTransitionedDown(Mouse.RightButtonState)) { - HandledMouseInput = HandleMouseDownPanelInteractionOrRecurse(FirstPanel, PanelEdit_Destroy, WindowBounds, Mouse, State); + EditMode = PanelEdit_Destroy; + } + + if (EditMode != PanelEdit_Invalid) + { + HandledMouseInput = HandleMouseDownPanelInteractionOrRecurse(FirstPanel, EditMode, Mouse, State); } return HandledMouseInput; @@ -456,21 +450,36 @@ RenderPanel(panel* Panel, rect2 PanelBounds, rect2 WindowBounds, render_command_ } internal void -DrawAllPanels(panel_layout PanelLayout, render_command_buffer* RenderBuffer, mouse_state* Mouse, app_state* State, context Context) +DrawPanelRecursive(panel* Panel, render_command_buffer* RenderBuffer, mouse_state* Mouse, app_state* State, context Context) { - for (u32 i = 0; i < PanelLayout.PanelsCount; i++) + switch (Panel->SplitDirection) { - panel_with_layout PanelWithLayout = PanelLayout.Panels[i]; - panel* Panel = PanelWithLayout.Panel; - rect2 PanelBounds = PanelWithLayout.Bounds; + case PanelSplit_Horizontal: + case PanelSplit_Vertical: + { + DrawPanelRecursive(Panel->Left, RenderBuffer, Mouse, State, Context); + DrawPanelRecursive(Panel->Right, RenderBuffer, Mouse, State, Context); + }break; - RenderPanel(Panel, PanelBounds, State->WindowBounds, RenderBuffer, State, Context, *Mouse); - v4 BorderColor = v4{0, 0, 0, 1}; + case PanelSplit_NoSplit: + { + RenderPanel(Panel, Panel->Bounds, State->WindowBounds, RenderBuffer, State, Context, *Mouse); + v4 BorderColor = v4{0, 0, 0, 1}; + + PushRenderOrthographic(RenderBuffer, State->WindowBounds); + DrawPanelBorder(*Panel, Panel->Bounds.Min, Panel->Bounds.Max, BorderColor, Mouse, RenderBuffer); + }break; - PushRenderOrthographic(RenderBuffer, State->WindowBounds); - DrawPanelBorder(*Panel, PanelBounds.Min, PanelBounds.Max, BorderColor, Mouse, RenderBuffer); + InvalidDefaultCase; } } +internal void +DrawAllPanels(panel_system System, render_command_buffer* RenderBuffer, mouse_state* Mouse, app_state* State, context Context) +{ + panel* PanelAt = System.Panels + 0; + DrawPanelRecursive(PanelAt, RenderBuffer, Mouse, State, Context); +} + #define FOLDHAUS_INTERFACE_CPP #endif // FOLDHAUS_INTERFACE_CPP \ No newline at end of file diff --git a/src/app/editor/foldhaus_panel.h b/src/app/editor/foldhaus_panel.h index 658a8a3..81961b9 100644 --- a/src/app/editor/foldhaus_panel.h +++ b/src/app/editor/foldhaus_panel.h @@ -18,7 +18,6 @@ enum panel_split_direction PanelSplit_Count, }; -typedef struct panel_entry panel_entry; typedef struct panel panel; #define PANEL_MODAL_OVERRIDE_CALLBACK(name) void name(panel* ReturningFrom, app_state* State, context Context) @@ -29,10 +28,11 @@ struct panel s32 TypeIndex; gs_data StateMemory; - panel_entry* ModalOverride; - panel* IsModalOverrideFor; // TODO(pjs): I don't like that this is panel* but ModalOverride is panel_entry* + panel* ModalOverride; + panel* IsModalOverrideFor; panel_modal_override_callback* ModalOverrideCB; + rect2 Bounds; panel_split_direction SplitDirection; r32 SplitPercent; @@ -40,25 +40,21 @@ struct panel // Probably belongs in a more generalized PanelInterfaceState or something b32 PanelSelectionMenuOpen; + panel* Parent; + union{ - panel_entry* Left; - panel_entry* Top; + panel* Left; + panel* Top; }; union{ - panel_entry* Right; - panel_entry* Bottom; + panel* Right; + panel* Bottom; }; }; struct free_panel { - panel_entry* Next; -}; - -struct panel_entry -{ - panel Panel; - free_panel Free; + free_panel* Next; }; #define PANEL_INIT_PROC(name) void name(panel* Panel, app_state* State, context Context) @@ -88,26 +84,10 @@ struct panel_system panel_definition* PanelDefs; u32 PanelDefsCount; - panel_entry Panels[PANELS_MAX]; + panel Panels[PANELS_MAX]; u32 PanelsUsed; - panel_entry FreeList; -}; - -// NOTE(Peter): This representation is used to let external code render and interact -// with panels. It shouldn't be stored across frame boundaries as the pointers to -// Panel's are liable to change. -struct panel_with_layout -{ - panel* Panel; - rect2 Bounds; -}; - -struct panel_layout -{ - panel_with_layout* Panels; - u32 PanelsCount; - u32 PanelsMax; + free_panel* FreeList; }; ///////////////////////////////// @@ -119,19 +99,20 @@ struct panel_layout internal void InitializePanelSystem(panel_system* PanelSystem, panel_definition* PanelDefs, u32 PanelDefsCount) { - PanelSystem->FreeList.Free.Next = &PanelSystem->FreeList; + PanelSystem->FreeList = 0; PanelSystem->PanelDefs = PanelDefs; PanelSystem->PanelDefsCount = PanelDefsCount; } -internal panel_entry* +internal panel* TakeNewPanelEntry(panel_system* PanelSystem) { - panel_entry* FreeEntry = 0; - if (PanelSystem->FreeList.Free.Next != &PanelSystem->FreeList) + panel* FreeEntry = 0; + if (PanelSystem->FreeList != 0) { - FreeEntry = PanelSystem->FreeList.Free.Next; - PanelSystem->FreeList.Free.Next = FreeEntry->Free.Next; + free_panel* FreePanel = PanelSystem->FreeList; + PanelSystem->FreeList = FreePanel->Next; + FreeEntry = (panel*)PanelSystem->FreeList; } else { @@ -142,43 +123,24 @@ TakeNewPanelEntry(panel_system* PanelSystem) } internal void -FreePanelEntry(panel_entry* Entry, panel_system* PanelSystem) +FreePanelEntry(panel* Panel, panel_system* PanelSystem) { - Assert(Entry >= PanelSystem->Panels && Entry <= PanelSystem->Panels + PANELS_MAX); - Entry->Panel = {0}; - Entry->Free.Next = PanelSystem->FreeList.Free.Next; - PanelSystem->FreeList.Free.Next = Entry; + Assert(Panel >= PanelSystem->Panels && Panel <= PanelSystem->Panels + PANELS_MAX); + + free_panel* FreeEntry = (free_panel*)Panel; + FreeEntry->Next = PanelSystem->FreeList; + PanelSystem->FreeList = FreeEntry; } internal void -FreePanelEntryRecursive(panel_entry* Entry, panel_system* PanelSystem) +FreePanelEntryRecursive(panel* Panel, panel_system* PanelSystem) { - if (Entry->Panel.SplitDirection != PanelSplit_NoSplit) + if (Panel->SplitDirection != PanelSplit_NoSplit) { - FreePanelEntryRecursive(Entry->Panel.Left, PanelSystem); - FreePanelEntryRecursive(Entry->Panel.Right, PanelSystem); + FreePanelEntryRecursive(Panel->Left, PanelSystem); + FreePanelEntryRecursive(Panel->Right, PanelSystem); } - FreePanelEntry(Entry, PanelSystem); -} - -internal void -FreePanelAtIndex(s32 Index, panel_system* PanelSystem) -{ - Assert(Index > 0 && Index < (s32)PanelSystem->PanelsUsed); - panel_entry* EntryToFree = PanelSystem->Panels + Index; - EntryToFree->Free.Next = PanelSystem->FreeList.Free.Next; - PanelSystem->FreeList.Free.Next = EntryToFree; -} - -internal panel_entry* -Panel_GetModalOverride(panel_entry* PanelEntry) -{ - panel_entry* Result = PanelEntry; - if (PanelEntry->Panel.ModalOverride != 0) - { - Result = Panel_GetModalOverride(PanelEntry->Panel.ModalOverride); - } - return Result; + FreePanelEntry(Panel, PanelSystem); } internal panel* @@ -187,17 +149,17 @@ Panel_GetModalOverride(panel* Panel) panel* Result = Panel; if (Panel->ModalOverride != 0) { - Result = &Panel_GetModalOverride(Panel->ModalOverride)->Panel; + Result = Panel_GetModalOverride(Panel->ModalOverride); } return Result; } internal void -Panel_PushModalOverride(panel* Root, panel_entry* Override, panel_modal_override_callback* Callback) +Panel_PushModalOverride(panel* Root, panel* Override, panel_modal_override_callback* Callback) { Root->ModalOverride = Override; Root->ModalOverrideCB = Callback; - Override->Panel.IsModalOverrideFor = Root; + Override->IsModalOverrideFor = Root; } internal void @@ -239,12 +201,12 @@ Panel_GetStateMemory(panel* Panel, u64 Size) return Result; } -internal panel_entry* +internal panel* PanelSystem_PushPanel(panel_system* PanelSystem, s32 PanelTypeIndex, app_state* State, context Context) { - panel_entry* PanelEntry = TakeNewPanelEntry(PanelSystem); - SetAndInitPanelType(&PanelEntry->Panel, PanelSystem, PanelTypeIndex, State, Context); - return PanelEntry; + panel* Panel = TakeNewPanelEntry(PanelSystem); + SetAndInitPanelType(Panel, PanelSystem, PanelTypeIndex, State, Context); + return Panel; } internal void @@ -257,11 +219,14 @@ SplitPanel(panel* Parent, r32 Percent, panel_split_direction SplitDirection, pan s32 ParentTypeIndex = Parent->TypeIndex; gs_data ParentStateMemory = Parent->StateMemory; + Parent->Left = TakeNewPanelEntry(PanelSystem); - Panel_SetCurrentType(&Parent->Left->Panel, PanelSystem, ParentTypeIndex, ParentStateMemory, State, Context); + Panel_SetCurrentType(Parent->Left, PanelSystem, ParentTypeIndex, ParentStateMemory, State, Context); + Parent->Left->Parent = Parent; Parent->Right = TakeNewPanelEntry(PanelSystem); - Panel_SetCurrentType(&Parent->Right->Panel, PanelSystem, ParentTypeIndex, ParentStateMemory, State, Context); + Panel_SetCurrentType(Parent->Right, PanelSystem, ParentTypeIndex, ParentStateMemory, State, Context); + Parent->Right->Parent = Parent; } } @@ -278,17 +243,17 @@ SplitPanelHorizontally(panel* Parent, r32 Percent, panel_system* PanelSystem, ap } internal void -ConsolidatePanelsKeepOne(panel* Parent, panel_entry* PanelEntryToKeep, panel_system* PanelSystem) +ConsolidatePanelsKeepOne(panel* Parent, panel* PanelToKeep, panel_system* PanelSystem) { - panel_entry* LeftChild = Parent->Left; - panel_entry* RightChild = Parent->Right; + panel* LeftChild = Parent->Left; + panel* RightChild = Parent->Right; - panel_entry* PanelEntryToDestroy = PanelEntryToKeep == LeftChild ? RightChild : LeftChild; + panel* PanelToDestroy = PanelToKeep == LeftChild ? RightChild : LeftChild; - *Parent = PanelEntryToKeep->Panel; + *Parent = *PanelToKeep; - FreePanelEntry(PanelEntryToKeep, PanelSystem); - FreePanelEntryRecursive(PanelEntryToDestroy, PanelSystem); + FreePanelEntry(PanelToKeep, PanelSystem); + FreePanelEntryRecursive(PanelToDestroy, PanelSystem); } ///////////////////////////////// @@ -297,6 +262,54 @@ ConsolidatePanelsKeepOne(panel* Parent, panel_entry* PanelEntryToKeep, panel_sys // ///////////////////////////////// +internal rect2 +GetTopPanelBounds(panel* Panel) +{ + rect2 Result = {}; + Result.Min = v2{ + Panel->Bounds.Min.x, + LerpR32(Panel->SplitPercent, Panel->Bounds.Min.y, Panel->Bounds.Max.y) + }; + Result.Max = Panel->Bounds.Max; + return Result; +} + +internal rect2 +GetBottomPanelBounds(panel* Panel) +{ + rect2 Result = {}; + Result.Min = Panel->Bounds.Min; + Result.Max = v2{ + Panel->Bounds.Max.x, + LerpR32(Panel->SplitPercent, Panel->Bounds.Min.y, Panel->Bounds.Max.y) + }; + return Result; +} + +internal rect2 +GetRightPanelBounds(panel* Panel) +{ + rect2 Result = {}; + Result.Min = v2{ + LerpR32(Panel->SplitPercent, Panel->Bounds.Min.x, Panel->Bounds.Max.x), + Panel->Bounds.Min.y + }; + Result.Max = Panel->Bounds.Max; + return Result; +} + +internal rect2 +GetLeftPanelBounds(panel* Panel) +{ + rect2 Result = {}; + Result.Min = Panel->Bounds.Min; + Result.Max = v2{ + LerpR32(Panel->SplitPercent, Panel->Bounds.Min.x, Panel->Bounds.Max.x), + Panel->Bounds.Max.y + }; + return Result; +} + internal rect2 GetTopPanelBounds(panel* Panel, rect2 PanelBounds) { @@ -346,103 +359,77 @@ GetLeftPanelBounds(panel* Panel, rect2 PanelBounds) } internal void -LayoutPanel(panel* Panel, rect2 PanelBounds, panel_layout* Layout) +Panel_UpdateLayout(panel* Panel, rect2 Bounds) { - if (Panel->SplitDirection == PanelSplit_NoSplit) + Panel->Bounds = Bounds; + + if (Panel->SplitDirection != PanelSplit_NoSplit) { - panel_with_layout* WithLayout = Layout->Panels + Layout->PanelsCount++; - WithLayout->Panel = Panel_GetModalOverride(Panel); - WithLayout->Bounds = PanelBounds; - } - else if (Panel->SplitDirection == PanelSplit_Horizontal) - { - rect2 TopPanelBounds = GetTopPanelBounds(Panel, PanelBounds); - rect2 BottomPanelBounds = GetBottomPanelBounds(Panel, PanelBounds); + rect2 LeftOrTopBounds = {}; + rect2 RightOrBottomBounds = {}; + switch (Panel->SplitDirection) + { + case PanelSplit_Horizontal: + { + LeftOrTopBounds = GetTopPanelBounds(Panel); + RightOrBottomBounds = GetBottomPanelBounds(Panel); + } break; + + case PanelSplit_Vertical: + { + LeftOrTopBounds = GetLeftPanelBounds(Panel); + RightOrBottomBounds = GetRightPanelBounds(Panel); + } break; + + InvalidDefaultCase; + } - panel* TopPanel = Panel_GetModalOverride(&Panel->Top->Panel); - panel* BottomPanel = Panel_GetModalOverride(&Panel->Bottom->Panel); - - LayoutPanel(&Panel->Top->Panel, TopPanelBounds, Layout); - LayoutPanel(&Panel->Bottom->Panel, BottomPanelBounds, Layout); - } - else if (Panel->SplitDirection == PanelSplit_Vertical) - { - rect2 LeftPanelBounds = GetLeftPanelBounds(Panel, PanelBounds); - rect2 RightPanelBounds = GetRightPanelBounds(Panel, PanelBounds); - - panel* LeftPanel = Panel_GetModalOverride(&Panel->Top->Panel); - panel* RightPanel = Panel_GetModalOverride(&Panel->Bottom->Panel); - - LayoutPanel(&Panel->Left->Panel, LeftPanelBounds, Layout); - LayoutPanel(&Panel->Right->Panel, RightPanelBounds, Layout); + Panel_UpdateLayout(Panel->Left, LeftOrTopBounds); + Panel_UpdateLayout(Panel->Right, RightOrBottomBounds); } } -internal panel_layout -GetPanelLayout(panel_system* System, rect2 WindowBounds, gs_memory_arena* Storage) +internal void +PanelSystem_UpdateLayout(panel_system* System, rect2 WindowBounds) { - panel_layout Result = {}; - Result.PanelsMax = System->PanelsUsed; - Result.Panels = PushArray(Storage, panel_with_layout, Result.PanelsMax); - - LayoutPanel(&System->Panels[0].Panel, WindowBounds, &Result); - - return Result; + panel* Root = System->Panels; + Panel_UpdateLayout(Root, WindowBounds); } -internal panel_with_layout -GetPanelContainingPoint(v2 Point, panel* Panel, rect2 PanelBounds) +internal panel* +GetPanelContainingPoint(v2 Point, panel* Panel) { - panel_with_layout Result = {0}; + panel* Result = 0; - if (Panel->SplitDirection == PanelSplit_NoSplit) + if (PointIsInRect(Panel->Bounds, Point)) { - Result.Panel = Panel; - Result.Bounds = PanelBounds; - } - else if (Panel->SplitDirection == PanelSplit_Horizontal) - { - rect2 TopPanelBounds = GetTopPanelBounds(Panel, PanelBounds); - rect2 BottomPanelBounds = GetBottomPanelBounds(Panel, PanelBounds); - - if (PointIsInRect(TopPanelBounds, Point)) + switch (Panel->SplitDirection) { - Result = GetPanelContainingPoint(Point, &Panel->Top->Panel, TopPanelBounds); - } - else if (PointIsInRect(BottomPanelBounds, Point)) - { - Result = GetPanelContainingPoint(Point, &Panel->Bottom->Panel, BottomPanelBounds); - } - } - else if (Panel->SplitDirection == PanelSplit_Vertical) - { - rect2 LeftPanelBounds = GetLeftPanelBounds(Panel, PanelBounds); - rect2 RightPanelBounds = GetRightPanelBounds(Panel, PanelBounds); - - if (PointIsInRect(LeftPanelBounds, Point)) - { - Result = GetPanelContainingPoint(Point, &Panel->Left->Panel, LeftPanelBounds); - } - else if (PointIsInRect(RightPanelBounds, Point)) - { - Result = GetPanelContainingPoint(Point, &Panel->Right->Panel, RightPanelBounds); + case PanelSplit_NoSplit: + { + Result = Panel; + }break; + + case PanelSplit_Vertical: + case PanelSplit_Horizontal: + { + if (PointIsInRect(Panel->Left->Bounds, Point)) + { + Result = GetPanelContainingPoint(Point, Panel->Left); + } + else if (PointIsInRect(Panel->Right->Bounds, Point)) + { + Result = GetPanelContainingPoint(Point, Panel->Right); + } + }break; + + InvalidDefaultCase; } } return Result; } -internal panel_with_layout -GetPanelContainingPoint(v2 Point, panel_system* PanelSystem, rect2 WindowBounds) -{ - panel_with_layout Result = {0}; - if (PanelSystem->PanelsUsed > 0) - { - Result = GetPanelContainingPoint(Point, &PanelSystem->Panels[0].Panel, WindowBounds); - } - return Result; -} - #define FOLDHAUS_PANEL_H #endif // FOLDHAUS_PANEL_H \ No newline at end of file diff --git a/src/app/editor/panels/foldhaus_panel_animation_timeline.h b/src/app/editor/panels/foldhaus_panel_animation_timeline.h index a37dc78..ee26944 100644 --- a/src/app/editor/panels/foldhaus_panel_animation_timeline.h +++ b/src/app/editor/panels/foldhaus_panel_animation_timeline.h @@ -264,9 +264,9 @@ FOLDHAUS_INPUT_COMMAND_PROC(AddAnimationBlockCommand) { animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem); - panel_with_layout ActivePanel = GetPanelContainingPoint(Mouse.Pos, &State->PanelSystem, State->WindowBounds); + panel* ActivePanel = GetPanelContainingPoint(Mouse.Pos, State->PanelSystem.Panels + 0); frame_range Range = ActiveAnim->PlayableRange; - u32 MouseDownFrame = GetFrameFromPointInAnimationPanel(Mouse.Pos, ActivePanel.Bounds, Range); + u32 MouseDownFrame = GetFrameFromPointInAnimationPanel(Mouse.Pos, ActivePanel->Bounds, Range); handle NewBlockHandle = Animation_AddBlock(ActiveAnim, MouseDownFrame, MouseDownFrame + SecondsToFrames(3, State->AnimationSystem), 4, State->SelectedAnimationLayer); SelectAnimationBlock(NewBlockHandle, State); @@ -641,7 +641,7 @@ AnimationTimeline_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* if (ui_LayoutButton(Interface, &TitleBarLayout, MakeString("Load"))) { - panel_entry* FileBrowser = PanelSystem_PushPanel(&State->PanelSystem, PanelType_FileView, State, Context); + panel* FileBrowser = PanelSystem_PushPanel(&State->PanelSystem, PanelType_FileView, State, Context); Panel_PushModalOverride(Panel, FileBrowser, LoadAnimationFileCallback); } } diff --git a/src/app/editor/panels/foldhaus_panel_hierarchy.h b/src/app/editor/panels/foldhaus_panel_hierarchy.h index fdecc36..2c076b3 100644 --- a/src/app/editor/panels/foldhaus_panel_hierarchy.h +++ b/src/app/editor/panels/foldhaus_panel_hierarchy.h @@ -75,7 +75,7 @@ HierarchyView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Ren PrintF(&TempString, "+ Add Assembly"); if (ui_ListButton(&State->Interface, TempString, LineBounds[AssembliesToDraw], AssembliesToDraw)) { - panel_entry* FileBrowser = PanelSystem_PushPanel(&State->PanelSystem, PanelType_FileView, State, Context); + panel* FileBrowser = PanelSystem_PushPanel(&State->PanelSystem, PanelType_FileView, State, Context); Panel_PushModalOverride(Panel, FileBrowser, LoadAssemblyCallback); } } diff --git a/src/app/foldhaus_app.cpp b/src/app/foldhaus_app.cpp index af0c7ae..f4afde3 100644 --- a/src/app/foldhaus_app.cpp +++ b/src/app/foldhaus_app.cpp @@ -162,66 +162,6 @@ INITIALIZE_APPLICATION(InitializeApplication) PanelSystem_PushPanel(&State->PanelSystem, PanelType_SculptureView, State, Context); } -internal void -HandleInput (app_state* State, rect2 WindowBounds, input_queue InputQueue, mouse_state Mouse, context Context) -{ - DEBUG_TRACK_FUNCTION; - - b32 PanelSystemHandledInput = HandleMousePanelInteraction(&State->PanelSystem, State->WindowBounds, Mouse, State); - if (!PanelSystemHandledInput) - { - input_command_registry ActiveCommands = {}; - if (State->Modes.ActiveModesCount > 0) - { - ActiveCommands = State->Modes.ActiveModes[State->Modes.ActiveModesCount - 1].Commands; - } - else - { - panel_with_layout PanelWithMouseOverIt = GetPanelContainingPoint(Mouse.Pos, &State->PanelSystem, WindowBounds); - if (!PanelWithMouseOverIt.Panel) { return; } - State->HotPanel = PanelWithMouseOverIt.Panel; - - s32 PanelTypeIndex = PanelWithMouseOverIt.Panel->TypeIndex; - panel_definition PanelDefinition = GlobalPanelDefs[PanelTypeIndex]; - if (!PanelDefinition.InputCommands) { return; } - - ActiveCommands.Commands = PanelDefinition.InputCommands; - ActiveCommands.Size = sizeof(*PanelDefinition.InputCommands) / sizeof(PanelDefinition.InputCommands[0]); - ActiveCommands.Used = ActiveCommands.Size; - } - - for (s32 EventIdx = 0; EventIdx < InputQueue.QueueUsed; EventIdx++) - { - input_entry Event = InputQueue.Entries[EventIdx]; - - // NOTE(Peter): These are in the order Down, Up, Held because we want to privalege - // Down and Up over Held. In other words, we don't want to call a Held command on the - // frame when the button was released, even if the command is registered to both events - if (KeyTransitionedDown(Event)) - { - FindAndPushExistingCommand(ActiveCommands, Event, Command_Began, &State->CommandQueue); - } - else if (KeyTransitionedUp(Event)) - { - FindAndPushExistingCommand(ActiveCommands, Event, Command_Ended, &State->CommandQueue); - } - else if (KeyHeldDown(Event)) - { - FindAndPushExistingCommand(ActiveCommands, Event, Command_Held, &State->CommandQueue); - } - } - } - - // Execute all commands in CommandQueue - for (s32 CommandIdx = State->CommandQueue.Used - 1; CommandIdx >= 0; CommandIdx--) - { - command_queue_entry* Entry = &State->CommandQueue.Commands[CommandIdx]; - Entry->Command.Proc(State, Entry->Event, Mouse, Context); - } - - ClearCommandQueue(&State->CommandQueue); -} - UPDATE_AND_RENDER(UpdateAndRender) { DEBUG_TRACK_FUNCTION; @@ -232,12 +172,8 @@ UPDATE_AND_RENDER(UpdateAndRender) // zero the Transient arena when we clear it so it wouldn't be a problem, but it is technically // incorrect to clear the arena, and then access the memory later. ClearArena(State->Transient); - Context->Mouse.CursorType = CursorType_Arrow; - PushRenderClearScreen(RenderBuffer); - State->Camera.AspectRatio = RectAspectRatio(Context->WindowBounds); - - HandleInput(State, State->WindowBounds, InputQueue, Context->Mouse, *Context); + Editor_Update(State, Context, InputQueue); { animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem); @@ -348,27 +284,7 @@ UPDATE_AND_RENDER(UpdateAndRender) UART_BuildOutputData(OutputData, UARTAssemblies, &State->LedSystem); } - PushRenderOrthographic(RenderBuffer, State->WindowBounds); - PushRenderClearScreen(RenderBuffer); - - State->WindowBounds = Context->WindowBounds; - State->Interface.RenderBuffer = RenderBuffer; - State->Interface.Mouse = Context->Mouse; - - panel_layout PanelsToRender = GetPanelLayout(&State->PanelSystem, State->WindowBounds, State->Transient); - DrawAllPanels(PanelsToRender, RenderBuffer, &Context->Mouse, State, *Context); - - for (s32 m = 0; m < State->Modes.ActiveModesCount; m++) - { - operation_mode OperationMode = State->Modes.ActiveModes[m]; - if (OperationMode.Render != 0) - { - OperationMode.Render(State, RenderBuffer, OperationMode, Context->Mouse, *Context); - } - } - - Context->GeneralWorkQueue->CompleteQueueWork(Context->GeneralWorkQueue, Context->ThreadContext); - Context->GeneralWorkQueue->ResetWorkQueue(Context->GeneralWorkQueue); + Editor_Render(State, Context, RenderBuffer); // Checking for overflows #if 0 diff --git a/src/app/foldhaus_app.h b/src/app/foldhaus_app.h index 05bd69f..60937fc 100644 --- a/src/app/foldhaus_app.h +++ b/src/app/foldhaus_app.h @@ -233,5 +233,7 @@ animation_clip GlobalAnimationClips[] = { #include "../meta/gs_meta_include.cpp" +#include "editor/foldhaus_editor.cpp" + #define FOLDHAUS_APP_H #endif // FOLDHAUS_APP_H \ No newline at end of file diff --git a/src/gs_libs/gs_types.h b/src/gs_libs/gs_types.h index e36f2ed..e647f5c 100644 --- a/src/gs_libs/gs_types.h +++ b/src/gs_libs/gs_types.h @@ -231,7 +231,7 @@ struct u64_array # define InvalidDefaultCase default: { AssertBreak("invalid default case"); } break; # define StaticAssert(c) \ enum { \ -Glue(gs_AssertFail_, __LINE__) = 1 / (int)(!!(c)), \ + Glue(gs_AssertFail_, __LINE__) = 1 / (int)(!!(c)), \ } #else # define Assert(c) From 723458c491dad30bee31948220f6190659d943c8 Mon Sep 17 00:00:00 2001 From: PS Date: Tue, 3 Nov 2020 12:49:16 -0800 Subject: [PATCH 02/13] fixed some issues with the panel system, and began rearraning the animation timeline window --- src/app/editor/foldhaus_editor.cpp | 2 +- src/app/editor/foldhaus_interface.cpp | 21 +- src/app/editor/foldhaus_panel.h | 37 ++- .../foldhaus_panel_animation_timeline.h | 304 ++++++++++++++---- src/app/foldhaus_app.cpp | 4 +- src/app/foldhaus_platform.h | 2 +- src/app/interface.h | 12 + src/gs_libs/gs_types.cpp | 1 + src/todo.txt | 12 + 9 files changed, 301 insertions(+), 94 deletions(-) diff --git a/src/app/editor/foldhaus_editor.cpp b/src/app/editor/foldhaus_editor.cpp index d2e1f6f..2548f54 100644 --- a/src/app/editor/foldhaus_editor.cpp +++ b/src/app/editor/foldhaus_editor.cpp @@ -26,7 +26,7 @@ Editor_HandleInput (app_state* State, rect2 WindowBounds, input_queue InputQueue State->HotPanel = PanelWithMouseOverIt; s32 PanelTypeIndex = PanelWithMouseOverIt->TypeIndex; - panel_definition PanelDefinition = GlobalPanelDefs[PanelTypeIndex]; + panel_definition PanelDefinition = State->PanelSystem.PanelDefs[PanelTypeIndex]; if (!PanelDefinition.InputCommands) { return; } ActiveCommands.Commands = PanelDefinition.InputCommands; diff --git a/src/app/editor/foldhaus_interface.cpp b/src/app/editor/foldhaus_interface.cpp index 8b7878c..c0bad58 100644 --- a/src/app/editor/foldhaus_interface.cpp +++ b/src/app/editor/foldhaus_interface.cpp @@ -245,7 +245,7 @@ FOLDHAUS_INPUT_COMMAND_PROC(EndSplitPanelOperation) gs_data PanelStateMemory = Panel->StateMemory; Panel_SetCurrentType(Panel->Left, &State->PanelSystem, PanelTypeIndex, PanelStateMemory, State, Context); - SetAndInitPanelType(Panel->Right, &State->PanelSystem, PanelTypeIndex, State, Context); + Panel_SetType(Panel->Right, &State->PanelSystem, PanelTypeIndex, State, Context); DeactivateCurrentOperationMode(&State->Modes); } @@ -396,23 +396,22 @@ DrawPanelFooter(panel* Panel, render_command_buffer* RenderBuffer, rect2 FooterB { ButtonBounds.Min, v2{ - ButtonBounds.Min.x + Rect2Width(ButtonBounds), ButtonBounds.Min.y + (Rect2Height(ButtonBounds) * GlobalPanelDefsCount) + ButtonBounds.Min.x + Rect2Width(ButtonBounds), ButtonBounds.Min.y + (Rect2Height(ButtonBounds) * State->PanelSystem.PanelDefsCount) }, }; - if (MouseButtonTransitionedDown(Mouse.LeftButtonState) - && !PointIsInRect(MenuBounds, Mouse.DownPos)) + if (ui_MouseClickedRect(State->Interface, MenuBounds)) { Panel->PanelSelectionMenuOpen = false; } for (s32 i = 0; i < GlobalPanelDefsCount; i++) { - panel_definition Def = GlobalPanelDefs[i]; + panel_definition Def = State->PanelSystem.PanelDefs[i]; gs_string DefName = MakeString(Def.PanelName, Def.PanelNameLength); if (ui_Button(&State->Interface, DefName, ButtonBounds)) { - SetAndInitPanelType(Panel, &State->PanelSystem, i, State, Context); + Panel_SetType(Panel, &State->PanelSystem, i, State, Context); Panel->PanelSelectionMenuOpen = false; } @@ -430,8 +429,9 @@ DrawPanelFooter(panel* Panel, render_command_buffer* RenderBuffer, rect2 FooterB internal void RenderPanel(panel* Panel, rect2 PanelBounds, rect2 WindowBounds, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse) { - s32 PanelType = Panel->TypeIndex; + u32 PanelType = Panel->TypeIndex; Assert(PanelType >= 0); + Assert(PanelType < State->PanelSystem.PanelDefsCount); rect2 FooterBounds = rect2{ PanelBounds.Min, @@ -442,7 +442,7 @@ RenderPanel(panel* Panel, rect2 PanelBounds, rect2 WindowBounds, render_command_ PanelBounds.Max, }; - panel_definition Definition = GlobalPanelDefs[PanelType]; + panel_definition Definition = State->PanelSystem.PanelDefs[PanelType]; Definition.Render(Panel, PanelViewBounds, RenderBuffer, State, Context); PushRenderOrthographic(RenderBuffer, WindowBounds); @@ -463,11 +463,12 @@ DrawPanelRecursive(panel* Panel, render_command_buffer* RenderBuffer, mouse_stat case PanelSplit_NoSplit: { - RenderPanel(Panel, Panel->Bounds, State->WindowBounds, RenderBuffer, State, Context, *Mouse); + panel* OverridePanel = Panel_GetModalOverride(Panel); + RenderPanel(OverridePanel, OverridePanel->Bounds, State->WindowBounds, RenderBuffer, State, Context, *Mouse); v4 BorderColor = v4{0, 0, 0, 1}; PushRenderOrthographic(RenderBuffer, State->WindowBounds); - DrawPanelBorder(*Panel, Panel->Bounds.Min, Panel->Bounds.Max, BorderColor, Mouse, RenderBuffer); + DrawPanelBorder(*OverridePanel, OverridePanel->Bounds.Min, OverridePanel->Bounds.Max, BorderColor, Mouse, RenderBuffer); }break; InvalidDefaultCase; diff --git a/src/app/editor/foldhaus_panel.h b/src/app/editor/foldhaus_panel.h index 81961b9..697db65 100644 --- a/src/app/editor/foldhaus_panel.h +++ b/src/app/editor/foldhaus_panel.h @@ -84,7 +84,7 @@ struct panel_system panel_definition* PanelDefs; u32 PanelDefsCount; - panel Panels[PANELS_MAX]; + panel* Panels; u32 PanelsUsed; free_panel* FreeList; @@ -97,22 +97,24 @@ struct panel_system ///////////////////////////////// internal void -InitializePanelSystem(panel_system* PanelSystem, panel_definition* PanelDefs, u32 PanelDefsCount) +PanelSystem_Init(panel_system* PanelSystem, panel_definition* PanelDefs, u32 PanelDefsCount, gs_memory_arena* Storage) { PanelSystem->FreeList = 0; PanelSystem->PanelDefs = PanelDefs; PanelSystem->PanelDefsCount = PanelDefsCount; + + PanelSystem->Panels = PushArray(Storage, panel, PANELS_MAX); } internal panel* -TakeNewPanelEntry(panel_system* PanelSystem) +PanelSystem_TakePanel(panel_system* PanelSystem) { panel* FreeEntry = 0; if (PanelSystem->FreeList != 0) { free_panel* FreePanel = PanelSystem->FreeList; PanelSystem->FreeList = FreePanel->Next; - FreeEntry = (panel*)PanelSystem->FreeList; + FreeEntry = (panel*)FreePanel; } else { @@ -123,7 +125,7 @@ TakeNewPanelEntry(panel_system* PanelSystem) } internal void -FreePanelEntry(panel* Panel, panel_system* PanelSystem) +PanelSystem_FreePanel(panel* Panel, panel_system* PanelSystem) { Assert(Panel >= PanelSystem->Panels && Panel <= PanelSystem->Panels + PANELS_MAX); @@ -133,14 +135,14 @@ FreePanelEntry(panel* Panel, panel_system* PanelSystem) } internal void -FreePanelEntryRecursive(panel* Panel, panel_system* PanelSystem) +PanelSystem_FreePanelRecursive(panel* Panel, panel_system* PanelSystem) { if (Panel->SplitDirection != PanelSplit_NoSplit) { - FreePanelEntryRecursive(Panel->Left, PanelSystem); - FreePanelEntryRecursive(Panel->Right, PanelSystem); + PanelSystem_FreePanelRecursive(Panel->Left, PanelSystem); + PanelSystem_FreePanelRecursive(Panel->Right, PanelSystem); } - FreePanelEntry(Panel, PanelSystem); + PanelSystem_FreePanel(Panel, PanelSystem); } internal panel* @@ -160,13 +162,14 @@ Panel_PushModalOverride(panel* Root, panel* Override, panel_modal_override_callb Root->ModalOverride = Override; Root->ModalOverrideCB = Callback; Override->IsModalOverrideFor = Root; + Override->Bounds = Root->Bounds; } internal void Panel_PopModalOverride(panel* Parent, panel_system* System) { // TODO(pjs): Free the overrided panel - FreePanelEntry(Parent->ModalOverride, System); + PanelSystem_FreePanel(Parent->ModalOverride, System); Parent->ModalOverride = 0; } @@ -185,7 +188,7 @@ Panel_SetCurrentType(panel* Panel, panel_system* System, s32 NewPanelType, gs_da } internal void -SetAndInitPanelType(panel* Panel, panel_system* System, s32 NewPanelTypeIndex, app_state* State, context Context) +Panel_SetType(panel* Panel, panel_system* System, s32 NewPanelTypeIndex, app_state* State, context Context) { gs_data EmptyStateData = {0}; Panel_SetCurrentType(Panel, System, NewPanelTypeIndex, EmptyStateData, State, Context); @@ -204,8 +207,8 @@ Panel_GetStateMemory(panel* Panel, u64 Size) internal panel* PanelSystem_PushPanel(panel_system* PanelSystem, s32 PanelTypeIndex, app_state* State, context Context) { - panel* Panel = TakeNewPanelEntry(PanelSystem); - SetAndInitPanelType(Panel, PanelSystem, PanelTypeIndex, State, Context); + panel* Panel = PanelSystem_TakePanel(PanelSystem); + Panel_SetType(Panel, PanelSystem, PanelTypeIndex, State, Context); return Panel; } @@ -220,11 +223,11 @@ SplitPanel(panel* Parent, r32 Percent, panel_split_direction SplitDirection, pan s32 ParentTypeIndex = Parent->TypeIndex; gs_data ParentStateMemory = Parent->StateMemory; - Parent->Left = TakeNewPanelEntry(PanelSystem); + Parent->Left = PanelSystem_TakePanel(PanelSystem); Panel_SetCurrentType(Parent->Left, PanelSystem, ParentTypeIndex, ParentStateMemory, State, Context); Parent->Left->Parent = Parent; - Parent->Right = TakeNewPanelEntry(PanelSystem); + Parent->Right = PanelSystem_TakePanel(PanelSystem); Panel_SetCurrentType(Parent->Right, PanelSystem, ParentTypeIndex, ParentStateMemory, State, Context); Parent->Right->Parent = Parent; } @@ -252,8 +255,8 @@ ConsolidatePanelsKeepOne(panel* Parent, panel* PanelToKeep, panel_system* PanelS *Parent = *PanelToKeep; - FreePanelEntry(PanelToKeep, PanelSystem); - FreePanelEntryRecursive(PanelToDestroy, PanelSystem); + PanelSystem_FreePanel(PanelToKeep, PanelSystem); + PanelSystem_FreePanelRecursive(PanelToDestroy, PanelSystem); } ///////////////////////////////// diff --git a/src/app/editor/panels/foldhaus_panel_animation_timeline.h b/src/app/editor/panels/foldhaus_panel_animation_timeline.h index ee26944..460f228 100644 --- a/src/app/editor/panels/foldhaus_panel_animation_timeline.h +++ b/src/app/editor/panels/foldhaus_panel_animation_timeline.h @@ -6,13 +6,13 @@ #ifndef FOLDHAUS_PANEL_ANIMATION_TIMELINE_H // Colors -global v4 TimeSliderColor = GreenV4; //v4{.36f, .52f, .78f, 1.f}; +global v4 TimeSliderColor = v4{.36f, .52f, .78f, 1.f}; // struct animation_timeline_state { frame_range VisibleRange; - handle SelectedAnimationBlockHandle; + handle SelectedBlockHandle; u32 SelectedAnimationLayer; }; @@ -43,18 +43,6 @@ AddAnimationBlockAtCurrentTime (u32 AnimationProcHandle, u32 LayerHandle, animat return AnimHandle; } -internal void -SelectAnimationBlock(handle BlockHandle, app_state* State) -{ - State->SelectedAnimationBlockHandle = BlockHandle; -} - -internal void -DeselectCurrentAnimationBlock(app_state* State) -{ - State->SelectedAnimationBlockHandle = {}; -} - FOLDHAUS_INPUT_COMMAND_PROC(DeleteAnimationBlockCommand) { handle SelectedAnimHandle = State->SelectedAnimationBlockHandle; @@ -122,6 +110,7 @@ StartDragTimeMarker(rect2 TimelineBounds, frame_range VisibleFrames, app_state* OPERATION_STATE_DEF(drag_animation_clip_state) { rect2 TimelineBounds; + handle BlockHandle; frame_range VisibleRange; frame_range ClipRange; }; @@ -158,7 +147,7 @@ OPERATION_RENDER_PROC(UpdateDragAnimationClip) u32 FrameAtMouseX = GetFrameFromPointInAnimationPanel(Mouse.Pos, OpState->TimelineBounds, OpState->VisibleRange); s32 FrameOffset = (s32)FrameAtMouseX - (s32)FrameAtMouseDownX; - animation_block* AnimationBlock = Animation_GetBlockFromHandle(ActiveAnim, State->SelectedAnimationBlockHandle); + animation_block* AnimationBlock = Animation_GetBlockFromHandle(ActiveAnim, OpState->BlockHandle); if (!AnimationBlock) { EndCurrentOperationMode(State, {}, Mouse, Context); @@ -242,9 +231,9 @@ input_command DragAnimationClipCommands [] = { }; internal void -SelectAndBeginDragAnimationBlock(handle BlockHandle, frame_range VisibleRange, rect2 TimelineBounds, app_state* State) +SelectAndBeginDragAnimationBlock(animation_timeline_state* TimelineState, handle BlockHandle, frame_range VisibleRange, rect2 TimelineBounds, app_state* State) { - SelectAnimationBlock(BlockHandle, State); + TimelineState->SelectedBlockHandle = BlockHandle; animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem); operation_mode* DragAnimationClipMode = ActivateOperationModeWithCommands(&State->Modes, DragAnimationClipCommands, UpdateDragAnimationClip); @@ -253,6 +242,7 @@ SelectAndBeginDragAnimationBlock(handle BlockHandle, frame_range VisibleRange, r &State->Modes, drag_animation_clip_state); OpState->TimelineBounds = TimelineBounds; + OpState->BlockHandle = BlockHandle; OpState->VisibleRange = VisibleRange; animation_block* SelectedBlock = Animation_GetBlockFromHandle(ActiveAnim, BlockHandle); @@ -265,11 +255,12 @@ FOLDHAUS_INPUT_COMMAND_PROC(AddAnimationBlockCommand) animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem); panel* ActivePanel = GetPanelContainingPoint(Mouse.Pos, State->PanelSystem.Panels + 0); + animation_timeline_state* TimelineState = Panel_GetStateStruct(ActivePanel, animation_timeline_state); frame_range Range = ActiveAnim->PlayableRange; u32 MouseDownFrame = GetFrameFromPointInAnimationPanel(Mouse.Pos, ActivePanel->Bounds, Range); handle NewBlockHandle = Animation_AddBlock(ActiveAnim, MouseDownFrame, MouseDownFrame + SecondsToFrames(3, State->AnimationSystem), 4, State->SelectedAnimationLayer); - SelectAnimationBlock(NewBlockHandle, State); + TimelineState->SelectedBlockHandle = NewBlockHandle; } input_command AnimationTimeline_Commands[] = { @@ -310,6 +301,8 @@ DrawFrameBar (animation_system* AnimationSystem, ui_interface Interface, frame_r r32 BarWidth = Rect2Width(BarBounds); // Mouse clicked inside frame nubmer bar -> change current frame on timeline + // TODO(pjs): both of these functions can get wrapped in a MouseClickedRect + // and an alternate MouseIsDraggingRect if (MouseButtonTransitionedDown(Interface.Mouse.LeftButtonState) && PointIsInRect(BarBounds, Interface.Mouse.DownPos)) { @@ -484,6 +477,8 @@ DrawAnimationBlock (animation_block AnimationBlock, v4 BlockColor, frame_range V PushRenderQuad2D(RenderBuffer, BlockBounds.Min, BlockBounds.Max, BlockColor); PushRenderBoundingBox2D(RenderBuffer, BlockBounds.Min, BlockBounds.Max, 1, WhiteV4); + // TODO(pjs): If mouse is on one of the border hot spots, render an off colored square to signal the region is hot + return BlockBounds; } @@ -546,7 +541,7 @@ DrawAnimationTimeline (animation_system* AnimationSystem, animation_timeline_sta if (MouseDownAndNotHandled && Handle_IsValid(DragBlockHandle)) { MouseDownAndNotHandled = false; - SelectAndBeginDragAnimationBlock(DragBlockHandle, AdjustedViewRange, TimelineBounds, State); + SelectAndBeginDragAnimationBlock(TimelineState, DragBlockHandle, AdjustedViewRange, TimelineBounds, State); } // Time Slider @@ -567,7 +562,7 @@ DrawAnimationTimeline (animation_system* AnimationSystem, animation_timeline_sta if (MouseDownAndNotHandled && PointIsInRect(TimelineBounds, Interface->Mouse.Pos)) { - DeselectCurrentAnimationBlock(State); + TimelineState->SelectedBlockHandle = {0}; } return Result; @@ -579,12 +574,15 @@ PANEL_MODAL_OVERRIDE_CALLBACK(LoadAnimationFileCallback) file_view_state* FileViewState = Panel_GetStateStruct(ReturningFrom, file_view_state); gs_file_info FileInfo = FileViewState->SelectedFile; - gs_file AnimFile = ReadEntireFile(Context.ThreadContext.FileHandler, FileInfo.Path); - gs_string AnimFileString = MakeString((char*)AnimFile.Data.Memory, AnimFile.Data.Size); - animation NewAnim = AnimParser_Parse(AnimFileString, State->AnimationSystem.Storage, GlobalAnimationClipsCount, GlobalAnimationClips); - - u32 NewAnimIndex = AnimationArray_Push(&State->AnimationSystem.Animations, NewAnim); - State->AnimationSystem.ActiveAnimationIndex = NewAnimIndex; + if (FileInfo.Path.Length > 0) + { + gs_file AnimFile = ReadEntireFile(Context.ThreadContext.FileHandler, FileInfo.Path); + gs_string AnimFileString = MakeString((char*)AnimFile.Data.Memory, AnimFile.Data.Size); + animation NewAnim = AnimParser_Parse(AnimFileString, State->AnimationSystem.Storage, GlobalAnimationClipsCount, GlobalAnimationClips); + + u32 NewAnimIndex = AnimationArray_Push(&State->AnimationSystem.Animations, NewAnim); + State->AnimationSystem.ActiveAnimationIndex = NewAnimIndex; + } } internal void @@ -602,56 +600,234 @@ DrawAnimationClipsList(rect2 PanelBounds, ui_interface* Interface, u32 SelectedA } } +internal void +PlayBar_Render(animation_timeline_state* TimelineState, rect2 Bounds, panel* Panel, render_command_buffer* RenderBuffer, app_state* State, context Context) +{ + animation_system* AnimSystem = &State->AnimationSystem; + ui_interface* Interface = &State->Interface; + ui_layout Layout = ui_CreateLayout(*Interface, Bounds); + + ui_FillRect(Interface, Bounds, Interface->Style.PanelBGColors[0]); + ui_StartRow(&Layout, 4); + { + if (ui_LayoutButton(Interface, &Layout, MakeString("Pause"))) + { + AnimSystem->TimelineShouldAdvance = false; + } + + if (ui_LayoutButton(Interface, &Layout, MakeString("Play"), (State->AnimationSystem.TimelineShouldAdvance ? PinkV4 : BlackV4), v4{.3f, .3f, .3f, 1.0f}, TealV4)) + { + AnimSystem->TimelineShouldAdvance = true; + } + + if (ui_LayoutButton(Interface, &Layout, MakeString("Stop"))) + { + AnimSystem->TimelineShouldAdvance = false; + AnimSystem->CurrentFrame = 0; + } + + if (ui_LayoutButton(Interface, &Layout, MakeString("Load"))) + { + panel* FileBrowser = PanelSystem_PushPanel(&State->PanelSystem, PanelType_FileView, State, Context); + Panel_PushModalOverride(Panel, FileBrowser, LoadAnimationFileCallback); + } + } + ui_EndRow(&Layout); +} + +internal void +FrameCount_Render(animation_timeline_state* TimelineState, rect2 Bounds, render_command_buffer* RenderBuffer, app_state* State, context Context) +{ + ui_interface* Interface = &State->Interface; + gs_string TempString = PushString(State->Transient, 256); + frame_range VisibleFrames = TimelineState->VisibleRange; + s32 VisibleFrameCount = VisibleFrames.Max - VisibleFrames.Min; + + ui_FillRect(Interface, Bounds, Interface->Style.PanelBGColors[0]); + + // Frame Ticks + u32 TickCount = 10; + for (u32 Tick = 0; Tick < TickCount; Tick++) + { + r32 Percent = (r32)Tick / (r32)TickCount; + u32 Frame = PercentToFrameInRange(Percent, VisibleFrames); + PrintF(&TempString, "%d", Frame); + r32 FramePercent = FrameToPercentRange(Frame, VisibleFrames); + r32 FrameX = LerpR32(FramePercent, Bounds.Min.x, Bounds.Max.x); + v2 FrameTextPos = v2{FrameX, Bounds.Min.y + 2}; + DrawString(Interface->RenderBuffer, TempString, Interface->Style.Font, FrameTextPos, WhiteV4); + } + + // Time Slider + s32 CurrentFrame = State->AnimationSystem.CurrentFrame; + if (FrameIsInRange(VisibleFrames, CurrentFrame)) + { + r32 FrameAtPercentVisibleRange = FrameToPercentRange(CurrentFrame, VisibleFrames); + r32 SliderX = LerpR32(FrameAtPercentVisibleRange, Bounds.Min.x, Bounds.Max.x); + + PrintF(&TempString, "%d", CurrentFrame); + + // space for each character + a margin on either side + r32 SliderWidth = (8 * TempString.Length) + 8; + r32 SliderHalfWidth = SliderWidth / 2.f; + v2 HeadMin = v2{SliderX - SliderHalfWidth, Bounds.Min.y}; + v2 HeadMax = v2{SliderX + SliderHalfWidth, Bounds.Max.y}; + PushRenderQuad2D(Interface->RenderBuffer, HeadMin, HeadMax, TimeSliderColor); + DrawString(Interface->RenderBuffer, TempString, Interface->Style.Font, HeadMin + v2{6, 4}, WhiteV4); + } + + // Interaction + // Mouse clicked inside frame nubmer bar -> change current frame on timeline + if (ui_MouseClickedRect(*Interface, Bounds)) + { + StartDragTimeMarker(Bounds, VisibleFrames, State); + } +} + +internal void +LayerList_Render(animation_timeline_state* TimelineState, rect2 Bounds, render_command_buffer* RenderBuffer, app_state* State, context Context) +{ + ui_interface* Interface = &State->Interface; + animation ActiveAnim = *AnimationSystem_GetActiveAnimation(&State->AnimationSystem); + + ui_FillRect(Interface, Bounds, Interface->Style.PanelBGColors[0]); + + v2 LayerDim = { Rect2Width(Bounds), LAYER_HEIGHT }; + rect2 LayerBounds = {0}; + LayerBounds.Min = Bounds.Min; + LayerBounds.Max = LayerBounds.Min + LayerDim; + for (u32 i = 0; i < ActiveAnim.Layers.Count; i++) + { + anim_layer* Layer = ActiveAnim.Layers.Values + i; + + if (ui_MouseClickedRect(*Interface, LayerBounds)) + { + TimelineState->SelectedAnimationLayer = i; + } + + v2 LayerTextPos = { LayerBounds.Min.x + 6, LayerBounds.Max.y - 16}; + if (TimelineState->SelectedAnimationLayer == i) + { + PushRenderBoundingBox2D(Interface->RenderBuffer, LayerBounds.Min, LayerBounds.Max, 1, WhiteV4); + } + DrawString(Interface->RenderBuffer, Layer->Name, Interface->Style.Font, LayerTextPos, WhiteV4); + + LayerBounds = Rect2TranslateY(LayerBounds, LayerDim.y); + } +} + +internal void +TimeRange_Render(animation_timeline_state* TimelineState, rect2 Bounds, render_command_buffer* RenderBuffer, app_state* State, context Context) +{ + ui_interface* Interface = &State->Interface; + frame_range ViewRange = TimelineState->VisibleRange; + + animation ActiveAnim = *AnimationSystem_GetActiveAnimation(&State->AnimationSystem); + handle SelectedBlockHandle = TimelineState->SelectedBlockHandle; + s32 CurrentFrame = State->AnimationSystem.CurrentFrame; + + // Animation Blocks + b32 MouseDownAndNotHandled = MouseButtonTransitionedDown(Interface->Mouse.LeftButtonState); + handle DragBlockHandle = {0}; + for (u32 i = 0; i < ActiveAnim.Blocks_.Count; i++) + { + animation_block* AnimationBlockAt = ActiveAnim.Blocks_.Values + i; + + // If either end is in the range, we should draw it + b32 RangeIsVisible = (FrameIsInRange(ViewRange, AnimationBlockAt->Range.Min) || + FrameIsInRange(ViewRange, AnimationBlockAt->Range.Max)); + // If neither end is in the range, but the ends surround the visible range, + // we should still draw it. + RangeIsVisible |= (AnimationBlockAt->Range.Min <= ViewRange.Min && + AnimationBlockAt->Range.Max>= ViewRange.Max); + if (RangeIsVisible) + { + v4 BlockColor = BlackV4; + if (SelectedBlockHandle.Index == i && SelectedBlockHandle.Generation == ActiveAnim.Blocks_.Generations[i]) + { + BlockColor = PinkV4; + } + rect2 BlockBounds = DrawAnimationBlock(*AnimationBlockAt, BlockColor, ViewRange, Bounds, Interface->RenderBuffer); + + if (PointIsInRect(BlockBounds, Interface->Mouse.Pos)) + { + DragBlockHandle.Index = i; + DragBlockHandle.Generation = ActiveAnim.Blocks_.Generations[i]; + } + } + } + + // Time Slider + if (FrameIsInRange(ViewRange, CurrentFrame)) + { + r32 FrameAtPercentVisibleRange = FrameToPercentRange(CurrentFrame, ViewRange); + r32 SliderX = LerpR32(FrameAtPercentVisibleRange, Bounds.Min.x, Bounds.Max.x); + rect2 SliderBounds = { + v2{ SliderX, Bounds.Min.y }, + v2{ SliderX + 1, Bounds.Max.y } + }; + ui_FillRect(Interface, SliderBounds, TimeSliderColor); + } + + // Interaction + if (MouseDownAndNotHandled) + { + if (Handle_IsValid(DragBlockHandle)) + { + MouseDownAndNotHandled = false; + SelectAndBeginDragAnimationBlock(TimelineState, DragBlockHandle, ViewRange, Bounds, State); + } + else if (PointIsInRect(Bounds, Interface->Mouse.Pos)) + { + TimelineState->SelectedBlockHandle = {0}; + } + } +} + +internal void +AnimInfoView_Render(animation_timeline_state* TimelineState, rect2 Bounds, render_command_buffer* RenderBuffer, app_state* State, context Context) +{ + ui_FillRect(&State->Interface, Bounds, PinkV4); +} + +internal void +SelectionInfoView_Render(animation_timeline_state* TimelineState, rect2 Bounds, render_command_buffer* RenderBuffer, app_state* State, context Context) +{ + ui_FillRect(&State->Interface, Bounds, YellowV4); +} + GSMetaTag(panel_render); GSMetaTag(panel_type_animation_timeline); internal void AnimationTimeline_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context) { animation_timeline_state* TimelineState = Panel_GetStateStruct(Panel, animation_timeline_state); - // TODO(pjs): SelectedAnimationBlockHandle should be a property of animation_timeline_state - // unless its used elsewhere. Audit later - handle SelectedBlockHandle = State->SelectedAnimationBlockHandle; - ui_interface* Interface = &State->Interface; - animation_system* AnimationSystem = &State->AnimationSystem; - rect2 TitleBarBounds, PanelContentsBounds; - rect2 AnimationListBounds, TimelineBounds; - RectHSplitAtDistanceFromTop(PanelBounds, Interface->Style.RowHeight, &TitleBarBounds, &PanelContentsBounds); - RectVSplitAtDistanceFromLeft(PanelContentsBounds, 300, &AnimationListBounds, &TimelineBounds); + rect2 TimelineBounds, InfoBounds; + RectVSplit(PanelBounds, 300, &InfoBounds, &TimelineBounds); - ui_FillRect(Interface, TitleBarBounds, Interface->Style.PanelBGColors[0]); - ui_layout TitleBarLayout = ui_CreateLayout(*Interface, TitleBarBounds); - ui_StartRow(&TitleBarLayout, 4); - { - if (ui_LayoutButton(Interface, &TitleBarLayout, MakeString("Pause"))) - { - State->AnimationSystem.TimelineShouldAdvance = false; - } + rect2 AnimInfoBounds, SelectionInfoBounds; + RectHSplitAtPercent(InfoBounds, .35f, &AnimInfoBounds, &SelectionInfoBounds); + + { // Timeline + rect2 LayersPanelBounds, TimeRangePanelBounds; + RectVSplitAtDistanceFromLeft(TimelineBounds, 200, &LayersPanelBounds, &TimeRangePanelBounds); - if (ui_LayoutButton(Interface, &TitleBarLayout, MakeString("Play"), (State->AnimationSystem.TimelineShouldAdvance ? PinkV4 : BlackV4), v4{.3f, .3f, .3f, 1.0f}, TealV4)) - { - State->AnimationSystem.TimelineShouldAdvance = true; - } + r32 TitleBarHeight = State->Interface.Style.RowHeight; + // These are the actual rects we will draw in + rect2 PlayBarBounds, FrameCountBounds; + rect2 LayersBounds, TimeRangeBounds; + RectHSplitAtDistanceFromTop(LayersPanelBounds, TitleBarHeight, &PlayBarBounds, &LayersBounds); + RectHSplitAtDistanceFromTop(TimeRangePanelBounds, TitleBarHeight, &FrameCountBounds, &TimeRangeBounds); - if (ui_LayoutButton(Interface, &TitleBarLayout, MakeString("Stop"))) - { - State->AnimationSystem.TimelineShouldAdvance = false; - State->AnimationSystem.CurrentFrame = 0; - } - - if (ui_LayoutButton(Interface, &TitleBarLayout, MakeString("Load"))) - { - panel* FileBrowser = PanelSystem_PushPanel(&State->PanelSystem, PanelType_FileView, State, Context); - Panel_PushModalOverride(Panel, FileBrowser, LoadAnimationFileCallback); - } + PlayBar_Render(TimelineState, PlayBarBounds, Panel, RenderBuffer, State, Context); + FrameCount_Render(TimelineState, FrameCountBounds, RenderBuffer, State, Context); + LayerList_Render(TimelineState, LayersBounds, RenderBuffer, State, Context); + TimeRange_Render(TimelineState, TimeRangeBounds, RenderBuffer, State, Context); } - ui_EndRow(&TitleBarLayout); - if (Rect2Height(TimelineBounds) > 0) - { - SelectedBlockHandle = DrawAnimationTimeline(AnimationSystem, TimelineState, TimelineBounds, SelectedBlockHandle, Interface, State); - DrawAnimationClipsList(AnimationListBounds, Interface, State->SelectedAnimationLayer, &State->AnimationSystem); - } + AnimInfoView_Render(TimelineState, AnimInfoBounds, RenderBuffer, State, Context); + SelectionInfoView_Render(TimelineState, SelectionInfoBounds, RenderBuffer, State, Context); } #define FOLDHAUS_PANEL_ANIMATION_TIMELINE_H diff --git a/src/app/foldhaus_app.cpp b/src/app/foldhaus_app.cpp index f4afde3..f9a1e3b 100644 --- a/src/app/foldhaus_app.cpp +++ b/src/app/foldhaus_app.cpp @@ -15,6 +15,8 @@ RELOAD_STATIC_DATA(ReloadStaticData) app_state* State = (app_state*)Context.MemoryBase; GlobalDebugServices = DebugServices; + State->PanelSystem.PanelDefs = GlobalPanelDefs; + State->PanelSystem.PanelDefsCount = GlobalPanelDefsCount; } INITIALIZE_APPLICATION(InitializeApplication) @@ -158,7 +160,7 @@ INITIALIZE_APPLICATION(InitializeApplication) } // End Animation Playground - InitializePanelSystem(&State->PanelSystem, GlobalPanelDefs, GlobalPanelDefsCount); + PanelSystem_Init(&State->PanelSystem, GlobalPanelDefs, GlobalPanelDefsCount, &State->Permanent); PanelSystem_PushPanel(&State->PanelSystem, PanelType_SculptureView, State, Context); } diff --git a/src/app/foldhaus_platform.h b/src/app/foldhaus_platform.h index 96c8685..d40a71a 100644 --- a/src/app/foldhaus_platform.h +++ b/src/app/foldhaus_platform.h @@ -148,7 +148,7 @@ typedef DRAW_FONT_CODEPOINT(platform_draw_font_codepoint); // Worker Threads -#define PLATFORM_THREAD_COUNT 4 +#define PLATFORM_THREAD_COUNT 0 RESET_WORK_QUEUE(ResetWorkQueue) { diff --git a/src/app/interface.h b/src/app/interface.h index d382f4c..12ed3d3 100644 --- a/src/app/interface.h +++ b/src/app/interface.h @@ -340,6 +340,18 @@ ui_LayoutRemaining(ui_layout Layout) return Result; } +// +// Interaction +// + +internal b32 +ui_MouseClickedRect(ui_interface Interface, rect2 Rect) +{ + b32 Result = MouseButtonTransitionedDown(Interface.Mouse.LeftButtonState); + Result &= PointIsInRect(Rect, Interface.Mouse.Pos); + return Result; +} + // // Drawing Functions // diff --git a/src/gs_libs/gs_types.cpp b/src/gs_libs/gs_types.cpp index 12bd157..05467cc 100644 --- a/src/gs_libs/gs_types.cpp +++ b/src/gs_libs/gs_types.cpp @@ -855,6 +855,7 @@ RectHSplit(rect2 Rect, r32 YValue, rect2* Top, rect2* Bottom) Bottom->Max = { Rect.Max.x, ClampedYValue }; Bottom->Min = Rect.Min; } + internal void RectVSplit(rect2 Rect, r32 XValue, rect2* Left, rect2* Right) { diff --git a/src/todo.txt b/src/todo.txt index 6c1bc22..3dcb1f0 100644 --- a/src/todo.txt +++ b/src/todo.txt @@ -1,5 +1,17 @@ TODO FOLDHAUS + +- engine environment + - primary color +- default controller + - gets its own update function + - has access to the engine state + - can select animations + - change playback speed, primary color +- user space controller +- socket listener + + STREAM #1: 3D Overhaul - Rendering (Working on this elsewhere) - OpenGL 3 From d5be2a2de89c0a4a49b54b3de1c5969c0fa0c49a Mon Sep 17 00:00:00 2001 From: PS Date: Sat, 7 Nov 2020 22:54:59 -0800 Subject: [PATCH 03/13] Pretty big ui overhaul. --- src/app/editor/foldhaus_editor.cpp | 64 +++ src/app/editor/foldhaus_interface.cpp | 29 +- src/app/editor/foldhaus_panel.h | 4 - .../foldhaus_panel_animation_timeline.h | 50 +- .../editor/panels/foldhaus_panel_file_view.h | 8 +- .../editor/panels/foldhaus_panel_hierarchy.h | 15 +- .../editor/panels/foldhaus_panel_profiler.h | 54 +- src/app/foldhaus_app.cpp | 8 +- src/app/interface.h | 499 +++++++++++++----- 9 files changed, 531 insertions(+), 200 deletions(-) diff --git a/src/app/editor/foldhaus_editor.cpp b/src/app/editor/foldhaus_editor.cpp index 2548f54..29ce994 100644 --- a/src/app/editor/foldhaus_editor.cpp +++ b/src/app/editor/foldhaus_editor.cpp @@ -84,8 +84,12 @@ Editor_Render(app_state* State, context* Context, render_command_buffer* RenderB PushRenderOrthographic(RenderBuffer, State->WindowBounds); PushRenderClearScreen(RenderBuffer); + ui_InterfaceReset(&State->Interface); State->Interface.RenderBuffer = RenderBuffer; + ui_layout Layout = ui_CreateLayout(&State->Interface, Context->WindowBounds); + ui_PushLayout(&State->Interface, Layout); + DrawAllPanels(State->PanelSystem, RenderBuffer, &Context->Mouse, State, *Context); for (s32 m = 0; m < State->Modes.ActiveModesCount; m++) @@ -97,6 +101,66 @@ Editor_Render(app_state* State, context* Context, render_command_buffer* RenderB } } + ui_PopLayout(&State->Interface); + + // Draw the Interface + for (u32 i = 0; i < State->Interface.WidgetsCount; i++) + { + ui_widget Widget = State->Interface.Widgets[i]; + + if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawBackground)) + { + v4 Color = State->Interface.Style.ButtonColor_Inactive; + if (ui_WidgetIdsEqual(Widget.Id, State->Interface.HotWidget)) + { + Color = State->Interface.Style.ButtonColor_Active; + } + if (ui_WidgetIdsEqual(Widget.Id, State->Interface.ActiveWidget)) + { + Color = State->Interface.Style.ButtonColor_Selected; + } + PushRenderQuad2D(RenderBuffer, Widget.Bounds.Min, Widget.Bounds.Max, Color); + } + + if (Widget.String.Length > 0) + { + v4 Color = State->Interface.Style.TextColor; + render_quad_batch_constructor BatchConstructor = PushRenderTexture2DBatch(RenderBuffer, + Widget.String.Length, + State->Interface.Style.Font->BitmapMemory, + State->Interface.Style.Font->BitmapTextureHandle, + State->Interface.Style.Font->BitmapWidth, + State->Interface.Style.Font->BitmapHeight, + State->Interface.Style.Font->BitmapBytesPerPixel, + State->Interface.Style.Font->BitmapStride); + + v2 RegisterPosition = Widget.Bounds.Min + State->Interface.Style.Margin; + + switch (Widget.Alignment) + { + case Align_Left: + { + RegisterPosition = DrawStringLeftAligned(&BatchConstructor, StringExpand(Widget.String), RegisterPosition, State->Interface.Style.Font, Color); + }break; + + case Align_Right: + { + RegisterPosition = DrawStringRightAligned(&BatchConstructor, StringExpand(Widget.String), RegisterPosition, State->Interface.Style.Font, Color); + }break; + + InvalidDefaultCase; + } + } + + if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawOutline)) + { + // TODO(pjs): replace these with values from the style + r32 Thickness = 1.0f; + v4 Color = WhiteV4; + PushRenderBoundingBox2D(RenderBuffer, Widget.Bounds.Min, Widget.Bounds.Max, Thickness, Color); + } + } + Context->GeneralWorkQueue->CompleteQueueWork(Context->GeneralWorkQueue, Context->ThreadContext); Context->GeneralWorkQueue->ResetWorkQueue(Context->GeneralWorkQueue); diff --git a/src/app/editor/foldhaus_interface.cpp b/src/app/editor/foldhaus_interface.cpp index c0bad58..0a33f8f 100644 --- a/src/app/editor/foldhaus_interface.cpp +++ b/src/app/editor/foldhaus_interface.cpp @@ -388,42 +388,19 @@ DrawPanelFooter(panel* Panel, render_command_buffer* RenderBuffer, rect2 FooterB rect2 PanelSelectBtnBounds = MakeRect2MinDim(FooterBounds.Min + v2{30, 1}, v2{100, 23}); - if (Panel->PanelSelectionMenuOpen) + if (ui_BeginDropdown(&State->Interface, MakeString("Select"), PanelSelectBtnBounds)) { - rect2 ButtonBounds = MakeRect2MinDim(v2{ PanelSelectBtnBounds.Min.x, FooterBounds.Max.y }, v2{ 100, 25 }); - - rect2 MenuBounds = rect2 - { - ButtonBounds.Min, - v2{ - ButtonBounds.Min.x + Rect2Width(ButtonBounds), ButtonBounds.Min.y + (Rect2Height(ButtonBounds) * State->PanelSystem.PanelDefsCount) - }, - }; - - if (ui_MouseClickedRect(State->Interface, MenuBounds)) - { - Panel->PanelSelectionMenuOpen = false; - } - for (s32 i = 0; i < GlobalPanelDefsCount; i++) { panel_definition Def = State->PanelSystem.PanelDefs[i]; gs_string DefName = MakeString(Def.PanelName, Def.PanelNameLength); - if (ui_Button(&State->Interface, DefName, ButtonBounds)) + if (ui_Button(&State->Interface, DefName)) { Panel_SetType(Panel, &State->PanelSystem, i, State, Context); - Panel->PanelSelectionMenuOpen = false; } - - ButtonBounds = Rect2TranslateY(ButtonBounds, Rect2Height(ButtonBounds)); } } - - if (ui_Button(&State->Interface, MakeString("Select"), PanelSelectBtnBounds)) - { - Panel->PanelSelectionMenuOpen = !Panel->PanelSelectionMenuOpen; - } - + ui_EndDropdown(&State->Interface); } internal void diff --git a/src/app/editor/foldhaus_panel.h b/src/app/editor/foldhaus_panel.h index 697db65..a715de3 100644 --- a/src/app/editor/foldhaus_panel.h +++ b/src/app/editor/foldhaus_panel.h @@ -36,10 +36,6 @@ struct panel 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; - panel* Parent; union{ diff --git a/src/app/editor/panels/foldhaus_panel_animation_timeline.h b/src/app/editor/panels/foldhaus_panel_animation_timeline.h index 460f228..d28fff5 100644 --- a/src/app/editor/panels/foldhaus_panel_animation_timeline.h +++ b/src/app/editor/panels/foldhaus_panel_animation_timeline.h @@ -588,7 +588,8 @@ PANEL_MODAL_OVERRIDE_CALLBACK(LoadAnimationFileCallback) internal void DrawAnimationClipsList(rect2 PanelBounds, ui_interface* Interface, u32 SelectedAnimationLayerHandle, animation_system* AnimationSystem) { - ui_layout Layout = ui_CreateLayout(*Interface, PanelBounds); + ui_layout Layout = ui_CreateLayout(Interface, PanelBounds); + ui_PushLayout(Interface, Layout); for (s32 i = 0; i < GlobalAnimationClipsCount; i++) { animation_clip Clip = GlobalAnimationClips[i]; @@ -598,6 +599,7 @@ DrawAnimationClipsList(rect2 PanelBounds, ui_interface* Interface, u32 SelectedA AddAnimationBlockAtCurrentTime(i + 1, SelectedAnimationLayerHandle, AnimationSystem); } } + ui_PopLayout(Interface); } internal void @@ -605,34 +607,36 @@ PlayBar_Render(animation_timeline_state* TimelineState, rect2 Bounds, panel* Pan { animation_system* AnimSystem = &State->AnimationSystem; ui_interface* Interface = &State->Interface; - ui_layout Layout = ui_CreateLayout(*Interface, Bounds); + ui_layout Layout = ui_CreateLayout(Interface, Bounds); + ui_PushLayout(Interface, Layout); ui_FillRect(Interface, Bounds, Interface->Style.PanelBGColors[0]); - ui_StartRow(&Layout, 4); + ui_StartRow(&State->Interface, 4); { - if (ui_LayoutButton(Interface, &Layout, MakeString("Pause"))) + if (ui_Button(Interface, MakeString("Pause"))) { AnimSystem->TimelineShouldAdvance = false; } - if (ui_LayoutButton(Interface, &Layout, MakeString("Play"), (State->AnimationSystem.TimelineShouldAdvance ? PinkV4 : BlackV4), v4{.3f, .3f, .3f, 1.0f}, TealV4)) + if (ui_Button(Interface, MakeString("Play"))) { AnimSystem->TimelineShouldAdvance = true; } - if (ui_LayoutButton(Interface, &Layout, MakeString("Stop"))) + if (ui_Button(Interface, MakeString("Stop"))) { AnimSystem->TimelineShouldAdvance = false; AnimSystem->CurrentFrame = 0; } - if (ui_LayoutButton(Interface, &Layout, MakeString("Load"))) + if (ui_Button(Interface, MakeString("Load"))) { panel* FileBrowser = PanelSystem_PushPanel(&State->PanelSystem, PanelType_FileView, State, Context); Panel_PushModalOverride(Panel, FileBrowser, LoadAnimationFileCallback); } } - ui_EndRow(&Layout); + ui_EndRow(&State->Interface); + ui_PopLayout(&State->Interface); } internal void @@ -787,7 +791,33 @@ TimeRange_Render(animation_timeline_state* TimelineState, rect2 Bounds, render_c internal void AnimInfoView_Render(animation_timeline_state* TimelineState, rect2 Bounds, render_command_buffer* RenderBuffer, app_state* State, context Context) { - ui_FillRect(&State->Interface, Bounds, PinkV4); + animation_system* AnimSystem = &State->AnimationSystem; + animation* ActiveAnim = AnimationSystem_GetActiveAnimation(AnimSystem); + + ui_interface* Interface = &State->Interface; + ui_layout Layout = ui_CreateLayout(Interface, Bounds); + ui_PushLayout(Interface, Layout); + + ui_FillRect(&State->Interface, Bounds, Interface->Style.PanelBGColors[0]); + + ui_StartRow(&State->Interface, 2); + { + ui_DrawString(Interface, MakeString("Active Animation")); + if (ui_BeginDropdown(Interface, ActiveAnim->Name)) + { + for (u32 i = 0; i < AnimSystem->Animations.Count; i++) + { + animation Animation = AnimSystem->Animations.Values[i]; + if (ui_Button(Interface, Animation.Name)) + { + AnimSystem->ActiveAnimationIndex = i; + } + } + } + ui_EndDropdown(Interface); + } + ui_EndRow(&State->Interface); + ui_PopLayout(Interface); } internal void @@ -807,7 +837,7 @@ AnimationTimeline_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RectVSplit(PanelBounds, 300, &InfoBounds, &TimelineBounds); rect2 AnimInfoBounds, SelectionInfoBounds; - RectHSplitAtPercent(InfoBounds, .35f, &AnimInfoBounds, &SelectionInfoBounds); + RectHSplitAtPercent(InfoBounds, .65f, &AnimInfoBounds, &SelectionInfoBounds); { // Timeline rect2 LayersPanelBounds, TimeRangePanelBounds; diff --git a/src/app/editor/panels/foldhaus_panel_file_view.h b/src/app/editor/panels/foldhaus_panel_file_view.h index e369e7f..f4427c0 100644 --- a/src/app/editor/panels/foldhaus_panel_file_view.h +++ b/src/app/editor/panels/foldhaus_panel_file_view.h @@ -88,15 +88,16 @@ internal void FileView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context) { file_view_state* FileViewState = Panel_GetStateStruct(Panel, file_view_state); - ui_layout Layout = ui_CreateLayout(State->Interface, PanelBounds); + ui_layout Layout = ui_CreateLayout(&State->Interface, PanelBounds); + ui_PushLayout(&State->Interface, Layout); - if (ui_LayoutButton(&State->Interface, &Layout, MakeString("Exit"))) + if (ui_Button(&State->Interface, MakeString("Exit"))) { FileView_Exit_(Panel, State, Context); } // Header - ui_LayoutDrawString(&State->Interface, &Layout, FileViewState->WorkingDirectory, v4{0, 1, 0, 1}); + ui_DrawString(&State->Interface, FileViewState->WorkingDirectory); // File Display for (u32 i = 0; i < FileViewState->FileNames.Count; i++) @@ -121,6 +122,7 @@ FileView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBu } } + ui_PopLayout(&State->Interface); } diff --git a/src/app/editor/panels/foldhaus_panel_hierarchy.h b/src/app/editor/panels/foldhaus_panel_hierarchy.h index 2c076b3..54b6b8c 100644 --- a/src/app/editor/panels/foldhaus_panel_hierarchy.h +++ b/src/app/editor/panels/foldhaus_panel_hierarchy.h @@ -38,7 +38,9 @@ GSMetaTag(panel_type_hierarchy); internal void HierarchyView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context) { - ui_layout Layout = ui_CreateLayout(State->Interface, PanelBounds); + ui_layout Layout = ui_CreateLayout(&State->Interface, PanelBounds); + ui_PushLayout(&State->Interface, Layout); + gs_string TempString = PushString(State->Transient, 256); u32 LineCount = (u32)(Rect2Height(PanelBounds) / Layout.RowHeight) + 1; u32 AssembliesToDraw = Min(LineCount, State->Assemblies.Count); @@ -57,16 +59,15 @@ HierarchyView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Ren assembly Assembly = State->Assemblies.Values[AssemblyIndex]; PrintF(&TempString, "%S", Assembly.Name); - ui_layout ItemLayout = ui_CreateLayout(State->Interface, LineBounds[AssemblyIndex]); - ui_StartRow(&ItemLayout, 2); + ui_StartRow(&State->Interface, 2); { - ui_LayoutDrawString(&State->Interface, &ItemLayout, TempString, State->Interface.Style.TextColor); - if (ui_LayoutListButton(&State->Interface, &ItemLayout, MakeString("X"), AssemblyIndex)) + ui_DrawString(&State->Interface, TempString); + if (ui_LayoutListButton(&State->Interface, &Layout, MakeString("X"), AssemblyIndex)) { UnloadAssembly(AssemblyIndex, State, Context); } } - ui_EndRow(&ItemLayout); + ui_EndRow(&State->Interface); } if (AssembliesToDraw < LineCount) @@ -79,6 +80,8 @@ HierarchyView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Ren Panel_PushModalOverride(Panel, FileBrowser, LoadAssemblyCallback); } } + + ui_PopLayout(&State->Interface); } diff --git a/src/app/editor/panels/foldhaus_panel_profiler.h b/src/app/editor/panels/foldhaus_panel_profiler.h index 90fbafa..0f38547 100644 --- a/src/app/editor/panels/foldhaus_panel_profiler.h +++ b/src/app/editor/panels/foldhaus_panel_profiler.h @@ -84,7 +84,7 @@ RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_layout Layout, deb PrintF(&String, "%S : %d - %d", HotRecordName->Name, HotRecord->StartCycles, HotRecord->EndCycles); rect2 TextBounds = MakeRect2MinDim(Interface->Mouse.Pos, v2{256, 32}); - ui_TextBox(Interface, TextBounds, String, BlackV4, WhiteV4); + ui_DrawString(Interface, String, TextBounds); } } @@ -95,15 +95,15 @@ RenderProfiler_ListVisualization(ui_interface* Interface, ui_layout Layout, debu gs_string String = MakeString(Backbuffer, 0, 256); r32 ColumnWidths[] = {256, 128, 128, 128, 128}; - ui_StartRow(&Layout, 5, &ColumnWidths[0]); + ui_StartRow(Interface, 5, &ColumnWidths[0]); { - ui_LayoutDrawString(Interface, &Layout, MakeString("Procedure"), Interface->Style.TextColor); - ui_LayoutDrawString(Interface, &Layout, MakeString("% Frame"), Interface->Style.TextColor); - ui_LayoutDrawString(Interface, &Layout, MakeString("Seconds"), Interface->Style.TextColor); - ui_LayoutDrawString(Interface, &Layout, MakeString("Cycles"), Interface->Style.TextColor); - ui_LayoutDrawString(Interface, &Layout, MakeString("Calls"), Interface->Style.TextColor); + ui_DrawString(Interface, MakeString("Procedure")); + ui_DrawString(Interface, MakeString("% Frame")); + ui_DrawString(Interface, MakeString("Seconds")); + ui_DrawString(Interface, MakeString("Cycles")); + ui_DrawString(Interface, MakeString("Calls")); } - ui_EndRow(&Layout); + ui_EndRow(Interface); for (s32 n = 0; n < VisibleFrame->ScopeNamesMax; n++) { @@ -112,24 +112,24 @@ RenderProfiler_ListVisualization(ui_interface* Interface, ui_layout Layout, debu { collated_scope_record* CollatedRecord = VisibleFrame->CollatedScopes + n; - ui_StartRow(&Layout, 5, &ColumnWidths[0]); + ui_StartRow(Interface, 5, &ColumnWidths[0]); { PrintF(&String, "%S", NameEntry.Name); - ui_LayoutDrawString(Interface, &Layout, String, Interface->Style.TextColor); + ui_DrawString(Interface, String); PrintF(&String, "%f%%", CollatedRecord->PercentFrameTime); - ui_LayoutDrawString(Interface, &Layout, String, Interface->Style.TextColor); + ui_DrawString(Interface, String); PrintF(&String, "%fs", CollatedRecord->TotalSeconds); - ui_LayoutDrawString(Interface, &Layout, String, Interface->Style.TextColor); + ui_DrawString(Interface, String); PrintF(&String, "%dcy", CollatedRecord->TotalCycles); - ui_LayoutDrawString(Interface, &Layout, String, Interface->Style.TextColor); + ui_DrawString(Interface, String); PrintF(&String, "%d", CollatedRecord->CallCount); - ui_LayoutDrawString(Interface, &Layout, String, Interface->Style.TextColor); + ui_DrawString(Interface, String); } - ui_EndRow(&Layout); + ui_EndRow(Interface); } } } @@ -179,41 +179,43 @@ ProfilerView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Rend debug_frame* VisibleFrame = GetLastDebugFrame(GlobalDebugServices); - ui_layout Layout = ui_CreateLayout(State->Interface, ProcListBounds); - ui_StartRow(&Layout, 4); + ui_layout Layout = ui_CreateLayout(&State->Interface, ProcListBounds); + ui_PushLayout(&State->Interface, Layout); + + ui_StartRow(&State->Interface, 4); { s64 FrameStartCycles = VisibleFrame->FrameStartCycles; s64 FrameTotalCycles = VisibleFrame->FrameEndCycles - VisibleFrame->FrameStartCycles; u32 CurrentDebugFrame = GlobalDebugServices->CurrentDebugFrame - 1; PrintF(&String, "Frame %d", CurrentDebugFrame); - ui_LayoutDrawString(&State->Interface, &Layout, String, WhiteV4); + ui_DrawString(&State->Interface, String); PrintF(&String, "Total Cycles: %lld", FrameTotalCycles); - ui_LayoutDrawString(&State->Interface, &Layout, String, WhiteV4); + ui_DrawString(&State->Interface, String); // NOTE(NAME): Skipping a space for aesthetic reasons, not functional, and could // be removed, or used for something else ui_ReserveElementBounds(&Layout); - if (ui_LayoutButton(&State->Interface, &Layout, MakeString("Resume Recording"))) + if (ui_Button(&State->Interface, MakeString("Resume Recording"))) { GlobalDebugServices->RecordFrames = true; } } - ui_EndRow(&Layout); + ui_EndRow(&State->Interface); - ui_StartRow(&Layout, 8); + ui_StartRow(&State->Interface, 8); { - if (ui_LayoutButton(&State->Interface, &Layout, MakeString("Scope View"))) + if (ui_Button(&State->Interface, MakeString("Scope View"))) { GlobalDebugServices->Interface.FrameView = FRAME_VIEW_PROFILER; } - if (ui_LayoutButton(&State->Interface, &Layout, MakeString("List View"))) + if (ui_Button(&State->Interface, MakeString("List View"))) { GlobalDebugServices->Interface.FrameView = FRAME_VIEW_SCOPE_LIST; } } - ui_EndRow(&Layout); + ui_EndRow(&State->Interface); if (GlobalDebugServices->Interface.FrameView == FRAME_VIEW_PROFILER) { @@ -223,6 +225,8 @@ ProfilerView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Rend { RenderProfiler_ListVisualization(&State->Interface, Layout, VisibleFrame, Memory); } + + ui_PopLayout(&State->Interface); } diff --git a/src/app/foldhaus_app.cpp b/src/app/foldhaus_app.cpp index f9a1e3b..2f6acaf 100644 --- a/src/app/foldhaus_app.cpp +++ b/src/app/foldhaus_app.cpp @@ -103,7 +103,7 @@ INITIALIZE_APPLICATION(InitializeApplication) State->Interface.Style.PanelBGColors[3] = v4{.6f, .6f, .6f, 1}; State->Interface.Style.ButtonColor_Inactive = BlackV4; State->Interface.Style.ButtonColor_Active = v4{.1f, .1f, .1f, 1}; - State->Interface.Style.ButtonColor_Selected = v4{.1f, .1f, .3f, 1}; + State->Interface.Style.ButtonColor_Selected = v4{.3f, .3f, .3f, 1}; State->Interface.Style.TextColor = WhiteV4; State->Interface.Style.ListBGColors[0] = v4{ .16f, .16f, .16f, 1.f }; State->Interface.Style.ListBGColors[1] = v4{ .18f, .18f, .18f, 1.f }; @@ -112,6 +112,9 @@ INITIALIZE_APPLICATION(InitializeApplication) State->Interface.Style.Margin = v2{5, 5}; State->Interface.Style.RowHeight = ui_GetTextLineHeight(State->Interface); + State->Interface.WidgetsCountMax = 4096; + State->Interface.Widgets = PushArray(&State->Permanent, ui_widget, State->Interface.WidgetsCountMax); + State->SACN = SACN_Initialize(Context); State->Camera.FieldOfView = 45.0f; @@ -119,8 +122,7 @@ INITIALIZE_APPLICATION(InitializeApplication) State->Camera.Near = .1f; State->Camera.Far = 800.0f; State->Camera.Position = v3{0, 0, 400}; - State->Camera.LookAt = v3{0, 0, 0 - }; + State->Camera.LookAt = v3{0, 0, 0}; State->LedSystem = LedSystemInitialize(Context.ThreadContext.Allocator, 128); diff --git a/src/app/interface.h b/src/app/interface.h index 12ed3d3..d390069 100644 --- a/src/app/interface.h +++ b/src/app/interface.h @@ -5,6 +5,14 @@ // #ifndef INTERFACE_H +// Widget Capabilities +// - string +// - background +// - outline +// - active (mouse is interacting) +// - hot (mouse could be about to interact) +// - retained state - if a toggle is active, or a drop down is open + enum gs_string_alignment { Align_Left, @@ -129,7 +137,7 @@ DrawCursor (render_quad_batch_constructor* BatchConstructor, v2 Position, v4 Col } internal v2 -Drawgs_stringWithCursor (render_command_buffer* RenderBuffer, gs_string String, s32 CursorPosition, bitmap_font* Font, v2 Position, v4 Color, v4 CursorColor, gs_string_alignment Alignment = Align_Left) +DrawStringWithCursor (render_command_buffer* RenderBuffer, gs_string String, s32 CursorPosition, bitmap_font* Font, v2 Position, v4 Color, v4 CursorColor, gs_string_alignment Alignment = Align_Left) { DEBUG_TRACK_FUNCTION; v2 LowerRight = Position; @@ -180,10 +188,44 @@ Drawgs_stringWithCursor (render_command_buffer* RenderBuffer, gs_string String, return LowerRight; } +// TODO(pjs): remove the need for htis (go thru and remove code that's in the #else block of #ifdef EXTERNAL_RENDERER s +#define EXTERNAL_RENDERER + +enum ui_widget_flag +{ + UIWidgetFlag_DrawBackground, + UIWidgetFlag_DrawOutline, + UIWidgetFlag_Clickable, +}; + +struct ui_widget_id +{ + u64 Index; + u64 LayoutId; +}; + +struct ui_widget +{ + ui_widget_id Id; + + gs_string String; + gs_string_alignment Alignment; + + rect2 Bounds; + u64 Flags; + bool RetainedState; +}; + +struct ui_eval_result +{ + bool Clicked; +}; + struct interface_config { v4 PanelBGColors[4]; + // TODO(pjs): Turn these into _Default, _Hot, _Active v4 ButtonColor_Inactive, ButtonColor_Active, ButtonColor_Selected; v4 TextColor; @@ -199,17 +241,38 @@ struct interface_config r32 RowHeight; }; +enum ui_layout_direction +{ + LayoutDirection_TopDown, + LayoutDirection_BottomUp, +}; + struct ui_layout { + u64 Id; + rect2 Bounds; v2 Margin; r32 RowHeight; r32 RowYAt; + ui_layout_direction FillDirection; + b32 DrawHorizontal; u32 ColumnsMax; r32* ColumnWidths; u32 ColumnsCount; + + // NOTE(pjs): I'm not sure this will stay but + // its here so that when we end things like a dropdown, + // we can check the retained state of that dropdown + ui_widget_id WidgetReference; +}; + +struct ui_widget_retained_state +{ + ui_widget_id Id; + bool Value; }; struct ui_interface @@ -217,49 +280,144 @@ struct ui_interface interface_config Style; mouse_state Mouse; render_command_buffer* RenderBuffer; + + ui_widget* Widgets; + u64 WidgetsCount; + u64 WidgetsCountMax; + + ui_widget_id HotWidget; + ui_widget_id ActiveWidget; + +#define LAYOUT_COUNT_MAX 8 + ui_layout LayoutStack[LAYOUT_COUNT_MAX]; + u64 LayoutStackCount; + u64 LayoutIdAcc; + +#define RETAINED_STATE_MAX 128 + ui_widget_retained_state RetainedState[RETAINED_STATE_MAX]; + u64 RetainedStateCount; }; +internal void +ui_InterfaceReset(ui_interface* Interface) +{ + Interface->WidgetsCount = 0; + Interface->LayoutStackCount = 0; + Interface->LayoutIdAcc = 0; +} + +internal bool +ui_WidgetIdsEqual(ui_widget_id A, ui_widget_id B) +{ + bool Result = (A.Index == B.Index) && (A.LayoutId == B.LayoutId); + return Result; +} + +internal ui_widget_retained_state* +ui_GetRetainedState(ui_interface* Interface, ui_widget_id Id) +{ + ui_widget_retained_state* Result = 0; + for (u64 i = 0; i < Interface->RetainedStateCount; i++) + { + if (ui_WidgetIdsEqual(Interface->RetainedState[i].Id, Id)) + { + Result = Interface->RetainedState + i; + break; + } + } + return Result; +} + +internal ui_widget_retained_state* +ui_CreateRetainedState(ui_interface* Interface, ui_widget_id Id) +{ + u64 Index = Interface->RetainedStateCount++; + ui_widget_retained_state* Result = Interface->RetainedState + Index; + Result->Id = Id; + return Result; +} + +// +// Interaction +// + +internal b32 +ui_MouseClickedRect(ui_interface Interface, rect2 Rect) +{ + b32 Result = MouseButtonTransitionedDown(Interface.Mouse.LeftButtonState); + Result &= PointIsInRect(Rect, Interface.Mouse.Pos); + return Result; +} + +// Layout + static ui_layout -ui_CreateLayout(ui_interface Interface, rect2 Bounds) +ui_CreateLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDirection = LayoutDirection_TopDown) { ui_layout Result = {0}; Result.Bounds = Bounds; - Result.Margin = Interface.Style.Margin; - Result.RowHeight = Interface.Style.RowHeight; - Result.RowYAt = Bounds.Max.y - Result.RowHeight; + Result.Margin = Interface->Style.Margin; + Result.RowHeight = Interface->Style.RowHeight; + Result.FillDirection = FillDirection; + switch(FillDirection) + { + case LayoutDirection_BottomUp: + { + Result.RowYAt = Bounds.Min.y; + }break; + + case LayoutDirection_TopDown: + { + Result.RowYAt = Bounds.Max.y - Result.RowHeight; + }break; + } + + Result.Id = ++Interface->LayoutIdAcc; + return Result; } static void -ui_StartRow(ui_layout* Layout, u32 ColumnsMax) +ui_PushLayout(ui_interface* Interface, ui_layout Layout) { - Layout->DrawHorizontal = true; - Layout->ColumnsMax = ColumnsMax; - Layout->ColumnWidths = 0; - Layout->ColumnsCount = 0; + Assert(Interface->LayoutStackCount < LAYOUT_COUNT_MAX); + Interface->LayoutStack[Interface->LayoutStackCount++] = Layout; } static void -ui_StartRow(ui_layout* Layout) +ui_PopLayout(ui_interface* Interface) { - ui_StartRow(Layout, 0); + Assert(Interface->LayoutStackCount > 0); + Interface->LayoutStackCount -= 1; } static void -ui_StartRow(ui_layout* Layout, u32 ColumnsMax, r32* ColumnWidths) +ui_StartRow(ui_interface* Interface, u32 ColumnsMax = 0) { - Layout->DrawHorizontal = true; - Layout->ColumnsMax = ColumnsMax; - Layout->ColumnWidths = ColumnWidths; - Layout->ColumnsCount = 0; + u64 LayoutIdx = Interface->LayoutStackCount - 1; + Interface->LayoutStack[LayoutIdx].DrawHorizontal = true; + Interface->LayoutStack[LayoutIdx].ColumnsMax = ColumnsMax; + Interface->LayoutStack[LayoutIdx].ColumnWidths = 0; + Interface->LayoutStack[LayoutIdx].ColumnsCount = 0; } static void -ui_EndRow(ui_layout* Layout) +ui_StartRow(ui_interface* Interface, u32 ColumnsMax, r32* ColumnWidths) { - Layout->DrawHorizontal = false; - Layout->ColumnWidths = 0; - Layout->RowYAt -= Layout->RowHeight; + u64 LayoutIdx = Interface->LayoutStackCount - 1; + Interface->LayoutStack[LayoutIdx].DrawHorizontal = true; + Interface->LayoutStack[LayoutIdx].ColumnsMax = ColumnsMax; + Interface->LayoutStack[LayoutIdx].ColumnWidths = ColumnWidths; + Interface->LayoutStack[LayoutIdx].ColumnsCount = 0; +} + +static void +ui_EndRow(ui_interface* Interface) +{ + u64 LayoutIdx = Interface->LayoutStackCount - 1; + Interface->LayoutStack[LayoutIdx].DrawHorizontal = false; + Interface->LayoutStack[LayoutIdx].ColumnWidths = 0; + Interface->LayoutStack[LayoutIdx].RowYAt -= Interface->LayoutStack[LayoutIdx].RowHeight; } static b32 @@ -270,7 +428,21 @@ ui_TryReserveElementBounds(ui_layout* Layout, rect2* Bounds) { Bounds->Min = { Layout->Bounds.Min.x, Layout->RowYAt }; Bounds->Max = { Layout->Bounds.Max.x, Bounds->Min.y + Layout->RowHeight }; - Layout->RowYAt -= Layout->RowHeight; + + switch (Layout->FillDirection) + { + case LayoutDirection_BottomUp: + { + Layout->RowYAt += Layout->RowHeight; + }break; + + case LayoutDirection_TopDown: + { + Layout->RowYAt -= Layout->RowHeight; + }break; + + InvalidDefaultCase; + } } else { @@ -309,14 +481,6 @@ ui_TryReserveElementBounds(ui_layout* Layout, rect2* Bounds) return Result; } -static rect2 -ui_ReserveTextLineBounds(ui_interface Interface, gs_string Text, ui_layout* Layout) -{ - rect2 Bounds = {0}; - - return Bounds; -} - static rect2 ui_ReserveElementBounds(ui_layout* Layout) { @@ -340,18 +504,81 @@ ui_LayoutRemaining(ui_layout Layout) return Result; } -// -// Interaction -// +// Widgets -internal b32 -ui_MouseClickedRect(ui_interface Interface, rect2 Rect) +internal ui_widget +ui_CreateWidget(gs_string String) { - b32 Result = MouseButtonTransitionedDown(Interface.Mouse.LeftButtonState); - Result &= PointIsInRect(Rect, Interface.Mouse.Pos); + ui_widget Result = {}; + Result.String = String; + Result.Alignment = Align_Left; return Result; } +internal void +ui_WidgetSetFlag(ui_widget* Widget, u64 Flag) +{ + u64 Value = ((u64)1 << Flag); + Widget->Flags = Widget->Flags | Value; +} + +internal bool +ui_WidgetIsFlagSet(ui_widget Widget, u64 Flag) +{ + u64 Value = ((u64)1 << Flag); + bool Result = (Widget.Flags & Value); + return Result; +} + +internal ui_eval_result +ui_EvaluateWidget(ui_interface* Interface, ui_widget* Widget, rect2 Bounds) +{ + ui_eval_result Result = {}; + + Assert(Interface->WidgetsCount < Interface->WidgetsCountMax); + Widget->Id.Index = Interface->WidgetsCount++; + Widget->Id.LayoutId = Interface->LayoutStack[Interface->LayoutStackCount - 1].Id; + + Widget->Bounds = Bounds; + Interface->Widgets[Widget->Id.Index] = *Widget; + + if (ui_WidgetIsFlagSet(*Widget, UIWidgetFlag_Clickable)) + { + if (PointIsInRect(Widget->Bounds, Interface->Mouse.Pos)) + { + if (ui_WidgetIdsEqual(Interface->HotWidget, Widget->Id) && MouseButtonTransitionedDown(Interface->Mouse.LeftButtonState)) + { + Result.Clicked = true; + Interface->ActiveWidget = Widget->Id; + } + + if (ui_WidgetIdsEqual(Interface->ActiveWidget, Widget->Id) && + MouseButtonTransitionedUp(Interface->Mouse.LeftButtonState)) + { + Interface->ActiveWidget = {}; + } + + Interface->HotWidget = Widget->Id; + } + } + + return Result; +} + +internal ui_eval_result +ui_EvaluateWidget(ui_interface* Interface, ui_widget* Widget) +{ + rect2 Bounds = {0}; + ui_layout* Layout = Interface->LayoutStack + Interface->LayoutStackCount - 1; + if (!ui_TryReserveElementBounds(Layout, &Bounds)) + { + // TODO(pjs): This isn't invalid, but Idk when we'd hit this case yet + InvalidCodePath; + } + + return ui_EvaluateWidget(Interface, Widget, Bounds); +} + // // Drawing Functions // @@ -376,78 +603,40 @@ ui_OutlineRect(ui_interface* Interface, rect2 Bounds, r32 Thickness, v4 Color) } internal void -ui_DrawString(ui_interface* Interface, gs_string String, rect2 Bounds, v4 Color, gs_string_alignment Alignment = Align_Left) +ui_DrawString(ui_interface* Interface, gs_string String, rect2 Bounds, gs_string_alignment Alignment = Align_Left) { DEBUG_TRACK_FUNCTION; - render_quad_batch_constructor BatchConstructor = PushRenderTexture2DBatch(Interface->RenderBuffer, - String.Length, - Interface->Style.Font->BitmapMemory, - Interface->Style.Font->BitmapTextureHandle, - Interface->Style.Font->BitmapWidth, - Interface->Style.Font->BitmapHeight, - Interface->Style.Font->BitmapBytesPerPixel, - Interface->Style.Font->BitmapStride); - - v2 RegisterPosition = Bounds.Min + Interface->Style.Margin; - if (Alignment == Align_Left) - { - RegisterPosition = DrawStringLeftAligned(&BatchConstructor, StringExpand(String), RegisterPosition, Interface->Style.Font, Color); - } - else if (Alignment == Align_Right) - { - RegisterPosition = DrawStringRightAligned(&BatchConstructor, StringExpand(String), RegisterPosition, Interface->Style.Font, Color); - } - else - { - InvalidCodePath; - } + ui_widget Widget = ui_CreateWidget(String); + Widget.Bounds = Bounds; + ui_EvaluateWidget(Interface, &Widget); } -static void -ui_LayoutDrawString(ui_interface* Interface, ui_layout* Layout, gs_string String, v4 Color, gs_string_alignment Alignment = Align_Left) +internal void +ui_DrawString(ui_interface* Interface, gs_string String, gs_string_alignment Alignment = Align_Left) { - rect2 Bounds = {0}; - if (!ui_TryReserveElementBounds(Layout, &Bounds)) - { - // TODO(NAME): Not invalid, just haven't implemented yet. - // This is the case where Layout is in row mode without a fixed number of elements - InvalidCodePath; - } - ui_DrawString(Interface, String, Bounds, Color, Alignment); -} - -static void -ui_TextBox(ui_interface* Interface, rect2 Bounds, gs_string Text, v4 BGColor, v4 TextColor) -{ - ui_FillRect(Interface, Bounds, BGColor); - ui_DrawString(Interface, Text, Bounds, TextColor); + DEBUG_TRACK_FUNCTION; + ui_widget Widget = ui_CreateWidget(String); + ui_EvaluateWidget(Interface, &Widget); } static b32 -ui_Button(ui_interface* Interface, gs_string Text, rect2 Bounds, v4 InactiveColor, v4 HoverColor, v4 ClickedColor) +ui_Button(ui_interface* Interface, gs_string Text) { - b32 Pressed = false; - v4 ButtonBG = InactiveColor; - if (PointIsInRect(Bounds, Interface->Mouse.Pos)) - { - ButtonBG = HoverColor; - if (MouseButtonTransitionedDown(Interface->Mouse.LeftButtonState)) - { - ButtonBG = ClickedColor; - Pressed = true; - } - } - ui_TextBox(Interface, Bounds, Text, ButtonBG, Interface->Style.TextColor); - return Pressed; + ui_widget Widget = ui_CreateWidget(Text); + ui_WidgetSetFlag(&Widget, UIWidgetFlag_Clickable); + ui_WidgetSetFlag(&Widget, UIWidgetFlag_DrawBackground); + ui_eval_result Result = ui_EvaluateWidget(Interface, &Widget); + return Result.Clicked; } static b32 ui_Button(ui_interface* Interface, gs_string Text, rect2 Bounds) { - v4 BGColor = Interface->Style.ButtonColor_Inactive; - v4 HoverColor = Interface->Style.ButtonColor_Active; - v4 SelectedColor = Interface->Style.ButtonColor_Selected; - return ui_Button(Interface, Text, Bounds, BGColor, HoverColor, SelectedColor); + ui_widget Widget = ui_CreateWidget(Text); + ui_WidgetSetFlag(&Widget, UIWidgetFlag_Clickable); + ui_WidgetSetFlag(&Widget, UIWidgetFlag_DrawBackground); + ui_eval_result Result = ui_EvaluateWidget(Interface, &Widget, Bounds); + return Result.Clicked; } struct list_item_colors @@ -477,35 +666,19 @@ ui_GetListItemColors(ui_interface* Interface, u32 ListItemIndex) static b32 ui_ListButton(ui_interface* Interface, gs_string Text, rect2 Bounds, u32 ListItemIndex) { - list_item_colors Colors = ui_GetListItemColors(Interface, ListItemIndex); - return ui_Button(Interface, Text, Bounds, Colors.Hover, Colors.Selected, Colors.BGColor); -} - -static b32 -ui_LayoutButton(ui_interface* Interface, ui_layout* Layout, gs_string Text, v4 BGColor, v4 HoverColor, v4 SelectColor) -{ - rect2 ButtonBounds = {0}; - if (!ui_TryReserveElementBounds(Layout, &ButtonBounds)) - { - ButtonBounds = ui_ReserveTextLineBounds(*Interface, Text, Layout); - } - return ui_Button(Interface, Text, ButtonBounds, BGColor, HoverColor, SelectColor); -} - -static b32 -ui_LayoutButton(ui_interface* Interface, ui_layout* Layout, gs_string Text) -{ - v4 BGColor = Interface->Style.ButtonColor_Inactive; - v4 HoverColor = Interface->Style.ButtonColor_Active; - v4 SelectedColor = Interface->Style.ButtonColor_Selected; - return ui_LayoutButton(Interface, Layout, Text, BGColor, HoverColor, SelectedColor); + ui_widget Widget = ui_CreateWidget(Text); + ui_WidgetSetFlag(&Widget, UIWidgetFlag_DrawBackground); + ui_WidgetSetFlag(&Widget, UIWidgetFlag_Clickable); + // TODO(pjs): Reimplement alternating color backgrounds + Widget.Bounds = Bounds; + ui_eval_result Result = ui_EvaluateWidget(Interface, &Widget); + return Result.Clicked; } static b32 ui_LayoutListButton(ui_interface* Interface, ui_layout* Layout, gs_string Text, u32 ListItemIndex) { - list_item_colors Colors = ui_GetListItemColors(Interface, ListItemIndex); - return ui_LayoutButton(Interface, Layout, Text, Colors.Hover, Colors.Selected, Colors.BGColor); + return ui_Button(Interface, Text); } static b32 @@ -520,10 +693,90 @@ ui_LayoutListEntry(ui_interface* Interface, ui_layout* Layout, gs_string Text, u // Punting this till I have a use case InvalidCodePath; } - v4 BGColor = ui_GetListItemBGColor(Interface->Style, Index); - v4 HoverColor = Interface->Style.ListBGHover; - v4 SelectedColor = Interface->Style.ListBGSelected; - return ui_Button(Interface, Text, Bounds, BGColor, HoverColor, SelectedColor); + return ui_Button(Interface, Text, Bounds); +} + +internal bool +ui_EvaluateDropdown(ui_interface* Interface, ui_widget Widget, ui_eval_result EvalResult) +{ + ui_widget_retained_state* State = ui_GetRetainedState(Interface, Widget.Id); + if (!State) { + State = ui_CreateRetainedState(Interface, Widget.Id); + } + + if (EvalResult.Clicked) + { + State->Value = !State->Value; + } + + if (State->Value) + { + ui_layout ParentLayout = Interface->LayoutStack[Interface->LayoutStackCount - 1]; + + r32 SpaceAbove = ParentLayout.Bounds.Max.y - Widget.Bounds.Max.y; + r32 SpaceBelow = Widget.Bounds.Min.y - ParentLayout.Bounds.Min.y; + ui_layout_direction Direction = LayoutDirection_TopDown; + rect2 MenuBounds = {}; + + if (SpaceAbove > SpaceBelow) + { + r32 ParentLayoutMaxY = ParentLayout.Bounds.Max.y; + Direction = LayoutDirection_BottomUp; + MenuBounds = rect2{ + v2{ Widget.Bounds.Min.x, Widget.Bounds.Max.y }, + v2{ Widget.Bounds.Max.x, ParentLayoutMaxY } + }; + } + else + { + r32 ParentLayoutMinY = ParentLayout.Bounds.Min.y; + Direction = LayoutDirection_TopDown; + MenuBounds = rect2{ + v2{ Widget.Bounds.Min.x, ParentLayoutMinY }, + v2{ Widget.Bounds.Max.x, Widget.Bounds.Min.y } + }; + } + + ui_layout Layout = ui_CreateLayout(Interface, MenuBounds, Direction); + Layout.WidgetReference = Widget.Id; + ui_PushLayout(Interface, Layout); + } + + return State->Value; +} + +internal bool +ui_BeginDropdown(ui_interface* Interface, gs_string Text, rect2 Bounds) +{ + ui_widget Widget = ui_CreateWidget(Text); + ui_WidgetSetFlag(&Widget, UIWidgetFlag_Clickable); + ui_WidgetSetFlag(&Widget, UIWidgetFlag_DrawBackground); + ui_eval_result Result = ui_EvaluateWidget(Interface, &Widget, Bounds); + return ui_EvaluateDropdown(Interface, Widget, Result); +} + +internal bool +ui_BeginDropdown(ui_interface* Interface, gs_string Text) +{ + ui_widget Widget = ui_CreateWidget(Text); + ui_WidgetSetFlag(&Widget, UIWidgetFlag_Clickable); + ui_WidgetSetFlag(&Widget, UIWidgetFlag_DrawBackground); + ui_eval_result Result = ui_EvaluateWidget(Interface, &Widget); + return ui_EvaluateDropdown(Interface, Widget, Result); +} + +internal void +ui_EndDropdown(ui_interface* Interface) +{ + ui_layout Layout = Interface->LayoutStack[Interface->LayoutStackCount - 1]; + ui_widget_retained_state* State = ui_GetRetainedState(Interface, Layout.WidgetReference); + if (State) + { + if (State->Value) + { + ui_PopLayout(Interface); + } + } } // From e9945df6ca1e2b31c5b163eafc573f9cb21bb840 Mon Sep 17 00:00:00 2001 From: PS Date: Sat, 7 Nov 2020 23:15:39 -0800 Subject: [PATCH 04/13] Moved camera state into the state for each sculpture view --- src/app/editor/foldhaus_command_dispatch.h | 6 ++-- src/app/editor/foldhaus_editor.cpp | 3 +- src/app/editor/foldhaus_panel.h | 14 ++++++-- .../foldhaus_panel_animation_timeline.h | 2 +- .../panels/foldhaus_panel_sculpture_view.h | 32 +++++++++++++++---- src/app/foldhaus_app.cpp | 13 +------- src/app/foldhaus_app.h | 1 - 7 files changed, 43 insertions(+), 28 deletions(-) diff --git a/src/app/editor/foldhaus_command_dispatch.h b/src/app/editor/foldhaus_command_dispatch.h index e9db217..bad6250 100644 --- a/src/app/editor/foldhaus_command_dispatch.h +++ b/src/app/editor/foldhaus_command_dispatch.h @@ -86,12 +86,12 @@ GetCommandIndexInQueue(input_command_queue* Queue, input_command Command, input_ } internal input_command_queue -InitializeCommandQueue(command_queue_entry* Memory, s32 MemorySize) +CommandQueue_Create(gs_memory_arena* Storage, u64 CommandMaxCount) { input_command_queue Result = {}; - Result.Size = MemorySize; + Result.Size = CommandMaxCount; Result.Used = 0; - Result.Commands = Memory; + Result.Commands = PushArray(Storage, command_queue_entry, CommandMaxCount); return Result; } diff --git a/src/app/editor/foldhaus_editor.cpp b/src/app/editor/foldhaus_editor.cpp index 29ce994..5ad1dfe 100644 --- a/src/app/editor/foldhaus_editor.cpp +++ b/src/app/editor/foldhaus_editor.cpp @@ -21,7 +21,7 @@ Editor_HandleInput (app_state* State, rect2 WindowBounds, input_queue InputQueue } else { - panel* PanelWithMouseOverIt = GetPanelContainingPoint(Mouse.Pos, State->PanelSystem.Panels + 0); + panel* PanelWithMouseOverIt = PanelSystem_GetPanelContainingPoint(&State->PanelSystem, Mouse.Pos); if (!PanelWithMouseOverIt) { return; } State->HotPanel = PanelWithMouseOverIt; @@ -72,7 +72,6 @@ Editor_Update(app_state* State, context* Context, input_queue InputQueue) Context->Mouse.CursorType = CursorType_Arrow; State->WindowBounds = Context->WindowBounds; State->Interface.Mouse = Context->Mouse; - State->Camera.AspectRatio = RectAspectRatio(Context->WindowBounds); PanelSystem_UpdateLayout(&State->PanelSystem, State->WindowBounds); Editor_HandleInput(State, State->WindowBounds, InputQueue, Context->Mouse, *Context); diff --git a/src/app/editor/foldhaus_panel.h b/src/app/editor/foldhaus_panel.h index a715de3..aec8cb9 100644 --- a/src/app/editor/foldhaus_panel.h +++ b/src/app/editor/foldhaus_panel.h @@ -396,7 +396,7 @@ PanelSystem_UpdateLayout(panel_system* System, rect2 WindowBounds) } internal panel* -GetPanelContainingPoint(v2 Point, panel* Panel) +GetPanelContainingPoint(panel* Panel, v2 Point) { panel* Result = 0; @@ -414,11 +414,11 @@ GetPanelContainingPoint(v2 Point, panel* Panel) { if (PointIsInRect(Panel->Left->Bounds, Point)) { - Result = GetPanelContainingPoint(Point, Panel->Left); + Result = GetPanelContainingPoint(Panel->Left, Point); } else if (PointIsInRect(Panel->Right->Bounds, Point)) { - Result = GetPanelContainingPoint(Point, Panel->Right); + Result = GetPanelContainingPoint(Panel->Right, Point); } }break; @@ -429,6 +429,14 @@ GetPanelContainingPoint(v2 Point, panel* Panel) return Result; } +internal panel* +PanelSystem_GetPanelContainingPoint(panel_system* System, v2 Point) +{ + panel* Result = 0; + panel* Root = System->Panels; + Result = GetPanelContainingPoint(Root, Point); + return Result; +} #define FOLDHAUS_PANEL_H #endif // FOLDHAUS_PANEL_H \ No newline at end of file diff --git a/src/app/editor/panels/foldhaus_panel_animation_timeline.h b/src/app/editor/panels/foldhaus_panel_animation_timeline.h index d28fff5..3a9bdf9 100644 --- a/src/app/editor/panels/foldhaus_panel_animation_timeline.h +++ b/src/app/editor/panels/foldhaus_panel_animation_timeline.h @@ -254,7 +254,7 @@ FOLDHAUS_INPUT_COMMAND_PROC(AddAnimationBlockCommand) { animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem); - panel* ActivePanel = GetPanelContainingPoint(Mouse.Pos, State->PanelSystem.Panels + 0); + panel* ActivePanel = PanelSystem_GetPanelContainingPoint(&State->PanelSystem, Mouse.Pos); animation_timeline_state* TimelineState = Panel_GetStateStruct(ActivePanel, animation_timeline_state); frame_range Range = ActiveAnim->PlayableRange; u32 MouseDownFrame = GetFrameFromPointInAnimationPanel(Mouse.Pos, ActivePanel->Bounds, Range); diff --git a/src/app/editor/panels/foldhaus_panel_sculpture_view.h b/src/app/editor/panels/foldhaus_panel_sculpture_view.h index 6bc24a5..4214261 100644 --- a/src/app/editor/panels/foldhaus_panel_sculpture_view.h +++ b/src/app/editor/panels/foldhaus_panel_sculpture_view.h @@ -5,11 +5,17 @@ // #ifndef FOLDHAUS_PANEL_SCULPTURE_VIEW_H +struct sculpture_view_panel_state +{ + camera Camera; +}; + // 3D Mouse View OPERATION_STATE_DEF(mouse_rotate_view_operation_state) { v4 CameraStartPos; + camera* Camera; }; OPERATION_RENDER_PROC(Update3DViewMouseRotate) @@ -22,7 +28,7 @@ OPERATION_RENDER_PROC(Update3DViewMouseRotate) m44 YRotation = M44RotationY(TotalDeltaPos.x * State->PixelsToWorldScale); m44 Combined = XRotation * YRotation; - State->Camera.Position = (Combined * OpState->CameraStartPos).xyz; + OpState->Camera->Position = (Combined * OpState->CameraStartPos).xyz; } FOLDHAUS_INPUT_COMMAND_PROC(End3DViewMouseRotate) @@ -36,11 +42,15 @@ input_command MouseRotateViewCommands [] = { FOLDHAUS_INPUT_COMMAND_PROC(Begin3DViewMouseRotate) { + panel* Panel = PanelSystem_GetPanelContainingPoint(&State->PanelSystem, Context.Mouse.DownPos); + sculpture_view_panel_state* PanelState = Panel_GetStateStruct(Panel, sculpture_view_panel_state); + operation_mode* RotateViewMode = ActivateOperationModeWithCommands(&State->Modes, MouseRotateViewCommands, Update3DViewMouseRotate); mouse_rotate_view_operation_state* OpState = CreateOperationState(RotateViewMode, &State->Modes, mouse_rotate_view_operation_state); - OpState->CameraStartPos = ToV4Point(State->Camera.Position); + OpState->CameraStartPos = ToV4Point(PanelState->Camera.Position); + OpState->Camera = &PanelState->Camera; } // ---------------- @@ -57,7 +67,16 @@ GSMetaTag(panel_type_sculpture_view); internal void SculptureView_Init(panel* Panel, app_state* State, context Context) { + sculpture_view_panel_state* PanelState = PushStruct(&State->Permanent, sculpture_view_panel_state); + PanelState->Camera.FieldOfView = 45.0f; + PanelState->Camera.AspectRatio = RectAspectRatio(State->WindowBounds); + PanelState->Camera.Near = .1f; + PanelState->Camera.Far = 800.0f; + PanelState->Camera.Position = v3{0, 0, 400}; + PanelState->Camera.LookAt = v3{0, 0, 0}; + + Panel->StateMemory = StructToData(PanelState, sculpture_view_panel_state); } GSMetaTag(panel_cleanup); @@ -159,9 +178,10 @@ internal void SculptureView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context) { DEBUG_TRACK_SCOPE(RenderSculpture); - State->Camera.AspectRatio = RectAspectRatio(PanelBounds); + sculpture_view_panel_state* PanelState = Panel_GetStateStruct(Panel, sculpture_view_panel_state); + PanelState->Camera.AspectRatio = RectAspectRatio(PanelBounds); - PushRenderPerspective(RenderBuffer, PanelBounds, State->Camera); + PushRenderPerspective(RenderBuffer, PanelBounds, PanelState->Camera); u32 MaxLEDsPerJob = 2048; render_quad_batch_constructor RenderLEDsBatch = PushRenderQuad3DBatch(RenderBuffer, State->LedSystem.LedsCountTotal); @@ -184,7 +204,7 @@ SculptureView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Ren JobData->Batch = &RenderLEDsBatch; JobData->BatchReservedRange = ReserveRangeInQuadConstructor(JobData->Batch, JobLedCount * 2); JobData->LEDHalfWidth = .5f; - JobData->CameraPosition = ToV4Point(State->Camera.Position); + JobData->CameraPosition = ToV4Point(PanelState->Camera.Position); #if 1 Context.GeneralWorkQueue->PushWorkOnQueue(Context.GeneralWorkQueue, (thread_proc*)DrawLEDsInBufferRangeJob, Data, ConstString("Sculpture Draw LEDS")); #else @@ -204,7 +224,7 @@ SculptureView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Ren led_buffer* LedBuffer = LedSystemGetBuffer(&State->LedSystem, Assembly.LedBufferIndex); v4 LedPosition = LedBuffer->Positions[FocusPixel]; - v2 LedOnScreenPosition = SculptureView_WorldToScreenPosition(LedPosition, State->Camera, PanelBounds); + v2 LedOnScreenPosition = SculptureView_WorldToScreenPosition(LedPosition, PanelState->Camera, PanelBounds); gs_string Tempgs_string = PushString(State->Transient, 256); PrintF(&Tempgs_string, "%f %f", LedOnScreenPosition.x, LedOnScreenPosition.y); diff --git a/src/app/foldhaus_app.cpp b/src/app/foldhaus_app.cpp index 2f6acaf..f3038f6 100644 --- a/src/app/foldhaus_app.cpp +++ b/src/app/foldhaus_app.cpp @@ -32,11 +32,7 @@ INITIALIZE_APPLICATION(InitializeApplication) State->GlobalLog = PushStruct(State->Transient, event_log); *State->GlobalLog = {0}; - s32 CommandQueueSize = 32; - command_queue_entry* CommandQueueMemory = PushArray(&State->Permanent, - command_queue_entry, - CommandQueueSize); - State->CommandQueue = InitializeCommandQueue(CommandQueueMemory, CommandQueueSize); + State->CommandQueue = CommandQueue_Create(&State->Permanent, 32); // TODO(Peter): put in InitializeInterface? r32 FontSize = 14; @@ -117,13 +113,6 @@ INITIALIZE_APPLICATION(InitializeApplication) State->SACN = SACN_Initialize(Context); - State->Camera.FieldOfView = 45.0f; - State->Camera.AspectRatio = RectAspectRatio(State->WindowBounds); - State->Camera.Near = .1f; - State->Camera.Far = 800.0f; - State->Camera.Position = v3{0, 0, 400}; - State->Camera.LookAt = v3{0, 0, 0}; - State->LedSystem = LedSystemInitialize(Context.ThreadContext.Allocator, 128); #if 1 diff --git a/src/app/foldhaus_app.h b/src/app/foldhaus_app.h index 60937fc..44b0605 100644 --- a/src/app/foldhaus_app.h +++ b/src/app/foldhaus_app.h @@ -62,7 +62,6 @@ struct app_state panel_system PanelSystem; panel* HotPanel; - camera Camera; // TODO(Peter): move into the sculpture view r32 PixelsToWorldScale; handle SelectedAnimationBlockHandle; // TODO(Peter): move into animation panel u32 SelectedAnimationLayer; // TODO(Peter): move into animation panel From 6193af25552890fa8f3971329fd3c3278b7740a1 Mon Sep 17 00:00:00 2001 From: PS Date: Sat, 7 Nov 2020 23:21:37 -0800 Subject: [PATCH 05/13] Pulled animation timeline state out of the app struct --- .../foldhaus_panel_animation_timeline.h | 24 +++++++++++-------- src/app/foldhaus_app.h | 2 -- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/app/editor/panels/foldhaus_panel_animation_timeline.h b/src/app/editor/panels/foldhaus_panel_animation_timeline.h index 3a9bdf9..38ea145 100644 --- a/src/app/editor/panels/foldhaus_panel_animation_timeline.h +++ b/src/app/editor/panels/foldhaus_panel_animation_timeline.h @@ -45,13 +45,16 @@ AddAnimationBlockAtCurrentTime (u32 AnimationProcHandle, u32 LayerHandle, animat FOLDHAUS_INPUT_COMMAND_PROC(DeleteAnimationBlockCommand) { - handle SelectedAnimHandle = State->SelectedAnimationBlockHandle; + panel* Panel = PanelSystem_GetPanelContainingPoint(&State->PanelSystem, Context.Mouse.Pos); + animation_timeline_state* PanelState = Panel_GetStateStruct(Panel, animation_timeline_state); + + handle SelectedBlockHandle = PanelState->SelectedBlockHandle; animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem); - if(SelectedAnimHandle.Index < ActiveAnim->Blocks_.Count && - ActiveAnim->Blocks_.Generations[SelectedAnimHandle.Index] == SelectedAnimHandle.Generation) + if(SelectedBlockHandle.Index < ActiveAnim->Blocks_.Count && + ActiveAnim->Blocks_.Generations[SelectedBlockHandle.Index] == SelectedBlockHandle.Generation) { - Animation_RemoveBlock(ActiveAnim, State->SelectedAnimationBlockHandle); - State->SelectedAnimationBlockHandle = {0}; + Animation_RemoveBlock(ActiveAnim, PanelState->SelectedBlockHandle); + PanelState->SelectedBlockHandle = {0}; // TODO(pjs): Introduce an animation_block_selection in this file // it should have a handle to the animation, block, and a HasSelection flag // as it is now, you kind of always have the first block selected @@ -252,14 +255,15 @@ SelectAndBeginDragAnimationBlock(animation_timeline_state* TimelineState, handle FOLDHAUS_INPUT_COMMAND_PROC(AddAnimationBlockCommand) { + panel* Panel = PanelSystem_GetPanelContainingPoint(&State->PanelSystem, Context.Mouse.Pos); + animation_timeline_state* TimelineState = Panel_GetStateStruct(Panel, animation_timeline_state); + animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem); - panel* ActivePanel = PanelSystem_GetPanelContainingPoint(&State->PanelSystem, Mouse.Pos); - animation_timeline_state* TimelineState = Panel_GetStateStruct(ActivePanel, animation_timeline_state); frame_range Range = ActiveAnim->PlayableRange; - u32 MouseDownFrame = GetFrameFromPointInAnimationPanel(Mouse.Pos, ActivePanel->Bounds, Range); + u32 MouseDownFrame = GetFrameFromPointInAnimationPanel(Mouse.Pos, Panel->Bounds, Range); - handle NewBlockHandle = Animation_AddBlock(ActiveAnim, MouseDownFrame, MouseDownFrame + SecondsToFrames(3, State->AnimationSystem), 4, State->SelectedAnimationLayer); + handle NewBlockHandle = Animation_AddBlock(ActiveAnim, MouseDownFrame, MouseDownFrame + SecondsToFrames(3, State->AnimationSystem), 4, TimelineState->SelectedAnimationLayer); TimelineState->SelectedBlockHandle = NewBlockHandle; } @@ -500,7 +504,7 @@ DrawAnimationTimeline (animation_system* AnimationSystem, animation_timeline_sta RectHSplitAtDistanceFromTop(TimelineBounds, 32, &TimelineFrameBarBounds, &TimelineBounds); RectHSplitAtDistanceFromBottom(TimelineBounds, 24, &TimelineBlockDisplayBounds, &TimelineRangeBarBounds); - DrawLayerMenu(AnimationSystem, CurrAnimation, *Interface, LayerMenuBounds, &State->SelectedAnimationLayer); + DrawLayerMenu(AnimationSystem, CurrAnimation, *Interface, LayerMenuBounds, &TimelineState->SelectedAnimationLayer); frame_range AdjustedViewRange = DrawTimelineRangeBar(AnimationSystem, CurrAnimation, TimelineState, *Interface, TimelineRangeBarBounds); diff --git a/src/app/foldhaus_app.h b/src/app/foldhaus_app.h index 44b0605..3e6bf1f 100644 --- a/src/app/foldhaus_app.h +++ b/src/app/foldhaus_app.h @@ -63,8 +63,6 @@ struct app_state panel* HotPanel; r32 PixelsToWorldScale; - handle SelectedAnimationBlockHandle; // TODO(Peter): move into animation panel - u32 SelectedAnimationLayer; // TODO(Peter): move into animation panel }; internal void OpenColorPicker(app_state* State, v4* Address); From f53becef5bf50f211aea939430c2276cff707fc8 Mon Sep 17 00:00:00 2001 From: PS Date: Sat, 7 Nov 2020 23:43:41 -0800 Subject: [PATCH 06/13] Hot panel is passed to input event handlers --- src/app/editor/foldhaus_command_dispatch.h | 2 +- src/app/editor/foldhaus_editor.cpp | 32 +++++++++++-------- src/app/editor/foldhaus_interface.cpp | 2 -- .../foldhaus_panel_animation_timeline.h | 6 ++-- .../panels/foldhaus_panel_sculpture_view.h | 1 - src/app/foldhaus_app.h | 5 ++- 6 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/app/editor/foldhaus_command_dispatch.h b/src/app/editor/foldhaus_command_dispatch.h index bad6250..6c6cf1c 100644 --- a/src/app/editor/foldhaus_command_dispatch.h +++ b/src/app/editor/foldhaus_command_dispatch.h @@ -5,7 +5,7 @@ // #ifndef FOLDHAUS_COMMAND_DISPATCH_H -#define FOLDHAUS_INPUT_COMMAND_PROC(name) void name(app_state* State, input_entry Event, mouse_state Mouse, context Context) +#define FOLDHAUS_INPUT_COMMAND_PROC(name) void name(app_state* State, input_entry Event, mouse_state Mouse, context Context, panel* Panel) typedef FOLDHAUS_INPUT_COMMAND_PROC(input_command_proc); // NOTE(Peter): Helper function so I don't have to remember the parameters to this define diff --git a/src/app/editor/foldhaus_editor.cpp b/src/app/editor/foldhaus_editor.cpp index 5ad1dfe..ed01de2 100644 --- a/src/app/editor/foldhaus_editor.cpp +++ b/src/app/editor/foldhaus_editor.cpp @@ -10,10 +10,13 @@ Editor_HandleInput (app_state* State, rect2 WindowBounds, input_queue InputQueue { DEBUG_TRACK_FUNCTION; + panel* ActivePanel = PanelSystem_GetPanelContainingPoint(&State->PanelSystem, Mouse.Pos); b32 PanelSystemHandledInput = HandleMousePanelInteraction(&State->PanelSystem, State->WindowBounds, Mouse, State); - if (!PanelSystemHandledInput) + if (!PanelSystemHandledInput && ActivePanel) { + panel_definition ActiveDef = State->PanelSystem.PanelDefs[ActivePanel->TypeIndex]; + input_command_registry ActiveCommands = {}; if (State->Modes.ActiveModesCount > 0) { @@ -21,19 +24,15 @@ Editor_HandleInput (app_state* State, rect2 WindowBounds, input_queue InputQueue } else { - panel* PanelWithMouseOverIt = PanelSystem_GetPanelContainingPoint(&State->PanelSystem, Mouse.Pos); - if (!PanelWithMouseOverIt) { return; } - State->HotPanel = PanelWithMouseOverIt; - - s32 PanelTypeIndex = PanelWithMouseOverIt->TypeIndex; - panel_definition PanelDefinition = State->PanelSystem.PanelDefs[PanelTypeIndex]; - if (!PanelDefinition.InputCommands) { return; } - - ActiveCommands.Commands = PanelDefinition.InputCommands; - ActiveCommands.Size = sizeof(*PanelDefinition.InputCommands) / sizeof(PanelDefinition.InputCommands[0]); - ActiveCommands.Used = ActiveCommands.Size; + if (ActiveDef.InputCommands) + { + ActiveCommands.Commands = ActiveDef.InputCommands; + ActiveCommands.Size = sizeof(*ActiveDef.InputCommands) / sizeof(ActiveDef.InputCommands[0]); + ActiveCommands.Used = ActiveCommands.Size; + } } + // Fill up the command queue for (s32 EventIdx = 0; EventIdx < InputQueue.QueueUsed; EventIdx++) { input_entry Event = InputQueue.Entries[EventIdx]; @@ -60,7 +59,14 @@ Editor_HandleInput (app_state* State, rect2 WindowBounds, input_queue InputQueue for (s32 CommandIdx = State->CommandQueue.Used - 1; CommandIdx >= 0; CommandIdx--) { command_queue_entry* Entry = &State->CommandQueue.Commands[CommandIdx]; - Entry->Command.Proc(State, Entry->Event, Mouse, Context); + if (Entry->Command.Proc) + { + Entry->Command.Proc(State, Entry->Event, Mouse, Context, ActivePanel); + } + else + { + EndCurrentOperationMode(State); + } } ClearCommandQueue(&State->CommandQueue); diff --git a/src/app/editor/foldhaus_interface.cpp b/src/app/editor/foldhaus_interface.cpp index 0a33f8f..7a83912 100644 --- a/src/app/editor/foldhaus_interface.cpp +++ b/src/app/editor/foldhaus_interface.cpp @@ -94,7 +94,6 @@ OPERATION_RENDER_PROC(UpdateAndRenderDragPanelBorder) FOLDHAUS_INPUT_COMMAND_PROC(EndDragPanelBorderOperation) { drag_panel_border_operation_state* OpState = GetCurrentOperationState(State->Modes, drag_panel_border_operation_state); - panel* Panel = OpState->Panel; rect2 PanelBounds = OpState->InitialPanelBounds; if (OpState->PanelEditMode == PanelEdit_Modify) @@ -224,7 +223,6 @@ OPERATION_RENDER_PROC(UpdateAndRenderSplitPanel) FOLDHAUS_INPUT_COMMAND_PROC(EndSplitPanelOperation) { split_panel_operation_state* OpState = GetCurrentOperationState(State->Modes, split_panel_operation_state); - panel* Panel = OpState->Panel; rect2 PanelBounds = OpState->InitialPanelBounds; r32 XDistance = Abs(Mouse.Pos.x - Mouse.DownPos.x); diff --git a/src/app/editor/panels/foldhaus_panel_animation_timeline.h b/src/app/editor/panels/foldhaus_panel_animation_timeline.h index 38ea145..6210cfa 100644 --- a/src/app/editor/panels/foldhaus_panel_animation_timeline.h +++ b/src/app/editor/panels/foldhaus_panel_animation_timeline.h @@ -45,7 +45,6 @@ AddAnimationBlockAtCurrentTime (u32 AnimationProcHandle, u32 LayerHandle, animat FOLDHAUS_INPUT_COMMAND_PROC(DeleteAnimationBlockCommand) { - panel* Panel = PanelSystem_GetPanelContainingPoint(&State->PanelSystem, Context.Mouse.Pos); animation_timeline_state* PanelState = Panel_GetStateStruct(Panel, animation_timeline_state); handle SelectedBlockHandle = PanelState->SelectedBlockHandle; @@ -153,7 +152,7 @@ OPERATION_RENDER_PROC(UpdateDragAnimationClip) animation_block* AnimationBlock = Animation_GetBlockFromHandle(ActiveAnim, OpState->BlockHandle); if (!AnimationBlock) { - EndCurrentOperationMode(State, {}, Mouse, Context); + EndCurrentOperationMode(State); return; } @@ -230,7 +229,7 @@ OPERATION_RENDER_PROC(UpdateDragAnimationClip) } input_command DragAnimationClipCommands [] = { - { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, EndCurrentOperationMode }, + { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, 0 }, }; internal void @@ -255,7 +254,6 @@ SelectAndBeginDragAnimationBlock(animation_timeline_state* TimelineState, handle FOLDHAUS_INPUT_COMMAND_PROC(AddAnimationBlockCommand) { - panel* Panel = PanelSystem_GetPanelContainingPoint(&State->PanelSystem, Context.Mouse.Pos); animation_timeline_state* TimelineState = Panel_GetStateStruct(Panel, animation_timeline_state); animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem); diff --git a/src/app/editor/panels/foldhaus_panel_sculpture_view.h b/src/app/editor/panels/foldhaus_panel_sculpture_view.h index 4214261..ee4fecb 100644 --- a/src/app/editor/panels/foldhaus_panel_sculpture_view.h +++ b/src/app/editor/panels/foldhaus_panel_sculpture_view.h @@ -42,7 +42,6 @@ input_command MouseRotateViewCommands [] = { FOLDHAUS_INPUT_COMMAND_PROC(Begin3DViewMouseRotate) { - panel* Panel = PanelSystem_GetPanelContainingPoint(&State->PanelSystem, Context.Mouse.DownPos); sculpture_view_panel_state* PanelState = Panel_GetStateStruct(Panel, sculpture_view_panel_state); operation_mode* RotateViewMode = ActivateOperationModeWithCommands(&State->Modes, MouseRotateViewCommands, Update3DViewMouseRotate); diff --git a/src/app/foldhaus_app.h b/src/app/foldhaus_app.h index 3e6bf1f..66755c6 100644 --- a/src/app/foldhaus_app.h +++ b/src/app/foldhaus_app.h @@ -26,6 +26,8 @@ typedef struct app_state app_state; +typedef struct panel panel; + #include "editor/foldhaus_command_dispatch.h" #include "editor/foldhaus_operation_mode.h" @@ -201,7 +203,8 @@ TestPatternThree(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* // END TEMPORARY PATTERNS -FOLDHAUS_INPUT_COMMAND_PROC(EndCurrentOperationMode) +internal void +EndCurrentOperationMode(app_state* State) { DeactivateCurrentOperationMode(&State->Modes); } From a42d2e81c5a73beed4efb9191c93299d9b3ad41a Mon Sep 17 00:00:00 2001 From: PS Date: Sat, 7 Nov 2020 23:50:41 -0800 Subject: [PATCH 07/13] Cleaned up panel event handling --- src/app/editor/foldhaus_editor.cpp | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/app/editor/foldhaus_editor.cpp b/src/app/editor/foldhaus_editor.cpp index ed01de2..5d08c1f 100644 --- a/src/app/editor/foldhaus_editor.cpp +++ b/src/app/editor/foldhaus_editor.cpp @@ -10,10 +10,10 @@ Editor_HandleInput (app_state* State, rect2 WindowBounds, input_queue InputQueue { DEBUG_TRACK_FUNCTION; - panel* ActivePanel = PanelSystem_GetPanelContainingPoint(&State->PanelSystem, Mouse.Pos); - b32 PanelSystemHandledInput = HandleMousePanelInteraction(&State->PanelSystem, State->WindowBounds, Mouse, State); + b32 MouseInputHandled = HandleMousePanelInteraction(&State->PanelSystem, State->WindowBounds, Mouse, State); - if (!PanelSystemHandledInput && ActivePanel) + panel* ActivePanel = PanelSystem_GetPanelContainingPoint(&State->PanelSystem, Mouse.Pos); + if (ActivePanel) { panel_definition ActiveDef = State->PanelSystem.PanelDefs[ActivePanel->TypeIndex]; @@ -22,14 +22,11 @@ Editor_HandleInput (app_state* State, rect2 WindowBounds, input_queue InputQueue { ActiveCommands = State->Modes.ActiveModes[State->Modes.ActiveModesCount - 1].Commands; } - else + else if (ActiveDef.InputCommands) { - if (ActiveDef.InputCommands) - { - ActiveCommands.Commands = ActiveDef.InputCommands; - ActiveCommands.Size = sizeof(*ActiveDef.InputCommands) / sizeof(ActiveDef.InputCommands[0]); - ActiveCommands.Used = ActiveCommands.Size; - } + ActiveCommands.Commands = ActiveDef.InputCommands; + ActiveCommands.Size = sizeof(*ActiveDef.InputCommands) / sizeof(ActiveDef.InputCommands[0]); + ActiveCommands.Used = ActiveCommands.Size; } // Fill up the command queue @@ -37,6 +34,14 @@ Editor_HandleInput (app_state* State, rect2 WindowBounds, input_queue InputQueue { input_entry Event = InputQueue.Entries[EventIdx]; + bool IsMouseEvent = (Event.Key == KeyCode_MouseLeftButton || + Event.Key == KeyCode_MouseMiddleButton || + Event.Key == KeyCode_MouseRightButton); + if (IsMouseEvent && MouseInputHandled) + { + continue; + } + // NOTE(Peter): These are in the order Down, Up, Held because we want to privalege // Down and Up over Held. In other words, we don't want to call a Held command on the // frame when the button was released, even if the command is registered to both events From 82ed9d84acc2e959c1b0b94b955b02fc4beb96b3 Mon Sep 17 00:00:00 2001 From: PS Date: Sun, 8 Nov 2020 21:05:14 -0800 Subject: [PATCH 08/13] Got to connect to Ryan's code --- src/app/platform_win32/win32_foldhaus.cpp | 34 ++++ .../platform_win32/win32_foldhaus_socket.h | 168 +++++++++++++++--- 2 files changed, 176 insertions(+), 26 deletions(-) diff --git a/src/app/platform_win32/win32_foldhaus.cpp b/src/app/platform_win32/win32_foldhaus.cpp index 653dbe6..7f9b24a 100644 --- a/src/app/platform_win32/win32_foldhaus.cpp +++ b/src/app/platform_win32/win32_foldhaus.cpp @@ -423,6 +423,26 @@ Win32_SendAddressedDataBuffers_Job(gs_thread_context Context, gs_data Arg) Win32_SendAddressedDataBuffers(Context, *OutputData); } +#pragma pack(push, 1) +struct test_microphone_packet +{ + b8 ChangeAnimation; + char AnimationFileName[32]; + b8 SetLayer; + char LayerName[32]; + r32 LayerOpacity; + b8 SetLayerParamColor; + char LayerParamColor[7]; + r32 OverrideDuration; +}; +#pragma pack(pop) + +inline u32 +UpackB4(const u8* ptr) +{ + return (u32)(ptr[3] | (ptr[2] << 8) | (ptr[1] << 16) | (ptr[0] << 24)); +} + int WINAPI WinMain ( HINSTANCE HInstance, @@ -562,6 +582,20 @@ WinMain ( WSAStartup(MAKEWORD(2, 2), &WSAData); Win32Sockets = Win32SocketArray_Create(16, &PlatformPermanent); + + win32_socket TestSocket = Win32Socket_ConnectToAddress("127.0.0.1", "20185"); + test_microphone_packet* Recv = 0; + while (true) + { + gs_data Data = Win32Socket_Receive(&TestSocket, ThreadContext.Transient); + if (Data.Size > 0) + { + OutputDebugStringA("Received\n"); + Recv = (test_microphone_packet*)Data.Memory; + } + ClearArena(ThreadContext.Transient); + } + Win32SerialArray_Create(ThreadContext); s32 RenderMemorySize = MB(12); diff --git a/src/app/platform_win32/win32_foldhaus_socket.h b/src/app/platform_win32/win32_foldhaus_socket.h index 18df318..a95b806 100644 --- a/src/app/platform_win32/win32_foldhaus_socket.h +++ b/src/app/platform_win32/win32_foldhaus_socket.h @@ -54,6 +54,82 @@ Win32SocketArray_Get(win32_socket_array Array, s32 Index) global win32_socket_array Win32Sockets; +internal win32_socket +Win32Socket_Create(s32 AddressFamily, s32 Type, s32 Protocol) +{ + win32_socket Result = {0}; + Result.Socket = socket(AddressFamily, Type, Protocol); + if (Result.Socket == INVALID_SOCKET) + { + s32 Error = WSAGetLastError(); + InvalidCodePath; + } + return Result; +} + +internal void +Win32Socket_Bind(win32_socket* Socket, s32 AddressFamily, char* Address, s32 Port) +{ + sockaddr_in Service = {0}; + Service.sin_family = AddressFamily; + Service.sin_addr.s_addr = inet_addr(Address); + Service.sin_port = htons(Port); + + s32 Result = bind(Socket->Socket, (SOCKADDR*)&Service, sizeof(Service)); + if (Result == SOCKET_ERROR) + { + s32 Error = WSAGetLastError(); + InvalidCodePath; + } +} + +internal win32_socket +Win32Socket_ConnectToAddress(char* Address, char* DefaultPort) +{ + win32_socket Result = {}; + + addrinfo Hints = {0}; + Hints.ai_family = AF_UNSPEC; + Hints.ai_socktype = SOCK_STREAM; + Hints.ai_protocol = IPPROTO_TCP; + + addrinfo* PotentialConnections; + s32 Error = getaddrinfo(Address, DefaultPort, &Hints, &PotentialConnections); + if (Error == 0) + { + for (addrinfo* InfoAt = PotentialConnections; InfoAt != NULL; InfoAt = InfoAt->ai_next) + { + win32_socket Socket = Win32Socket_Create(InfoAt->ai_family, InfoAt->ai_socktype, InfoAt->ai_protocol); + if (Socket.Socket == INVALID_SOCKET) + { + Error = WSAGetLastError(); + InvalidCodePath; + } + + Error = connect(Socket.Socket, InfoAt->ai_addr, (int)InfoAt->ai_addrlen); + if (Error == SOCKET_ERROR) + { + closesocket(Socket.Socket); + continue; + } + else + { + Result = Socket; + break; + } + } + } + else + { + Error = WSAGetLastError(); + InvalidCodePath; + } + + freeaddrinfo(PotentialConnections); + + return Result; +} + internal s32 Win32Socket_SetOption(win32_socket* Socket, s32 Level, s32 Option, const char* OptionValue, s32 OptionLength) { @@ -74,32 +150,6 @@ Win32Socket_SetOption(platform_socket_handle SocketHandle, s32 Level, s32 Option return Win32Socket_SetOption(Socket, Level, Option, OptionValue, OptionLength); } -PLATFORM_GET_SOCKET_HANDLE(Win32GetSocketHandle) -{ - // NOTE(Peter): These used to be passed in as paramters, but we only use this function - // with AF_INET, SOCK_DGRAM, and Protocol = 0. These are also platform specific values - // so I was having to include windows.h in the platform agnostic code to accomodate that - // function signature. - s32 AddressFamily = AF_INET; - s32 Type = SOCK_DGRAM; - s32 Protocol = 0; - - s32 Result = Win32SocketArray_Take(&Win32Sockets); - win32_socket* Socket = Win32SocketArray_Get(Win32Sockets, Result); - Socket->Socket = socket(AddressFamily, Type, Protocol); - if (Socket->Socket != INVALID_SOCKET) - { - int Error = Win32Socket_SetOption(Socket, IPPROTO_IP, IP_MULTICAST_TTL, - (const char*)(&Multicast_TimeToLive), sizeof(Multicast_TimeToLive)); - } - else - { - s32 Error = WSAGetLastError(); - InvalidCodePath; - } - - return (platform_socket_handle)Result; -} internal s32 Win32Socket_SendTo(platform_socket_handle SocketHandle, u32 Address, u32 Port, const char* Buffer, s32 BufferLength, s32 Flags) @@ -129,6 +179,61 @@ Win32Socket_SendTo(platform_socket_handle SocketHandle, u32 Address, u32 Port, c return LengthSent; } +internal void +Win32Socket_SetListening(win32_socket* Socket) +{ + if (listen(Socket->Socket, SOMAXCONN) == SOCKET_ERROR) + { + // TODO(pjs): Error logging + s32 Error = WSAGetLastError(); + InvalidCodePath; + } +} + +internal s32 +Win32Socket_PeekGetTotalSize(win32_socket* Socket) +{ + s32 Flags = MSG_PEEK; + char Temp[4]; + s32 BytesQueued = recv(Socket->Socket, Temp, 4, Flags); + if (BytesQueued == SOCKET_ERROR) + { + // TODO(pjs): Error logging + s32 Error = WSAGetLastError(); + BytesQueued = 0; + } + return BytesQueued; +} + +internal gs_data +Win32Socket_Receive(win32_socket* Socket, gs_memory_arena* Storage) +{ +#if 0 + gs_data Result = {}; + s32 BytesQueued = Win32Socket_PeekGetTotalSize(Socket); + if (BytesQueued > 0) + { + Result = PushSizeToData(Storage, BytesQueued); + s32 Flags = 0; + s32 BytesReceived = recv(Socket->Socket, (char*)Result.Memory, Result.Size, Flags); + Assert(BytesReceived == BytesQueued); + } + return Result; +#else + gs_data Result = PushSizeToData(Storage, 1024); + s32 Flags = 0; + s32 BytesReceived = recv(Socket->Socket, (char*)Result.Memory, Result.Size, Flags); + if (BytesReceived == SOCKET_ERROR) + { + // TODO(pjs): Error logging + s32 Error = WSAGetLastError(); + InvalidCodePath; + } + Result.Size = BytesReceived; + return Result; +#endif +} + internal void Win32Socket_Close(win32_socket* Socket) { @@ -136,5 +241,16 @@ Win32Socket_Close(win32_socket* Socket) Socket->Socket = INVALID_SOCKET; } +PLATFORM_GET_SOCKET_HANDLE(Win32GetSocketHandle) +{ + s32 Result = Win32SocketArray_Take(&Win32Sockets); + s32 Error = 0; + win32_socket* Socket = Win32SocketArray_Get(Win32Sockets, Result); + *Socket = Win32Socket_Create(AF_INET, SOCK_DGRAM, 0); + Error = Win32Socket_SetOption(Socket, IPPROTO_IP, IP_MULTICAST_TTL, + (const char*)(&Multicast_TimeToLive), sizeof(Multicast_TimeToLive)); + return (platform_socket_handle)Result; +} + #define WIN32_FOLDHAUS_SOCKET_H #endif // WIN32_FOLDHAUS_SOCKET_H \ No newline at end of file From a52d8645e693030a4180f2ce42b8a991cdb48dc8 Mon Sep 17 00:00:00 2001 From: PS Date: Sat, 14 Nov 2020 11:43:20 -0800 Subject: [PATCH 09/13] refactored clips -> patterns --- .../foldhaus_panel_animation_timeline.h | 28 +++++++++---------- src/app/engine/animation/foldhaus_animation.h | 2 +- .../foldhaus_animation_serializer.cpp | 6 ++-- src/app/foldhaus_app.cpp | 2 +- src/app/foldhaus_app.h | 4 +-- src/app/platform_win32/win32_foldhaus.cpp | 2 -- 6 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/app/editor/panels/foldhaus_panel_animation_timeline.h b/src/app/editor/panels/foldhaus_panel_animation_timeline.h index 6210cfa..9bedf30 100644 --- a/src/app/editor/panels/foldhaus_panel_animation_timeline.h +++ b/src/app/editor/panels/foldhaus_panel_animation_timeline.h @@ -109,7 +109,7 @@ StartDragTimeMarker(rect2 TimelineBounds, frame_range VisibleFrames, app_state* #define CLICK_ANIMATION_BLOCK_EDGE_MAX_SCREEN_DISTANCE 10 -OPERATION_STATE_DEF(drag_animation_clip_state) +OPERATION_STATE_DEF(drag_animation_block_state) { rect2 TimelineBounds; handle BlockHandle; @@ -129,9 +129,9 @@ AttemptToSnapPosition(u32 SnappingFrame, u32 SnapToFrame) return Result; } -OPERATION_RENDER_PROC(UpdateDragAnimationClip) +OPERATION_RENDER_PROC(UpdateDragAnimationBlock) { - drag_animation_clip_state* OpState = (drag_animation_clip_state*)Operation.OpStateMemory; + drag_animation_block_state* OpState = (drag_animation_block_state*)Operation.OpStateMemory; animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem); @@ -228,7 +228,7 @@ OPERATION_RENDER_PROC(UpdateDragAnimationClip) AnimationBlock->Range.Max = (u32)Clamp(PlayableStartFrame, (s32)AnimationBlock->Range.Max, PlayableEndFrame); } -input_command DragAnimationClipCommands [] = { +input_command DragAnimationBlockCommands [] = { { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, 0 }, }; @@ -238,11 +238,11 @@ SelectAndBeginDragAnimationBlock(animation_timeline_state* TimelineState, handle TimelineState->SelectedBlockHandle = BlockHandle; animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem); - operation_mode* DragAnimationClipMode = ActivateOperationModeWithCommands(&State->Modes, DragAnimationClipCommands, UpdateDragAnimationClip); + operation_mode* DragAnimationBlockMode = ActivateOperationModeWithCommands(&State->Modes, DragAnimationBlockCommands, UpdateDragAnimationBlock); - drag_animation_clip_state* OpState = CreateOperationState(DragAnimationClipMode, - &State->Modes, - drag_animation_clip_state); + drag_animation_block_state* OpState = CreateOperationState(DragAnimationBlockMode, + &State->Modes, + drag_animation_block_state); OpState->TimelineBounds = TimelineBounds; OpState->BlockHandle = BlockHandle; OpState->VisibleRange = VisibleRange; @@ -580,7 +580,7 @@ PANEL_MODAL_OVERRIDE_CALLBACK(LoadAnimationFileCallback) { gs_file AnimFile = ReadEntireFile(Context.ThreadContext.FileHandler, FileInfo.Path); gs_string AnimFileString = MakeString((char*)AnimFile.Data.Memory, AnimFile.Data.Size); - animation NewAnim = AnimParser_Parse(AnimFileString, State->AnimationSystem.Storage, GlobalAnimationClipsCount, GlobalAnimationClips); + animation NewAnim = AnimParser_Parse(AnimFileString, State->AnimationSystem.Storage, GlobalAnimationPatternsCount, GlobalAnimationPatterns); u32 NewAnimIndex = AnimationArray_Push(&State->AnimationSystem.Animations, NewAnim); State->AnimationSystem.ActiveAnimationIndex = NewAnimIndex; @@ -588,15 +588,15 @@ PANEL_MODAL_OVERRIDE_CALLBACK(LoadAnimationFileCallback) } internal void -DrawAnimationClipsList(rect2 PanelBounds, ui_interface* Interface, u32 SelectedAnimationLayerHandle, animation_system* AnimationSystem) +DrawAnimationPatternList(rect2 PanelBounds, ui_interface* Interface, u32 SelectedAnimationLayerHandle, animation_system* AnimationSystem) { ui_layout Layout = ui_CreateLayout(Interface, PanelBounds); ui_PushLayout(Interface, Layout); - for (s32 i = 0; i < GlobalAnimationClipsCount; i++) + for (s32 i = 0; i < GlobalAnimationPatternsCount; i++) { - animation_clip Clip = GlobalAnimationClips[i]; - gs_string ClipName = MakeString(Clip.Name, Clip.NameLength); - if (ui_LayoutListEntry(Interface, &Layout, ClipName, i)) + animation_pattern Pattern = GlobalAnimationPatterns[i]; + gs_string PatternName = MakeString(Pattern.Name, Pattern.NameLength); + if (ui_LayoutListEntry(Interface, &Layout, PatternName, i)) { AddAnimationBlockAtCurrentTime(i + 1, SelectedAnimationLayerHandle, AnimationSystem); } diff --git a/src/app/engine/animation/foldhaus_animation.h b/src/app/engine/animation/foldhaus_animation.h index 81e2080..bbdb1a5 100644 --- a/src/app/engine/animation/foldhaus_animation.h +++ b/src/app/engine/animation/foldhaus_animation.h @@ -103,7 +103,7 @@ struct animation_system }; // TODO(pjs): Better name - something like animation_prototype -struct animation_clip +struct animation_pattern { char* Name; s32 NameLength; diff --git a/src/app/engine/animation/foldhaus_animation_serializer.cpp b/src/app/engine/animation/foldhaus_animation_serializer.cpp index ac9954e..8607b0f 100644 --- a/src/app/engine/animation/foldhaus_animation_serializer.cpp +++ b/src/app/engine/animation/foldhaus_animation_serializer.cpp @@ -6,7 +6,7 @@ #ifndef FOLDHAUS_ANIMATION_SERIALIZER_CPP internal gs_string -AnimSerializer_Serialize(animation Anim, animation_clip* GlobalClips, gs_memory_arena* Arena) +AnimSerializer_Serialize(animation Anim, animation_pattern* GlobalClips, gs_memory_arena* Arena) { serializer Serializer = {0}; Serializer.String = PushString(Arena, 4096); @@ -48,7 +48,7 @@ AnimSerializer_Serialize(animation Anim, animation_clip* GlobalClips, gs_memory_ // TODO(pjs): Systematize the AnimationProcHandle // :AnimProcHandle u32 AnimationProcIndex = AnimationBlockAt.AnimationProcHandle - 1; - animation_clip Animation = GlobalClips[AnimationProcIndex]; + animation_pattern Animation = GlobalClips[AnimationProcIndex]; Serializer_OpenStruct(&Serializer, AnimField_Block); { @@ -70,7 +70,7 @@ AnimSerializer_Serialize(animation Anim, animation_clip* GlobalClips, gs_memory_ } internal animation -AnimParser_Parse(gs_string File, gs_memory_arena* Arena, u32 AnimClipsCount, animation_clip* AnimClips) +AnimParser_Parse(gs_string File, gs_memory_arena* Arena, u32 AnimClipsCount, animation_pattern* AnimClips) { animation Result = {0}; diff --git a/src/app/foldhaus_app.cpp b/src/app/foldhaus_app.cpp index f3038f6..8eee729 100644 --- a/src/app/foldhaus_app.cpp +++ b/src/app/foldhaus_app.cpp @@ -211,7 +211,7 @@ UPDATE_AND_RENDER(UpdateAndRender) // :AnimProcHandle u32 AnimationProcIndex = Block.AnimationProcHandle - 1; - animation_proc* AnimationProc = GlobalAnimationClips[AnimationProcIndex].Proc; + animation_proc* AnimationProc = GlobalAnimationPatterns[AnimationProcIndex].Proc; AnimationProc(&LayerLEDBuffers[Layer], *Assembly, SecondsIntoBlock, State->Transient); } diff --git a/src/app/foldhaus_app.h b/src/app/foldhaus_app.h index 66755c6..83e1de1 100644 --- a/src/app/foldhaus_app.h +++ b/src/app/foldhaus_app.h @@ -209,8 +209,8 @@ EndCurrentOperationMode(app_state* State) DeactivateCurrentOperationMode(&State->Modes); } -s32 GlobalAnimationClipsCount = 3; -animation_clip GlobalAnimationClips[] = { +s32 GlobalAnimationPatternsCount = 3; +animation_pattern GlobalAnimationPatterns[] = { { "Test Pattern One", 16, TestPatternOne }, { "Test Pattern Two", 16, TestPatternTwo }, { "Test Pattern Three", 18, TestPatternThree }, diff --git a/src/app/platform_win32/win32_foldhaus.cpp b/src/app/platform_win32/win32_foldhaus.cpp index 7f9b24a..dda8da8 100644 --- a/src/app/platform_win32/win32_foldhaus.cpp +++ b/src/app/platform_win32/win32_foldhaus.cpp @@ -479,8 +479,6 @@ WinMain ( #endif - - MainWindow = Win32CreateWindow (HInstance, "Foldhaus", 1440, 768, HandleWindowEvents); Win32UpdateWindowDimension(&MainWindow); From 708ac91afe990eed36b5034a95c8027758251191 Mon Sep 17 00:00:00 2001 From: PS Date: Sat, 14 Nov 2020 12:19:36 -0800 Subject: [PATCH 10/13] pulled animation update and render functions out of foldhaus_app.cpp --- src/app/engine/animation/foldhaus_animation.h | 40 +++++- .../animation/foldhaus_animation_renderer.cpp | 126 ++++++++++++++++++ src/app/foldhaus_app.cpp | 105 ++------------- src/app/foldhaus_app.h | 1 + src/app/platform_win32/win32_foldhaus.cpp | 9 ++ 5 files changed, 183 insertions(+), 98 deletions(-) create mode 100644 src/app/engine/animation/foldhaus_animation_renderer.cpp diff --git a/src/app/engine/animation/foldhaus_animation.h b/src/app/engine/animation/foldhaus_animation.h index bbdb1a5..80117db 100644 --- a/src/app/engine/animation/foldhaus_animation.h +++ b/src/app/engine/animation/foldhaus_animation.h @@ -14,6 +14,10 @@ struct frame_range s32 Max; }; +// NOTE(pjs): An animation block is a time range paired with an +// animation_pattern (see below). While a timeline's current time +// is within the range of a block, that particular block's animation +// will run struct animation_block { frame_range Range; @@ -37,6 +41,8 @@ enum blend_mode BlendMode_Count, }; +typedef pixel led_blend_proc(pixel PixelA, pixel PixelB); + global gs_const_string BlendModeStrings[] = { ConstString("Overwrite"), ConstString("Add"), @@ -57,11 +63,15 @@ struct anim_layer_array u32 CountMax; }; +// NOTE(pjs): An animation is a stack of layers, each of which +// is a timeline of animation blocks. struct animation { gs_string Name; anim_layer_array Layers; + // TODO(pjs): Pretty sure Blocks_ should be obsolete and + // Layers should contain their own blocks animation_block_array Blocks_; frame_range PlayableRange; @@ -74,6 +84,8 @@ struct animation_array u32 CountMax; }; +// NOTE(pjs): This is an evaluated frame - across all layers in an +// animation, these are the blocks that need to be run struct animation_frame { // NOTE(pjs): These are all parallel arrays of equal length @@ -102,7 +114,9 @@ struct animation_system }; -// TODO(pjs): Better name - something like animation_prototype +// NOTE(pjs): A Pattern is a named procedure which can be used as +// an element of an animation. Patterns are sequenced on a timeline +// and blended via layers to create an animation struct animation_pattern { char* Name; @@ -431,5 +445,29 @@ AnimationSystem_CalculateAnimationFrame(animation_system* System, gs_memory_aren return Result; } +internal void +AnimationSystem_Update(animation_system* System) +{ + animation* ActiveAnim = AnimationSystem_GetActiveAnimation(System); + if (System->TimelineShouldAdvance) { + // TODO(Peter): Revisit this. This implies that the framerate of the animation system + // is tied to the framerate of the simulation. That seems correct to me, but I'm not sure + System->CurrentFrame += 1; + + // Loop back to the beginning + if (System->CurrentFrame > ActiveAnim->PlayableRange.Max) + { + System->CurrentFrame = 0; + } + } +} + +inline bool +AnimationSystem_NeedsRender(animation_system System) +{ + bool Result = (System.CurrentFrame != System.LastUpdatedFrame); + return Result; +} + #define FOLDHAUS_ANIMATION #endif // FOLDHAUS_ANIMATION \ No newline at end of file diff --git a/src/app/engine/animation/foldhaus_animation_renderer.cpp b/src/app/engine/animation/foldhaus_animation_renderer.cpp new file mode 100644 index 0000000..dfd8ab6 --- /dev/null +++ b/src/app/engine/animation/foldhaus_animation_renderer.cpp @@ -0,0 +1,126 @@ +// +// File: foldhaus_animation_renderer.cpp +// Author: Peter Slattery +// Creation Date: 2020-11-14 +// +#ifndef FOLDHAUS_ANIMATION_RENDERER_CPP + +internal pixel +LedBlend_Overwrite(pixel PixelA, pixel PixelB) +{ + return PixelB; +} + +internal pixel +LedBlend_Add(pixel PixelA, pixel PixelB) +{ + pixel Result = {}; + + u32 R = (u32)PixelA.R + (u32)PixelB.R; + u32 G = (u32)PixelA.G + (u32)PixelB.G; + u32 B = (u32)PixelA.B + (u32)PixelB.B; + + Result.R = (u8)Min(R, (u32)255); + Result.G = (u8)Min(G, (u32)255); + Result.B = (u8)Min(B, (u32)255); + + return Result; +} + +internal pixel +LedBlend_Multiply(pixel PixelA, pixel PixelB) +{ + pixel Result = {}; + + r32 DR = (r32)PixelA.R / 255.f; + r32 DG = (r32)PixelA.G / 255.f; + r32 DB = (r32)PixelA.B / 255.f; + + r32 SR = (r32)PixelB.R / 255.f; + r32 SG = (r32)PixelB.G / 255.f; + r32 SB = (r32)PixelB.B / 255.f; + + Result.R = (u8)((DR * SR) * 255.f); + Result.G = (u8)((DG * SG) * 255.f); + Result.B = (u8)((DB * SB) * 255.f); + + return Result; +} + +internal pixel +LedBlend_Overlay(pixel PixelA, pixel PixelB) +{ + pixel Result = {}; + return Result; +} + +internal led_blend_proc* +LedBlend_GetProc(blend_mode BlendMode) +{ + led_blend_proc* Result = 0; + switch (BlendMode) + { + case BlendMode_Overwrite: { Result = LedBlend_Overwrite; }break; + case BlendMode_Add: { Result = LedBlend_Add; }break; + case BlendMode_Multiply: { Result = LedBlend_Multiply; }break; + InvalidDefaultCase; + } + return Result; +} + +internal void +AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Assemblies, + led_system* LedSystem, + animation_pattern* Patterns, + gs_memory_arena* Transient) +{ + s32 CurrentFrame = System->CurrentFrame; + r32 FrameTime = CurrentFrame * System->SecondsPerFrame; + + animation_frame CurrFrame = AnimationSystem_CalculateAnimationFrame(System, Transient); + + led_buffer* LayerLEDBuffers = PushArray(Transient, led_buffer, CurrFrame.BlocksCountMax); + for (u32 AssemblyIndex = 0; AssemblyIndex < Assemblies.Count; AssemblyIndex++) + { + assembly* Assembly = &Assemblies.Values[AssemblyIndex]; + led_buffer* AssemblyLedBuffer = LedSystemGetBuffer(LedSystem, Assembly->LedBufferIndex); + + for (u32 Layer = 0; Layer < CurrFrame.BlocksCountMax; Layer++) + { + if (!CurrFrame.BlocksFilled[Layer]) { continue; } + animation_block Block = CurrFrame.Blocks[Layer]; + + // Prep Temp Buffer + LayerLEDBuffers[Layer] = *AssemblyLedBuffer; + LayerLEDBuffers[Layer].Colors = PushArray(Transient, pixel, AssemblyLedBuffer->LedCount); + + u32 FramesIntoBlock = CurrentFrame - Block.Range.Min; + r32 SecondsIntoBlock = FramesIntoBlock * System->SecondsPerFrame; + + // :AnimProcHandle + u32 AnimationProcIndex = Block.AnimationProcHandle - 1; + animation_proc* AnimationProc = Patterns[AnimationProcIndex].Proc; + AnimationProc(&LayerLEDBuffers[Layer], *Assembly, SecondsIntoBlock, Transient); + } + + // Consolidate Temp Buffers + // We do this in reverse order so that they go from top to bottom + animation* ActiveAnim = AnimationSystem_GetActiveAnimation(System); + for (u32 Layer = 0; Layer < CurrFrame.BlocksCountMax; Layer++) + { + if (!CurrFrame.BlocksFilled[Layer]) { continue; } + + led_blend_proc* Blend = LedBlend_GetProc(ActiveAnim->Layers.Values[Layer].BlendMode); + Assert(Blend != 0); + for (u32 LED = 0; LED < AssemblyLedBuffer->LedCount; LED++) + { + pixel A = AssemblyLedBuffer->Colors[LED]; + pixel B = LayerLEDBuffers[Layer].Colors[LED]; + AssemblyLedBuffer->Colors[LED] = Blend(A, B); + } + } + } +} + +#define FOLDHAUS_ANIMATION_RENDERER_CPP +#endif // FOLDHAUS_ANIMATION_RENDERER_CPP \ No newline at end of file diff --git a/src/app/foldhaus_app.cpp b/src/app/foldhaus_app.cpp index 8eee729..68bd4e2 100644 --- a/src/app/foldhaus_app.cpp +++ b/src/app/foldhaus_app.cpp @@ -168,104 +168,15 @@ UPDATE_AND_RENDER(UpdateAndRender) Editor_Update(State, Context, InputQueue); + AnimationSystem_Update(&State->AnimationSystem); + if (AnimationSystem_NeedsRender(State->AnimationSystem)) { - animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem); - if (State->AnimationSystem.TimelineShouldAdvance) { - // TODO(Peter): Revisit this. This implies that the framerate of the animation system - // is tied to the framerate of the simulation. That seems correct to me, but I'm not sure - State->AnimationSystem.CurrentFrame += 1; - - // Loop back to the beginning - if (State->AnimationSystem.CurrentFrame > ActiveAnim->PlayableRange.Max) - { - State->AnimationSystem.CurrentFrame = 0; - } - } - } - - s32 CurrentFrame = State->AnimationSystem.CurrentFrame; - if (CurrentFrame != State->AnimationSystem.LastUpdatedFrame) - { - State->AnimationSystem.LastUpdatedFrame = CurrentFrame; - r32 FrameTime = CurrentFrame * State->AnimationSystem.SecondsPerFrame; - - animation_frame CurrFrame = AnimationSystem_CalculateAnimationFrame(&State->AnimationSystem, State->Transient); - - led_buffer* LayerLEDBuffers = PushArray(State->Transient, led_buffer, CurrFrame.BlocksCountMax); - for (u32 AssemblyIndex = 0; AssemblyIndex < State->Assemblies.Count; AssemblyIndex++) - { - assembly* Assembly = &State->Assemblies.Values[AssemblyIndex]; - led_buffer* AssemblyLedBuffer = LedSystemGetBuffer(&State->LedSystem, Assembly->LedBufferIndex); - - for (u32 Layer = 0; Layer < CurrFrame.BlocksCountMax; Layer++) - { - if (!CurrFrame.BlocksFilled[Layer]) { continue; } - animation_block Block = CurrFrame.Blocks[Layer]; - - // Prep Temp Buffer - LayerLEDBuffers[Layer] = *AssemblyLedBuffer; - LayerLEDBuffers[Layer].Colors = PushArray(State->Transient, pixel, AssemblyLedBuffer->LedCount); - - u32 FramesIntoBlock = CurrentFrame - Block.Range.Min; - r32 SecondsIntoBlock = FramesIntoBlock * State->AnimationSystem.SecondsPerFrame; - - // :AnimProcHandle - u32 AnimationProcIndex = Block.AnimationProcHandle - 1; - animation_proc* AnimationProc = GlobalAnimationPatterns[AnimationProcIndex].Proc; - AnimationProc(&LayerLEDBuffers[Layer], *Assembly, SecondsIntoBlock, State->Transient); - } - - // Consolidate Temp Buffers - // We do this in reverse order so that they go from top to bottom - animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem); - for (u32 Layer = 0; Layer < CurrFrame.BlocksCountMax; Layer++) - { - if (!CurrFrame.BlocksFilled[Layer]) { continue; } - - switch (ActiveAnim->Layers.Values[Layer].BlendMode) - { - case BlendMode_Overwrite: - { - for (u32 LED = 0; LED < AssemblyLedBuffer->LedCount; LED++) - { - AssemblyLedBuffer->Colors[LED] = LayerLEDBuffers[Layer].Colors[LED]; - } - }break; - - case BlendMode_Add: - { - for (u32 LED = 0; LED < AssemblyLedBuffer->LedCount; LED++) - { - u32 R = (u32)AssemblyLedBuffer->Colors[LED].R + (u32)LayerLEDBuffers[Layer].Colors[LED].R; - u32 G = (u32)AssemblyLedBuffer->Colors[LED].G + (u32)LayerLEDBuffers[Layer].Colors[LED].G; - u32 B = (u32)AssemblyLedBuffer->Colors[LED].B + (u32)LayerLEDBuffers[Layer].Colors[LED].B; - - AssemblyLedBuffer->Colors[LED].R = (u8)Min(R, (u32)255); - AssemblyLedBuffer->Colors[LED].G = (u8)Min(G, (u32)255); - AssemblyLedBuffer->Colors[LED].B = (u8)Min(B, (u32)255); - } - }break; - - case BlendMode_Multiply: - { - for (u32 LED = 0; LED < AssemblyLedBuffer->LedCount; LED++) - { - r32 DR = (r32)AssemblyLedBuffer->Colors[LED].R / 255.f; - r32 DG = (r32)AssemblyLedBuffer->Colors[LED].G / 255.f; - r32 DB = (r32)AssemblyLedBuffer->Colors[LED].B / 255.f; - - r32 SR = (r32)LayerLEDBuffers[Layer].Colors[LED].R / 255.f; - r32 SG = (r32)LayerLEDBuffers[Layer].Colors[LED].G / 255.f; - r32 SB = (r32)LayerLEDBuffers[Layer].Colors[LED].B / 255.f; - - AssemblyLedBuffer->Colors[LED].R = (u8)((DR * SR) * 255.f); - AssemblyLedBuffer->Colors[LED].G = (u8)((DG * SG) * 255.f); - AssemblyLedBuffer->Colors[LED].B = (u8)((DB * SB) * 255.f); - } - }break; - } - } - } + State->AnimationSystem.LastUpdatedFrame = State->AnimationSystem.CurrentFrame; + AnimationSystem_RenderToLedBuffers(&State->AnimationSystem, + State->Assemblies, + &State->LedSystem, + GlobalAnimationPatterns, + State->Transient); } { diff --git a/src/app/foldhaus_app.h b/src/app/foldhaus_app.h index 83e1de1..3939714 100644 --- a/src/app/foldhaus_app.h +++ b/src/app/foldhaus_app.h @@ -38,6 +38,7 @@ typedef struct panel panel; #include "engine/animation/foldhaus_animation.h" #include "engine/animation/foldhaus_animation_serializer.cpp" +#include "engine/animation/foldhaus_animation_renderer.cpp" struct app_state { diff --git a/src/app/platform_win32/win32_foldhaus.cpp b/src/app/platform_win32/win32_foldhaus.cpp index dda8da8..f3d12c5 100644 --- a/src/app/platform_win32/win32_foldhaus.cpp +++ b/src/app/platform_win32/win32_foldhaus.cpp @@ -454,6 +454,10 @@ WinMain ( gs_thread_context ThreadContext = Win32CreateThreadContext(); #if 0 + // NOTE(pjs): UART TEST CODE + // NOTE(pjs): UART TEST CODE + // NOTE(pjs): UART TEST CODE + u32 LedCount = 48; u32 MessageBaseSize = sizeof(uart_header) + sizeof(uart_channel) + sizeof(uart_footer); MessageBaseSize += sizeof(u8) * 3 * LedCount; @@ -580,6 +584,10 @@ WinMain ( WSAStartup(MAKEWORD(2, 2), &WSAData); Win32Sockets = Win32SocketArray_Create(16, &PlatformPermanent); +#if 0 + // NOTE(pjs): SOCKET READING TEST CODE + // NOTE(pjs): SOCKET READING TEST CODE + // NOTE(pjs): SOCKET READING TEST CODE win32_socket TestSocket = Win32Socket_ConnectToAddress("127.0.0.1", "20185"); test_microphone_packet* Recv = 0; @@ -593,6 +601,7 @@ WinMain ( } ClearArena(ThreadContext.Transient); } +#endif Win32SerialArray_Create(ThreadContext); From a6c8d0c9550f16f179567ac842661544a47c5acb Mon Sep 17 00:00:00 2001 From: PS Date: Sat, 14 Nov 2020 12:47:51 -0800 Subject: [PATCH 11/13] refactored layer blending --- src/app/engine/animation/foldhaus_animation.h | 13 +++++++++ .../animation/foldhaus_animation_renderer.cpp | 28 +++++++++++++------ src/app/engine/assembly/foldhaus_assembly.h | 11 ++++++++ 3 files changed, 44 insertions(+), 8 deletions(-) diff --git a/src/app/engine/animation/foldhaus_animation.h b/src/app/engine/animation/foldhaus_animation.h index 80117db..85173d5 100644 --- a/src/app/engine/animation/foldhaus_animation.h +++ b/src/app/engine/animation/foldhaus_animation.h @@ -41,6 +41,7 @@ enum blend_mode BlendMode_Count, }; +// TODO(pjs): Add Opacity to this typedef pixel led_blend_proc(pixel PixelA, pixel PixelB); global gs_const_string BlendModeStrings[] = { @@ -84,10 +85,22 @@ struct animation_array u32 CountMax; }; +struct animation_layer_frame +{ + animation_block Hot; + animation_block NextHot; + bool HasNextHot; +}; + // NOTE(pjs): This is an evaluated frame - across all layers in an // animation, these are the blocks that need to be run struct animation_frame { + animation_layer_frame* Layers; + b8* LayersFilled; + u32 LayersCount; + u32 LayersCountMax; + // NOTE(pjs): These are all parallel arrays of equal length animation_block* Blocks; b8* BlocksFilled; diff --git a/src/app/engine/animation/foldhaus_animation_renderer.cpp b/src/app/engine/animation/foldhaus_animation_renderer.cpp index dfd8ab6..7839da6 100644 --- a/src/app/engine/animation/foldhaus_animation_renderer.cpp +++ b/src/app/engine/animation/foldhaus_animation_renderer.cpp @@ -77,35 +77,47 @@ AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Asse s32 CurrentFrame = System->CurrentFrame; r32 FrameTime = CurrentFrame * System->SecondsPerFrame; + animation* ActiveAnim = AnimationSystem_GetActiveAnimation(System); animation_frame CurrFrame = AnimationSystem_CalculateAnimationFrame(System, Transient); - led_buffer* LayerLEDBuffers = PushArray(Transient, led_buffer, CurrFrame.BlocksCountMax); + led_buffer* LayerLedBuffers = PushArray(Transient, led_buffer, CurrFrame.BlocksCountMax); + for (u32 AssemblyIndex = 0; AssemblyIndex < Assemblies.Count; AssemblyIndex++) { assembly* Assembly = &Assemblies.Values[AssemblyIndex]; led_buffer* AssemblyLedBuffer = LedSystemGetBuffer(LedSystem, Assembly->LedBufferIndex); + // Create the LayerLEDBuffers for (u32 Layer = 0; Layer < CurrFrame.BlocksCountMax; Layer++) { + led_buffer TempBuffer = {}; + TempBuffer.LedCount = AssemblyLedBuffer->LedCount; + TempBuffer.Positions = AssemblyLedBuffer->Positions; + TempBuffer.Colors = PushArray(Transient, pixel, TempBuffer.LedCount); + LedBuffer_ClearToBlack(&TempBuffer); + + LayerLedBuffers[Layer] = TempBuffer; + } + + // Render Each layer's block to the appropriate temp buffer + for (u32 Layer = 0; Layer < CurrFrame.BlocksCountMax; Layer++) + { + led_buffer TempBuffer = LayerLedBuffers[Layer]; + if (!CurrFrame.BlocksFilled[Layer]) { continue; } animation_block Block = CurrFrame.Blocks[Layer]; - // Prep Temp Buffer - LayerLEDBuffers[Layer] = *AssemblyLedBuffer; - LayerLEDBuffers[Layer].Colors = PushArray(Transient, pixel, AssemblyLedBuffer->LedCount); - u32 FramesIntoBlock = CurrentFrame - Block.Range.Min; r32 SecondsIntoBlock = FramesIntoBlock * System->SecondsPerFrame; // :AnimProcHandle u32 AnimationProcIndex = Block.AnimationProcHandle - 1; animation_proc* AnimationProc = Patterns[AnimationProcIndex].Proc; - AnimationProc(&LayerLEDBuffers[Layer], *Assembly, SecondsIntoBlock, Transient); + AnimationProc(&TempBuffer, *Assembly, SecondsIntoBlock, Transient); } // Consolidate Temp Buffers // We do this in reverse order so that they go from top to bottom - animation* ActiveAnim = AnimationSystem_GetActiveAnimation(System); for (u32 Layer = 0; Layer < CurrFrame.BlocksCountMax; Layer++) { if (!CurrFrame.BlocksFilled[Layer]) { continue; } @@ -115,7 +127,7 @@ AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Asse for (u32 LED = 0; LED < AssemblyLedBuffer->LedCount; LED++) { pixel A = AssemblyLedBuffer->Colors[LED]; - pixel B = LayerLEDBuffers[Layer].Colors[LED]; + pixel B = LayerLedBuffers[Layer].Colors[LED]; AssemblyLedBuffer->Colors[LED] = Blend(A, B); } } diff --git a/src/app/engine/assembly/foldhaus_assembly.h b/src/app/engine/assembly/foldhaus_assembly.h index 94982a5..f1d7ba9 100644 --- a/src/app/engine/assembly/foldhaus_assembly.h +++ b/src/app/engine/assembly/foldhaus_assembly.h @@ -168,6 +168,17 @@ LedSystemGetBuffer(led_system* System, u32 Index) return Result; } +internal void +LedBuffer_ClearToBlack(led_buffer* Buffer) +{ + for (u32 i = 0; i < Buffer->LedCount; i++) + { + Buffer->Colors[i].R = 0; + Buffer->Colors[i].G = 0; + Buffer->Colors[i].B = 0; + } +} + internal u32 StripGenData_CountLeds(strip_gen_data Data) { From 5e6ac2549070f6725073d2cfdb46c2af4b6912c7 Mon Sep 17 00:00:00 2001 From: PS Date: Sat, 14 Nov 2020 13:41:27 -0800 Subject: [PATCH 12/13] on frames with overlapping blocks, the blocks are blended together --- src/app/engine/animation/foldhaus_animation.h | 43 +++++++- .../animation/foldhaus_animation_renderer.cpp | 103 ++++++++++++++---- src/app/foldhaus_app.h | 14 ++- 3 files changed, 136 insertions(+), 24 deletions(-) diff --git a/src/app/engine/animation/foldhaus_animation.h b/src/app/engine/animation/foldhaus_animation.h index 85173d5..07ec227 100644 --- a/src/app/engine/animation/foldhaus_animation.h +++ b/src/app/engine/animation/foldhaus_animation.h @@ -88,8 +88,12 @@ struct animation_array struct animation_layer_frame { animation_block Hot; + bool HasHot; + animation_block NextHot; bool HasNextHot; + + r32 HotOpacity; }; // NOTE(pjs): This is an evaluated frame - across all layers in an @@ -97,9 +101,7 @@ struct animation_layer_frame struct animation_frame { animation_layer_frame* Layers; - b8* LayersFilled; u32 LayersCount; - u32 LayersCountMax; // NOTE(pjs): These are all parallel arrays of equal length animation_block* Blocks; @@ -438,6 +440,10 @@ AnimationSystem_CalculateAnimationFrame(animation_system* System, gs_memory_aren animation* ActiveAnim = AnimationSystem_GetActiveAnimation(System); animation_frame Result = {0}; + Result.LayersCount = ActiveAnim->Layers.Count; + Result.Layers = PushArray(Arena, animation_layer_frame, Result.LayersCount); + ZeroArray(Result.Layers, animation_frame, Result.LayersCount); + Result.BlocksCountMax = ActiveAnim->Layers.Count; Result.Blocks = PushArray(Arena, animation_block, Result.BlocksCountMax); Result.BlocksFilled = PushArray(Arena, b8, Result.BlocksCountMax); @@ -449,6 +455,39 @@ AnimationSystem_CalculateAnimationFrame(animation_system* System, gs_memory_aren if (FrameIsInRange(Block.Range, System->CurrentFrame)) { + animation_layer_frame* Layer = Result.Layers + Block.Layer; + if (Layer->HasHot) + { + // NOTE(pjs): With current implementation, we don't allow + // animations to hvae more than 2 concurrent blocks in the + // timeline + Assert(!Layer->HasNextHot); + + // NOTE(pjs): Make sure that Hot comes before NextHot + if (Layer->Hot.Range.Min < Block.Range.Min) + { + Layer->NextHot = Block; + } + else + { + Layer->NextHot = Layer->Hot; + Layer->Hot = Block; + } + Layer->HasNextHot = true; + + frame_range BlendRange = {}; + BlendRange.Min = Layer->NextHot.Range.Min; + BlendRange.Max = Layer->Hot.Range.Max; + Layer->HotOpacity = 1.0f - FrameToPercentRange(System->CurrentFrame, BlendRange); + } + else + { + Layer->Hot = Block; + Layer->HotOpacity = 1.0f; + Layer->HasHot = true; + } + + // TODO(pjs): Get rid of these fields, they're redundant now Result.BlocksFilled[Block.Layer] = true; Result.Blocks[Block.Layer] = Block; Result.BlocksCount++; diff --git a/src/app/engine/animation/foldhaus_animation_renderer.cpp b/src/app/engine/animation/foldhaus_animation_renderer.cpp index 7839da6..1ff7783 100644 --- a/src/app/engine/animation/foldhaus_animation_renderer.cpp +++ b/src/app/engine/animation/foldhaus_animation_renderer.cpp @@ -11,6 +11,18 @@ LedBlend_Overwrite(pixel PixelA, pixel PixelB) return PixelB; } +internal pixel +LedBlend_Overwrite(pixel PixelA, pixel PixelB, r32 Opacity) +{ + pixel Result = {}; + + r32 BOpacity = 1.0f - Opacity; + Result.R = (u8)((PixelA.R * Opacity) + (PixelB.R * BOpacity)); + Result.G = (u8)((PixelA.G * Opacity) + (PixelB.G * BOpacity)); + Result.B = (u8)((PixelA.B * Opacity) + (PixelB.B * BOpacity)); + return Result; +} + internal pixel LedBlend_Add(pixel PixelA, pixel PixelB) { @@ -68,6 +80,18 @@ LedBlend_GetProc(blend_mode BlendMode) return Result; } +internal void +AnimationSystem_RenderBlockToLedBuffer(animation_system* System, animation_block Block, led_buffer* Buffer, assembly Assembly, animation_pattern* Patterns, gs_memory_arena* Transient) +{ + u32 FramesIntoBlock = System->CurrentFrame - Block.Range.Min; + r32 SecondsIntoBlock = FramesIntoBlock * System->SecondsPerFrame; + + // :AnimProcHandle + u32 AnimationProcIndex = Block.AnimationProcHandle - 1; + animation_proc* AnimationProc = Patterns[AnimationProcIndex].Proc; + AnimationProc(Buffer, Assembly, SecondsIntoBlock, Transient); +} + internal void AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Assemblies, led_system* LedSystem, @@ -80,7 +104,15 @@ AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Asse animation* ActiveAnim = AnimationSystem_GetActiveAnimation(System); animation_frame CurrFrame = AnimationSystem_CalculateAnimationFrame(System, Transient); - led_buffer* LayerLedBuffers = PushArray(Transient, led_buffer, CurrFrame.BlocksCountMax); + // NOTE(pjs): This mirrors animation_layer_frame to account + // for overlapping + struct layer_led_buffer + { + led_buffer HotBuffer; + led_buffer NextHotBuffer; + }; + + layer_led_buffer* LayerBuffers = PushArray(Transient, layer_led_buffer, CurrFrame.LayersCount); for (u32 AssemblyIndex = 0; AssemblyIndex < Assemblies.Count; AssemblyIndex++) { @@ -88,32 +120,61 @@ AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Asse led_buffer* AssemblyLedBuffer = LedSystemGetBuffer(LedSystem, Assembly->LedBufferIndex); // Create the LayerLEDBuffers - for (u32 Layer = 0; Layer < CurrFrame.BlocksCountMax; Layer++) + for (u32 Layer = 0; Layer < CurrFrame.LayersCount; Layer++) { - led_buffer TempBuffer = {}; - TempBuffer.LedCount = AssemblyLedBuffer->LedCount; - TempBuffer.Positions = AssemblyLedBuffer->Positions; - TempBuffer.Colors = PushArray(Transient, pixel, TempBuffer.LedCount); - LedBuffer_ClearToBlack(&TempBuffer); + layer_led_buffer TempBuffer = {}; + if (CurrFrame.Layers[Layer].HasHot) + { + TempBuffer.HotBuffer.LedCount = AssemblyLedBuffer->LedCount; + TempBuffer.HotBuffer.Positions = AssemblyLedBuffer->Positions; + TempBuffer.HotBuffer.Colors = PushArray(Transient, pixel, TempBuffer.HotBuffer.LedCount); + LedBuffer_ClearToBlack(&TempBuffer.HotBuffer); + } - LayerLedBuffers[Layer] = TempBuffer; + if (CurrFrame.Layers[Layer].HasNextHot) + { + TempBuffer.NextHotBuffer.LedCount = AssemblyLedBuffer->LedCount; + TempBuffer.NextHotBuffer.Positions = AssemblyLedBuffer->Positions; + TempBuffer.NextHotBuffer.Colors = PushArray(Transient, pixel, TempBuffer.HotBuffer.LedCount); + LedBuffer_ClearToBlack(&TempBuffer.NextHotBuffer); + } + + LayerBuffers[Layer] = TempBuffer; } // Render Each layer's block to the appropriate temp buffer - for (u32 Layer = 0; Layer < CurrFrame.BlocksCountMax; Layer++) + for (u32 Layer = 0; Layer < CurrFrame.LayersCount; Layer++) { - led_buffer TempBuffer = LayerLedBuffers[Layer]; + animation_layer_frame LayerFrame = CurrFrame.Layers[Layer]; + if (LayerFrame.HasHot) + { + led_buffer TempBuffer = LayerBuffers[Layer].HotBuffer; + animation_block Block = LayerFrame.Hot; + AnimationSystem_RenderBlockToLedBuffer(System, Block, &TempBuffer, *Assembly, Patterns, Transient); + } - if (!CurrFrame.BlocksFilled[Layer]) { continue; } - animation_block Block = CurrFrame.Blocks[Layer]; - - u32 FramesIntoBlock = CurrentFrame - Block.Range.Min; - r32 SecondsIntoBlock = FramesIntoBlock * System->SecondsPerFrame; - - // :AnimProcHandle - u32 AnimationProcIndex = Block.AnimationProcHandle - 1; - animation_proc* AnimationProc = Patterns[AnimationProcIndex].Proc; - AnimationProc(&TempBuffer, *Assembly, SecondsIntoBlock, Transient); + if (LayerFrame.HasNextHot) + { + led_buffer TempBuffer = LayerBuffers[Layer].NextHotBuffer; + animation_block Block = LayerFrame.NextHot; + AnimationSystem_RenderBlockToLedBuffer(System, Block, &TempBuffer, *Assembly, Patterns, Transient); + } + } + + // Blend together any layers that have a hot and next hot buffer + for (u32 Layer = 0; Layer < CurrFrame.LayersCount; Layer++) + { + animation_layer_frame LayerFrame = CurrFrame.Layers[Layer]; + layer_led_buffer LayerBuffer = LayerBuffers[Layer]; + if (LayerFrame.HasNextHot) + { + for (u32 LED = 0; LED < AssemblyLedBuffer->LedCount; LED++) + { + pixel A = LayerBuffer.HotBuffer.Colors[LED]; + pixel B = LayerBuffer.NextHotBuffer.Colors[LED]; + LayerBuffer.HotBuffer.Colors[LED] = LedBlend_Overwrite(A, B, LayerFrame.HotOpacity); + } + } } // Consolidate Temp Buffers @@ -127,7 +188,7 @@ AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Asse for (u32 LED = 0; LED < AssemblyLedBuffer->LedCount; LED++) { pixel A = AssemblyLedBuffer->Colors[LED]; - pixel B = LayerLedBuffers[Layer].Colors[LED]; + pixel B = LayerBuffers[Layer].HotBuffer.Colors[LED]; AssemblyLedBuffer->Colors[LED] = Blend(A, B); } } diff --git a/src/app/foldhaus_app.h b/src/app/foldhaus_app.h index 3939714..d8b7bbe 100644 --- a/src/app/foldhaus_app.h +++ b/src/app/foldhaus_app.h @@ -202,6 +202,17 @@ TestPatternThree(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* } } +internal void +Pattern_AllGreen(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient) +{ + for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) + { + Leds->Colors[LedIndex].R = 0; + Leds->Colors[LedIndex].B = 255; + Leds->Colors[LedIndex].G = 255; + } +} + // END TEMPORARY PATTERNS internal void @@ -210,11 +221,12 @@ EndCurrentOperationMode(app_state* State) DeactivateCurrentOperationMode(&State->Modes); } -s32 GlobalAnimationPatternsCount = 3; +s32 GlobalAnimationPatternsCount = 4; animation_pattern GlobalAnimationPatterns[] = { { "Test Pattern One", 16, TestPatternOne }, { "Test Pattern Two", 16, TestPatternTwo }, { "Test Pattern Three", 18, TestPatternThree }, + { "Pattern_AllGreen", 16, Pattern_AllGreen }, }; #include "editor/panels/foldhaus_panel_types.h" From e51188398dd721e4945606547ff36573eb1f2af5 Mon Sep 17 00:00:00 2001 From: PS Date: Sat, 14 Nov 2020 13:48:17 -0800 Subject: [PATCH 13/13] cleaned up unneeded fields in animation_frame --- src/app/engine/animation/foldhaus_animation.h | 19 +------------------ .../animation/foldhaus_animation_renderer.cpp | 19 ++++++++++--------- 2 files changed, 11 insertions(+), 27 deletions(-) diff --git a/src/app/engine/animation/foldhaus_animation.h b/src/app/engine/animation/foldhaus_animation.h index 07ec227..0f160a0 100644 --- a/src/app/engine/animation/foldhaus_animation.h +++ b/src/app/engine/animation/foldhaus_animation.h @@ -102,13 +102,6 @@ struct animation_frame { animation_layer_frame* Layers; u32 LayersCount; - - // NOTE(pjs): These are all parallel arrays of equal length - animation_block* Blocks; - b8* BlocksFilled; - - u32 BlocksCountMax; - u32 BlocksCount; }; #define ANIMATION_SYSTEM_LAYERS_MAX 128 @@ -442,12 +435,7 @@ AnimationSystem_CalculateAnimationFrame(animation_system* System, gs_memory_aren animation_frame Result = {0}; Result.LayersCount = ActiveAnim->Layers.Count; Result.Layers = PushArray(Arena, animation_layer_frame, Result.LayersCount); - ZeroArray(Result.Layers, animation_frame, Result.LayersCount); - - Result.BlocksCountMax = ActiveAnim->Layers.Count; - Result.Blocks = PushArray(Arena, animation_block, Result.BlocksCountMax); - Result.BlocksFilled = PushArray(Arena, b8, Result.BlocksCountMax); - ZeroArray(Result.BlocksFilled, b8, Result.BlocksCountMax); + ZeroArray(Result.Layers, animation_layer_frame, Result.LayersCount); for (u32 i = 0; i < ActiveAnim->Blocks_.Count; i++) { @@ -486,11 +474,6 @@ AnimationSystem_CalculateAnimationFrame(animation_system* System, gs_memory_aren Layer->HotOpacity = 1.0f; Layer->HasHot = true; } - - // TODO(pjs): Get rid of these fields, they're redundant now - Result.BlocksFilled[Block.Layer] = true; - Result.Blocks[Block.Layer] = Block; - Result.BlocksCount++; } } diff --git a/src/app/engine/animation/foldhaus_animation_renderer.cpp b/src/app/engine/animation/foldhaus_animation_renderer.cpp index 1ff7783..83dc221 100644 --- a/src/app/engine/animation/foldhaus_animation_renderer.cpp +++ b/src/app/engine/animation/foldhaus_animation_renderer.cpp @@ -179,17 +179,18 @@ AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Asse // Consolidate Temp Buffers // We do this in reverse order so that they go from top to bottom - for (u32 Layer = 0; Layer < CurrFrame.BlocksCountMax; Layer++) + for (u32 Layer = 0; Layer < CurrFrame.LayersCount; Layer++) { - if (!CurrFrame.BlocksFilled[Layer]) { continue; } - - led_blend_proc* Blend = LedBlend_GetProc(ActiveAnim->Layers.Values[Layer].BlendMode); - Assert(Blend != 0); - for (u32 LED = 0; LED < AssemblyLedBuffer->LedCount; LED++) + if (CurrFrame.Layers[Layer].HasHot) { - pixel A = AssemblyLedBuffer->Colors[LED]; - pixel B = LayerBuffers[Layer].HotBuffer.Colors[LED]; - AssemblyLedBuffer->Colors[LED] = Blend(A, B); + led_blend_proc* Blend = LedBlend_GetProc(ActiveAnim->Layers.Values[Layer].BlendMode); + Assert(Blend != 0); + for (u32 LED = 0; LED < AssemblyLedBuffer->LedCount; LED++) + { + pixel A = AssemblyLedBuffer->Colors[LED]; + pixel B = LayerBuffers[Layer].HotBuffer.Colors[LED]; + AssemblyLedBuffer->Colors[LED] = Blend(A, B); + } } } }