From fa1d5a5afca53a7c7a454637547e2a08b79c108f Mon Sep 17 00:00:00 2001 From: PS Date: Sun, 8 Nov 2020 19:42:14 -0800 Subject: [PATCH 01/44] began turning ui_layout into ui_widgets that just have children. Currently, layout works, but the id system needs some thinking. --- src/app/editor/foldhaus_editor.cpp | 152 +++++--- .../foldhaus_panel_animation_timeline.h | 20 +- .../editor/panels/foldhaus_panel_file_view.h | 5 +- .../editor/panels/foldhaus_panel_hierarchy.h | 14 +- .../editor/panels/foldhaus_panel_profiler.h | 11 +- src/app/interface.h | 339 +++++++++--------- src/gs_libs/gs_types.cpp | 18 + 7 files changed, 309 insertions(+), 250 deletions(-) diff --git a/src/app/editor/foldhaus_editor.cpp b/src/app/editor/foldhaus_editor.cpp index 5d08c1f..ecef055 100644 --- a/src/app/editor/foldhaus_editor.cpp +++ b/src/app/editor/foldhaus_editor.cpp @@ -88,6 +88,72 @@ Editor_Update(app_state* State, context* Context, input_queue InputQueue) Editor_HandleInput(State, State->WindowBounds, InputQueue, Context->Mouse, *Context); } +internal void +Editor_DrawWidget(app_state* State, context* Context, render_command_buffer* RenderBuffer, ui_widget Widget) +{ + 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); + } + + if (Widget.ChildrenRoot) + { + Editor_DrawWidget(State, Context, RenderBuffer, *Widget.ChildrenRoot); + } + + if (Widget.Next) + { + Editor_DrawWidget(State, Context, RenderBuffer, *Widget.Next); + } +} + internal void Editor_Render(app_state* State, context* Context, render_command_buffer* RenderBuffer) { @@ -97,9 +163,32 @@ Editor_Render(app_state* State, context* Context, render_command_buffer* RenderB ui_InterfaceReset(&State->Interface); State->Interface.RenderBuffer = RenderBuffer; - ui_layout Layout = ui_CreateLayout(&State->Interface, Context->WindowBounds); - ui_PushLayout(&State->Interface, Layout); + ui_PushLayout(&State->Interface, Context->WindowBounds, LayoutDirection_TopDown); + rect2 Rects[2]; + RectVSplitAtPercent(Context->WindowBounds, .5f, &Rects[0], &Rects[1]); + for (u32 j = 0; j < 2; j++) + { + ui_PushLayout(&State->Interface, Rects[j], LayoutDirection_TopDown); + + if (ui_BeginDropdown(&State->Interface, MakeString("Select"))) + { + 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)) + { + + } + } + } + ui_EndDropdown(&State->Interface); + + ui_PopLayout(&State->Interface); + } + +#if 0 DrawAllPanels(State->PanelSystem, RenderBuffer, &Context->Mouse, State, *Context); for (s32 m = 0; m < State->Modes.ActiveModesCount; m++) @@ -110,66 +199,13 @@ Editor_Render(app_state* State, context* Context, render_command_buffer* RenderB OperationMode.Render(State, RenderBuffer, OperationMode, Context->Mouse, *Context); } } +#endif 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); - } - } + ui_widget Widget = *State->Interface.DrawOrderRoot; + Editor_DrawWidget(State, Context, RenderBuffer, Widget); Context->GeneralWorkQueue->CompleteQueueWork(Context->GeneralWorkQueue, Context->ThreadContext); Context->GeneralWorkQueue->ResetWorkQueue(Context->GeneralWorkQueue); diff --git a/src/app/editor/panels/foldhaus_panel_animation_timeline.h b/src/app/editor/panels/foldhaus_panel_animation_timeline.h index 6210cfa..1bd2d16 100644 --- a/src/app/editor/panels/foldhaus_panel_animation_timeline.h +++ b/src/app/editor/panels/foldhaus_panel_animation_timeline.h @@ -240,14 +240,14 @@ SelectAndBeginDragAnimationBlock(animation_timeline_state* TimelineState, handle animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem); operation_mode* DragAnimationClipMode = ActivateOperationModeWithCommands(&State->Modes, DragAnimationClipCommands, UpdateDragAnimationClip); + animation_block* SelectedBlock = Animation_GetBlockFromHandle(ActiveAnim, BlockHandle); + drag_animation_clip_state* OpState = CreateOperationState(DragAnimationClipMode, &State->Modes, drag_animation_clip_state); OpState->TimelineBounds = TimelineBounds; OpState->BlockHandle = BlockHandle; OpState->VisibleRange = VisibleRange; - - animation_block* SelectedBlock = Animation_GetBlockFromHandle(ActiveAnim, BlockHandle); OpState->ClipRange = SelectedBlock->Range; } // ------------------- @@ -303,10 +303,7 @@ 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)) + if (ui_MouseClickedRect(Interface, BarBounds)) { StartDragTimeMarker(BarBounds, VisibleFrames, State); } @@ -590,13 +587,12 @@ 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_PushLayout(Interface, Layout); + ui_PushLayout(Interface, PanelBounds, LayoutDirection_TopDown); for (s32 i = 0; i < GlobalAnimationClipsCount; i++) { animation_clip Clip = GlobalAnimationClips[i]; gs_string ClipName = MakeString(Clip.Name, Clip.NameLength); - if (ui_LayoutListEntry(Interface, &Layout, ClipName, i)) + if (ui_LayoutListButton(Interface, ClipName, i)) { AddAnimationBlockAtCurrentTime(i + 1, SelectedAnimationLayerHandle, AnimationSystem); } @@ -609,8 +605,7 @@ 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_PushLayout(Interface, Layout); + ui_PushLayout(Interface, Bounds, LayoutDirection_TopDown); ui_FillRect(Interface, Bounds, Interface->Style.PanelBGColors[0]); ui_StartRow(&State->Interface, 4); @@ -797,8 +792,7 @@ AnimInfoView_Render(animation_timeline_state* TimelineState, rect2 Bounds, rende animation* ActiveAnim = AnimationSystem_GetActiveAnimation(AnimSystem); ui_interface* Interface = &State->Interface; - ui_layout Layout = ui_CreateLayout(Interface, Bounds); - ui_PushLayout(Interface, Layout); + ui_PushLayout(Interface, Bounds, LayoutDirection_TopDown); ui_FillRect(&State->Interface, Bounds, Interface->Style.PanelBGColors[0]); diff --git a/src/app/editor/panels/foldhaus_panel_file_view.h b/src/app/editor/panels/foldhaus_panel_file_view.h index f4427c0..b80ba25 100644 --- a/src/app/editor/panels/foldhaus_panel_file_view.h +++ b/src/app/editor/panels/foldhaus_panel_file_view.h @@ -88,8 +88,7 @@ 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_PushLayout(&State->Interface, Layout); + ui_PushLayout(&State->Interface, PanelBounds, LayoutDirection_TopDown); if (ui_Button(&State->Interface, MakeString("Exit"))) { @@ -108,7 +107,7 @@ FileView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBu gs_const_string FileName = Substring(File.Path, LastSlashIndex + 1, File.Path.Length); gs_string PathString = PushString(State->Transient, FileName.Length); PrintF(&PathString, "%S", FileName); - if (ui_LayoutListButton(&State->Interface, &Layout, PathString, i)) + if (ui_LayoutListButton(&State->Interface, PathString, i)) { if (File.IsDirectory) { diff --git a/src/app/editor/panels/foldhaus_panel_hierarchy.h b/src/app/editor/panels/foldhaus_panel_hierarchy.h index 54b6b8c..d110e17 100644 --- a/src/app/editor/panels/foldhaus_panel_hierarchy.h +++ b/src/app/editor/panels/foldhaus_panel_hierarchy.h @@ -38,18 +38,21 @@ 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_PushLayout(&State->Interface, Layout); + ui_PushLayout(&State->Interface, PanelBounds, LayoutDirection_TopDown); + // TODO(pjs): Come back to this after the layout stuff is handled. + // Ideally it handles the visuals of the hierarchy itself. + +#if 0 gs_string TempString = PushString(State->Transient, 256); - u32 LineCount = (u32)(Rect2Height(PanelBounds) / Layout.RowHeight) + 1; + u32 LineCount = (u32)(Rect2Height(PanelBounds) / Layout->RowHeight) + 1; u32 AssembliesToDraw = Min(LineCount, State->Assemblies.Count); rect2* LineBounds = PushArray(State->Transient, rect2, LineCount); // Fill in alternating color rows for the backgrounds for (u32 Line = 0; Line < LineCount; Line++) { - LineBounds[Line] = ui_ReserveElementBounds(&Layout); + //LineBounds[Line] = ui_ReserveElementBounds(Layout); v4 ListItemBGColor = ui_GetListItemBGColor(State->Interface.Style, Line); ui_FillRect(&State->Interface, LineBounds[Line], ListItemBGColor); } @@ -62,7 +65,7 @@ HierarchyView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Ren ui_StartRow(&State->Interface, 2); { ui_DrawString(&State->Interface, TempString); - if (ui_LayoutListButton(&State->Interface, &Layout, MakeString("X"), AssemblyIndex)) + if (ui_LayoutListButton(&State->Interface, MakeString("X"), AssemblyIndex)) { UnloadAssembly(AssemblyIndex, State, Context); } @@ -80,6 +83,7 @@ HierarchyView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Ren Panel_PushModalOverride(Panel, FileBrowser, LoadAssemblyCallback); } } +#endif 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 0f38547..7cdf042 100644 --- a/src/app/editor/panels/foldhaus_panel_profiler.h +++ b/src/app/editor/panels/foldhaus_panel_profiler.h @@ -25,7 +25,7 @@ ProfilerView_Cleanup(panel* Panel, app_state* State) } internal void -RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_layout Layout, debug_frame* VisibleFrame, gs_memory_arena* Memory) +RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_widget* Layout, debug_frame* VisibleFrame, gs_memory_arena* Memory) { v4 ThreadColors[] = { v4{.73f, .33f, .83f, 1}, @@ -35,7 +35,7 @@ RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_layout Layout, deb v4{.74f, .40f, .25f, 1}, }; - rect2 Bounds = ui_LayoutRemaining(Layout); + rect2 Bounds = ui_LayoutRemaining(*Layout); r32 Width = Rect2Width(Bounds); r32 DepthHeight = 64; @@ -89,7 +89,7 @@ RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_layout Layout, deb } internal void -RenderProfiler_ListVisualization(ui_interface* Interface, ui_layout Layout, debug_frame* VisibleFrame, gs_memory_arena* Memory) +RenderProfiler_ListVisualization(ui_interface* Interface, ui_widget* Layout, debug_frame* VisibleFrame, gs_memory_arena* Memory) { char Backbuffer[256]; gs_string String = MakeString(Backbuffer, 0, 256); @@ -179,8 +179,7 @@ ProfilerView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Rend debug_frame* VisibleFrame = GetLastDebugFrame(GlobalDebugServices); - ui_layout Layout = ui_CreateLayout(&State->Interface, ProcListBounds); - ui_PushLayout(&State->Interface, Layout); + ui_widget* Layout = ui_PushLayout(&State->Interface, ProcListBounds, LayoutDirection_TopDown); ui_StartRow(&State->Interface, 4); { @@ -195,7 +194,7 @@ ProfilerView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Rend // NOTE(NAME): Skipping a space for aesthetic reasons, not functional, and could // be removed, or used for something else - ui_ReserveElementBounds(&Layout); + ui_ReserveElementBounds(Layout); if (ui_Button(&State->Interface, MakeString("Resume Recording"))) { diff --git a/src/app/interface.h b/src/app/interface.h index d390069..6509468 100644 --- a/src/app/interface.h +++ b/src/app/interface.h @@ -194,14 +194,21 @@ DrawStringWithCursor (render_command_buffer* RenderBuffer, gs_string String, s32 enum ui_widget_flag { UIWidgetFlag_DrawBackground, + UIWidgetFlag_DrawString, UIWidgetFlag_DrawOutline, UIWidgetFlag_Clickable, }; struct ui_widget_id { - u64 Index; - u64 LayoutId; + u64 Id; + u64 ParentId; +}; + +enum ui_layout_direction +{ + LayoutDirection_TopDown, + LayoutDirection_BottomUp, }; struct ui_widget @@ -213,7 +220,31 @@ struct ui_widget rect2 Bounds; u64 Flags; - bool RetainedState; + + ui_widget* Next; + + // Layout + ui_widget* Parent; + + 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; + + ui_widget* ChildrenRoot; + ui_widget* ChildrenHead; + u32 ChildCount; }; struct ui_eval_result @@ -241,34 +272,6 @@ 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; @@ -285,13 +288,13 @@ struct ui_interface u64 WidgetsCount; u64 WidgetsCountMax; + ui_widget* DrawOrderHead; + ui_widget* DrawOrderRoot; + ui_widget_id HotWidget; ui_widget_id ActiveWidget; -#define LAYOUT_COUNT_MAX 8 - ui_layout LayoutStack[LAYOUT_COUNT_MAX]; - u64 LayoutStackCount; - u64 LayoutIdAcc; + ui_widget* ActiveLayout; #define RETAINED_STATE_MAX 128 ui_widget_retained_state RetainedState[RETAINED_STATE_MAX]; @@ -302,14 +305,14 @@ internal void ui_InterfaceReset(ui_interface* Interface) { Interface->WidgetsCount = 0; - Interface->LayoutStackCount = 0; - Interface->LayoutIdAcc = 0; + Interface->DrawOrderHead = 0; + Interface->DrawOrderRoot = 0; } internal bool ui_WidgetIdsEqual(ui_widget_id A, ui_widget_id B) { - bool Result = (A.Index == B.Index) && (A.LayoutId == B.LayoutId); + bool Result = (A.Id == B.Id) && (A.ParentId == B.ParentId); return Result; } @@ -337,6 +340,30 @@ ui_CreateRetainedState(ui_interface* Interface, ui_widget_id Id) return Result; } +internal ui_widget* +ui_CreateWidget(ui_interface* Interface, gs_string String) +{ + Assert(Interface->WidgetsCount < Interface->WidgetsCountMax); + ui_widget* Result = Interface->Widgets + Interface->WidgetsCount++; + Result->Parent = Interface->ActiveLayout; + + u64 Id = HashDJB2ToU64(StringExpand(String)); + if (Result->Parent) + { + Id = HashAppendDJB2ToU32(Id, Result->Parent->Id.Id); + Id = HashAppendDJB2ToU32(Id, Result->Parent->ChildCount); + } + Result->Id.Id = Id; + + Result->String = String; + Result->Alignment = Align_Left; + Result->Next = 0; + Result->ChildrenRoot = 0; + Result->ChildrenHead = 0; + Result->Flags = 0; + return Result; +} + // // Interaction // @@ -351,94 +378,95 @@ ui_MouseClickedRect(ui_interface Interface, rect2 Rect) // Layout -static ui_layout -ui_CreateLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDirection = LayoutDirection_TopDown) +static ui_widget* +ui_PushLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir) { - ui_layout Result = {0}; - Result.Bounds = Bounds; - Result.Margin = Interface->Style.Margin; - Result.RowHeight = Interface->Style.RowHeight; - Result.FillDirection = FillDirection; - switch(FillDirection) + ui_widget* Result = ui_CreateWidget(Interface, MakeString("Layout")); + Result->Bounds = Bounds; + Result->Margin = Interface->Style.Margin; + Result->RowHeight = Interface->Style.RowHeight; + Result->FillDirection = FillDir; + switch(FillDir) { case LayoutDirection_BottomUp: { - Result.RowYAt = Bounds.Min.y; + Result->RowYAt = Bounds.Min.y; }break; case LayoutDirection_TopDown: { - Result.RowYAt = Bounds.Max.y - Result.RowHeight; + Result->RowYAt = Bounds.Max.y - Result->RowHeight; }break; } - Result.Id = ++Interface->LayoutIdAcc; - + if (Interface->DrawOrderRoot) + { + SLLPushOrInit(Interface->ActiveLayout->ChildrenRoot, Interface->ActiveLayout->ChildrenHead, Result); + Interface->ActiveLayout->ChildCount++; + } + else + { + SLLPushOrInit(Interface->DrawOrderRoot, Interface->DrawOrderHead, Result); + } + Interface->ActiveLayout = Result; return Result; } -static void -ui_PushLayout(ui_interface* Interface, ui_layout Layout) -{ - Assert(Interface->LayoutStackCount < LAYOUT_COUNT_MAX); - Interface->LayoutStack[Interface->LayoutStackCount++] = Layout; -} +internal ui_eval_result ui_EvaluateWidget(ui_interface* Interface, ui_widget* Widget, rect2 Bounds); static void ui_PopLayout(ui_interface* Interface) { - Assert(Interface->LayoutStackCount > 0); - Interface->LayoutStackCount -= 1; + Assert(Interface->ActiveLayout != 0); + ui_EvaluateWidget(Interface, Interface->ActiveLayout, Interface->ActiveLayout->Bounds); + Interface->ActiveLayout = Interface->ActiveLayout->Parent; } static void ui_StartRow(ui_interface* Interface, u32 ColumnsMax = 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; + Interface->ActiveLayout->DrawHorizontal = true; + Interface->ActiveLayout->ColumnsMax = ColumnsMax; + Interface->ActiveLayout->ColumnWidths = 0; + Interface->ActiveLayout->ColumnsCount = 0; } static void ui_StartRow(ui_interface* Interface, u32 ColumnsMax, r32* ColumnWidths) { - 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; + Interface->ActiveLayout->DrawHorizontal = true; + Interface->ActiveLayout->ColumnsMax = ColumnsMax; + Interface->ActiveLayout->ColumnWidths = ColumnWidths; + Interface->ActiveLayout->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; + Interface->ActiveLayout->DrawHorizontal = false; + Interface->ActiveLayout->ColumnWidths = 0; + Interface->ActiveLayout->RowYAt -= Interface->ActiveLayout->RowHeight; } static b32 -ui_TryReserveElementBounds(ui_layout* Layout, rect2* Bounds) +ui_TryReserveElementBounds(ui_widget* Widget, rect2* Bounds) { b32 Result = true; - if (!Layout->DrawHorizontal) + if (!Widget->DrawHorizontal) { - Bounds->Min = { Layout->Bounds.Min.x, Layout->RowYAt }; - Bounds->Max = { Layout->Bounds.Max.x, Bounds->Min.y + Layout->RowHeight }; + Bounds->Min = { Widget->Bounds.Min.x, Widget->RowYAt }; + Bounds->Max = { Widget->Bounds.Max.x, Bounds->Min.y + Widget->RowHeight }; - switch (Layout->FillDirection) + switch (Widget->FillDirection) { case LayoutDirection_BottomUp: { - Layout->RowYAt += Layout->RowHeight; + Widget->RowYAt += Widget->RowHeight; }break; case LayoutDirection_TopDown: { - Layout->RowYAt -= Layout->RowHeight; + Widget->RowYAt -= Widget->RowHeight; }break; InvalidDefaultCase; @@ -446,32 +474,32 @@ ui_TryReserveElementBounds(ui_layout* Layout, rect2* Bounds) } else { - if (Layout->ColumnsMax > 0) + if (Widget->ColumnsMax > 0) { - Assert(Layout->ColumnsCount < Layout->ColumnsMax); - if (Layout->ColumnWidths != 0) + Assert(Widget->ColumnsCount < Widget->ColumnsMax); + if (Widget->ColumnWidths != 0) { - v2 Min = { Layout->Bounds.Min.x, Layout->RowYAt }; - for (u32 i = 0; i < Layout->ColumnsCount; i++) + v2 Min = { Widget->Bounds.Min.x, Widget->RowYAt }; + for (u32 i = 0; i < Widget->ColumnsCount; i++) { - Min.x += Layout->ColumnWidths[i]; + Min.x += Widget->ColumnWidths[i]; } Bounds->Min = Min; - Bounds->Max = Bounds->Min + v2{ Layout->ColumnWidths[Layout->ColumnsCount], Layout->RowHeight }; + Bounds->Max = Bounds->Min + v2{ Widget->ColumnWidths[Widget->ColumnsCount], Widget->RowHeight }; } else { - r32 ElementWidth = Rect2Width(Layout->Bounds) / Layout->ColumnsMax; + r32 ElementWidth = Rect2Width(Widget->Bounds) / Widget->ColumnsMax; Bounds->Min = { - Layout->Bounds.Min.x + (ElementWidth * Layout->ColumnsCount) + Layout->Margin.x, - Layout->RowYAt + Widget->Bounds.Min.x + (ElementWidth * Widget->ColumnsCount) + Widget->Margin.x, + Widget->RowYAt }; Bounds->Max = { - Bounds->Min.x + ElementWidth - Layout->Margin.x, - Bounds->Min.y + Layout->RowHeight + Bounds->Min.x + ElementWidth - Widget->Margin.x, + Bounds->Min.y + Widget->RowHeight }; } - Layout->ColumnsCount++; + Widget->ColumnsCount++; } else { @@ -482,7 +510,7 @@ ui_TryReserveElementBounds(ui_layout* Layout, rect2* Bounds) } static rect2 -ui_ReserveElementBounds(ui_layout* Layout) +ui_ReserveElementBounds(ui_widget* Layout) { rect2 Bounds = {0}; if (!ui_TryReserveElementBounds(Layout, &Bounds)) @@ -493,7 +521,7 @@ ui_ReserveElementBounds(ui_layout* Layout) } static rect2 -ui_LayoutRemaining(ui_layout Layout) +ui_LayoutRemaining(ui_widget Layout) { rect2 Result = Layout.Bounds; Result.Max.y = Layout.RowYAt; @@ -506,15 +534,6 @@ ui_LayoutRemaining(ui_layout Layout) // Widgets -internal ui_widget -ui_CreateWidget(gs_string String) -{ - ui_widget Result = {}; - Result.String = String; - Result.Alignment = Align_Left; - return Result; -} - internal void ui_WidgetSetFlag(ui_widget* Widget, u64 Flag) { @@ -535,12 +554,15 @@ 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; + //Assert(Interface->WidgetsCount < Interface->WidgetsCountMax); + //u64 Index = Interface->WidgetsCount++; + + Widget->Id.Id = HashDJB2ToU64(StringExpand(Widget->String)); + Widget->Id.ParentId = Interface->ActiveLayout->Id.Id; Widget->Bounds = Bounds; - Interface->Widgets[Widget->Id.Index] = *Widget; + //Interface->Widgets[Index] = *Widget; + SLLPushOrInit(Interface->ActiveLayout->ChildrenRoot, Interface->ActiveLayout->ChildrenHead, Widget); if (ui_WidgetIsFlagSet(*Widget, UIWidgetFlag_Clickable)) { @@ -569,7 +591,7 @@ internal ui_eval_result ui_EvaluateWidget(ui_interface* Interface, ui_widget* Widget) { rect2 Bounds = {0}; - ui_layout* Layout = Interface->LayoutStack + Interface->LayoutStackCount - 1; + ui_widget* Layout = Interface->ActiveLayout; if (!ui_TryReserveElementBounds(Layout, &Bounds)) { // TODO(pjs): This isn't invalid, but Idk when we'd hit this case yet @@ -606,36 +628,38 @@ internal void ui_DrawString(ui_interface* Interface, gs_string String, rect2 Bounds, gs_string_alignment Alignment = Align_Left) { DEBUG_TRACK_FUNCTION; - ui_widget Widget = ui_CreateWidget(String); - Widget.Bounds = Bounds; - ui_EvaluateWidget(Interface, &Widget); + ui_widget* Widget = ui_CreateWidget(Interface, String); + Widget->Bounds = Bounds; + ui_EvaluateWidget(Interface, Widget); } internal void ui_DrawString(ui_interface* Interface, gs_string String, gs_string_alignment Alignment = Align_Left) { DEBUG_TRACK_FUNCTION; - ui_widget Widget = ui_CreateWidget(String); - ui_EvaluateWidget(Interface, &Widget); + ui_widget* Widget = ui_CreateWidget(Interface, String); + ui_EvaluateWidget(Interface, Widget); } static b32 ui_Button(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); + ui_widget* Widget = ui_CreateWidget(Interface, Text); + ui_WidgetSetFlag(Widget, UIWidgetFlag_Clickable); + ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawBackground); + ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawString); + ui_eval_result Result = ui_EvaluateWidget(Interface, Widget); return Result.Clicked; } static b32 ui_Button(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); + ui_widget* Widget = ui_CreateWidget(Interface, Text); + ui_WidgetSetFlag(Widget, UIWidgetFlag_Clickable); + ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawBackground); + ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawString); + ui_eval_result Result = ui_EvaluateWidget(Interface, Widget, Bounds); return Result.Clicked; } @@ -666,42 +690,28 @@ ui_GetListItemColors(ui_interface* Interface, u32 ListItemIndex) static b32 ui_ListButton(ui_interface* Interface, gs_string Text, rect2 Bounds, u32 ListItemIndex) { - ui_widget Widget = ui_CreateWidget(Text); - ui_WidgetSetFlag(&Widget, UIWidgetFlag_DrawBackground); - ui_WidgetSetFlag(&Widget, UIWidgetFlag_Clickable); + ui_widget* Widget = ui_CreateWidget(Interface, 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); + 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) +ui_LayoutListButton(ui_interface* Interface, gs_string Text, u32 ListItemIndex) { + // TODO(pjs): Reimplement alternating colors return ui_Button(Interface, Text); } -static b32 -ui_LayoutListEntry(ui_interface* Interface, ui_layout* Layout, gs_string Text, u32 Index) -{ - rect2 Bounds = {0}; - if (!ui_TryReserveElementBounds(Layout, &Bounds)) - { - // TODO(Peter): this isn't really invalid, but I don't have a concrete use case - // for it yet. This should only fire if the Layout component is drawing a row, - // but if you're in row mode during a list, what should happen? - // Punting this till I have a use case - InvalidCodePath; - } - return ui_Button(Interface, Text, Bounds); -} - internal bool -ui_EvaluateDropdown(ui_interface* Interface, ui_widget Widget, ui_eval_result EvalResult) +ui_EvaluateDropdown(ui_interface* Interface, ui_widget* Widget, ui_eval_result EvalResult) { - ui_widget_retained_state* State = ui_GetRetainedState(Interface, Widget.Id); + ui_widget_retained_state* State = ui_GetRetainedState(Interface, Widget->Id); if (!State) { - State = ui_CreateRetainedState(Interface, Widget.Id); + State = ui_CreateRetainedState(Interface, Widget->Id); } if (EvalResult.Clicked) @@ -711,10 +721,10 @@ ui_EvaluateDropdown(ui_interface* Interface, ui_widget Widget, ui_eval_result Ev if (State->Value) { - ui_layout ParentLayout = Interface->LayoutStack[Interface->LayoutStackCount - 1]; + ui_widget ParentLayout = *Interface->ActiveLayout; - r32 SpaceAbove = ParentLayout.Bounds.Max.y - Widget.Bounds.Max.y; - r32 SpaceBelow = Widget.Bounds.Min.y - ParentLayout.Bounds.Min.y; + 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 = {}; @@ -723,8 +733,8 @@ ui_EvaluateDropdown(ui_interface* Interface, ui_widget Widget, ui_eval_result Ev 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 } + v2{ Widget->Bounds.Min.x, Widget->Bounds.Max.y }, + v2{ Widget->Bounds.Max.x, ParentLayoutMaxY } }; } else @@ -732,14 +742,13 @@ ui_EvaluateDropdown(ui_interface* Interface, ui_widget Widget, ui_eval_result Ev 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 } + 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); + ui_widget* Layout = ui_PushLayout(Interface, MenuBounds, Direction); + Layout->WidgetReference = Widget->Id; } return State->Value; @@ -748,28 +757,28 @@ ui_EvaluateDropdown(ui_interface* Interface, ui_widget Widget, ui_eval_result Ev 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); + ui_widget* Widget = ui_CreateWidget(Interface, 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); + ui_widget* Widget = ui_CreateWidget(Interface, 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); + ui_widget* Layout = Interface->ActiveLayout; + ui_widget_retained_state* State = ui_GetRetainedState(Interface, Layout->WidgetReference); if (State) { if (State->Value) diff --git a/src/gs_libs/gs_types.cpp b/src/gs_libs/gs_types.cpp index 05467cc..a42bdae 100644 --- a/src/gs_libs/gs_types.cpp +++ b/src/gs_libs/gs_types.cpp @@ -3111,6 +3111,24 @@ TimeHandlerGetSecondsElapsed(gs_time_handler TimeHandler, s64 StartCycles, s64 E // // Hashes +internal u32 +HashAppendDJB2ToU32(u32 Hash, u8 Byte) +{ + u32 Result = Hash; + if (Result == 0) { Result = 5381; } + Result = ((Result << 5) + Result) + Byte; + return Result; +} + +internal u64 +HashAppendDJB2ToU32(u64 Hash, u8 Byte) +{ + u64 Result = Hash; + if (Result == 0) { Result = 5381; } + Result = ((Result << 5) + Result) + Byte; + return Result; +} + internal u32 HashDJB2ToU32(char* String) { From 30123e47a2fb371c32a2a3926175457a32a1a91b Mon Sep 17 00:00:00 2001 From: PS Date: Sat, 14 Nov 2020 17:18:38 -0800 Subject: [PATCH 02/44] fixed some problems with ui retained states --- src/app/editor/foldhaus_editor.cpp | 53 ++++++++----- src/app/editor/foldhaus_interface.cpp | 3 +- .../foldhaus_panel_animation_timeline.h | 6 +- .../editor/panels/foldhaus_panel_file_view.h | 2 +- .../editor/panels/foldhaus_panel_hierarchy.h | 2 +- .../editor/panels/foldhaus_panel_profiler.h | 2 +- src/app/foldhaus_app.cpp | 3 +- src/app/interface.h | 76 +++++++++++-------- src/app/platform_win32/win32_foldhaus.cpp | 6 +- .../win32_foldhaus_work_queue.h | 2 + src/gs_libs/gs_types.cpp | 25 ++++-- src/todo.txt | 1 - src/todo_done.txt | 2 + 13 files changed, 120 insertions(+), 63 deletions(-) diff --git a/src/app/editor/foldhaus_editor.cpp b/src/app/editor/foldhaus_editor.cpp index ecef055..cd3e5f5 100644 --- a/src/app/editor/foldhaus_editor.cpp +++ b/src/app/editor/foldhaus_editor.cpp @@ -105,7 +105,7 @@ Editor_DrawWidget(app_state* State, context* Context, render_command_buffer* Ren PushRenderQuad2D(RenderBuffer, Widget.Bounds.Min, Widget.Bounds.Max, Color); } - if (Widget.String.Length > 0) + if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawString) && Widget.String.Length > 0) { v4 Color = State->Interface.Style.TextColor; render_quad_batch_constructor BatchConstructor = PushRenderTexture2DBatch(RenderBuffer, @@ -155,25 +155,22 @@ Editor_DrawWidget(app_state* State, context* Context, render_command_buffer* Ren } internal void -Editor_Render(app_state* State, context* Context, render_command_buffer* RenderBuffer) +TestRender(app_state* State, context* Context, render_command_buffer* RenderBuffer) { - PushRenderOrthographic(RenderBuffer, State->WindowBounds); - PushRenderClearScreen(RenderBuffer); - ui_InterfaceReset(&State->Interface); State->Interface.RenderBuffer = RenderBuffer; - ui_PushLayout(&State->Interface, Context->WindowBounds, LayoutDirection_TopDown); + ui_PushLayout(&State->Interface, Context->WindowBounds, LayoutDirection_TopDown, MakeString("TestRender Layout")); - rect2 Rects[2]; - RectVSplitAtPercent(Context->WindowBounds, .5f, &Rects[0], &Rects[1]); + ui_widget_id Ids[2]; + + gs_string String = MakeString("Select"); + ui_StartRow(&State->Interface, 2); for (u32 j = 0; j < 2; j++) { - ui_PushLayout(&State->Interface, Rects[j], LayoutDirection_TopDown); - - if (ui_BeginDropdown(&State->Interface, MakeString("Select"))) + if (ui_BeginDropdown(&State->Interface, String)) { - for (s32 i = 0; i < GlobalPanelDefsCount; i++) + for (u32 i = 0; i < State->PanelSystem.PanelDefsCount; i++) { panel_definition Def = State->PanelSystem.PanelDefs[i]; gs_string DefName = MakeString(Def.PanelName, Def.PanelNameLength); @@ -184,11 +181,30 @@ Editor_Render(app_state* State, context* Context, render_command_buffer* RenderB } } ui_EndDropdown(&State->Interface); - - ui_PopLayout(&State->Interface); } + ui_EndRow(&State->Interface); + + ui_PopLayout(&State->Interface); + + Assert(!ui_WidgetIdsEqual(Ids[0], Ids[1])); +} + +internal void +Editor_Render(app_state* State, context* Context, render_command_buffer* RenderBuffer) +{ + PushRenderOrthographic(RenderBuffer, State->WindowBounds); + PushRenderClearScreen(RenderBuffer); #if 0 + TestRender(State, Context, RenderBuffer); + //ui_widget_id IdTwo = TestRender(State, Context, RenderBuffer); + //Assert(ui_WidgetIdsEqual(IdOne, IdTwo)); + +#else + ui_InterfaceReset(&State->Interface); + State->Interface.RenderBuffer = RenderBuffer; + ui_PushLayout(&State->Interface, Context->WindowBounds, LayoutDirection_TopDown, MakeString("Editor Layout")); + DrawAllPanels(State->PanelSystem, RenderBuffer, &Context->Mouse, State, *Context); for (s32 m = 0; m < State->Modes.ActiveModesCount; m++) @@ -199,13 +215,16 @@ Editor_Render(app_state* State, context* Context, render_command_buffer* RenderB OperationMode.Render(State, RenderBuffer, OperationMode, Context->Mouse, *Context); } } -#endif ui_PopLayout(&State->Interface); +#endif // Draw the Interface - ui_widget Widget = *State->Interface.DrawOrderRoot; - Editor_DrawWidget(State, Context, RenderBuffer, Widget); + if (State->Interface.DrawOrderRoot != 0) + { + ui_widget Widget = *State->Interface.DrawOrderRoot; + Editor_DrawWidget(State, Context, RenderBuffer, Widget); + } 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 7a83912..29258ec 100644 --- a/src/app/editor/foldhaus_interface.cpp +++ b/src/app/editor/foldhaus_interface.cpp @@ -386,7 +386,8 @@ DrawPanelFooter(panel* Panel, render_command_buffer* RenderBuffer, rect2 FooterB rect2 PanelSelectBtnBounds = MakeRect2MinDim(FooterBounds.Min + v2{30, 1}, v2{100, 23}); - if (ui_BeginDropdown(&State->Interface, MakeString("Select"), PanelSelectBtnBounds)) + panel_definition CurrentDef = State->PanelSystem.PanelDefs[Panel->TypeIndex]; + if (ui_BeginDropdown(&State->Interface, MakeString(CurrentDef.PanelName, CurrentDef.PanelNameLength), PanelSelectBtnBounds)) { for (s32 i = 0; i < GlobalPanelDefsCount; i++) { diff --git a/src/app/editor/panels/foldhaus_panel_animation_timeline.h b/src/app/editor/panels/foldhaus_panel_animation_timeline.h index 1bd2d16..253f42e 100644 --- a/src/app/editor/panels/foldhaus_panel_animation_timeline.h +++ b/src/app/editor/panels/foldhaus_panel_animation_timeline.h @@ -587,7 +587,7 @@ PANEL_MODAL_OVERRIDE_CALLBACK(LoadAnimationFileCallback) internal void DrawAnimationClipsList(rect2 PanelBounds, ui_interface* Interface, u32 SelectedAnimationLayerHandle, animation_system* AnimationSystem) { - ui_PushLayout(Interface, PanelBounds, LayoutDirection_TopDown); + ui_PushLayout(Interface, PanelBounds, LayoutDirection_TopDown, MakeString("AnimClips Layout")); for (s32 i = 0; i < GlobalAnimationClipsCount; i++) { animation_clip Clip = GlobalAnimationClips[i]; @@ -605,7 +605,7 @@ PlayBar_Render(animation_timeline_state* TimelineState, rect2 Bounds, panel* Pan { animation_system* AnimSystem = &State->AnimationSystem; ui_interface* Interface = &State->Interface; - ui_PushLayout(Interface, Bounds, LayoutDirection_TopDown); + ui_PushLayout(Interface, Bounds, LayoutDirection_TopDown, MakeString("PlayBar Layout")); ui_FillRect(Interface, Bounds, Interface->Style.PanelBGColors[0]); ui_StartRow(&State->Interface, 4); @@ -792,7 +792,7 @@ AnimInfoView_Render(animation_timeline_state* TimelineState, rect2 Bounds, rende animation* ActiveAnim = AnimationSystem_GetActiveAnimation(AnimSystem); ui_interface* Interface = &State->Interface; - ui_PushLayout(Interface, Bounds, LayoutDirection_TopDown); + ui_PushLayout(Interface, Bounds, LayoutDirection_TopDown, MakeString("AnimInfo Layout")); ui_FillRect(&State->Interface, Bounds, Interface->Style.PanelBGColors[0]); diff --git a/src/app/editor/panels/foldhaus_panel_file_view.h b/src/app/editor/panels/foldhaus_panel_file_view.h index b80ba25..fdf8b54 100644 --- a/src/app/editor/panels/foldhaus_panel_file_view.h +++ b/src/app/editor/panels/foldhaus_panel_file_view.h @@ -88,7 +88,7 @@ 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_PushLayout(&State->Interface, PanelBounds, LayoutDirection_TopDown); + ui_PushLayout(&State->Interface, PanelBounds, LayoutDirection_TopDown, MakeString("FileView Layout")); if (ui_Button(&State->Interface, MakeString("Exit"))) { diff --git a/src/app/editor/panels/foldhaus_panel_hierarchy.h b/src/app/editor/panels/foldhaus_panel_hierarchy.h index d110e17..12c9fc2 100644 --- a/src/app/editor/panels/foldhaus_panel_hierarchy.h +++ b/src/app/editor/panels/foldhaus_panel_hierarchy.h @@ -38,7 +38,7 @@ GSMetaTag(panel_type_hierarchy); internal void HierarchyView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context) { - ui_PushLayout(&State->Interface, PanelBounds, LayoutDirection_TopDown); + ui_PushLayout(&State->Interface, PanelBounds, LayoutDirection_TopDown, MakeString("Hierarchy Layout")); // TODO(pjs): Come back to this after the layout stuff is handled. // Ideally it handles the visuals of the hierarchy itself. diff --git a/src/app/editor/panels/foldhaus_panel_profiler.h b/src/app/editor/panels/foldhaus_panel_profiler.h index 7cdf042..d58b3fb 100644 --- a/src/app/editor/panels/foldhaus_panel_profiler.h +++ b/src/app/editor/panels/foldhaus_panel_profiler.h @@ -179,7 +179,7 @@ ProfilerView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Rend debug_frame* VisibleFrame = GetLastDebugFrame(GlobalDebugServices); - ui_widget* Layout = ui_PushLayout(&State->Interface, ProcListBounds, LayoutDirection_TopDown); + ui_widget* Layout = ui_PushLayout(&State->Interface, ProcListBounds, LayoutDirection_TopDown, MakeString("Profiler Layout")); ui_StartRow(&State->Interface, 4); { diff --git a/src/app/foldhaus_app.cpp b/src/app/foldhaus_app.cpp index f3038f6..90ce10b 100644 --- a/src/app/foldhaus_app.cpp +++ b/src/app/foldhaus_app.cpp @@ -110,6 +110,8 @@ INITIALIZE_APPLICATION(InitializeApplication) State->Interface.WidgetsCountMax = 4096; State->Interface.Widgets = PushArray(&State->Permanent, ui_widget, State->Interface.WidgetsCountMax); + State->Interface.PerFrameMemory = PushStruct(&State->Permanent, gs_memory_arena); + *State->Interface.PerFrameMemory = CreateMemoryArena(Context.ThreadContext.Allocator); State->SACN = SACN_Initialize(Context); @@ -150,7 +152,6 @@ INITIALIZE_APPLICATION(InitializeApplication) AnimationArray_Push(&State->AnimationSystem.Animations, Anim); } // End Animation Playground - PanelSystem_Init(&State->PanelSystem, GlobalPanelDefs, GlobalPanelDefsCount, &State->Permanent); PanelSystem_PushPanel(&State->PanelSystem, PanelType_SculptureView, State, Context); } diff --git a/src/app/interface.h b/src/app/interface.h index 6509468..80b3ada 100644 --- a/src/app/interface.h +++ b/src/app/interface.h @@ -276,6 +276,7 @@ struct ui_widget_retained_state { ui_widget_id Id; bool Value; + u32 FramesSinceAccess; }; struct ui_interface @@ -299,6 +300,8 @@ struct ui_interface #define RETAINED_STATE_MAX 128 ui_widget_retained_state RetainedState[RETAINED_STATE_MAX]; u64 RetainedStateCount; + + gs_memory_arena* PerFrameMemory; }; internal void @@ -307,6 +310,16 @@ ui_InterfaceReset(ui_interface* Interface) Interface->WidgetsCount = 0; Interface->DrawOrderHead = 0; Interface->DrawOrderRoot = 0; + ClearArena(Interface->PerFrameMemory); + + for (u32 i = 0; i < Interface->RetainedStateCount; i++) + { + Interface->RetainedState[i].FramesSinceAccess += 1; + if (Interface->RetainedState[i].FramesSinceAccess > 1) + { + Interface->RetainedState[i] = {0}; + } + } } internal bool @@ -324,6 +337,7 @@ ui_GetRetainedState(ui_interface* Interface, ui_widget_id Id) { if (ui_WidgetIdsEqual(Interface->RetainedState[i].Id, Id)) { + Interface->RetainedState[i].FramesSinceAccess = 0; Result = Interface->RetainedState + i; break; } @@ -332,11 +346,11 @@ ui_GetRetainedState(ui_interface* Interface, ui_widget_id Id) } internal ui_widget_retained_state* -ui_CreateRetainedState(ui_interface* Interface, ui_widget_id Id) +ui_CreateRetainedState(ui_interface* Interface, ui_widget* Widget) { u64 Index = Interface->RetainedStateCount++; ui_widget_retained_state* Result = Interface->RetainedState + Index; - Result->Id = Id; + Result->Id = Widget->Id; return Result; } @@ -345,6 +359,8 @@ ui_CreateWidget(ui_interface* Interface, gs_string String) { Assert(Interface->WidgetsCount < Interface->WidgetsCountMax); ui_widget* Result = Interface->Widgets + Interface->WidgetsCount++; + ZeroStruct(Result); + Result->Parent = Interface->ActiveLayout; u64 Id = HashDJB2ToU64(StringExpand(String)); @@ -352,10 +368,11 @@ ui_CreateWidget(ui_interface* Interface, gs_string String) { Id = HashAppendDJB2ToU32(Id, Result->Parent->Id.Id); Id = HashAppendDJB2ToU32(Id, Result->Parent->ChildCount); + Result->Id.ParentId = Result->Parent->Id.Id; } Result->Id.Id = Id; - Result->String = String; + Result->String = PushStringCopy(Interface->PerFrameMemory, String.ConstString); Result->Alignment = Align_Left; Result->Next = 0; Result->ChildrenRoot = 0; @@ -364,6 +381,21 @@ ui_CreateWidget(ui_interface* Interface, gs_string String) 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; +} + // // Interaction // @@ -379,13 +411,16 @@ ui_MouseClickedRect(ui_interface Interface, rect2 Rect) // Layout static ui_widget* -ui_PushLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir) +ui_PushLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir, gs_string Name) { - ui_widget* Result = ui_CreateWidget(Interface, MakeString("Layout")); + ui_widget* Result = ui_CreateWidget(Interface, Name); + ui_WidgetSetFlag(Result, UIWidgetFlag_DrawOutline); + Result->Bounds = Bounds; Result->Margin = Interface->Style.Margin; Result->RowHeight = Interface->Style.RowHeight; Result->FillDirection = FillDir; + switch(FillDir) { case LayoutDirection_BottomUp: @@ -418,7 +453,7 @@ static void ui_PopLayout(ui_interface* Interface) { Assert(Interface->ActiveLayout != 0); - ui_EvaluateWidget(Interface, Interface->ActiveLayout, Interface->ActiveLayout->Bounds); + //ui_EvaluateWidget(Interface, Interface->ActiveLayout, Interface->ActiveLayout->Bounds); Interface->ActiveLayout = Interface->ActiveLayout->Parent; } @@ -534,35 +569,14 @@ ui_LayoutRemaining(ui_widget Layout) // Widgets -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); - //u64 Index = Interface->WidgetsCount++; - - Widget->Id.Id = HashDJB2ToU64(StringExpand(Widget->String)); - Widget->Id.ParentId = Interface->ActiveLayout->Id.Id; - Widget->Bounds = Bounds; - //Interface->Widgets[Index] = *Widget; SLLPushOrInit(Interface->ActiveLayout->ChildrenRoot, Interface->ActiveLayout->ChildrenHead, Widget); + Interface->ActiveLayout->ChildCount += 1; if (ui_WidgetIsFlagSet(*Widget, UIWidgetFlag_Clickable)) { @@ -711,7 +725,7 @@ ui_EvaluateDropdown(ui_interface* Interface, ui_widget* Widget, ui_eval_result E { ui_widget_retained_state* State = ui_GetRetainedState(Interface, Widget->Id); if (!State) { - State = ui_CreateRetainedState(Interface, Widget->Id); + State = ui_CreateRetainedState(Interface, Widget); } if (EvalResult.Clicked) @@ -747,7 +761,7 @@ ui_EvaluateDropdown(ui_interface* Interface, ui_widget* Widget, ui_eval_result E }; } - ui_widget* Layout = ui_PushLayout(Interface, MenuBounds, Direction); + ui_widget* Layout = ui_PushLayout(Interface, MenuBounds, Direction, MakeString("WidgetLayout")); Layout->WidgetReference = Widget->Id; } @@ -760,6 +774,7 @@ ui_BeginDropdown(ui_interface* Interface, gs_string Text, rect2 Bounds) ui_widget* Widget = ui_CreateWidget(Interface, Text); ui_WidgetSetFlag(Widget, UIWidgetFlag_Clickable); ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawBackground); + ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawString); ui_eval_result Result = ui_EvaluateWidget(Interface, Widget, Bounds); return ui_EvaluateDropdown(Interface, Widget, Result); } @@ -770,6 +785,7 @@ ui_BeginDropdown(ui_interface* Interface, gs_string Text) ui_widget* Widget = ui_CreateWidget(Interface, Text); ui_WidgetSetFlag(Widget, UIWidgetFlag_Clickable); ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawBackground); + ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawString); ui_eval_result Result = ui_EvaluateWidget(Interface, Widget); return ui_EvaluateDropdown(Interface, Widget, Result); } diff --git a/src/app/platform_win32/win32_foldhaus.cpp b/src/app/platform_win32/win32_foldhaus.cpp index 653dbe6..1d2bb65 100644 --- a/src/app/platform_win32/win32_foldhaus.cpp +++ b/src/app/platform_win32/win32_foldhaus.cpp @@ -413,7 +413,7 @@ Win32_SendAddressedDataBuffers(gs_thread_context Context, addressed_data_buffer_ gs_string OutputStr = AllocatorAllocString(Context.Allocator, 256); PrintF(&OutputStr, "Buffers Sent: %d\n", BuffersSent); NullTerminate(&OutputStr); - OutputDebugStringA(OutputStr.Str); + //OutputDebugStringA(OutputStr.Str); } internal void @@ -685,6 +685,10 @@ WinMain ( LastFrameSecondsElapsed = SecondsElapsed; LastFrameEnd = GetWallClock(); + + + OutputDebugStringA("-- Frame END -- \n"); + } Context.CleanupApplication(Context); diff --git a/src/app/platform_win32/win32_foldhaus_work_queue.h b/src/app/platform_win32/win32_foldhaus_work_queue.h index 2db58f3..0b31fa6 100644 --- a/src/app/platform_win32/win32_foldhaus_work_queue.h +++ b/src/app/platform_win32/win32_foldhaus_work_queue.h @@ -46,6 +46,8 @@ Win32CreateThreadContext(gs_memory_arena* Transient = 0) Win32EnumerateDirectory, Result.Transient); + Result.DebugOutput.Print = Win32DebugPrint; + return Result; } diff --git a/src/gs_libs/gs_types.cpp b/src/gs_libs/gs_types.cpp index a42bdae..f69657c 100644 --- a/src/gs_libs/gs_types.cpp +++ b/src/gs_libs/gs_types.cpp @@ -1979,31 +1979,31 @@ PrintFArgsList (gs_string* String, char* Format, va_list Args) if (FormatAt[0] == 'h' && FormatAt[1] == 'h') { LengthSpecified = true; - LengthSpecified = 1; + Length = 1; FormatAt += 2; } else if (FormatAt[0] == 'h') { LengthSpecified = true; - LengthSpecified = 2; + Length = 2; FormatAt++; } else if (FormatAt[0] == 'l' && FormatAt[1] == 'l') { LengthSpecified = true; - LengthSpecified = 8; + Length = 8; FormatAt += 2; } else if (FormatAt[0] == 'l') { LengthSpecified = true; - LengthSpecified = 4; + Length = 4; FormatAt++; } else if (FormatAt[0] == 'j') { LengthSpecified = true; - LengthSpecified = 8; + Length = 8; FormatAt++; } else if (FormatAt[0] == 'z') @@ -2034,7 +2034,7 @@ PrintFArgsList (gs_string* String, char* Format, va_list Args) } else if (FormatAt[0] == 'u') { - u32 UnsignedInt = ReadVarArgsUnsignedInteger(Length, &Args); + u64 UnsignedInt = ReadVarArgsUnsignedInteger(Length, &Args); U64ToASCII(&StringRemaining, UnsignedInt, 10, Base10Chars); } else if (FormatAt[0] == 'o') @@ -2475,6 +2475,19 @@ PushStringF(gs_memory_arena* Arena, u32 MaxLength, char* Format, ...) return Result; } +internal gs_string +PushStringCopy(gs_memory_arena* Arena, gs_const_string String) +{ + gs_string Result = PushString(Arena, String.Length); + Result.Size = String.Length; + Result.Length = String.Length; + for (u32 i = 0; i < String.Length; i++) + { + Result.Str[i] = String.Str[i]; + } + return Result; +} + internal void ClearArena(gs_memory_arena* Arena) { diff --git a/src/todo.txt b/src/todo.txt index 3dcb1f0..c2ef7b1 100644 --- a/src/todo.txt +++ b/src/todo.txt @@ -43,7 +43,6 @@ STREAM #1: 3D Overhaul - :ErrorLogging - Animation System - - blending between animation - layers - layer masks by sculpture - layer masks by tag / value diff --git a/src/todo_done.txt b/src/todo_done.txt index 6aae2d4..ac67406 100644 --- a/src/todo_done.txt +++ b/src/todo_done.txt @@ -1,3 +1,5 @@ +x blending between animation + x saving animation timelines x Buckets & Lists x On second thought, I just really don't like these. Lets get rid of them, and put custom structures in place From 31ee768032a80053062766ed62d10b2fdffe6b85 Mon Sep 17 00:00:00 2001 From: PS Date: Sat, 14 Nov 2020 22:08:13 -0800 Subject: [PATCH 03/44] Editing patterns --- src/app/foldhaus_app.cpp | 4 +- src/app/foldhaus_app.h | 119 ++++++++++++++++++++++++++++++++++++++- src/gs_libs/gs_types.cpp | 15 +++++ 3 files changed, 134 insertions(+), 4 deletions(-) diff --git a/src/app/foldhaus_app.cpp b/src/app/foldhaus_app.cpp index 68bd4e2..a1b0d95 100644 --- a/src/app/foldhaus_app.cpp +++ b/src/app/foldhaus_app.cpp @@ -145,9 +145,11 @@ INITIALIZE_APPLICATION(InitializeApplication) Animation_AddLayer(&Anim, MakeString("Color Layer"), BlendMode_Multiply, &State->AnimationSystem); Animation_AddLayer(&Anim, MakeString("Sparkles"), BlendMode_Add, &State->AnimationSystem); - Animation_AddBlock(&Anim, 22, 123, 2, 0); + Animation_AddBlock(&Anim, 0, Anim.PlayableRange.Max, 4, 0); AnimationArray_Push(&State->AnimationSystem.Animations, Anim); + + State->AnimationSystem.TimelineShouldAdvance = true; } // End Animation Playground diff --git a/src/app/foldhaus_app.h b/src/app/foldhaus_app.h index d8b7bbe..df2d3d9 100644 --- a/src/app/foldhaus_app.h +++ b/src/app/foldhaus_app.h @@ -202,15 +202,128 @@ TestPatternThree(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* } } +v4 HSVToRGB (v4 In) +{ + float Hue = In.x; + while (Hue > 360.0f) { Hue -= 360.0f; } + while (Hue < 0.0f) { Hue += 360.0f; } + + float Sat = In.y; + float Value = In.z; + + float hh, p, q, t, ff; + long i; + v4 Result = {}; + Result.a = In.a; + + if(Sat <= 0.0f) { // < is bogus, just shuts up warnings + Result.r = Value; + Result.g = Value; + Result.b = Value; + return Result; + } + hh = Hue; + if(hh >= 360.0f) hh = 0.0f; + hh /= 60.0f; + i = (long)hh; + ff = hh - i; + p = Value * (1.0f - Sat); + q = Value * (1.0f - (Sat * ff)); + t = Value * (1.0f - (Sat * (1.0f - ff))); + + switch(i) { + case 0: + {Result.r = Value; + Result.g = t; + Result.b = p; + }break; + + case 1: + { + Result.r = q; + Result.g = Value; + Result.b = p; + }break; + + case 2: + { + Result.r = p; + Result.g = Value; + Result.b = t; + }break; + + case 3: + { + Result.r = p; + Result.g = q; + Result.b = Value; + }break; + + case 4: + { + Result.r = t; + Result.g = p; + Result.b = Value; + }break; + + case 5: + default: + { + Result.r = Value; + Result.g = p; + Result.b = q; + }break; + } + + return Result; +} + internal void Pattern_AllGreen(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient) { +#if 1 + r32 Height = SinR32(Time) * 25; + + r32 CycleLength = 5.0f; + r32 CycleProgress = FractR32(Time / CycleLength); + r32 CycleBlend = (SinR32(Time) * .5f) + .5f; + for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) { - Leds->Colors[LedIndex].R = 0; - Leds->Colors[LedIndex].B = 255; - Leds->Colors[LedIndex].G = 255; + v4 Pos = Leds->Positions[LedIndex]; + r32 Dist = Pos.y - Height; + + v4 HSV = { (ModR32(Dist, 25) / 25) * 360, 1, 1, 1 }; + v4 RGB = HSVToRGB(HSV); + + u8 R = (u8)(RGB.x * 255); + u8 G = (u8)(RGB.y * 255); + u8 B = (u8)(RGB.z * 255); + + Leds->Colors[LedIndex].R = R; + Leds->Colors[LedIndex].G = G; + Leds->Colors[LedIndex].B = B; } +#else + for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) + { + u32 I = LedIndex + 1; + Leds->Colors[LedIndex] = {}; + if (I % 3 == 0) + { + Leds->Colors[LedIndex].R = 255; + } + else if (I % 3 == 1) + { + Leds->Colors[LedIndex].G = 255; + } + else if (I % 3 == 2) + { + Leds->Colors[LedIndex].B = 255; + } + + } +#endif } // END TEMPORARY PATTERNS diff --git a/src/gs_libs/gs_types.cpp b/src/gs_libs/gs_types.cpp index 05467cc..7d6b174 100644 --- a/src/gs_libs/gs_types.cpp +++ b/src/gs_libs/gs_types.cpp @@ -441,6 +441,21 @@ SqrtU32(u32 V) return sqrt(V); } +internal r32 +ModR32(r32 Value, r32 Int) +{ + r32 Div = Value / Int; + r32 Fract = Abs(FractR32(Div)); + return Int * Fract; +} +internal r64 +ModR64(r64 Value, r64 Int) +{ + r64 Div = Value / Int; + r64 Fract = Abs(FractR64(Div)); + return Int * Fract; +} + internal r32 SinR32(r32 Rad) { From e5ab90fcb1b7674507ccadb5e889bfb2e9346a41 Mon Sep 17 00:00:00 2001 From: PS Date: Sat, 14 Nov 2020 23:30:24 -0800 Subject: [PATCH 04/44] Did some styling updates to the ui, added a range slider and a toggle --- src/app/editor/foldhaus_editor.cpp | 94 ++++++++---- src/app/interface.h | 168 +++++++++++++++++----- src/app/platform_win32/win32_foldhaus.cpp | 17 ++- src/gs_libs/gs_input.h | 53 ++++--- 4 files changed, 242 insertions(+), 90 deletions(-) diff --git a/src/app/editor/foldhaus_editor.cpp b/src/app/editor/foldhaus_editor.cpp index cd3e5f5..595d53c 100644 --- a/src/app/editor/foldhaus_editor.cpp +++ b/src/app/editor/foldhaus_editor.cpp @@ -88,6 +88,36 @@ Editor_Update(app_state* State, context* Context, input_queue InputQueue) Editor_HandleInput(State, State->WindowBounds, InputQueue, Context->Mouse, *Context); } +internal void +Editor_DrawWidgetString(app_state* State, context* Context, render_command_buffer* RenderBuffer, ui_widget Widget, v4 Color) +{ + 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; + } +} + internal void Editor_DrawWidget(app_state* State, context* Context, render_command_buffer* RenderBuffer, ui_widget Widget) { @@ -108,33 +138,39 @@ Editor_DrawWidget(app_state* State, context* Context, render_command_buffer* Ren if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawString) && 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) + Editor_DrawWidgetString(State, Context, RenderBuffer, Widget, Color); + } + + if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawHorizontalFill)) + { + v4 Color = PinkV4; //State->Interface.Style.ButtonColor_Active; + if (ui_WidgetIdsEqual(Widget.Id, State->Interface.HotWidget)) { - 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; + Color = GreenV4; //State->Interface.Style.ButtonColor_Selected; + } + if (ui_WidgetIdsEqual(Widget.Id, State->Interface.ActiveWidget)) + { + Color = TealV4; //State->Interface.Style.ButtonColor_Selected; + } + + rect2 HFillBounds = {}; + HFillBounds.Min = Widget.Bounds.Min; + HFillBounds.Max = { + LerpR32(Widget.HorizontalFillPercent, Widget.Bounds.Min.x, Widget.Bounds.Max.x), + Widget.Bounds.Max.y + }; + PushRenderQuad2D(RenderBuffer, HFillBounds.Min, HFillBounds.Max, Color); + + if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawString) && Widget.String.Length > 0) + { + // TODO(pjs): Mask this text by the horizontal fill + // TODO(pjs): add this color to the style + v4 TextColor = BlackV4; + Editor_DrawWidgetString(State, Context, RenderBuffer, Widget, TextColor); } } + if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawOutline)) { // TODO(pjs): replace these with values from the style @@ -154,6 +190,11 @@ Editor_DrawWidget(app_state* State, context* Context, render_command_buffer* Ren } } +global r32 TestSlider_Value = 5; +global r32 TestSlider_Min = 0; +global r32 TestSlider_Max = 10; +global bool TestToggle = true; + internal void TestRender(app_state* State, context* Context, render_command_buffer* RenderBuffer) { @@ -183,6 +224,11 @@ TestRender(app_state* State, context* Context, render_command_buffer* RenderBuff ui_EndDropdown(&State->Interface); } ui_EndRow(&State->Interface); + TestSlider_Value = ui_RangeSlider(&State->Interface, MakeString("Test Slider"), TestSlider_Value, TestSlider_Min, TestSlider_Max); + + TestToggle = ui_Toggle(&State->Interface, MakeString("test toggle"), TestToggle); + + ui_Button(&State->Interface, MakeString("Hello")); ui_PopLayout(&State->Interface); @@ -195,7 +241,7 @@ Editor_Render(app_state* State, context* Context, render_command_buffer* RenderB PushRenderOrthographic(RenderBuffer, State->WindowBounds); PushRenderClearScreen(RenderBuffer); -#if 0 +#if 1 TestRender(State, Context, RenderBuffer); //ui_widget_id IdTwo = TestRender(State, Context, RenderBuffer); //Assert(ui_WidgetIdsEqual(IdOne, IdTwo)); diff --git a/src/app/interface.h b/src/app/interface.h index 80b3ada..f9214d1 100644 --- a/src/app/interface.h +++ b/src/app/interface.h @@ -5,14 +5,6 @@ // #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, @@ -188,15 +180,13 @@ DrawStringWithCursor (render_command_buffer* RenderBuffer, gs_string String, s32 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_DrawString, UIWidgetFlag_DrawOutline, UIWidgetFlag_Clickable, + UIWidgetFlag_DrawHorizontalFill, }; struct ui_widget_id @@ -223,6 +213,9 @@ struct ui_widget ui_widget* Next; + // Slider + r32 HorizontalFillPercent; + // Layout ui_widget* Parent; @@ -250,6 +243,8 @@ struct ui_widget struct ui_eval_result { bool Clicked; + bool Held; + v2 DragDelta; }; struct interface_config @@ -276,6 +271,7 @@ struct ui_widget_retained_state { ui_widget_id Id; bool Value; + r32 InitialValueR32; u32 FramesSinceAccess; }; @@ -414,7 +410,7 @@ static ui_widget* ui_PushLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir, gs_string Name) { ui_widget* Result = ui_CreateWidget(Interface, Name); - ui_WidgetSetFlag(Result, UIWidgetFlag_DrawOutline); + //ui_WidgetSetFlag(Result, UIWidgetFlag_DrawOutline); Result->Bounds = Bounds; Result->Margin = Interface->Style.Margin; @@ -425,12 +421,12 @@ ui_PushLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir { case LayoutDirection_BottomUp: { - Result->RowYAt = Bounds.Min.y; + Result->RowYAt = Bounds.Min.y + Result->Margin.y; }break; case LayoutDirection_TopDown: { - Result->RowYAt = Bounds.Max.y - Result->RowHeight; + Result->RowYAt = Bounds.Max.y - (Result->RowHeight + Result->Margin.y); }break; } @@ -447,13 +443,10 @@ ui_PushLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir return Result; } -internal ui_eval_result ui_EvaluateWidget(ui_interface* Interface, ui_widget* Widget, rect2 Bounds); - static void ui_PopLayout(ui_interface* Interface) { Assert(Interface->ActiveLayout != 0); - //ui_EvaluateWidget(Interface, Interface->ActiveLayout, Interface->ActiveLayout->Bounds); Interface->ActiveLayout = Interface->ActiveLayout->Parent; } @@ -480,7 +473,7 @@ ui_EndRow(ui_interface* Interface) { Interface->ActiveLayout->DrawHorizontal = false; Interface->ActiveLayout->ColumnWidths = 0; - Interface->ActiveLayout->RowYAt -= Interface->ActiveLayout->RowHeight; + Interface->ActiveLayout->RowYAt -= (Interface->ActiveLayout->RowHeight + Interface->ActiveLayout->Margin.y); } static b32 @@ -489,19 +482,20 @@ ui_TryReserveElementBounds(ui_widget* Widget, rect2* Bounds) b32 Result = true; if (!Widget->DrawHorizontal) { - Bounds->Min = { Widget->Bounds.Min.x, Widget->RowYAt }; - Bounds->Max = { Widget->Bounds.Max.x, Bounds->Min.y + Widget->RowHeight }; + Bounds->Min = { Widget->Bounds.Min.x + Widget->Margin.x, Widget->RowYAt }; + Bounds->Max = { Widget->Bounds.Max.x - Widget->Margin.x, Bounds->Min.y + Widget->RowHeight }; + r32 RowOffset = Widget->RowHeight + Widget->Margin.y; switch (Widget->FillDirection) { case LayoutDirection_BottomUp: { - Widget->RowYAt += Widget->RowHeight; + Widget->RowYAt += RowOffset; }break; case LayoutDirection_TopDown: { - Widget->RowYAt -= Widget->RowHeight; + Widget->RowYAt -= RowOffset; }break; InvalidDefaultCase; @@ -514,13 +508,19 @@ ui_TryReserveElementBounds(ui_widget* Widget, rect2* Bounds) Assert(Widget->ColumnsCount < Widget->ColumnsMax); if (Widget->ColumnWidths != 0) { - v2 Min = { Widget->Bounds.Min.x, Widget->RowYAt }; + v2 Min = { + Widget->Bounds.Min.x + Widget->Margin.x, + Widget->RowYAt + }; for (u32 i = 0; i < Widget->ColumnsCount; i++) { Min.x += Widget->ColumnWidths[i]; } Bounds->Min = Min; - Bounds->Max = Bounds->Min + v2{ Widget->ColumnWidths[Widget->ColumnsCount], Widget->RowHeight }; + Bounds->Max = Bounds->Min + v2{ + Widget->ColumnWidths[Widget->ColumnsCount] - Widget->Margin.x, + Widget->RowHeight + }; } else { @@ -530,7 +530,7 @@ ui_TryReserveElementBounds(ui_widget* Widget, rect2* Bounds) Widget->RowYAt }; Bounds->Max = { - Bounds->Min.x + ElementWidth - Widget->Margin.x, + Bounds->Min.x + ElementWidth - (Widget->Margin.x * 2), Bounds->Min.y + Widget->RowHeight }; } @@ -584,18 +584,27 @@ ui_EvaluateWidget(ui_interface* Interface, ui_widget* Widget, rect2 Bounds) { if (ui_WidgetIdsEqual(Interface->HotWidget, Widget->Id) && MouseButtonTransitionedDown(Interface->Mouse.LeftButtonState)) { + Assert(!ui_WidgetIdsEqual(Interface->ActiveWidget, Widget->Id)); Result.Clicked = true; Interface->ActiveWidget = Widget->Id; } - - if (ui_WidgetIdsEqual(Interface->ActiveWidget, Widget->Id) && - MouseButtonTransitionedUp(Interface->Mouse.LeftButtonState)) - { - Interface->ActiveWidget = {}; - } - Interface->HotWidget = Widget->Id; } + + + if (MouseButtonHeldDown(Interface->Mouse.LeftButtonState) && + PointIsInRect(Widget->Bounds, Interface->Mouse.DownPos)) + { + Result.Held = true; + Result.DragDelta = Interface->Mouse.Pos - Interface->Mouse.DownPos; + } + + if (ui_WidgetIdsEqual(Interface->ActiveWidget, Widget->Id) && + MouseButtonTransitionedUp(Interface->Mouse.LeftButtonState)) + { + Interface->ActiveWidget = {}; + } + } return Result; @@ -655,24 +664,29 @@ ui_DrawString(ui_interface* Interface, gs_string String, gs_string_alignment Ali ui_EvaluateWidget(Interface, Widget); } -static b32 -ui_Button(ui_interface* Interface, gs_string Text) +internal ui_widget* +ui_CreateButtonWidget(ui_interface* Interface, gs_string Text) { ui_widget* Widget = ui_CreateWidget(Interface, Text); ui_WidgetSetFlag(Widget, UIWidgetFlag_Clickable); ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawBackground); ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawString); + ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawOutline); + return Widget; +} + +internal b32 +ui_Button(ui_interface* Interface, gs_string Text) +{ + ui_widget* Widget = ui_CreateButtonWidget(Interface, Text); ui_eval_result Result = ui_EvaluateWidget(Interface, Widget); return Result.Clicked; } -static b32 +internal b32 ui_Button(ui_interface* Interface, gs_string Text, rect2 Bounds) { - ui_widget* Widget = ui_CreateWidget(Interface, Text); - ui_WidgetSetFlag(Widget, UIWidgetFlag_Clickable); - ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawBackground); - ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawString); + ui_widget* Widget = ui_CreateButtonWidget(Interface, Text); ui_eval_result Result = ui_EvaluateWidget(Interface, Widget, Bounds); return Result.Clicked; } @@ -762,6 +776,7 @@ ui_EvaluateDropdown(ui_interface* Interface, ui_widget* Widget, ui_eval_result E } ui_widget* Layout = ui_PushLayout(Interface, MenuBounds, Direction, MakeString("WidgetLayout")); + Layout->Margin.y = 0; Layout->WidgetReference = Widget->Id; } @@ -775,6 +790,7 @@ ui_BeginDropdown(ui_interface* Interface, gs_string Text, rect2 Bounds) ui_WidgetSetFlag(Widget, UIWidgetFlag_Clickable); ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawBackground); ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawString); + ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawOutline); ui_eval_result Result = ui_EvaluateWidget(Interface, Widget, Bounds); return ui_EvaluateDropdown(Interface, Widget, Result); } @@ -786,6 +802,7 @@ ui_BeginDropdown(ui_interface* Interface, gs_string Text) ui_WidgetSetFlag(Widget, UIWidgetFlag_Clickable); ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawBackground); ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawString); + ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawOutline); ui_eval_result Result = ui_EvaluateWidget(Interface, Widget); return ui_EvaluateDropdown(Interface, Widget, Result); } @@ -804,6 +821,79 @@ ui_EndDropdown(ui_interface* Interface) } } +internal r32 +ui_EvaluateRangeSlider(ui_interface* Interface, ui_widget* Widget, ui_eval_result EvalResult, r32 Value, r32 MinValue, r32 MaxValue) +{ + r32 NewValue = Value; + + ui_widget_retained_state* State = ui_GetRetainedState(Interface, Widget->Id); + if (!State) + { + State = ui_CreateRetainedState(Interface, Widget); + } + + if (EvalResult.Clicked) + { + State->InitialValueR32 = Value; + } + + if (EvalResult.Held) + { + r32 Percent = (Interface->Mouse.Pos.x - Widget->Bounds.Min.x) / Rect2Width(Widget->Bounds); + NewValue = LerpR32(Percent, MinValue, MaxValue); + } + + NewValue = Clamp(MinValue, NewValue, MaxValue); + Widget->HorizontalFillPercent = RemapR32(NewValue, MinValue, MaxValue, 0, 1); + return NewValue; +} + +internal ui_widget* +ui_CreateRangeSliderWidget(ui_interface* Interface, gs_string Text, r32 Value) +{ + ui_widget* Widget = ui_CreateWidget(Interface, Text); + ui_WidgetSetFlag(Widget, UIWidgetFlag_Clickable); + ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawBackground); + ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawString); + ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawHorizontalFill); + ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawOutline); + Widget->String = PushStringF(Interface->PerFrameMemory, 128, "%f", Value); + return Widget; +} + +internal r32 +ui_RangeSlider(ui_interface* Interface, gs_string Text, r32 Value, r32 ValueMin, r32 ValueMax) +{ + ui_widget* Widget = ui_CreateRangeSliderWidget(Interface, Text, Value); + ui_eval_result Result = ui_EvaluateWidget(Interface, Widget); + return ui_EvaluateRangeSlider(Interface, Widget, Result, Value, ValueMin, ValueMax); + +} + +internal r32 +ui_RangeSlider(ui_interface* Interface, gs_string Text, rect2 Bounds, r32 Value, r32 ValueMin, r32 ValueMax) +{ + ui_widget* Widget = ui_CreateRangeSliderWidget(Interface, Text, Value); + ui_eval_result Result = ui_EvaluateWidget(Interface, Widget, Bounds); + return ui_EvaluateRangeSlider(Interface, Widget, Result, Value, ValueMin, ValueMax); +} + +internal bool +ui_Toggle(ui_interface* Interface, gs_string Text, bool Value) +{ + ui_widget* Widget = ui_CreateWidget(Interface, Text); + ui_WidgetSetFlag(Widget, UIWidgetFlag_Clickable); + ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawBackground); + ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawHorizontalFill); + ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawOutline); + ui_eval_result Eval = ui_EvaluateWidget(Interface, Widget); + + bool Result = Eval.Clicked ? !Value : Value; + Widget->HorizontalFillPercent = Result ? 1.0f : 0.0f; + return Result; +} + + // // OLD // diff --git a/src/app/platform_win32/win32_foldhaus.cpp b/src/app/platform_win32/win32_foldhaus.cpp index 1d2bb65..362c898 100644 --- a/src/app/platform_win32/win32_foldhaus.cpp +++ b/src/app/platform_win32/win32_foldhaus.cpp @@ -187,7 +187,7 @@ HandleWindowMessage (MSG Message, window* Window, input_queue* InputQueue, mouse AddInputEventEntry(InputQueue, KeyCode_MouseLeftButton, false, true, ShiftDown, AltDown, CtrlDown, false); - Mouse->LeftButtonState = KeyState_IsDown & ~KeyState_WasDown; + Mouse->LeftButtonState |= KeyState_IsDown; Mouse->DownPos = Mouse->Pos; // :Win32MouseEventCapture @@ -237,7 +237,7 @@ HandleWindowMessage (MSG Message, window* Window, input_queue* InputQueue, mouse AddInputEventEntry(InputQueue, KeyCode_MouseLeftButton, true, false, ShiftDown, AltDown, CtrlDown, false); - Mouse->LeftButtonState = ~KeyState_IsDown & KeyState_WasDown; + Mouse->LeftButtonState &= ~KeyState_IsDown; // :Win32MouseEventCapture ReleaseCapture(); @@ -593,7 +593,7 @@ WinMain ( AddressedDataBufferList_Clear(&OutputData); - { // Mouse Position + { // Mouse POINT MousePos; GetCursorPos (&MousePos); ScreenToClient(MainWindow.Handle, &MousePos); @@ -602,6 +602,15 @@ WinMain ( Context.Mouse.OldPos = Context.Mouse.Pos; Context.Mouse.Pos = v2{(r32)MousePos.x, (r32)MainWindow.Height - MousePos.y}; Context.Mouse.DeltaPos = Context.Mouse.Pos - Context.Mouse.OldPos; + + if (KeyIsDown(Context.Mouse.LeftButtonState)) + { + SetKeyWasDown(Context.Mouse.LeftButtonState); + } + else + { + SetKeyWasUp(Context.Mouse.LeftButtonState); + } } MSG Message; @@ -687,7 +696,7 @@ WinMain ( LastFrameEnd = GetWallClock(); - OutputDebugStringA("-- Frame END -- \n"); + //OutputDebugStringA("-- Frame END -- \n"); } diff --git a/src/gs_libs/gs_input.h b/src/gs_libs/gs_input.h index d4a83f0..daabf05 100644 --- a/src/gs_libs/gs_input.h +++ b/src/gs_libs/gs_input.h @@ -15,32 +15,32 @@ enum key_code KeyCode_CapsLock, KeyCode_LeftShift, KeyCode_RightShift, KeyCode_LeftCtrl, KeyCode_RightCtrl, - KeyCode_Fn, - KeyCode_Alt, + KeyCode_Fn, + KeyCode_Alt, KeyCode_PageUp, KeyCode_PageDown, KeyCode_Backspace, KeyCode_Delete, KeyCode_Enter, // Function Keys KeyCode_F0, KeyCode_F1, KeyCode_F2, KeyCode_F3, KeyCode_F4, KeyCode_F5, KeyCode_F6, KeyCode_F7, - KeyCode_F8, KeyCode_F9, KeyCode_F10, KeyCode_F11, KeyCode_F12, + KeyCode_F8, KeyCode_F9, KeyCode_F10, KeyCode_F11, KeyCode_F12, // Letters KeyCode_a, KeyCode_b, KeyCode_c, KeyCode_d, KeyCode_e, KeyCode_f, KeyCode_g, KeyCode_h, - KeyCode_i, KeyCode_j, KeyCode_k, KeyCode_l, KeyCode_m, KeyCode_n, KeyCode_o, KeyCode_p, - KeyCode_q, KeyCode_r, KeyCode_s, KeyCode_t, KeyCode_u, KeyCode_v, KeyCode_w, KeyCode_x, + KeyCode_i, KeyCode_j, KeyCode_k, KeyCode_l, KeyCode_m, KeyCode_n, KeyCode_o, KeyCode_p, + KeyCode_q, KeyCode_r, KeyCode_s, KeyCode_t, KeyCode_u, KeyCode_v, KeyCode_w, KeyCode_x, KeyCode_y, KeyCode_z, KeyCode_A, KeyCode_B, KeyCode_C, KeyCode_D, KeyCode_E, KeyCode_F, KeyCode_G, KeyCode_H, - KeyCode_I, KeyCode_J, KeyCode_K, KeyCode_L, KeyCode_M, KeyCode_N, KeyCode_O, KeyCode_P, - KeyCode_Q, KeyCode_R, KeyCode_S, KeyCode_T, KeyCode_U, KeyCode_V, KeyCode_W, KeyCode_X, + KeyCode_I, KeyCode_J, KeyCode_K, KeyCode_L, KeyCode_M, KeyCode_N, KeyCode_O, KeyCode_P, + KeyCode_Q, KeyCode_R, KeyCode_S, KeyCode_T, KeyCode_U, KeyCode_V, KeyCode_W, KeyCode_X, KeyCode_Y, KeyCode_Z, // Numbers KeyCode_0, KeyCode_1, KeyCode_2, KeyCode_3, KeyCode_4, KeyCode_5, KeyCode_6, KeyCode_7, KeyCode_8, KeyCode_9, - KeyCode_Num0, KeyCode_Num1, KeyCode_Num2, KeyCode_Num3, KeyCode_Num4, KeyCode_Num5, + KeyCode_Num0, KeyCode_Num1, KeyCode_Num2, KeyCode_Num3, KeyCode_Num4, KeyCode_Num5, KeyCode_Num6, KeyCode_Num7, KeyCode_Num8, KeyCode_Num9, // Symbols @@ -48,7 +48,7 @@ enum key_code KeyCode_Ampersand, KeyCode_Star, KeyCode_LeftParen, KeyCode_RightParen, KeyCode_Minus, KeyCode_Plus, KeyCode_Equals, KeyCode_Underscore, KeyCode_LeftBrace, KeyCode_RightBrace, KeyCode_LeftBracket, KeyCode_RightBracket, KeyCode_Colon, KeyCode_SemiColon, KeyCode_SingleQuote, KeyCode_DoubleQuote, - KeyCode_ForwardSlash, KeyCode_Backslash, KeyCode_Pipe, KeyCode_Comma, KeyCode_Period, + KeyCode_ForwardSlash, KeyCode_Backslash, KeyCode_Pipe, KeyCode_Comma, KeyCode_Period, KeyCode_QuestionMark, KeyCode_LessThan, KeyCode_GreaterThan, KeyCode_Tilde, KeyCode_BackQuote, // Arrows @@ -77,9 +77,9 @@ CharacterFromKeyCode (key_code Code) case KeyCode_Tab: { Result = '\t'; }break; // Letters - case KeyCode_a: { Result = 'a'; }break; - case KeyCode_b: { Result = 'b'; }break; - case KeyCode_c: { Result = 'c'; }break; + case KeyCode_a: { Result = 'a'; }break; + case KeyCode_b: { Result = 'b'; }break; + case KeyCode_c: { Result = 'c'; }break; case KeyCode_d: { Result = 'd'; }break; case KeyCode_e: { Result = 'e'; }break; case KeyCode_f: { Result = 'f'; }break; @@ -92,7 +92,7 @@ CharacterFromKeyCode (key_code Code) case KeyCode_m: { Result = 'm'; }break; case KeyCode_n: { Result = 'n'; }break; case KeyCode_o: { Result = 'o'; }break; - case KeyCode_p: { Result = 'p'; }break; + case KeyCode_p: { Result = 'p'; }break; case KeyCode_q: { Result = 'q'; }break; case KeyCode_r: { Result = 'r'; }break; case KeyCode_s: { Result = 's'; }break; @@ -100,7 +100,7 @@ CharacterFromKeyCode (key_code Code) case KeyCode_u: { Result = 'u'; }break; case KeyCode_v: { Result = 'v'; }break; case KeyCode_w: { Result = 'w'; }break; - case KeyCode_x: { Result = 'x'; }break; + case KeyCode_x: { Result = 'x'; }break; case KeyCode_y: { Result = 'y'; }break; case KeyCode_z: { Result = 'z'; }break; @@ -119,7 +119,7 @@ CharacterFromKeyCode (key_code Code) case KeyCode_M: { Result = 'M'; }break; case KeyCode_N: { Result = 'N'; }break; case KeyCode_O: { Result = 'O'; }break; - case KeyCode_P: { Result = 'P'; }break; + case KeyCode_P: { Result = 'P'; }break; case KeyCode_Q: { Result = 'Q'; }break; case KeyCode_R: { Result = 'R'; }break; case KeyCode_S: { Result = 'S'; }break; @@ -127,7 +127,7 @@ CharacterFromKeyCode (key_code Code) case KeyCode_U: { Result = 'U'; }break; case KeyCode_V: { Result = 'V'; }break; case KeyCode_W: { Result = 'W'; }break; - case KeyCode_X: { Result = 'X'; }break; + case KeyCode_X: { Result = 'X'; }break; case KeyCode_Y: { Result = 'Y'; }break; case KeyCode_Z: { Result = 'Z'; }break; @@ -148,7 +148,7 @@ CharacterFromKeyCode (key_code Code) case KeyCode_Num2: { Result = '2'; }break; case KeyCode_Num3: { Result = '3'; }break; case KeyCode_Num4: { Result = '4'; }break; - case KeyCode_Num5: { Result = '5'; }break; + case KeyCode_Num5: { Result = '5'; }break; case KeyCode_Num6: { Result = '6'; }break; case KeyCode_Num7: { Result = '7'; }break; case KeyCode_Num8: { Result = '8'; }break; @@ -181,7 +181,7 @@ CharacterFromKeyCode (key_code Code) case KeyCode_Backslash: { Result = '\\'; }break; case KeyCode_Pipe: { Result = '|'; }break; case KeyCode_Comma: { Result = ','; }break; - case KeyCode_Period: { Result = '.'; }break; + case KeyCode_Period: { Result = '.'; }break; case KeyCode_QuestionMark: { Result = '?'; }break; case KeyCode_LessThan: { Result = '<'; }break; case KeyCode_GreaterThan: { Result = '>'; }break; @@ -227,6 +227,11 @@ enum key_state_flags #define KeyWasDown(event) ((event & KeyState_WasDown) > 0) #define KeyIsDown(event) ((event & KeyState_IsDown) > 0) +#define SetKeyDown(key) (key |= KeyState_IsDown) +#define SetKeyWasDown(key) (key |= KeyState_WasDown) +#define SetKeyUp(key) (key &= ~KeyState_IsDown) +#define SetKeyWasUp(key) (key &= ~KeyState_WasDown) + struct input_entry { key_code Key; @@ -266,6 +271,8 @@ struct mouse_state b32 MiddleButtonState; b32 RightButtonState; + + cursor_type CursorType; }; @@ -327,7 +334,7 @@ KeyTransitionedUp (input Input, key_code Key) } internal void -AddInputEventEntry (input_queue* Queue, key_code Key, +AddInputEventEntry (input_queue* Queue, key_code Key, b32 WasDown, b32 IsDown, b32 ShiftDown, b32 AltDown, b32 CtrlDown, b32 SysDown) { Assert(Queue->QueueUsed < Queue->QueueSize); @@ -392,10 +399,10 @@ GetMouseButtonStateAdvanced (b32 ButtonState) !((ButtonState & KeyState_IsDown) > 0)) { Result= 0; - } - else if (ButtonState & KeyState_IsDown) - { - Result |= KeyState_WasDown; + } + else if (ButtonState & KeyState_IsDown) + { + Result |= KeyState_WasDown; } return Result; } From 1db26150baba2434b1194853ff9108f1d1ea2c4a Mon Sep 17 00:00:00 2001 From: PS Date: Sat, 14 Nov 2020 23:38:56 -0800 Subject: [PATCH 05/44] implemented overlay layouts --- src/app/interface.h | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/app/interface.h b/src/app/interface.h index f9214d1..785c620 100644 --- a/src/app/interface.h +++ b/src/app/interface.h @@ -406,8 +406,8 @@ ui_MouseClickedRect(ui_interface Interface, rect2 Rect) // Layout -static ui_widget* -ui_PushLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir, gs_string Name) +internal ui_widget* +ui_CreateLayoutWidget(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir, gs_string Name) { ui_widget* Result = ui_CreateWidget(Interface, Name); //ui_WidgetSetFlag(Result, UIWidgetFlag_DrawOutline); @@ -430,6 +430,14 @@ ui_PushLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir }break; } + return Result; +} + +static ui_widget* +ui_PushLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir, gs_string Name) +{ + ui_widget* Result = ui_CreateLayoutWidget(Interface, Bounds, FillDir, Name); + if (Interface->DrawOrderRoot) { SLLPushOrInit(Interface->ActiveLayout->ChildrenRoot, Interface->ActiveLayout->ChildrenHead, Result); @@ -439,6 +447,16 @@ ui_PushLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir { SLLPushOrInit(Interface->DrawOrderRoot, Interface->DrawOrderHead, Result); } + + Interface->ActiveLayout = Result; + return Result; +} + +static ui_widget* +ui_PushOverlayLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir, gs_string Name) +{ + ui_widget* Result = ui_CreateLayoutWidget(Interface, Bounds, FillDir, Name); + SLLPushOrInit(Interface->DrawOrderRoot, Interface->DrawOrderHead, Result); Interface->ActiveLayout = Result; return Result; } @@ -775,7 +793,7 @@ ui_EvaluateDropdown(ui_interface* Interface, ui_widget* Widget, ui_eval_result E }; } - ui_widget* Layout = ui_PushLayout(Interface, MenuBounds, Direction, MakeString("WidgetLayout")); + ui_widget* Layout = ui_PushOverlayLayout(Interface, MenuBounds, Direction, MakeString("WidgetLayout")); Layout->Margin.y = 0; Layout->WidgetReference = Widget->Id; } From 50b6980bec5de9b3149c2f519f79262df31e0df3 Mon Sep 17 00:00:00 2001 From: PS Date: Sat, 14 Nov 2020 23:44:06 -0800 Subject: [PATCH 06/44] ui_DrawString -> ui_Label --- src/app/editor/foldhaus_editor.cpp | 2 +- .../foldhaus_panel_animation_timeline.h | 2 +- .../editor/panels/foldhaus_panel_file_view.h | 2 +- .../editor/panels/foldhaus_panel_profiler.h | 26 +++++++++---------- src/app/interface.h | 12 +++++---- 5 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/app/editor/foldhaus_editor.cpp b/src/app/editor/foldhaus_editor.cpp index 595d53c..39460fd 100644 --- a/src/app/editor/foldhaus_editor.cpp +++ b/src/app/editor/foldhaus_editor.cpp @@ -241,7 +241,7 @@ Editor_Render(app_state* State, context* Context, render_command_buffer* RenderB PushRenderOrthographic(RenderBuffer, State->WindowBounds); PushRenderClearScreen(RenderBuffer); -#if 1 +#if 0 TestRender(State, Context, RenderBuffer); //ui_widget_id IdTwo = TestRender(State, Context, RenderBuffer); //Assert(ui_WidgetIdsEqual(IdOne, IdTwo)); diff --git a/src/app/editor/panels/foldhaus_panel_animation_timeline.h b/src/app/editor/panels/foldhaus_panel_animation_timeline.h index 253f42e..e9ec1c8 100644 --- a/src/app/editor/panels/foldhaus_panel_animation_timeline.h +++ b/src/app/editor/panels/foldhaus_panel_animation_timeline.h @@ -798,7 +798,7 @@ AnimInfoView_Render(animation_timeline_state* TimelineState, rect2 Bounds, rende ui_StartRow(&State->Interface, 2); { - ui_DrawString(Interface, MakeString("Active Animation")); + ui_Label(Interface, MakeString("Active Animation")); if (ui_BeginDropdown(Interface, ActiveAnim->Name)) { for (u32 i = 0; i < AnimSystem->Animations.Count; i++) diff --git a/src/app/editor/panels/foldhaus_panel_file_view.h b/src/app/editor/panels/foldhaus_panel_file_view.h index fdf8b54..8183829 100644 --- a/src/app/editor/panels/foldhaus_panel_file_view.h +++ b/src/app/editor/panels/foldhaus_panel_file_view.h @@ -96,7 +96,7 @@ FileView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBu } // Header - ui_DrawString(&State->Interface, FileViewState->WorkingDirectory); + ui_Label(&State->Interface, FileViewState->WorkingDirectory); // File Display for (u32 i = 0; i < FileViewState->FileNames.Count; i++) diff --git a/src/app/editor/panels/foldhaus_panel_profiler.h b/src/app/editor/panels/foldhaus_panel_profiler.h index d58b3fb..80b7890 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_widget* Layout, de PrintF(&String, "%S : %d - %d", HotRecordName->Name, HotRecord->StartCycles, HotRecord->EndCycles); rect2 TextBounds = MakeRect2MinDim(Interface->Mouse.Pos, v2{256, 32}); - ui_DrawString(Interface, String, TextBounds); + ui_Label(Interface, String, TextBounds); } } @@ -97,11 +97,11 @@ RenderProfiler_ListVisualization(ui_interface* Interface, ui_widget* Layout, deb r32 ColumnWidths[] = {256, 128, 128, 128, 128}; ui_StartRow(Interface, 5, &ColumnWidths[0]); { - 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_Label(Interface, MakeString("Procedure")); + ui_Label(Interface, MakeString("% Frame")); + ui_Label(Interface, MakeString("Seconds")); + ui_Label(Interface, MakeString("Cycles")); + ui_Label(Interface, MakeString("Calls")); } ui_EndRow(Interface); @@ -115,19 +115,19 @@ RenderProfiler_ListVisualization(ui_interface* Interface, ui_widget* Layout, deb ui_StartRow(Interface, 5, &ColumnWidths[0]); { PrintF(&String, "%S", NameEntry.Name); - ui_DrawString(Interface, String); + ui_Label(Interface, String); PrintF(&String, "%f%%", CollatedRecord->PercentFrameTime); - ui_DrawString(Interface, String); + ui_Label(Interface, String); PrintF(&String, "%fs", CollatedRecord->TotalSeconds); - ui_DrawString(Interface, String); + ui_Label(Interface, String); PrintF(&String, "%dcy", CollatedRecord->TotalCycles); - ui_DrawString(Interface, String); + ui_Label(Interface, String); PrintF(&String, "%d", CollatedRecord->CallCount); - ui_DrawString(Interface, String); + ui_Label(Interface, String); } ui_EndRow(Interface); } @@ -187,10 +187,10 @@ ProfilerView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Rend s64 FrameTotalCycles = VisibleFrame->FrameEndCycles - VisibleFrame->FrameStartCycles; u32 CurrentDebugFrame = GlobalDebugServices->CurrentDebugFrame - 1; PrintF(&String, "Frame %d", CurrentDebugFrame); - ui_DrawString(&State->Interface, String); + ui_Label(&State->Interface, String); PrintF(&String, "Total Cycles: %lld", FrameTotalCycles); - ui_DrawString(&State->Interface, String); + ui_Label(&State->Interface, String); // NOTE(NAME): Skipping a space for aesthetic reasons, not functional, and could // be removed, or used for something else diff --git a/src/app/interface.h b/src/app/interface.h index 785c620..c2c0b22 100644 --- a/src/app/interface.h +++ b/src/app/interface.h @@ -666,19 +666,20 @@ ui_OutlineRect(ui_interface* Interface, rect2 Bounds, r32 Thickness, v4 Color) } internal void -ui_DrawString(ui_interface* Interface, gs_string String, rect2 Bounds, gs_string_alignment Alignment = Align_Left) +ui_Label(ui_interface* Interface, gs_string String, rect2 Bounds, gs_string_alignment Alignment = Align_Left) { DEBUG_TRACK_FUNCTION; ui_widget* Widget = ui_CreateWidget(Interface, String); - Widget->Bounds = Bounds; - ui_EvaluateWidget(Interface, Widget); + ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawString); + ui_EvaluateWidget(Interface, Widget, Bounds); } internal void -ui_DrawString(ui_interface* Interface, gs_string String, gs_string_alignment Alignment = Align_Left) +ui_Label(ui_interface* Interface, gs_string String, gs_string_alignment Alignment = Align_Left) { DEBUG_TRACK_FUNCTION; ui_widget* Widget = ui_CreateWidget(Interface, String); + ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawString); ui_EvaluateWidget(Interface, Widget); } @@ -756,7 +757,8 @@ 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) { + if (!State) + { State = ui_CreateRetainedState(Interface, Widget); } From 296472a5881968ba1a4c901bd64575c3ac89add9 Mon Sep 17 00:00:00 2001 From: PS Date: Sun, 15 Nov 2020 14:48:04 -0800 Subject: [PATCH 07/44] Implemented variable sized row specifications --- src/app/editor/foldhaus_editor.cpp | 98 +++- .../foldhaus_panel_animation_timeline.h | 4 +- .../editor/panels/foldhaus_panel_hierarchy.h | 1 - .../editor/panels/foldhaus_panel_profiler.h | 17 +- src/app/foldhaus_app.cpp | 2 +- src/app/interface.h | 463 ++++++++++++------ 6 files changed, 410 insertions(+), 175 deletions(-) diff --git a/src/app/editor/foldhaus_editor.cpp b/src/app/editor/foldhaus_editor.cpp index 39460fd..6fda7e6 100644 --- a/src/app/editor/foldhaus_editor.cpp +++ b/src/app/editor/foldhaus_editor.cpp @@ -200,39 +200,86 @@ TestRender(app_state* State, context* Context, render_command_buffer* RenderBuff { ui_InterfaceReset(&State->Interface); State->Interface.RenderBuffer = RenderBuffer; + State->Interface.WindowBounds = Context->WindowBounds; - ui_PushLayout(&State->Interface, Context->WindowBounds, LayoutDirection_TopDown, MakeString("TestRender Layout")); + gs_string A = MakeString("TestRender Layout"); - ui_widget_id Ids[2]; - - gs_string String = MakeString("Select"); - ui_StartRow(&State->Interface, 2); - for (u32 j = 0; j < 2; j++) + ui_PushLayout(&State->Interface, A); { - if (ui_BeginDropdown(&State->Interface, String)) +#if 1 + ui_column_spec ColumnRules[] = { + { UIColumnSize_Fixed, 128 }, + { UIColumnSize_Fill, 0 }, + { UIColumnSize_Percent, .5f } + }; + ui_BeginRow(&State->Interface, 3, ColumnRules); + { - for (u32 i = 0; i < State->PanelSystem.PanelDefsCount; i++) + ui_Button(&State->Interface, MakeString("B")); + ui_Button(&State->Interface, MakeString("B")); + ui_Button(&State->Interface, MakeString("B")); + } + ui_EndRow(&State->Interface); + ui_Button(&State->Interface, MakeString("B")); + ui_Button(&State->Interface, MakeString("C")); +#elif 0 + ui_PushLayout(&State->Interface, MakeString("Outer")); + { + for (u32 i = 0; i < 3; i++) { - panel_definition Def = State->PanelSystem.PanelDefs[i]; - gs_string DefName = MakeString(Def.PanelName, Def.PanelNameLength); - if (ui_Button(&State->Interface, DefName)) - { - - } + ui_Button(&State->Interface, MakeString("A")); } } - ui_EndDropdown(&State->Interface); + ui_PopLayout(&State->Interface); + + ui_BeginRow(&State->Interface, 2); + { + ui_PushLayout(&State->Interface, MakeString("TestLayout")); + { + for (u32 i = 0; i < 5; i++) + { + ui_Button(&State->Interface, MakeString("TestButon")); + } + } + ui_PopLayout(&State->Interface); + + ui_PushLayout(&State->Interface, MakeString("TestLayout")); + { + ui_Button(&State->Interface, MakeString("TestButon")); + TestToggle = ui_Toggle(&State->Interface, MakeString("Toggle"), TestToggle); + TestSlider_Value = ui_RangeSlider(&State->Interface, MakeString("TestSlider"), TestSlider_Value, TestSlider_Min, TestSlider_Max); + if (ui_BeginDropdown(&State->Interface, MakeString("TestDropdown"))) + { + ui_Button(&State->Interface, MakeString("TestButon")); + ui_Button(&State->Interface, MakeString("TestButon")); + ui_Button(&State->Interface, MakeString("TestButon")); + } + ui_EndDropdown(&State->Interface); + } + ui_PopLayout(&State->Interface); + } + ui_EndRow(&State->Interface); + + ui_PushLayout(&State->Interface, MakeString("Outer")); + { + for (u32 i = 0; i < 3; i++) + { + ui_Button(&State->Interface, MakeString("B")); + } + } + ui_PopLayout(&State->Interface); +#else + ui_BeginList(&State->Interface, MakeString("Test List"), 10); + { + for (u32 i = 0; i < 32; i++) + { + ui_Button(&State->Interface, MakeString("Option")); + } + } + ui_EndList(&State->Interface); +#endif } - ui_EndRow(&State->Interface); - TestSlider_Value = ui_RangeSlider(&State->Interface, MakeString("Test Slider"), TestSlider_Value, TestSlider_Min, TestSlider_Max); - - TestToggle = ui_Toggle(&State->Interface, MakeString("test toggle"), TestToggle); - - ui_Button(&State->Interface, MakeString("Hello")); - ui_PopLayout(&State->Interface); - - Assert(!ui_WidgetIdsEqual(Ids[0], Ids[1])); } internal void @@ -243,9 +290,6 @@ Editor_Render(app_state* State, context* Context, render_command_buffer* RenderB #if 0 TestRender(State, Context, RenderBuffer); - //ui_widget_id IdTwo = TestRender(State, Context, RenderBuffer); - //Assert(ui_WidgetIdsEqual(IdOne, IdTwo)); - #else ui_InterfaceReset(&State->Interface); State->Interface.RenderBuffer = RenderBuffer; diff --git a/src/app/editor/panels/foldhaus_panel_animation_timeline.h b/src/app/editor/panels/foldhaus_panel_animation_timeline.h index e9ec1c8..d66b36a 100644 --- a/src/app/editor/panels/foldhaus_panel_animation_timeline.h +++ b/src/app/editor/panels/foldhaus_panel_animation_timeline.h @@ -608,7 +608,7 @@ PlayBar_Render(animation_timeline_state* TimelineState, rect2 Bounds, panel* Pan ui_PushLayout(Interface, Bounds, LayoutDirection_TopDown, MakeString("PlayBar Layout")); ui_FillRect(Interface, Bounds, Interface->Style.PanelBGColors[0]); - ui_StartRow(&State->Interface, 4); + ui_BeginRow(&State->Interface, 4); { if (ui_Button(Interface, MakeString("Pause"))) { @@ -796,7 +796,7 @@ AnimInfoView_Render(animation_timeline_state* TimelineState, rect2 Bounds, rende ui_FillRect(&State->Interface, Bounds, Interface->Style.PanelBGColors[0]); - ui_StartRow(&State->Interface, 2); + ui_BeginRow(&State->Interface, 2); { ui_Label(Interface, MakeString("Active Animation")); if (ui_BeginDropdown(Interface, ActiveAnim->Name)) diff --git a/src/app/editor/panels/foldhaus_panel_hierarchy.h b/src/app/editor/panels/foldhaus_panel_hierarchy.h index 12c9fc2..ec6ca55 100644 --- a/src/app/editor/panels/foldhaus_panel_hierarchy.h +++ b/src/app/editor/panels/foldhaus_panel_hierarchy.h @@ -52,7 +52,6 @@ HierarchyView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Ren // Fill in alternating color rows for the backgrounds for (u32 Line = 0; Line < LineCount; Line++) { - //LineBounds[Line] = ui_ReserveElementBounds(Layout); v4 ListItemBGColor = ui_GetListItemBGColor(State->Interface.Style, Line); ui_FillRect(&State->Interface, LineBounds[Line], ListItemBGColor); } diff --git a/src/app/editor/panels/foldhaus_panel_profiler.h b/src/app/editor/panels/foldhaus_panel_profiler.h index 80b7890..f6d1ce8 100644 --- a/src/app/editor/panels/foldhaus_panel_profiler.h +++ b/src/app/editor/panels/foldhaus_panel_profiler.h @@ -94,8 +94,13 @@ RenderProfiler_ListVisualization(ui_interface* Interface, ui_widget* Layout, deb char Backbuffer[256]; gs_string String = MakeString(Backbuffer, 0, 256); - r32 ColumnWidths[] = {256, 128, 128, 128, 128}; - ui_StartRow(Interface, 5, &ColumnWidths[0]); + ui_column_spec ColumnWidths[] = { + { UIColumnSize_Fixed, 256 }, + { UIColumnSize_Fixed, 128 }, + { UIColumnSize_Fixed, 128 }, + { UIColumnSize_Fixed, 128 }, + { UIColumnSize_Fixed, 128 }}; + ui_BeginRow(Interface, 5, &ColumnWidths[0]); { ui_Label(Interface, MakeString("Procedure")); ui_Label(Interface, MakeString("% Frame")); @@ -112,7 +117,7 @@ RenderProfiler_ListVisualization(ui_interface* Interface, ui_widget* Layout, deb { collated_scope_record* CollatedRecord = VisibleFrame->CollatedScopes + n; - ui_StartRow(Interface, 5, &ColumnWidths[0]); + ui_BeginRow(Interface, 5, &ColumnWidths[0]); { PrintF(&String, "%S", NameEntry.Name); ui_Label(Interface, String); @@ -181,7 +186,7 @@ ProfilerView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Rend ui_widget* Layout = ui_PushLayout(&State->Interface, ProcListBounds, LayoutDirection_TopDown, MakeString("Profiler Layout")); - ui_StartRow(&State->Interface, 4); + ui_BeginRow(&State->Interface, 4); { s64 FrameStartCycles = VisibleFrame->FrameStartCycles; s64 FrameTotalCycles = VisibleFrame->FrameEndCycles - VisibleFrame->FrameStartCycles; @@ -194,7 +199,7 @@ ProfilerView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Rend // NOTE(NAME): Skipping a space for aesthetic reasons, not functional, and could // be removed, or used for something else - ui_ReserveElementBounds(Layout); + ui_ReserveBounds(Layout, true); if (ui_Button(&State->Interface, MakeString("Resume Recording"))) { @@ -203,7 +208,7 @@ ProfilerView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Rend } ui_EndRow(&State->Interface); - ui_StartRow(&State->Interface, 8); + ui_BeginRow(&State->Interface, 8); { if (ui_Button(&State->Interface, MakeString("Scope View"))) { diff --git a/src/app/foldhaus_app.cpp b/src/app/foldhaus_app.cpp index 90ce10b..c56bcaf 100644 --- a/src/app/foldhaus_app.cpp +++ b/src/app/foldhaus_app.cpp @@ -106,7 +106,7 @@ INITIALIZE_APPLICATION(InitializeApplication) State->Interface.Style.ListBGHover = v4{ .22f, .22f, .22f, 1.f }; State->Interface.Style.ListBGSelected = v4{.44f, .44f, .44f, 1.f }; State->Interface.Style.Margin = v2{5, 5}; - State->Interface.Style.RowHeight = ui_GetTextLineHeight(State->Interface); + State->Interface.Style.RowHeight = ui_GetTextLineHeight(State->Interface) + (2 * State->Interface.Style.Margin.y); State->Interface.WidgetsCountMax = 4096; State->Interface.Widgets = PushArray(&State->Permanent, ui_widget, State->Interface.WidgetsCountMax); diff --git a/src/app/interface.h b/src/app/interface.h index c2c0b22..cc20c18 100644 --- a/src/app/interface.h +++ b/src/app/interface.h @@ -199,6 +199,13 @@ enum ui_layout_direction { LayoutDirection_TopDown, LayoutDirection_BottomUp, + LayoutDirection_Inherit, +}; + +struct ui_column +{ + r32 XMin; + r32 XMax; }; struct ui_widget @@ -225,10 +232,9 @@ struct ui_widget ui_layout_direction FillDirection; - b32 DrawHorizontal; - u32 ColumnsMax; - r32* ColumnWidths; + ui_column* Columns; u32 ColumnsCount; + u32 ColumnsFilled; // NOTE(pjs): I'm not sure this will stay but // its here so that when we end things like a dropdown, @@ -278,7 +284,10 @@ struct ui_widget_retained_state struct ui_interface { interface_config Style; + mouse_state Mouse; + rect2 WindowBounds; + render_command_buffer* RenderBuffer; ui_widget* Widgets; @@ -325,6 +334,28 @@ ui_WidgetIdsEqual(ui_widget_id A, ui_widget_id B) return Result; } +internal void +ui_WidgetSetFlag(ui_widget* Widget, u64 Flag) +{ + u64 Value = ((u64)1 << Flag); + Widget->Flags = Widget->Flags | Value; +} + +internal void +ui_WidgetClearFlag(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_widget_retained_state* ui_GetRetainedState(ui_interface* Interface, ui_widget_id Id) { @@ -374,21 +405,7 @@ ui_CreateWidget(ui_interface* Interface, gs_string String) Result->ChildrenRoot = 0; Result->ChildrenHead = 0; Result->Flags = 0; - 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; } @@ -406,37 +423,146 @@ ui_MouseClickedRect(ui_interface Interface, rect2 Rect) // Layout +static rect2 +ui_ReserveBounds(ui_widget* Widget, bool Inset) +{ + Assert(Widget->ColumnsCount > 0); + rect2 Bounds = {0}; + u32 ColumnIndex = Widget->ChildCount % Widget->ColumnsCount; + + ui_column Column = Widget->Columns[ColumnIndex]; + Bounds.Min.x = Column.XMin; + Bounds.Min.y = Widget->RowYAt; + Bounds.Max.x = Column.XMax; + Bounds.Max.y = Bounds.Min.y + Widget->RowHeight; + + if (Inset) + { + Bounds.Min.x += Widget->Margin.x; + Bounds.Min.y += Widget->Margin.y; + Bounds.Max.x -= Widget->Margin.x; + Bounds.Max.y -= Widget->Margin.y; + } + + return Bounds; +} + +internal void +ui_CommitBounds(ui_widget* Parent, rect2 Bounds) +{ + u32 ColumnIndex = Parent->ChildCount % Parent->ColumnsCount; + if (ColumnIndex == 0) + { + switch (Parent->FillDirection) + { + case LayoutDirection_BottomUp: + { + Parent->RowYAt = Bounds.Max.y; + }break; + + case LayoutDirection_TopDown: + { + Parent->RowYAt = Bounds.Min.y - Parent->RowHeight; + }break; + } + } +} + +internal void +ui_ExpandParentToFit(ui_widget* Widget) +{ + ui_widget* Parent = Widget->Parent; + switch (Widget->FillDirection) + { + case LayoutDirection_TopDown: + { + Parent->Bounds.Min.y = Min(Parent->Bounds.Min.y, Widget->Bounds.Min.y - Parent->Margin.y); + }break; + + case LayoutDirection_BottomUp: + { + Parent->Bounds.Max.y = Max(Parent->Bounds.Max.y, Widget->Bounds.Max.y + Parent->Margin.y); + }break; + + InvalidDefaultCase; + } +} + +internal void +ui_WidgetCreateColumns(ui_widget* Widget, u32 ColumnsCount, ui_interface* Interface) +{ + Widget->Columns = PushArray(Interface->PerFrameMemory, ui_column, ColumnsCount); + Widget->ColumnsCount = ColumnsCount; + Widget->ColumnsFilled = 0; +} + +internal void +ui_WidgetInitUniformColumns(ui_widget* Widget) +{ + r32 CurrentRowWidth = Rect2Width(Widget->Bounds); + r32 ColumnWidth = CurrentRowWidth / Widget->ColumnsCount; + for (u32 i = 0; i < Widget->ColumnsCount; i++) + { + ui_column* Column = Widget->Columns + i; + Column->XMin = Widget->Bounds.Min.x + (ColumnWidth * i); + Column->XMax = Column->XMin + ColumnWidth; + } +} + internal ui_widget* -ui_CreateLayoutWidget(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir, gs_string Name) +ui_CreateLayoutWidget(ui_interface* Interface, rect2 Bounds, gs_string Name, ui_layout_direction FillDir = LayoutDirection_Inherit) { ui_widget* Result = ui_CreateWidget(Interface, Name); - //ui_WidgetSetFlag(Result, UIWidgetFlag_DrawOutline); + ui_WidgetSetFlag(Result, UIWidgetFlag_DrawOutline); Result->Bounds = Bounds; Result->Margin = Interface->Style.Margin; Result->RowHeight = Interface->Style.RowHeight; - Result->FillDirection = FillDir; - switch(FillDir) + // Single Column Layout + ui_WidgetCreateColumns(Result, 1, Interface); + ui_WidgetInitUniformColumns(Result); + + if (FillDir == LayoutDirection_Inherit && Result->Parent != 0) + { + Result->FillDirection = Result->Parent->FillDirection; + } + else + { + Result->FillDirection = FillDir; + } + + switch(Result->FillDirection) { case LayoutDirection_BottomUp: { - Result->RowYAt = Bounds.Min.y + Result->Margin.y; + Result->RowYAt = Bounds.Min.y; }break; case LayoutDirection_TopDown: { - Result->RowYAt = Bounds.Max.y - (Result->RowHeight + Result->Margin.y); + Result->RowYAt = Bounds.Max.y - Result->RowHeight; }break; + + InvalidDefaultCase; } return Result; } +static ui_widget* +ui_PushOverlayLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir, gs_string Name) +{ + ui_widget* Result = ui_CreateLayoutWidget(Interface, Bounds, Name, FillDir); + SLLPushOrInit(Interface->DrawOrderRoot, Interface->DrawOrderHead, Result); + Interface->ActiveLayout = Result; + return Result; +} + static ui_widget* ui_PushLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir, gs_string Name) { - ui_widget* Result = ui_CreateLayoutWidget(Interface, Bounds, FillDir, Name); + ui_widget* Result = ui_CreateLayoutWidget(Interface, Bounds, Name, FillDir); if (Interface->DrawOrderRoot) { @@ -453,124 +579,178 @@ ui_PushLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir } static ui_widget* -ui_PushOverlayLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir, gs_string Name) +ui_PushLayout(ui_interface* Interface, gs_string Name, bool Inset = true) { - ui_widget* Result = ui_CreateLayoutWidget(Interface, Bounds, FillDir, Name); - SLLPushOrInit(Interface->DrawOrderRoot, Interface->DrawOrderHead, Result); - Interface->ActiveLayout = Result; - return Result; + rect2 Bounds = {}; + ui_layout_direction Direction = LayoutDirection_TopDown; + if (Interface->ActiveLayout) + { + Bounds = ui_ReserveBounds(Interface->ActiveLayout, Inset); + Direction = Interface->ActiveLayout->FillDirection; + } + else + { + Bounds.Min.x = Interface->WindowBounds.Min.x; + Bounds.Min.y = Interface->WindowBounds.Max.y; + Bounds.Max.x = Interface->WindowBounds.Max.x; + Bounds.Max.y = Interface->WindowBounds.Max.y; + + if (Inset) + { + Bounds.Min.x += Interface->Style.Margin.x; + Bounds.Max.x -= Interface->Style.Margin.x; + } + + Direction = LayoutDirection_TopDown; + } + return ui_PushLayout(Interface, Bounds, Direction, Name); +} + +internal void +ui_ExpandToFitChildren(ui_widget* Parent) +{ + v2 Extents = { Parent->Bounds.Max.y, Parent->Bounds.Min.y }; + for (ui_widget* Child = Parent->ChildrenRoot; Child != 0; Child = Child->Next) + { + Extents.x = Min(Extents.x, Child->Bounds.Min.y); + Extents.y = Max(Extents.y, Child->Bounds.Max.y); + } + + switch(Parent->FillDirection) + { + case LayoutDirection_BottomUp: + { + Parent->Bounds.Max.y = Extents.y + Parent->Margin.y; + }break; + + case LayoutDirection_TopDown: + { + Parent->Bounds.Min.y = Extents.x - Parent->Margin.y; + }break; + + InvalidDefaultCase; + } } static void ui_PopLayout(ui_interface* Interface) { Assert(Interface->ActiveLayout != 0); + + ui_widget* Layout = Interface->ActiveLayout; + ui_ExpandToFitChildren(Layout); + Interface->ActiveLayout = Interface->ActiveLayout->Parent; + + // NOTE(pjs): This indicates that the parent layout should + // expand to fit the layout that we just popped + if (Interface->ActiveLayout != 0 && + Interface->ActiveLayout->ChildrenHead == Layout) + { + ui_CommitBounds(Interface->ActiveLayout, Layout->Bounds); + } } static void -ui_StartRow(ui_interface* Interface, u32 ColumnsMax = 0) +ui_BeginRow(ui_interface* Interface, u32 ColumnsMax) { - Interface->ActiveLayout->DrawHorizontal = true; - Interface->ActiveLayout->ColumnsMax = ColumnsMax; - Interface->ActiveLayout->ColumnWidths = 0; - Interface->ActiveLayout->ColumnsCount = 0; + ui_widget* Layout = ui_PushLayout(Interface, MakeString("Row"), false); + ui_WidgetCreateColumns(Layout, ColumnsMax, Interface); + ui_WidgetInitUniformColumns(Layout); } -static void -ui_StartRow(ui_interface* Interface, u32 ColumnsMax, r32* ColumnWidths) +enum ui_column_size_rule { - Interface->ActiveLayout->DrawHorizontal = true; - Interface->ActiveLayout->ColumnsMax = ColumnsMax; - Interface->ActiveLayout->ColumnWidths = ColumnWidths; - Interface->ActiveLayout->ColumnsCount = 0; + UIColumnSize_Fixed, + UIColumnSize_Percent, + UIColumnSize_Fill, +}; + +struct ui_column_spec +{ + ui_column_size_rule Rule; + union + { + r32 Width; + r32 Percent; + }; +}; + +static void +ui_BeginRow(ui_interface* Interface, u32 ColumnsMax, ui_column_spec* ColumnRules) +{ + ui_widget* Layout = ui_PushLayout(Interface, MakeString("Row"), false); + ui_WidgetCreateColumns(Layout, ColumnsMax, Interface); + + // First Pass, determine widths of each column, and how much space is left to be divided by the fill columns + r32 RowWidth = Rect2Width(Layout->Bounds); + r32 RemainingSpace = RowWidth; + u32 FillColumnsCount = 0; + for (u32 i = 0; i < Layout->ColumnsCount; i++) + { + ui_column_spec Spec = ColumnRules[i]; + ui_column* Column = Layout->Columns + i; + + switch (Spec.Rule) + { + case UIColumnSize_Fixed: + { + Column->XMax = Spec.Width; + RemainingSpace -= Column->XMax; + }break; + + case UIColumnSize_Percent: + { + Column->XMax = Spec.Percent * RowWidth; + RemainingSpace -= Column->XMax; + }break; + + case UIColumnSize_Fill: + { + FillColumnsCount += 1; + }break; + InvalidDefaultCase; + } + } + + r32 FillColumnWidth = RemainingSpace / FillColumnsCount; + + // Second Pass, specify the actual XMin and XMax of each column + r32 ColumnStartX = Layout->Bounds.Min.x; + for (u32 i = 0; i < Layout->ColumnsCount; i++) + { + ui_column_spec Spec = ColumnRules[i]; + ui_column* Column = Layout->Columns + i; + + r32 ColumnWidth = 0; + switch (Spec.Rule) + { + case UIColumnSize_Fixed: + case UIColumnSize_Percent: + { + ColumnWidth = Column->XMax; + }break; + + case UIColumnSize_Fill: + { + ColumnWidth = FillColumnWidth; + }break; + } + + Column->XMin = ColumnStartX ; + Column->XMax = Column->XMin + Max(0, ColumnWidth); + ColumnStartX = Column->XMax; + } } static void ui_EndRow(ui_interface* Interface) { - Interface->ActiveLayout->DrawHorizontal = false; - Interface->ActiveLayout->ColumnWidths = 0; - Interface->ActiveLayout->RowYAt -= (Interface->ActiveLayout->RowHeight + Interface->ActiveLayout->Margin.y); -} - -static b32 -ui_TryReserveElementBounds(ui_widget* Widget, rect2* Bounds) -{ - b32 Result = true; - if (!Widget->DrawHorizontal) - { - Bounds->Min = { Widget->Bounds.Min.x + Widget->Margin.x, Widget->RowYAt }; - Bounds->Max = { Widget->Bounds.Max.x - Widget->Margin.x, Bounds->Min.y + Widget->RowHeight }; - - r32 RowOffset = Widget->RowHeight + Widget->Margin.y; - switch (Widget->FillDirection) - { - case LayoutDirection_BottomUp: - { - Widget->RowYAt += RowOffset; - }break; - - case LayoutDirection_TopDown: - { - Widget->RowYAt -= RowOffset; - }break; - - InvalidDefaultCase; - } - } - else - { - if (Widget->ColumnsMax > 0) - { - Assert(Widget->ColumnsCount < Widget->ColumnsMax); - if (Widget->ColumnWidths != 0) - { - v2 Min = { - Widget->Bounds.Min.x + Widget->Margin.x, - Widget->RowYAt - }; - for (u32 i = 0; i < Widget->ColumnsCount; i++) - { - Min.x += Widget->ColumnWidths[i]; - } - Bounds->Min = Min; - Bounds->Max = Bounds->Min + v2{ - Widget->ColumnWidths[Widget->ColumnsCount] - Widget->Margin.x, - Widget->RowHeight - }; - } - else - { - r32 ElementWidth = Rect2Width(Widget->Bounds) / Widget->ColumnsMax; - Bounds->Min = { - Widget->Bounds.Min.x + (ElementWidth * Widget->ColumnsCount) + Widget->Margin.x, - Widget->RowYAt - }; - Bounds->Max = { - Bounds->Min.x + ElementWidth - (Widget->Margin.x * 2), - Bounds->Min.y + Widget->RowHeight - }; - } - Widget->ColumnsCount++; - } - else - { - Result = false; - } - } - return Result; -} - -static rect2 -ui_ReserveElementBounds(ui_widget* Layout) -{ - rect2 Bounds = {0}; - if (!ui_TryReserveElementBounds(Layout, &Bounds)) - { - InvalidCodePath; - } - return Bounds; + ui_PopLayout(Interface); + //ui_widget* Layout = Interface->ActiveLayout; + //Layout->DrawHorizontal = false; + //Layout->RowYAt -= (Layout->RowHeight + Layout->Margin.y); + } static rect2 @@ -578,10 +758,6 @@ ui_LayoutRemaining(ui_widget Layout) { rect2 Result = Layout.Bounds; Result.Max.y = Layout.RowYAt; - if (Layout.DrawHorizontal) - { - Result.Max.y -= Layout.RowHeight; - } return Result; } @@ -625,20 +801,17 @@ ui_EvaluateWidget(ui_interface* Interface, ui_widget* Widget, rect2 Bounds) } + Assert(Widget->Parent != 0); + ui_CommitBounds(Widget->Parent, Widget->Bounds); + return Result; } internal ui_eval_result ui_EvaluateWidget(ui_interface* Interface, ui_widget* Widget) { - rect2 Bounds = {0}; ui_widget* Layout = Interface->ActiveLayout; - if (!ui_TryReserveElementBounds(Layout, &Bounds)) - { - // TODO(pjs): This isn't invalid, but Idk when we'd hit this case yet - InvalidCodePath; - } - + rect2 Bounds = ui_ReserveBounds(Layout, true); return ui_EvaluateWidget(Interface, Widget, Bounds); } @@ -781,8 +954,8 @@ ui_EvaluateDropdown(ui_interface* Interface, ui_widget* Widget, ui_eval_result E 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 } + v2{ Widget->Bounds.Min.x - ParentLayout.Margin.x, Widget->Bounds.Max.y }, + v2{ Widget->Bounds.Max.x + ParentLayout.Margin.x, ParentLayoutMaxY } }; } else @@ -790,14 +963,15 @@ ui_EvaluateDropdown(ui_interface* Interface, ui_widget* Widget, ui_eval_result E 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 } + v2{ Widget->Bounds.Min.x - ParentLayout.Margin.x, ParentLayoutMinY }, + v2{ Widget->Bounds.Max.x + ParentLayout.Margin.x, Widget->Bounds.Min.y } }; } ui_widget* Layout = ui_PushOverlayLayout(Interface, MenuBounds, Direction, MakeString("WidgetLayout")); Layout->Margin.y = 0; Layout->WidgetReference = Widget->Id; + ui_WidgetClearFlag(Layout, UIWidgetFlag_DrawOutline); } return State->Value; @@ -913,6 +1087,19 @@ ui_Toggle(ui_interface* Interface, gs_string Text, bool Value) return Result; } +internal void +ui_BeginList(ui_interface* Interface, gs_string Text, u32 ViewportRows) +{ + ui_widget* Layout = ui_PushLayout(Interface, Text); + +} + +internal void +ui_EndList(ui_interface* Interface) +{ + +} + // // OLD From 118b734d6c9ac07c7af0b2a7083e5a72c946fdfa Mon Sep 17 00:00:00 2001 From: PS Date: Sun, 15 Nov 2020 16:29:13 -0800 Subject: [PATCH 08/44] Implemented a list view, which included upgrading rendering strings to accept clipping masks --- src/app/editor/foldhaus_editor.cpp | 173 +++++--- .../editor/panels/foldhaus_panel_profiler.h | 2 +- src/app/foldhaus_renderer.h | 15 + src/app/interface.h | 377 +++++++++--------- src/gs_libs/gs_types.cpp | 39 ++ 5 files changed, 352 insertions(+), 254 deletions(-) diff --git a/src/app/editor/foldhaus_editor.cpp b/src/app/editor/foldhaus_editor.cpp index 6fda7e6..9d9cce6 100644 --- a/src/app/editor/foldhaus_editor.cpp +++ b/src/app/editor/foldhaus_editor.cpp @@ -89,7 +89,7 @@ Editor_Update(app_state* State, context* Context, input_queue InputQueue) } internal void -Editor_DrawWidgetString(app_state* State, context* Context, render_command_buffer* RenderBuffer, ui_widget Widget, v4 Color) +Editor_DrawWidgetString(app_state* State, context* Context, render_command_buffer* RenderBuffer, ui_widget Widget, rect2 ClippingBox, v4 Color) { render_quad_batch_constructor BatchConstructor = PushRenderTexture2DBatch(RenderBuffer, Widget.String.Length, @@ -106,12 +106,12 @@ Editor_DrawWidgetString(app_state* State, context* Context, render_command_buffe { case Align_Left: { - RegisterPosition = DrawStringLeftAligned(&BatchConstructor, StringExpand(Widget.String), RegisterPosition, State->Interface.Style.Font, Color); + RegisterPosition = DrawStringLeftAligned(&BatchConstructor, StringExpand(Widget.String), RegisterPosition, State->Interface.Style.Font, ClippingBox, Color); }break; case Align_Right: { - RegisterPosition = DrawStringRightAligned(&BatchConstructor, StringExpand(Widget.String), RegisterPosition, State->Interface.Style.Font, Color); + RegisterPosition = DrawStringRightAligned(&BatchConstructor, StringExpand(Widget.String), RegisterPosition, State->Interface.Style.Font, ClippingBox, Color); }break; InvalidDefaultCase; @@ -121,62 +121,109 @@ Editor_DrawWidgetString(app_state* State, context* Context, render_command_buffe internal void Editor_DrawWidget(app_state* State, context* Context, render_command_buffer* RenderBuffer, ui_widget Widget) { - if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawBackground)) + rect2 WidgetParentUnion = Widget.Bounds; + if (Widget.Parent) { - 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); + WidgetParentUnion = Rect2Union(Widget.Bounds, Widget.Parent->Bounds); } - if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawString) && Widget.String.Length > 0) + if (!Widget.Parent || (Rect2Area(WidgetParentUnion) > 0)) { - v4 Color = State->Interface.Style.TextColor; - Editor_DrawWidgetString(State, Context, RenderBuffer, Widget, Color); - } - - if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawHorizontalFill)) - { - v4 Color = PinkV4; //State->Interface.Style.ButtonColor_Active; - if (ui_WidgetIdsEqual(Widget.Id, State->Interface.HotWidget)) + if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawBackground)) { - Color = GreenV4; //State->Interface.Style.ButtonColor_Selected; + 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; + } + PushRenderQuad2DClipped(RenderBuffer, Widget.Bounds, WidgetParentUnion, Color); } - if (ui_WidgetIdsEqual(Widget.Id, State->Interface.ActiveWidget)) - { - Color = TealV4; //State->Interface.Style.ButtonColor_Selected; - } - - rect2 HFillBounds = {}; - HFillBounds.Min = Widget.Bounds.Min; - HFillBounds.Max = { - LerpR32(Widget.HorizontalFillPercent, Widget.Bounds.Min.x, Widget.Bounds.Max.x), - Widget.Bounds.Max.y - }; - PushRenderQuad2D(RenderBuffer, HFillBounds.Min, HFillBounds.Max, Color); if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawString) && Widget.String.Length > 0) { - // TODO(pjs): Mask this text by the horizontal fill - // TODO(pjs): add this color to the style - v4 TextColor = BlackV4; - Editor_DrawWidgetString(State, Context, RenderBuffer, Widget, TextColor); + v4 Color = State->Interface.Style.TextColor; + Editor_DrawWidgetString(State, Context, RenderBuffer, Widget, WidgetParentUnion, Color); + } + + if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawHorizontalFill) || + ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawVerticalFill)) + { + v4 Color = State->Interface.Style.ButtonColor_Active; + if (ui_WidgetIdsEqual(Widget.Id, State->Interface.HotWidget)) + { + Color = State->Interface.Style.ButtonColor_Selected; + } + if (ui_WidgetIdsEqual(Widget.Id, State->Interface.ActiveWidget)) + { + Color = State->Interface.Style.ButtonColor_Selected; + } + + rect2 FillBounds = {}; + if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawHorizontalFill)) + { + FillBounds.Min.y = Widget.Bounds.Min.y; + FillBounds.Max.y = Widget.Bounds.Max.y; + r32 FillToPoint = LerpR32(Widget.FillPercent, Widget.Bounds.Min.x, Widget.Bounds.Max.x); + if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawFillReversed)) + { + FillBounds.Min.x = FillToPoint; + FillBounds.Max.x = Widget.Bounds.Max.x; + } + else if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawFillAsHandle)) + { + FillBounds.Min.x = FillToPoint - 5; + FillBounds.Max.x = FillToPoint + 5; + } + else + { + FillBounds.Min.x = Widget.Bounds.Min.x; + FillBounds.Max.x = FillToPoint; + } + } + else if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawVerticalFill)) + { + FillBounds.Min.x = Widget.Bounds.Min.x; + FillBounds.Max.x = Widget.Bounds.Max.x; + r32 FillToPoint = LerpR32(Widget.FillPercent, Widget.Bounds.Min.y, Widget.Bounds.Max.y); + if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawFillReversed)) + { + FillBounds.Min.y = FillToPoint; + FillBounds.Max.y = Widget.Bounds.Max.y; + } + else if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawFillAsHandle)) + { + FillBounds.Min.y = FillToPoint - 5; + FillBounds.Max.y = FillToPoint + 5; + } + else + { + FillBounds.Min.y = Widget.Bounds.Min.y; + FillBounds.Max.y = FillToPoint; + } + } + PushRenderQuad2D(RenderBuffer, FillBounds.Min, FillBounds.Max, Color); + + if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawString) && Widget.String.Length > 0) + { + // TODO(pjs): Mask this text by the horizontal fill + // TODO(pjs): add this color to the style + v4 TextColor = BlackV4; + Editor_DrawWidgetString(State, Context, RenderBuffer, Widget, WidgetParentUnion, TextColor); + } + } + + + if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawOutline)) + { + // TODO(pjs): replace these with values from the style + r32 Thickness = 1.0f; + v4 Color = WhiteV4; + PushRenderBoundingBox2D(RenderBuffer, WidgetParentUnion.Min, WidgetParentUnion.Max, Thickness, Color); } - } - - - 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); } if (Widget.ChildrenRoot) @@ -207,21 +254,29 @@ TestRender(app_state* State, context* Context, render_command_buffer* RenderBuff ui_PushLayout(&State->Interface, A); { #if 1 - ui_column_spec ColumnRules[] = { - { UIColumnSize_Fixed, 128 }, - { UIColumnSize_Fill, 0 }, - { UIColumnSize_Percent, .5f } - }; - ui_BeginRow(&State->Interface, 3, ColumnRules); + ui_Label(&State->Interface, MakeString("Spacer")); + ui_Label(&State->Interface, MakeString("Spacer")); + ui_Label(&State->Interface, MakeString("Spacer")); + ui_Label(&State->Interface, MakeString("Spacer")); + ui_Label(&State->Interface, MakeString("Spacer")); + ui_BeginList(&State->Interface, MakeString("TestList"), 5, 9); { ui_Button(&State->Interface, MakeString("B")); ui_Button(&State->Interface, MakeString("B")); ui_Button(&State->Interface, MakeString("B")); + ui_Button(&State->Interface, MakeString("B")); + ui_Button(&State->Interface, MakeString("B")); + ui_Button(&State->Interface, MakeString("B")); + ui_Button(&State->Interface, MakeString("B")); + ui_Button(&State->Interface, MakeString("B")); + ui_Button(&State->Interface, MakeString("B")); + } - ui_EndRow(&State->Interface); - ui_Button(&State->Interface, MakeString("B")); - ui_Button(&State->Interface, MakeString("C")); + ui_EndList(&State->Interface); + //ui_Button(&State->Interface, MakeString("B")); + //ui_Button(&State->Interface, MakeString("C")); + //TestSlider_Value = ui_RangeSlider(&State->Interface, MakeString("TestSlider"), TestSlider_Value, TestSlider_Min, TestSlider_Max); #elif 0 ui_PushLayout(&State->Interface, MakeString("Outer")); { @@ -288,7 +343,7 @@ Editor_Render(app_state* State, context* Context, render_command_buffer* RenderB PushRenderOrthographic(RenderBuffer, State->WindowBounds); PushRenderClearScreen(RenderBuffer); -#if 0 +#if 1 TestRender(State, Context, RenderBuffer); #else ui_InterfaceReset(&State->Interface); diff --git a/src/app/editor/panels/foldhaus_panel_profiler.h b/src/app/editor/panels/foldhaus_panel_profiler.h index f6d1ce8..133a0d1 100644 --- a/src/app/editor/panels/foldhaus_panel_profiler.h +++ b/src/app/editor/panels/foldhaus_panel_profiler.h @@ -199,7 +199,7 @@ ProfilerView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Rend // NOTE(NAME): Skipping a space for aesthetic reasons, not functional, and could // be removed, or used for something else - ui_ReserveBounds(Layout, true); + ui_ReserveBounds(&State->Interface, Layout, true); if (ui_Button(&State->Interface, MakeString("Resume Recording"))) { diff --git a/src/app/foldhaus_renderer.h b/src/app/foldhaus_renderer.h index e316c71..a40c0f4 100644 --- a/src/app/foldhaus_renderer.h +++ b/src/app/foldhaus_renderer.h @@ -589,6 +589,21 @@ PushRenderQuad2D (render_command_buffer* Buffer, v2 Min, v2 Max, v4 Color) PushQuad2DOnBatch(&Batch, Min, Max, Color); } +internal void +PushRenderQuad2D (render_command_buffer* Buffer, rect2 Rect, v4 Color) +{ + render_quad_batch_constructor Batch = PushRenderQuad2DBatch(Buffer, 1); + PushQuad2DOnBatch(&Batch, Rect.Min, Rect.Max, Color); +} + +internal void +PushRenderQuad2DClipped (render_command_buffer* Buffer, rect2 Rect, rect2 ClippingBox, v4 Color) +{ + rect2 Clipped = Rect2Union(Rect, ClippingBox); + render_quad_batch_constructor Batch = PushRenderQuad2DBatch(Buffer, 1); + PushQuad2DOnBatch(&Batch, Clipped.Min, Clipped.Max, Color); +} + internal void PushRenderQuad2D(render_command_buffer* Buffer, v2 P0, v2 P1, v2 P2, v2 P3, v4 Color) { diff --git a/src/app/interface.h b/src/app/interface.h index cc20c18..89bdc42 100644 --- a/src/app/interface.h +++ b/src/app/interface.h @@ -13,22 +13,68 @@ enum gs_string_alignment }; internal void -DrawCharacter_ (render_quad_batch_constructor* BatchConstructor, r32 MinX, r32 MinY, codepoint_bitmap CodepointInfo, v4 Color) +ClipUVRect(rect2* Bounds, rect2* UVs, rect2 ClippingBox) { + rect2 NewBounds = Rect2Union(*Bounds, ClippingBox); + + r32 OldWidth = Rect2Width(*Bounds); + r32 OldHeight = Rect2Height(*Bounds); + + v2 MinInsetPercent = v2{ + (NewBounds.Min.x - Bounds->Min.x) / OldWidth, + (NewBounds.Min.y - Bounds->Min.y) / OldHeight, + }; + + v2 MaxInsetPercent = v2{ + (NewBounds.Max.x - Bounds->Min.x) / OldWidth, + (NewBounds.Max.y - Bounds->Min.y) / OldHeight, + }; + + UVs->Min.x = LerpR32(MinInsetPercent.x, UVs->Min.x, UVs->Max.x); + UVs->Min.y = LerpR32(MinInsetPercent.y, UVs->Min.y, UVs->Max.y); + UVs->Max.x = LerpR32(MaxInsetPercent.x, UVs->Min.x, UVs->Max.x); + UVs->Max.y = LerpR32(MaxInsetPercent.y, UVs->Min.y, UVs->Max.y); + + *Bounds = NewBounds; +} + +internal void +DrawCharacter_ (render_quad_batch_constructor* BatchConstructor, r32 MinX, r32 MinY, codepoint_bitmap CodepointInfo, rect2 ClippingBox, v4 Color) +{ + rect2 Bounds = {}; + Bounds.Min.x = FloorR32(MinX); + Bounds.Min.y = FloorR32(MinY); + Bounds.Max.x = Bounds.Min.x + (CodepointInfo.Width); + Bounds.Max.y = Bounds.Min.y + (CodepointInfo.Height); + + rect2 UVBounds = {}; + UVBounds.Min = CodepointInfo.UVMin; + UVBounds.Max = CodepointInfo.UVMax; + + ClipUVRect(&Bounds, &UVBounds, ClippingBox); + s32 AlignedMinX = (s32)(MinX); s32 AlignedMinY = (s32)(MinY); s32 AlignedMaxX = AlignedMinX + (CodepointInfo.Width); s32 AlignedMaxY = AlignedMinY + (CodepointInfo.Height); +#if 1 + PushQuad2DOnBatch(BatchConstructor, + Rect2BottomLeft(Bounds), Rect2BottomRight(Bounds), + Rect2TopRight(Bounds), Rect2TopLeft(Bounds), + UVBounds.Min, UVBounds.Max, + Color); +#else PushQuad2DOnBatch(BatchConstructor, v2{(r32)AlignedMinX, (r32)AlignedMinY}, v2{(r32)AlignedMaxX, (r32)AlignedMinY}, v2{(r32)AlignedMaxX, (r32)AlignedMaxY}, v2{(r32)AlignedMinX, (r32)AlignedMaxY}, CodepointInfo.UVMin, CodepointInfo.UVMax, Color); +#endif } internal v2 -DrawCharacterLeftAligned (render_quad_batch_constructor* BatchConstructor, char C, bitmap_font Font, v2 Position, v4 Color) +DrawCharacterLeftAligned (render_quad_batch_constructor* BatchConstructor, char C, bitmap_font Font, v2 Position, rect2 ClippingBox, v4 Color) { s32 GlyphDataIndex = GetIndexForCodepoint(Font, C); codepoint_bitmap CodepointInfo = Font.CodepointValues[GlyphDataIndex]; @@ -36,7 +82,7 @@ DrawCharacterLeftAligned (render_quad_batch_constructor* BatchConstructor, char // NOTE(Peter): r32 MinX = Position.x + CodepointInfo.XOffset; r32 MinY = Position.y + CodepointInfo.YOffset; - DrawCharacter_(BatchConstructor, MinX, MinY, CodepointInfo, Color); + DrawCharacter_(BatchConstructor, MinX, MinY, CodepointInfo, ClippingBox, Color); // NOTE(Peter): v2 PointAfterCharacter = v2{Position.x + CodepointInfo.Width, Position.y}; @@ -44,7 +90,7 @@ DrawCharacterLeftAligned (render_quad_batch_constructor* BatchConstructor, char } internal v2 -DrawCharacterRightAligned (render_quad_batch_constructor* BatchConstructor, char C, bitmap_font Font, v2 Position, v4 Color) +DrawCharacterRightAligned (render_quad_batch_constructor* BatchConstructor, char C, bitmap_font Font, v2 Position, rect2 ClippingBox, v4 Color) { s32 GlyphDataIndex = GetIndexForCodepoint(Font, C); codepoint_bitmap CodepointInfo = Font.CodepointValues[GlyphDataIndex]; @@ -52,7 +98,7 @@ DrawCharacterRightAligned (render_quad_batch_constructor* BatchConstructor, char // NOTE(Peter): r32 MinX = Position.x - (CodepointInfo.XOffset + CodepointInfo.Width); r32 MinY = Position.y + CodepointInfo.YOffset + CodepointInfo.YOffset; - DrawCharacter_(BatchConstructor, MinX, MinY, CodepointInfo, Color); + DrawCharacter_(BatchConstructor, MinX, MinY, CodepointInfo, ClippingBox, Color); // NOTE(Peter): v2 PointAfterCharacter = v2{Position.x-(CodepointInfo.Width + CodepointInfo.XOffset), Position.y}; @@ -60,13 +106,13 @@ DrawCharacterRightAligned (render_quad_batch_constructor* BatchConstructor, char } internal v2 -DrawStringLeftAligned (render_quad_batch_constructor* BatchConstructor, s32 Length, char* gs_string, v2 InitialRegisterPosition, bitmap_font* Font, v4 Color) +DrawStringLeftAligned (render_quad_batch_constructor* BatchConstructor, s32 Length, char* gs_string, v2 InitialRegisterPosition, bitmap_font* Font, rect2 ClippingBox, v4 Color) { v2 RegisterPosition = InitialRegisterPosition; char* C = gs_string; for (s32 i = 0; i < Length; i++) { - v2 PositionAfterCharacter = DrawCharacterLeftAligned(BatchConstructor, *C, *Font, RegisterPosition, Color); + v2 PositionAfterCharacter = DrawCharacterLeftAligned(BatchConstructor, *C, *Font, RegisterPosition, ClippingBox, Color); RegisterPosition.x = PositionAfterCharacter.x; C++; } @@ -74,13 +120,13 @@ DrawStringLeftAligned (render_quad_batch_constructor* BatchConstructor, s32 Leng } internal v2 -DrawStringRightAligned (render_quad_batch_constructor* BatchConstructor, s32 Length, char* gs_string, v2 InitialRegisterPosition, bitmap_font* Font, v4 Color) +DrawStringRightAligned (render_quad_batch_constructor* BatchConstructor, s32 Length, char* gs_string, v2 InitialRegisterPosition, bitmap_font* Font, rect2 ClippingBox, v4 Color) { v2 RegisterPosition = InitialRegisterPosition; char* C = gs_string + Length - 1; for (s32 i = Length - 1; i >= 0; i--) { - v2 PositionAfterCharacter = DrawCharacterRightAligned(BatchConstructor, *C, *Font, RegisterPosition, Color); + v2 PositionAfterCharacter = DrawCharacterRightAligned(BatchConstructor, *C, *Font, RegisterPosition, ClippingBox, Color); RegisterPosition.x = PositionAfterCharacter.x; C--; } @@ -101,14 +147,22 @@ DrawString(render_command_buffer* RenderBuffer, gs_string String, bitmap_font* F Font->BitmapBytesPerPixel, Font->BitmapStride); + // TODO(pjs): I don't like this solution but it'll do for now and I want to focus on other problems + // especially since I think this one will go away once I finish the ui overhaul + rect2 InfiniteClipBox = {}; + InfiniteClipBox.Min.x = -100000; + InfiniteClipBox.Min.y = -100000; + InfiniteClipBox.Max.x = 100000; + InfiniteClipBox.Max.y = 100000; + v2 RegisterPosition = Position; if (Alignment == Align_Left) { - RegisterPosition = DrawStringLeftAligned(&BatchConstructor, StringExpand(String), RegisterPosition, Font, Color); + RegisterPosition = DrawStringLeftAligned(&BatchConstructor, StringExpand(String), RegisterPosition, Font, InfiniteClipBox, Color); } else if (Alignment == Align_Right) { - RegisterPosition = DrawStringRightAligned(&BatchConstructor, StringExpand(String), RegisterPosition, Font, Color); + RegisterPosition = DrawStringRightAligned(&BatchConstructor, StringExpand(String), RegisterPosition, Font, InfiniteClipBox, Color); } else { @@ -128,6 +182,7 @@ DrawCursor (render_quad_batch_constructor* BatchConstructor, v2 Position, v4 Col PushQuad2DOnBatch(BatchConstructor, Min, Max, Color); } +#if 0 internal v2 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) { @@ -179,14 +234,19 @@ DrawStringWithCursor (render_command_buffer* RenderBuffer, gs_string String, s32 LowerRight.x = RegisterPosition.x; return LowerRight; } +#endif enum ui_widget_flag { + UIWidgetFlag_ExpandsToFitChildren, UIWidgetFlag_DrawBackground, UIWidgetFlag_DrawString, UIWidgetFlag_DrawOutline, UIWidgetFlag_Clickable, UIWidgetFlag_DrawHorizontalFill, + UIWidgetFlag_DrawVerticalFill, + UIWidgetFlag_DrawFillReversed, + UIWidgetFlag_DrawFillAsHandle, }; struct ui_widget_id @@ -221,7 +281,7 @@ struct ui_widget ui_widget* Next; // Slider - r32 HorizontalFillPercent; + r32 FillPercent; // Layout ui_widget* Parent; @@ -279,6 +339,9 @@ struct ui_widget_retained_state bool Value; r32 InitialValueR32; u32 FramesSinceAccess; + + // For use in layouts that allow you to scroll / pan + v2 ChildrenDrawOffset; }; struct ui_interface @@ -381,6 +444,17 @@ ui_CreateRetainedState(ui_interface* Interface, ui_widget* Widget) return Result; } +internal ui_widget_retained_state* +ui_GetOrCreateRetainedState(ui_interface* Interface, ui_widget* Widget) +{ + ui_widget_retained_state* State = ui_GetRetainedState(Interface, Widget->Id); + if (!State) + { + State = ui_CreateRetainedState(Interface, Widget); + } + return State; +} + internal ui_widget* ui_CreateWidget(ui_interface* Interface, gs_string String) { @@ -405,6 +479,7 @@ ui_CreateWidget(ui_interface* Interface, gs_string String) Result->ChildrenRoot = 0; Result->ChildrenHead = 0; Result->Flags = 0; + ui_WidgetSetFlag(Result, UIWidgetFlag_ExpandsToFitChildren); return Result; } @@ -424,7 +499,7 @@ ui_MouseClickedRect(ui_interface Interface, rect2 Rect) // Layout static rect2 -ui_ReserveBounds(ui_widget* Widget, bool Inset) +ui_ReserveBounds(ui_interface* Interface, ui_widget* Widget, bool Inset) { Assert(Widget->ColumnsCount > 0); rect2 Bounds = {0}; @@ -444,6 +519,15 @@ ui_ReserveBounds(ui_widget* Widget, bool Inset) Bounds.Max.y -= Widget->Margin.y; } + if (Widget->ChildCount == 0) + { + ui_widget_retained_state* State = ui_GetRetainedState(Interface, Widget->Id); + if (State) + { + Bounds = Rect2Translate(Bounds, State->ChildrenDrawOffset); + } + } + return Bounds; } @@ -585,7 +669,7 @@ ui_PushLayout(ui_interface* Interface, gs_string Name, bool Inset = true) ui_layout_direction Direction = LayoutDirection_TopDown; if (Interface->ActiveLayout) { - Bounds = ui_ReserveBounds(Interface->ActiveLayout, Inset); + Bounds = ui_ReserveBounds(Interface, Interface->ActiveLayout, Inset); Direction = Interface->ActiveLayout->FillDirection; } else @@ -609,6 +693,8 @@ ui_PushLayout(ui_interface* Interface, gs_string Name, bool Inset = true) internal void ui_ExpandToFitChildren(ui_widget* Parent) { + if (!ui_WidgetIsFlagSet(*Parent, UIWidgetFlag_ExpandsToFitChildren)) { return; } + v2 Extents = { Parent->Bounds.Max.y, Parent->Bounds.Min.y }; for (ui_widget* Child = Parent->ChildrenRoot; Child != 0; Child = Child->Next) { @@ -620,12 +706,12 @@ ui_ExpandToFitChildren(ui_widget* Parent) { case LayoutDirection_BottomUp: { - Parent->Bounds.Max.y = Extents.y + Parent->Margin.y; + Parent->Bounds.Max.y = Max(Extents.y + Parent->Margin.y, Parent->Bounds.Max.y); }break; case LayoutDirection_TopDown: { - Parent->Bounds.Min.y = Extents.x - Parent->Margin.y; + Parent->Bounds.Min.y = Min(Extents.x - Parent->Margin.y, Parent->Bounds.Min.y); }break; InvalidDefaultCase; @@ -651,12 +737,13 @@ ui_PopLayout(ui_interface* Interface) } } -static void +static ui_widget* ui_BeginRow(ui_interface* Interface, u32 ColumnsMax) { ui_widget* Layout = ui_PushLayout(Interface, MakeString("Row"), false); ui_WidgetCreateColumns(Layout, ColumnsMax, Interface); ui_WidgetInitUniformColumns(Layout); + return Layout; } enum ui_column_size_rule @@ -676,13 +763,14 @@ struct ui_column_spec }; }; -static void +static ui_widget* ui_BeginRow(ui_interface* Interface, u32 ColumnsMax, ui_column_spec* ColumnRules) { ui_widget* Layout = ui_PushLayout(Interface, MakeString("Row"), false); ui_WidgetCreateColumns(Layout, ColumnsMax, Interface); // First Pass, determine widths of each column, and how much space is left to be divided by the fill columns + // If a size is specified, it is stored in Column->XMax r32 RowWidth = Rect2Width(Layout->Bounds); r32 RemainingSpace = RowWidth; u32 FillColumnsCount = 0; @@ -741,16 +829,14 @@ ui_BeginRow(ui_interface* Interface, u32 ColumnsMax, ui_column_spec* ColumnRules Column->XMax = Column->XMin + Max(0, ColumnWidth); ColumnStartX = Column->XMax; } + + return Layout; } static void ui_EndRow(ui_interface* Interface) { ui_PopLayout(Interface); - //ui_widget* Layout = Interface->ActiveLayout; - //Layout->DrawHorizontal = false; - //Layout->RowYAt -= (Layout->RowHeight + Layout->Margin.y); - } static rect2 @@ -771,10 +857,12 @@ ui_EvaluateWidget(ui_interface* Interface, ui_widget* Widget, rect2 Bounds) Widget->Bounds = Bounds; SLLPushOrInit(Interface->ActiveLayout->ChildrenRoot, Interface->ActiveLayout->ChildrenHead, Widget); Interface->ActiveLayout->ChildCount += 1; + ui_CommitBounds(Widget->Parent, Widget->Bounds); if (ui_WidgetIsFlagSet(*Widget, UIWidgetFlag_Clickable)) { - if (PointIsInRect(Widget->Bounds, Interface->Mouse.Pos)) + if (PointIsInRect(Widget->Parent->Bounds, Interface->Mouse.Pos) && + PointIsInRect(Widget->Bounds, Interface->Mouse.Pos)) { if (ui_WidgetIdsEqual(Interface->HotWidget, Widget->Id) && MouseButtonTransitionedDown(Interface->Mouse.LeftButtonState)) { @@ -785,7 +873,6 @@ ui_EvaluateWidget(ui_interface* Interface, ui_widget* Widget, rect2 Bounds) Interface->HotWidget = Widget->Id; } - if (MouseButtonHeldDown(Interface->Mouse.LeftButtonState) && PointIsInRect(Widget->Bounds, Interface->Mouse.DownPos)) { @@ -802,8 +889,6 @@ ui_EvaluateWidget(ui_interface* Interface, ui_widget* Widget, rect2 Bounds) } Assert(Widget->Parent != 0); - ui_CommitBounds(Widget->Parent, Widget->Bounds); - return Result; } @@ -811,7 +896,7 @@ internal ui_eval_result ui_EvaluateWidget(ui_interface* Interface, ui_widget* Widget) { ui_widget* Layout = Interface->ActiveLayout; - rect2 Bounds = ui_ReserveBounds(Layout, true); + rect2 Bounds = ui_ReserveBounds(Interface, Layout, true); return ui_EvaluateWidget(Interface, Widget, Bounds); } @@ -1019,12 +1104,7 @@ internal r32 ui_EvaluateRangeSlider(ui_interface* Interface, ui_widget* Widget, ui_eval_result EvalResult, r32 Value, r32 MinValue, r32 MaxValue) { r32 NewValue = Value; - - ui_widget_retained_state* State = ui_GetRetainedState(Interface, Widget->Id); - if (!State) - { - State = ui_CreateRetainedState(Interface, Widget); - } + ui_widget_retained_state* State = ui_GetOrCreateRetainedState(Interface, Widget); if (EvalResult.Clicked) { @@ -1038,7 +1118,7 @@ ui_EvaluateRangeSlider(ui_interface* Interface, ui_widget* Widget, ui_eval_resul } NewValue = Clamp(MinValue, NewValue, MaxValue); - Widget->HorizontalFillPercent = RemapR32(NewValue, MinValue, MaxValue, 0, 1); + Widget->FillPercent = RemapR32(NewValue, MinValue, MaxValue, 0, 1); return NewValue; } @@ -1083,21 +1163,86 @@ ui_Toggle(ui_interface* Interface, gs_string Text, bool Value) ui_eval_result Eval = ui_EvaluateWidget(Interface, Widget); bool Result = Eval.Clicked ? !Value : Value; - Widget->HorizontalFillPercent = Result ? 1.0f : 0.0f; + Widget->FillPercent = Result ? 1.0f : 0.0f; return Result; } internal void -ui_BeginList(ui_interface* Interface, gs_string Text, u32 ViewportRows) +ui_BeginList(ui_interface* Interface, gs_string Text, u32 ViewportRows, u32 ElementCount) { - ui_widget* Layout = ui_PushLayout(Interface, Text); + ui_column_spec ColumnRules[] = { + { UIColumnSize_Fixed, 32 }, + { UIColumnSize_Fill, 0 }, + }; + ui_widget* Layout = ui_BeginRow(Interface, 2, ColumnRules); + ui_WidgetClearFlag(Layout, UIWidgetFlag_ExpandsToFitChildren); + ui_widget_retained_state* State = ui_GetRetainedState(Interface, Layout->Id); + if (!State) + { + State = ui_CreateRetainedState(Interface, Layout); + State->InitialValueR32 = 1.0f; + } + + r32 LayoutHeight = Layout->RowHeight * ViewportRows; + switch (Layout->Parent->FillDirection) + { + case LayoutDirection_TopDown: + { + Layout->Bounds.Min.y = Layout->Bounds.Max.y - LayoutHeight; + }break; + + case LayoutDirection_BottomUp: + { + Layout->Bounds.Max.y = Layout->Bounds.Min.y + LayoutHeight; + }break; + + InvalidDefaultCase; + } + + // Create the scroll bar + // + + ui_widget* SliderRegion = ui_CreateWidget(Interface, MakeString("Slider")); + ui_WidgetSetFlag(SliderRegion, UIWidgetFlag_DrawOutline); + ui_WidgetSetFlag(SliderRegion, UIWidgetFlag_DrawVerticalFill); + ui_WidgetSetFlag(SliderRegion, UIWidgetFlag_DrawFillAsHandle); + + ui_WidgetSetFlag(SliderRegion, UIWidgetFlag_Clickable); + + rect2 SliderBounds = ui_ReserveBounds(Interface, Layout, true); + SliderBounds.Min.y = Layout->Bounds.Min.y + Layout->Margin.y; + SliderBounds.Max.y = Layout->Bounds.Max.y - Layout->Margin.y; + + ui_eval_result SliderEval = ui_EvaluateWidget(Interface, SliderRegion, SliderBounds); + if (SliderEval.Clicked || SliderEval.Held) + { + r32 Percent = (Interface->Mouse.Pos.y - SliderRegion->Bounds.Min.y) / Rect2Height(SliderRegion->Bounds); + State->InitialValueR32 = Clamp01(Percent); + } + SliderRegion->FillPercent = State->InitialValueR32; + + // Create the viewport that offsets list contents (and at render time determines what is visible) + // + ui_widget* ViewportLayout = ui_PushLayout(Interface, MakeString("Contents")); + ui_WidgetClearFlag(ViewportLayout, UIWidgetFlag_ExpandsToFitChildren); + + ViewportLayout->Bounds.Min.y = SliderBounds.Min.y; + ViewportLayout->Bounds.Max.y = SliderBounds.Max.y; + + ui_widget_retained_state* ViewportState = ui_GetOrCreateRetainedState(Interface, ViewportLayout); + ViewportState->ChildrenDrawOffset.x = 0; + ViewportState->ChildrenDrawOffset.y = ((1.0f - State->InitialValueR32) * (r32)(ElementCount - ViewportRows)) * ViewportLayout->RowHeight; } internal void ui_EndList(ui_interface* Interface) { - + // Pop the Viewport Layout + ui_PopLayout(Interface); + // TODO(pjs): Ensure that the active layout is the row layout we started in begin list + // Pop the actual list layout + ui_EndRow(Interface); } @@ -1105,60 +1250,6 @@ ui_EndList(ui_interface* Interface) // OLD // -enum selection_state -{ - Selection_None, - Selection_Selected, - Selection_Deselected, -}; - -struct interface_list -{ - rect2 ListBounds; - - v2 ListElementDimensions; - v2 ElementLabelIndent; - - v4 TextColor; - v4* LineBGColors; - s32 LineBGColorsCount; - v4 LineBGHoverColor; - - s32 ListElementsCount; -}; - -internal rect2 -DrawListElementBackground(interface_list* List, mouse_state Mouse, render_command_buffer* RenderBuffer) -{ - rect2 LineBounds = {}; - LineBounds.Min = v2{ - List->ListBounds.Min.x, - List->ListBounds.Max.y - (List->ListElementDimensions.y * (List->ListElementsCount + 1)) - }; - LineBounds.Max = LineBounds.Min + List->ListElementDimensions; - - v4 Color = List->LineBGColors[List->ListElementsCount % List->LineBGColorsCount]; - if (PointIsInRect(LineBounds, Mouse.Pos)) - { - Color = List->LineBGHoverColor; - } - - PushRenderQuad2D(RenderBuffer, LineBounds.Min, LineBounds.Max, Color); - return LineBounds; -} - -internal rect2 -DrawListElement(gs_string Label, interface_list* List, mouse_state Mouse, render_command_buffer* RenderBuffer, interface_config Interface) -{ - rect2 Bounds = DrawListElementBackground(List, Mouse, RenderBuffer); - - v2 LabelPosition = Bounds.Min + List->ElementLabelIndent; - DrawString(RenderBuffer, Label, Interface.Font, LabelPosition, List->TextColor); - - List->ListElementsCount++; - return Bounds; -} - internal r32 EvaluateColorChannelSlider (render_command_buffer* RenderBuffer, v4 ChannelMask, v2 Min, v2 Max, r32 Current, mouse_state Mouse) @@ -1200,107 +1291,5 @@ EvaluateColorChannelSlider (render_command_buffer* RenderBuffer, v4 ChannelMask, return Result; } -internal b32 -EvaluateColorPicker (render_command_buffer* RenderBuffer, v4* Value, v2 PanelMin, interface_config Config, mouse_state Mouse) -{ - b32 ShouldClose = false; - - v2 PanelMax = v2{400, 500}; - // TODO(Peter): Can this get passed from outside? rather pass rect2 than min/max pairs - rect2 PanelRect = rect2{PanelMin, PanelMax}; - if (MouseButtonTransitionedDown(Mouse.LeftButtonState) && !PointIsInRect(PanelRect, Mouse.Pos)) - { - ShouldClose = true; - } - else - { - PushRenderQuad2D(RenderBuffer, PanelRect.Min, PanelRect.Max, v4{.5f, .5f, .5f, 1.f}); - - v2 TitleMin = v2{PanelRect.Min.x + 5, PanelRect.Max.y - (Config.Font->PixelHeight + 5)}; - DrawString(RenderBuffer, MakeString("Color Picker"), Config.Font, - TitleMin, WhiteV4); - - v2 SliderDim = v2{(PanelMax.x - PanelMin.x) - 20, 32}; - // channel sliders - v2 SliderMin = TitleMin - v2{0, SliderDim.y + 10}; - Value->r = EvaluateColorChannelSlider(RenderBuffer, RedV4, SliderMin, SliderMin + SliderDim, Value->r, Mouse); - SliderMin.y -= SliderDim.y + 10; - Value->g = EvaluateColorChannelSlider(RenderBuffer, GreenV4, SliderMin, SliderMin + SliderDim, Value->g, Mouse); - SliderMin.y -= SliderDim.y + 10; - Value->b = EvaluateColorChannelSlider(RenderBuffer, BlueV4, SliderMin, SliderMin + SliderDim, Value->b, Mouse); - SliderMin.y -= SliderDim.y + 10; - Value->a = EvaluateColorChannelSlider(RenderBuffer, WhiteV4, SliderMin, SliderMin + SliderDim, Value->a, Mouse); - - // Output Color Display - SliderMin.y -= 100; - PushRenderQuad2D(RenderBuffer, SliderMin, SliderMin + v2{75, 75}, *Value); - } - - return ShouldClose; -} - -struct search_lister_result -{ - s32 HotItem; - s32 SelectedItem; - b32 ShouldRemainOpen; -}; - -typedef gs_string search_lister_get_list_item_at_offset(u8* ListMemory, s32 ListLength, gs_string Searchgs_string, s32 Offset); - -internal search_lister_result -EvaluateSearchLister (ui_interface* Interface, v2 TopLeft, v2 Dimension, gs_string Title, - gs_string* ItemList, s32* ListLUT, s32 ListLength, - s32 HotItem, - gs_string* Searchgs_string, s32 Searchgs_stringCursorPosition) -{ - search_lister_result Result = {}; - Result.ShouldRemainOpen = true; - Result.HotItem = HotItem; - - // TODO(Peter): Was tired. Nothing wrong with the code below - InvalidCodePath; -#if 0 - // Title Bar - rect2 TitleBarBounds = rect2{v2{TopLeft.x, TopLeft.y - 30}, v2{TopLeft.x + 300, TopLeft.y}}; - ui_FillRect(Interface, TitleBarBounds, v4{.3f, .3f, .3f, 1.f}); - ui_Drawgs_string(Interface, Title, TitleBarBounds, Interface->Style.TextColor); - - MakeStringBuffer(Debuggs_string, 256); - PrintF(&Debuggs_string, "Hot Item: %d | Filtered Items: %d", HotItem, ListLength); - rect2 DebugBounds = MakeRectMinWidth(v2{ TopLeft.x + 256, TopLeft.y - 25}, v2{256, Interface->Style.LineHeight}); - ui_Drawgs_string(Interface, Debuggs_string, DebugBounds, Interface->Style.TextColor); - - // Search Bar - PushRenderQuad2D(RenderBuffer, v2{TopLeft.x, TopLeft.y - 30}, v2{TopLeft.x + 300, TopLeft.y}, v4{.3f, .3f, .3f, 1.f}); - Drawgs_stringWithCursor(RenderBuffer, *Searchgs_string, Searchgs_stringCursorPosition, Font, v2{TopLeft.x, TopLeft.y - 25}, WhiteV4, GreenV4); - TopLeft.y -= 30; - - for (s32 i = 0; i < ListLength; i++) - { - s32 FilteredIndex = ListLUT[i]; - gs_string ListItemgs_string = ItemList[FilteredIndex]; - - v2 Min = v2{TopLeft.x, TopLeft.y - 30}; - v2 Max = Min + Dimension - v2{0, Config.Margin.y}; - - v4 ButtonColor = Config.ButtonColor_Inactive; - if (i == HotItem) - { - ButtonColor = Config.ButtonColor_Active; - } - - if (ui_Button(Interface, ListItemgs_string, rect2{Min, Max})) - { - Result.SelectedItem = i; - } - - TopLeft.y -= 30; - } -#endif - - return Result; -} - #define INTERFACE_H #endif // INTERFACE_H \ No newline at end of file diff --git a/src/gs_libs/gs_types.cpp b/src/gs_libs/gs_types.cpp index f69657c..cdd6252 100644 --- a/src/gs_libs/gs_types.cpp +++ b/src/gs_libs/gs_types.cpp @@ -927,6 +927,10 @@ Range2Union(range2 A, range2 B) Result.Min.y = Max(A.Min.y, B.Min.y); Result.Max.x = Min(A.Max.x, B.Max.x); Result.Max.y = Min(A.Max.y, B.Max.y); + + if (Rect2Width(Result) < 0) { Result.Min.x = Result.Max.x; } + if (Rect2Height(Result) < 0) { Result.Min.y = Result.Max.y; } + return Result; } internal range3 @@ -949,6 +953,41 @@ Rect2GetRectLocalPoint(rect2 Rect, v2 Point) return Result; } +internal r32 +Rect2Area(rect2 Rect) +{ + r32 Result = Rect2Width(Rect) * Rect2Height(Rect); + return Result; +} + +internal v2 +Rect2BottomLeft(rect2 Rect) +{ + v2 Result = Rect.Min; + return Result; +} + +internal v2 +Rect2BottomRight(rect2 Rect) +{ + v2 Result = v2{ Rect.Max.x, Rect.Min.y }; + return Result; +} + +internal v2 +Rect2TopRight(rect2 Rect) +{ + v2 Result = Rect.Max; + return Result; +} + +internal v2 +Rect2TopLeft(rect2 Rect) +{ + v2 Result = v2{ Rect.Min.x, Rect.Max.y }; + return Result; +} + /////////////////////////// // // Ray From 91b2b822f9b1d7f82fe540d83055d54983ec7b18 Mon Sep 17 00:00:00 2001 From: PS Date: Sun, 15 Nov 2020 16:36:11 -0800 Subject: [PATCH 09/44] did a few more tweaks to teh list --- src/app/editor/foldhaus_editor.cpp | 21 +++------- src/app/interface.h | 62 ++++-------------------------- 2 files changed, 14 insertions(+), 69 deletions(-) diff --git a/src/app/editor/foldhaus_editor.cpp b/src/app/editor/foldhaus_editor.cpp index 9d9cce6..e28480a 100644 --- a/src/app/editor/foldhaus_editor.cpp +++ b/src/app/editor/foldhaus_editor.cpp @@ -152,14 +152,11 @@ Editor_DrawWidget(app_state* State, context* Context, render_command_buffer* Ren if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawHorizontalFill) || ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawVerticalFill)) { - v4 Color = State->Interface.Style.ButtonColor_Active; - if (ui_WidgetIdsEqual(Widget.Id, State->Interface.HotWidget)) + v4 Color = State->Interface.Style.ButtonColor_Selected; + if (ui_WidgetIdsEqual(Widget.Id, State->Interface.HotWidget) || + ui_WidgetIdsEqual(Widget.Id, State->Interface.ActiveWidget)) { - Color = State->Interface.Style.ButtonColor_Selected; - } - if (ui_WidgetIdsEqual(Widget.Id, State->Interface.ActiveWidget)) - { - Color = State->Interface.Style.ButtonColor_Selected; + Color = WhiteV4; } rect2 FillBounds = {}; @@ -205,7 +202,7 @@ Editor_DrawWidget(app_state* State, context* Context, render_command_buffer* Ren FillBounds.Max.y = FillToPoint; } } - PushRenderQuad2D(RenderBuffer, FillBounds.Min, FillBounds.Max, Color); + PushRenderQuad2DClipped(RenderBuffer, FillBounds, WidgetParentUnion, Color); if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawString) && Widget.String.Length > 0) { @@ -260,18 +257,12 @@ TestRender(app_state* State, context* Context, render_command_buffer* RenderBuff ui_Label(&State->Interface, MakeString("Spacer")); ui_Label(&State->Interface, MakeString("Spacer")); - ui_BeginList(&State->Interface, MakeString("TestList"), 5, 9); + ui_BeginList(&State->Interface, MakeString("TestList"), 5, 4); { ui_Button(&State->Interface, MakeString("B")); ui_Button(&State->Interface, MakeString("B")); ui_Button(&State->Interface, MakeString("B")); ui_Button(&State->Interface, MakeString("B")); - ui_Button(&State->Interface, MakeString("B")); - ui_Button(&State->Interface, MakeString("B")); - ui_Button(&State->Interface, MakeString("B")); - ui_Button(&State->Interface, MakeString("B")); - ui_Button(&State->Interface, MakeString("B")); - } ui_EndList(&State->Interface); //ui_Button(&State->Interface, MakeString("B")); diff --git a/src/app/interface.h b/src/app/interface.h index 89bdc42..b66b771 100644 --- a/src/app/interface.h +++ b/src/app/interface.h @@ -58,19 +58,11 @@ DrawCharacter_ (render_quad_batch_constructor* BatchConstructor, r32 MinX, r32 M s32 AlignedMaxX = AlignedMinX + (CodepointInfo.Width); s32 AlignedMaxY = AlignedMinY + (CodepointInfo.Height); -#if 1 PushQuad2DOnBatch(BatchConstructor, Rect2BottomLeft(Bounds), Rect2BottomRight(Bounds), Rect2TopRight(Bounds), Rect2TopLeft(Bounds), UVBounds.Min, UVBounds.Max, Color); -#else - PushQuad2DOnBatch(BatchConstructor, - v2{(r32)AlignedMinX, (r32)AlignedMinY}, v2{(r32)AlignedMaxX, (r32)AlignedMinY}, - v2{(r32)AlignedMaxX, (r32)AlignedMaxY}, v2{(r32)AlignedMinX, (r32)AlignedMaxY}, - CodepointInfo.UVMin, CodepointInfo.UVMax, - Color); -#endif } internal v2 @@ -1170,6 +1162,11 @@ ui_Toggle(ui_interface* Interface, gs_string Text, bool Value) internal void ui_BeginList(ui_interface* Interface, gs_string Text, u32 ViewportRows, u32 ElementCount) { + if (ElementCount < ViewportRows) + { + ViewportRows = ElementCount; + } + ui_column_spec ColumnRules[] = { { UIColumnSize_Fixed, 32 }, { UIColumnSize_Fill, 0 }, @@ -1202,6 +1199,7 @@ ui_BeginList(ui_interface* Interface, gs_string Text, u32 ViewportRows, u32 Elem // Create the scroll bar // + // TODO(pjs): Maybe make this a vertical slider widget? ui_widget* SliderRegion = ui_CreateWidget(Interface, MakeString("Slider")); ui_WidgetSetFlag(SliderRegion, UIWidgetFlag_DrawOutline); @@ -1230,9 +1228,10 @@ ui_BeginList(ui_interface* Interface, gs_string Text, u32 ViewportRows, u32 Elem ViewportLayout->Bounds.Min.y = SliderBounds.Min.y; ViewportLayout->Bounds.Max.y = SliderBounds.Max.y; + s32 ScrollableElements = Max(0, ElementCount - ViewportRows); ui_widget_retained_state* ViewportState = ui_GetOrCreateRetainedState(Interface, ViewportLayout); ViewportState->ChildrenDrawOffset.x = 0; - ViewportState->ChildrenDrawOffset.y = ((1.0f - State->InitialValueR32) * (r32)(ElementCount - ViewportRows)) * ViewportLayout->RowHeight; + ViewportState->ChildrenDrawOffset.y = ((1.0f - State->InitialValueR32) * (r32)(ScrollableElements)) * ViewportLayout->RowHeight; } internal void @@ -1246,50 +1245,5 @@ ui_EndList(ui_interface* Interface) } -// -// OLD -// - - -internal r32 -EvaluateColorChannelSlider (render_command_buffer* RenderBuffer, v4 ChannelMask, v2 Min, v2 Max, r32 Current, mouse_state Mouse) -{ - r32 Result = Current; - - // TODO(Peter): Can this come from outside the function? Would rather pass rect around than min/max - rect2 Rect = rect2{ Min, Max }; - - render_quad_batch_constructor Batch = PushRenderQuad2DBatch(RenderBuffer, 2); - - v4 LeftColor = ChannelMask * 0; - LeftColor.a = 1.f; - v4 RightColor = ChannelMask; - PushQuad2DOnBatch(&Batch, - RectBottomLeft(Rect), RectBottomRight(Rect), - RectTopRight(Rect), RectTopLeft(Rect), - v2{0, 0}, v2{1, 0}, v2{1, 1}, v2{0, 1}, - LeftColor, RightColor, RightColor, LeftColor); - - if (MouseButtonTransitionedDown(Mouse.LeftButtonState)) - { - if (PointIsInRect(Rect, Mouse.DownPos)) - { - Result = ((r32)Mouse.Pos.x - Min.x) / (Max.x - Min.x); - Result = Clamp01(Result); - } - } - - r32 DragBarWidth = 8; - v2 DragBarMin = v2{ - LerpR32(Result, Min.x, Max.x) - (DragBarWidth / 2), - Min.y - 2 - }; - v2 DragBarMax = DragBarMin + v2{DragBarWidth, (Max.y - Min.y) + 4}; - - PushQuad2DOnBatch(&Batch, DragBarMin, DragBarMax, v4{.3f, .3f, .3f, 1.f}); - - return Result; -} - #define INTERFACE_H #endif // INTERFACE_H \ No newline at end of file From 8d737fd961b85b84591abb335545ad1f2515b324 Mon Sep 17 00:00:00 2001 From: PS Date: Sun, 15 Nov 2020 16:58:13 -0800 Subject: [PATCH 10/44] made the profiler list view a ui list --- src/app/editor/foldhaus_editor.cpp | 30 ++++++------ .../editor/panels/foldhaus_panel_profiler.h | 46 +++++++++++-------- src/app/foldhaus_debug.h | 4 ++ 3 files changed, 48 insertions(+), 32 deletions(-) diff --git a/src/app/editor/foldhaus_editor.cpp b/src/app/editor/foldhaus_editor.cpp index e28480a..067b4e6 100644 --- a/src/app/editor/foldhaus_editor.cpp +++ b/src/app/editor/foldhaus_editor.cpp @@ -119,13 +119,10 @@ Editor_DrawWidgetString(app_state* State, context* Context, render_command_buffe } internal void -Editor_DrawWidget(app_state* State, context* Context, render_command_buffer* RenderBuffer, ui_widget Widget) +Editor_DrawWidget(app_state* State, context* Context, render_command_buffer* RenderBuffer, ui_widget Widget, rect2 ParentClipBounds) { rect2 WidgetParentUnion = Widget.Bounds; - if (Widget.Parent) - { - WidgetParentUnion = Rect2Union(Widget.Bounds, Widget.Parent->Bounds); - } + WidgetParentUnion = Rect2Union(Widget.Bounds, ParentClipBounds); if (!Widget.Parent || (Rect2Area(WidgetParentUnion) > 0)) { @@ -225,12 +222,12 @@ Editor_DrawWidget(app_state* State, context* Context, render_command_buffer* Ren if (Widget.ChildrenRoot) { - Editor_DrawWidget(State, Context, RenderBuffer, *Widget.ChildrenRoot); + Editor_DrawWidget(State, Context, RenderBuffer, *Widget.ChildrenRoot, WidgetParentUnion); } if (Widget.Next) { - Editor_DrawWidget(State, Context, RenderBuffer, *Widget.Next); + Editor_DrawWidget(State, Context, RenderBuffer, *Widget.Next, ParentClipBounds); } } @@ -257,12 +254,17 @@ TestRender(app_state* State, context* Context, render_command_buffer* RenderBuff ui_Label(&State->Interface, MakeString("Spacer")); ui_Label(&State->Interface, MakeString("Spacer")); - ui_BeginList(&State->Interface, MakeString("TestList"), 5, 4); + ui_BeginList(&State->Interface, MakeString("TestList"), 5, 16); { - ui_Button(&State->Interface, MakeString("B")); - ui_Button(&State->Interface, MakeString("B")); - ui_Button(&State->Interface, MakeString("B")); - ui_Button(&State->Interface, MakeString("B")); + ui_BeginRow(&State->Interface, 3); + for (u32 i = 0; i < 16; i++) + { + + ui_Button(&State->Interface, MakeString("B")); + ui_Button(&State->Interface, MakeString("C")); + ui_Button(&State->Interface, MakeString("D")); + } + ui_EndRow(&State->Interface); } ui_EndList(&State->Interface); //ui_Button(&State->Interface, MakeString("B")); @@ -334,7 +336,7 @@ Editor_Render(app_state* State, context* Context, render_command_buffer* RenderB PushRenderOrthographic(RenderBuffer, State->WindowBounds); PushRenderClearScreen(RenderBuffer); -#if 1 +#if 0 TestRender(State, Context, RenderBuffer); #else ui_InterfaceReset(&State->Interface); @@ -359,7 +361,7 @@ Editor_Render(app_state* State, context* Context, render_command_buffer* RenderB if (State->Interface.DrawOrderRoot != 0) { ui_widget Widget = *State->Interface.DrawOrderRoot; - Editor_DrawWidget(State, Context, RenderBuffer, Widget); + Editor_DrawWidget(State, Context, RenderBuffer, Widget, Context->WindowBounds); } Context->GeneralWorkQueue->CompleteQueueWork(Context->GeneralWorkQueue, Context->ThreadContext); diff --git a/src/app/editor/panels/foldhaus_panel_profiler.h b/src/app/editor/panels/foldhaus_panel_profiler.h index 133a0d1..0268ef0 100644 --- a/src/app/editor/panels/foldhaus_panel_profiler.h +++ b/src/app/editor/panels/foldhaus_panel_profiler.h @@ -110,6 +110,18 @@ RenderProfiler_ListVisualization(ui_interface* Interface, ui_widget* Layout, deb } ui_EndRow(Interface); + s32 CountedScopes = 0; + for (s32 n = 0; n < VisibleFrame->ScopeNamesMax; n++) + { + scope_name NameEntry = VisibleFrame->ScopeNamesHash[n]; + if (NameEntry.Hash != 0) + { + CountedScopes += 1; + } + } + + ui_BeginList(Interface, MakeString("Scope List"), 10, CountedScopes); + ui_BeginRow(Interface, 5, &ColumnWidths[0]); for (s32 n = 0; n < VisibleFrame->ScopeNamesMax; n++) { scope_name NameEntry = VisibleFrame->ScopeNamesHash[n]; @@ -117,26 +129,24 @@ RenderProfiler_ListVisualization(ui_interface* Interface, ui_widget* Layout, deb { collated_scope_record* CollatedRecord = VisibleFrame->CollatedScopes + n; - ui_BeginRow(Interface, 5, &ColumnWidths[0]); - { - PrintF(&String, "%S", NameEntry.Name); - ui_Label(Interface, String); - - PrintF(&String, "%f%%", CollatedRecord->PercentFrameTime); - ui_Label(Interface, String); - - PrintF(&String, "%fs", CollatedRecord->TotalSeconds); - ui_Label(Interface, String); - - PrintF(&String, "%dcy", CollatedRecord->TotalCycles); - ui_Label(Interface, String); - - PrintF(&String, "%d", CollatedRecord->CallCount); - ui_Label(Interface, String); - } - ui_EndRow(Interface); + PrintF(&String, "%S", NameEntry.Name); + ui_Label(Interface, String); + + PrintF(&String, "%f%%", CollatedRecord->PercentFrameTime); + ui_Label(Interface, String); + + PrintF(&String, "%fs", CollatedRecord->TotalSeconds); + ui_Label(Interface, String); + + PrintF(&String, "%dcy", CollatedRecord->TotalCycles); + ui_Label(Interface, String); + + PrintF(&String, "%d", CollatedRecord->CallCount); + ui_Label(Interface, String); } } + ui_EndRow(Interface); + ui_EndList(Interface); } GSMetaTag(panel_render); diff --git a/src/app/foldhaus_debug.h b/src/app/foldhaus_debug.h index ca26188..7acdfcc 100644 --- a/src/app/foldhaus_debug.h +++ b/src/app/foldhaus_debug.h @@ -54,6 +54,7 @@ struct debug_frame s64 FrameEndCycles; s32 ScopeNamesMax; + s32 ScopeNamesCount; scope_name* ScopeNamesHash; s32 ThreadCount; @@ -302,6 +303,7 @@ EndDebugFrame (debug_services* Services) CollateThreadScopeCalls(ClosingFrame->ThreadCalls + t, ClosingFrame); } + s32 ScopeNamesCount = 0; for (s32 n = 0; n < ClosingFrame->ScopeNamesMax; n++) { if (ClosingFrame->ScopeNamesHash[n].Hash != 0) @@ -310,8 +312,10 @@ EndDebugFrame (debug_services* Services) CollatedRecord->TotalSeconds = (r32)CollatedRecord->TotalCycles / (r32)Services->PerformanceCountFrequency; CollatedRecord->PercentFrameTime = (r32)CollatedRecord->TotalCycles / (r32)FrameTotalCycles; CollatedRecord->AverageSecondsPerCall = CollatedRecord->TotalSeconds / CollatedRecord->CallCount; + ScopeNamesCount += 1; } } + ClosingFrame->ScopeNamesCount = ScopeNamesCount; Services->CurrentDebugFrame = (Services->CurrentDebugFrame + 1) % DEBUG_FRAME_COUNT; StartDebugFrame(&Services->Frames[Services->CurrentDebugFrame], Services); From 6e2405198245b06db688c2be9d4325f20b8c8db6 Mon Sep 17 00:00:00 2001 From: PS Date: Sun, 15 Nov 2020 17:07:59 -0800 Subject: [PATCH 11/44] Added a mouse hover layout and used it in the profiler --- .../editor/panels/foldhaus_panel_profiler.h | 25 +++++++------------ src/app/interface.h | 13 ++++++++++ 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/app/editor/panels/foldhaus_panel_profiler.h b/src/app/editor/panels/foldhaus_panel_profiler.h index 0268ef0..3a49177 100644 --- a/src/app/editor/panels/foldhaus_panel_profiler.h +++ b/src/app/editor/panels/foldhaus_panel_profiler.h @@ -25,7 +25,7 @@ ProfilerView_Cleanup(panel* Panel, app_state* State) } internal void -RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_widget* Layout, debug_frame* VisibleFrame, gs_memory_arena* Memory) +RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_widget* Layout, debug_frame* VisibleFrame, gs_memory_arena* Transient) { v4 ThreadColors[] = { v4{.73f, .33f, .83f, 1}, @@ -45,11 +45,7 @@ RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_widget* Layout, de debug_scope_record_list* ThreadScopeCalls = GetScopeListForThreadInFrame(GlobalDebugServices, VisibleFrame); - scope_record* HotRecord = 0; - scope_name* HotRecordName = 0; - - char Backbuffer[256]; - gs_string String = MakeString(Backbuffer, 0, 256); + gs_string String = PushString(Transient, 256); for (s32 i = 0; i < ThreadScopeCalls->Count; i++) { scope_record* Record = ThreadScopeCalls->Calls + i; @@ -70,22 +66,19 @@ RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_widget* Layout, de if (PointIsInRect(ScopeBounds, Interface->Mouse.Pos)) { Color = GreenV4; - HotRecord = Record; - HotRecordName = Name; + + ui_BeginMousePopup(Interface, rect2{ 25, 25, 300, 57 }, LayoutDirection_TopDown, MakeString("Hover")); + { + PrintF(&String, "%S : %d - %d", Name->Name, Record->StartCycles, Record->EndCycles); + ui_Label(Interface, String); + } + ui_EndMousePopup(Interface); } ui_FillRect(Interface, ScopeBounds, Color); ui_OutlineRect(Interface, ScopeBounds, 1, BlackV4); } } - - if (HotRecord != 0) - { - PrintF(&String, "%S : %d - %d", HotRecordName->Name, HotRecord->StartCycles, HotRecord->EndCycles); - - rect2 TextBounds = MakeRect2MinDim(Interface->Mouse.Pos, v2{256, 32}); - ui_Label(Interface, String, TextBounds); - } } internal void diff --git a/src/app/interface.h b/src/app/interface.h index b66b771..3cd2772 100644 --- a/src/app/interface.h +++ b/src/app/interface.h @@ -1244,6 +1244,19 @@ ui_EndList(ui_interface* Interface) ui_EndRow(Interface); } +internal void +ui_BeginMousePopup(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir, gs_string Text) +{ + rect2 FollowMouseBounds = Rect2Translate(Bounds, Interface->Mouse.Pos); + ui_widget* Layout = ui_PushOverlayLayout(Interface, FollowMouseBounds, FillDir, Text); + ui_WidgetSetFlag(Layout, UIWidgetFlag_DrawBackground); +} + +internal void +ui_EndMousePopup(ui_interface* Interface) +{ + ui_PopLayout(Interface); +} #define INTERFACE_H #endif // INTERFACE_H \ No newline at end of file From aac3ce5f008e22b8bb98909a3ad6ed1ea9d49f16 Mon Sep 17 00:00:00 2001 From: PS Date: Sun, 15 Nov 2020 17:23:17 -0800 Subject: [PATCH 12/44] removed extraneous files, and fixed an error introduced in the merge --- src/app/editor/panels/foldhaus_panel_animation_timeline.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/editor/panels/foldhaus_panel_animation_timeline.h b/src/app/editor/panels/foldhaus_panel_animation_timeline.h index 412cadf..3c9d375 100644 --- a/src/app/editor/panels/foldhaus_panel_animation_timeline.h +++ b/src/app/editor/panels/foldhaus_panel_animation_timeline.h @@ -240,8 +240,8 @@ SelectAndBeginDragAnimationBlock(animation_timeline_state* TimelineState, handle animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem); operation_mode* DragAnimationBlockMode = ActivateOperationModeWithCommands(&State->Modes, DragAnimationBlockCommands, UpdateDragAnimationBlock); + animation_block* SelectedBlock = Animation_GetBlockFromHandle(ActiveAnim, BlockHandle); drag_animation_block_state* OpState = CreateOperationState(DragAnimationBlockMode, - &State->Modes, drag_animation_block_state); OpState->TimelineBounds = TimelineBounds; @@ -591,7 +591,7 @@ DrawAnimationPatternList(rect2 PanelBounds, ui_interface* Interface, u32 Selecte { animation_pattern Pattern = GlobalAnimationPatterns[i]; gs_string PatternName = MakeString(Pattern.Name, Pattern.NameLength); - if (ui_LayoutListEntry(Interface, &Layout, PatternName, i)) + if (ui_Button(Interface, PatternName)) { AddAnimationBlockAtCurrentTime(i + 1, SelectedAnimationLayerHandle, AnimationSystem); } From e6f34d17adeb668de856c8250d37a7e5db5a5ff2 Mon Sep 17 00:00:00 2001 From: PS Date: Sun, 15 Nov 2020 17:33:55 -0800 Subject: [PATCH 13/44] fixed problem with adjusting panel borders after they've been created --- src/app/editor/foldhaus_interface.cpp | 28 +++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/app/editor/foldhaus_interface.cpp b/src/app/editor/foldhaus_interface.cpp index 29258ec..e86b30b 100644 --- a/src/app/editor/foldhaus_interface.cpp +++ b/src/app/editor/foldhaus_interface.cpp @@ -98,38 +98,38 @@ FOLDHAUS_INPUT_COMMAND_PROC(EndDragPanelBorderOperation) if (OpState->PanelEditMode == PanelEdit_Modify) { - if (Panel->SplitDirection == PanelSplit_Horizontal) + if (OpState->Panel->SplitDirection == PanelSplit_Horizontal) { r32 NewSplitY = Mouse.Pos.y; if (NewSplitY <= PanelBounds.Min.y) { - ConsolidatePanelsKeepOne(Panel, Panel->Top, &State->PanelSystem); + ConsolidatePanelsKeepOne(OpState->Panel, OpState->Panel->Top, &State->PanelSystem); } else if (NewSplitY >= PanelBounds.Max.y) { - ConsolidatePanelsKeepOne(Panel, Panel->Bottom, &State->PanelSystem); + ConsolidatePanelsKeepOne(OpState->Panel, OpState->Panel->Bottom, &State->PanelSystem); } else { - Panel->SplitPercent = (NewSplitY - PanelBounds.Min.y) / Rect2Height(PanelBounds); - Panel_UpdateLayout(Panel, PanelBounds); + OpState->Panel->SplitPercent = (NewSplitY - PanelBounds.Min.y) / Rect2Height(PanelBounds); + Panel_UpdateLayout(OpState->Panel, PanelBounds); } } - else if (Panel->SplitDirection == PanelSplit_Vertical) + else if (OpState->Panel->SplitDirection == PanelSplit_Vertical) { r32 NewSplitX = Mouse.Pos.x; if (NewSplitX <= PanelBounds.Min.x) { - ConsolidatePanelsKeepOne(Panel, Panel->Right, &State->PanelSystem); + ConsolidatePanelsKeepOne(OpState->Panel, OpState->Panel->Right, &State->PanelSystem); } else if (NewSplitX >= PanelBounds.Max.x) { - ConsolidatePanelsKeepOne(Panel, Panel->Left, &State->PanelSystem); + ConsolidatePanelsKeepOne(OpState->Panel, OpState->Panel->Left, &State->PanelSystem); } else { - Panel->SplitPercent = (NewSplitX - PanelBounds.Min.x) / Rect2Width(PanelBounds); - Panel_UpdateLayout(Panel, PanelBounds); + OpState->Panel->SplitPercent = (NewSplitX - PanelBounds.Min.x) / Rect2Width(PanelBounds); + Panel_UpdateLayout(OpState->Panel, PanelBounds); } } } @@ -140,11 +140,11 @@ FOLDHAUS_INPUT_COMMAND_PROC(EndDragPanelBorderOperation) r32 SplitY = LerpR32(OpState->Panel->SplitPercent, PanelBounds.Min.y, PanelBounds.Max.y); if (Mouse.Pos.y > SplitY) { - ConsolidatePanelsKeepOne(Panel, Panel->Bottom, &State->PanelSystem); + ConsolidatePanelsKeepOne(OpState->Panel, OpState->Panel->Bottom, &State->PanelSystem); } else { - ConsolidatePanelsKeepOne(Panel, Panel->Top, &State->PanelSystem); + ConsolidatePanelsKeepOne(OpState->Panel, OpState->Panel->Top, &State->PanelSystem); } } else if (OpState->PanelEdgeDirection == PanelSplit_Vertical) @@ -152,11 +152,11 @@ FOLDHAUS_INPUT_COMMAND_PROC(EndDragPanelBorderOperation) r32 SplitX = LerpR32(OpState->Panel->SplitPercent, PanelBounds.Min.x, PanelBounds.Max.x); if (Mouse.Pos.x > SplitX) { - ConsolidatePanelsKeepOne(Panel, Panel->Left, &State->PanelSystem); + ConsolidatePanelsKeepOne(OpState->Panel, OpState->Panel->Left, &State->PanelSystem); } else { - ConsolidatePanelsKeepOne(Panel, Panel->Right, &State->PanelSystem); + ConsolidatePanelsKeepOne(OpState->Panel, OpState->Panel->Right, &State->PanelSystem); } } } From 0b6b3c63677615858bce4908cd3f13cb04fc341a Mon Sep 17 00:00:00 2001 From: PS Date: Sun, 15 Nov 2020 17:40:51 -0800 Subject: [PATCH 14/44] Got the hierarchy window rendering again. --- .../editor/panels/foldhaus_panel_hierarchy.h | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/src/app/editor/panels/foldhaus_panel_hierarchy.h b/src/app/editor/panels/foldhaus_panel_hierarchy.h index ec6ca55..4a2277a 100644 --- a/src/app/editor/panels/foldhaus_panel_hierarchy.h +++ b/src/app/editor/panels/foldhaus_panel_hierarchy.h @@ -38,11 +38,38 @@ GSMetaTag(panel_type_hierarchy); internal void HierarchyView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context) { + gs_string TempString = PushString(State->Transient, 256); + ui_PushLayout(&State->Interface, PanelBounds, LayoutDirection_TopDown, MakeString("Hierarchy Layout")); + ui_BeginList(&State->Interface, MakeString("Hierarchy List"), 10, State->Assemblies.Count + 1); + { + ui_BeginRow(&State->Interface, 2); + for (u32 i = 0; i < State->Assemblies.Count; i++) + { + assembly Assembly = State->Assemblies.Values[i]; + PrintF(&TempString, "%S", Assembly.Name); + + ui_Label(&State->Interface, TempString); + if (ui_Button(&State->Interface, MakeString("X"))) + { + UnloadAssembly(i, State, Context); + } + } + + ui_Label(&State->Interface, MakeString(" ")); + if (ui_Button(&State->Interface, MakeString("+ Add Assembly"))) + { + panel* FileBrowser = PanelSystem_PushPanel(&State->PanelSystem, PanelType_FileView, State, Context); + Panel_PushModalOverride(Panel, FileBrowser, LoadAssemblyCallback); + } + + ui_EndRow(&State->Interface); + } + ui_EndList(&State->Interface); + // TODO(pjs): Come back to this after the layout stuff is handled. // Ideally it handles the visuals of the hierarchy itself. - #if 0 gs_string TempString = PushString(State->Transient, 256); u32 LineCount = (u32)(Rect2Height(PanelBounds) / Layout->RowHeight) + 1; @@ -76,14 +103,13 @@ HierarchyView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Ren { // NOTE(Peter): Add assembly button PrintF(&TempString, "+ Add Assembly"); - if (ui_ListButton(&State->Interface, TempString, LineBounds[AssembliesToDraw], AssembliesToDraw)) + if (ui_Button(&State->Interface, TempString)) { panel* FileBrowser = PanelSystem_PushPanel(&State->PanelSystem, PanelType_FileView, State, Context); Panel_PushModalOverride(Panel, FileBrowser, LoadAssemblyCallback); } } #endif - ui_PopLayout(&State->Interface); } From 8d923a5e3c612800859d1e811874ecdc63fc79f1 Mon Sep 17 00:00:00 2001 From: PS Date: Sun, 15 Nov 2020 20:03:35 -0800 Subject: [PATCH 15/44] Fixed problem with bounds checking on parent widgets, when they weren't expanding to fit children until they themselves were committed --- src/app/editor/foldhaus_editor.cpp | 11 ++++- .../editor/panels/foldhaus_panel_hierarchy.h | 44 ------------------- src/app/interface.h | 14 ++++-- 3 files changed, 20 insertions(+), 49 deletions(-) diff --git a/src/app/editor/foldhaus_editor.cpp b/src/app/editor/foldhaus_editor.cpp index 067b4e6..9d3b1a6 100644 --- a/src/app/editor/foldhaus_editor.cpp +++ b/src/app/editor/foldhaus_editor.cpp @@ -247,7 +247,7 @@ TestRender(app_state* State, context* Context, render_command_buffer* RenderBuff ui_PushLayout(&State->Interface, A); { -#if 1 +#if 0 ui_Label(&State->Interface, MakeString("Spacer")); ui_Label(&State->Interface, MakeString("Spacer")); ui_Label(&State->Interface, MakeString("Spacer")); @@ -270,7 +270,7 @@ TestRender(app_state* State, context* Context, render_command_buffer* RenderBuff //ui_Button(&State->Interface, MakeString("B")); //ui_Button(&State->Interface, MakeString("C")); //TestSlider_Value = ui_RangeSlider(&State->Interface, MakeString("TestSlider"), TestSlider_Value, TestSlider_Min, TestSlider_Max); -#elif 0 +#elif 1 ui_PushLayout(&State->Interface, MakeString("Outer")); { for (u32 i = 0; i < 3; i++) @@ -316,6 +316,13 @@ TestRender(app_state* State, context* Context, render_command_buffer* RenderBuff } } ui_PopLayout(&State->Interface); + + + ui_PushOverlayLayout(&State->Interface, rect2{25, 25, 200, 200}, LayoutDirection_TopDown, MakeString("t")); + { + ui_Label(&State->Interface, PushStringF(State->Interface.PerFrameMemory, 256, "Mouse Pos - %f %f", State->Interface.Mouse.Pos.x, State->Interface.Mouse.Pos.y)); + } + ui_PopLayout(&State->Interface); #else ui_BeginList(&State->Interface, MakeString("Test List"), 10); { diff --git a/src/app/editor/panels/foldhaus_panel_hierarchy.h b/src/app/editor/panels/foldhaus_panel_hierarchy.h index 4a2277a..d2f9804 100644 --- a/src/app/editor/panels/foldhaus_panel_hierarchy.h +++ b/src/app/editor/panels/foldhaus_panel_hierarchy.h @@ -66,50 +66,6 @@ HierarchyView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Ren ui_EndRow(&State->Interface); } ui_EndList(&State->Interface); - - - // TODO(pjs): Come back to this after the layout stuff is handled. - // Ideally it handles the visuals of the hierarchy itself. -#if 0 - gs_string TempString = PushString(State->Transient, 256); - u32 LineCount = (u32)(Rect2Height(PanelBounds) / Layout->RowHeight) + 1; - u32 AssembliesToDraw = Min(LineCount, State->Assemblies.Count); - rect2* LineBounds = PushArray(State->Transient, rect2, LineCount); - - // Fill in alternating color rows for the backgrounds - for (u32 Line = 0; Line < LineCount; Line++) - { - v4 ListItemBGColor = ui_GetListItemBGColor(State->Interface.Style, Line); - ui_FillRect(&State->Interface, LineBounds[Line], ListItemBGColor); - } - - for (u32 AssemblyIndex = 0; AssemblyIndex < AssembliesToDraw; AssemblyIndex++) - { - assembly Assembly = State->Assemblies.Values[AssemblyIndex]; - PrintF(&TempString, "%S", Assembly.Name); - - ui_StartRow(&State->Interface, 2); - { - ui_DrawString(&State->Interface, TempString); - if (ui_LayoutListButton(&State->Interface, MakeString("X"), AssemblyIndex)) - { - UnloadAssembly(AssemblyIndex, State, Context); - } - } - ui_EndRow(&State->Interface); - } - - if (AssembliesToDraw < LineCount) - { - // NOTE(Peter): Add assembly button - PrintF(&TempString, "+ Add Assembly"); - if (ui_Button(&State->Interface, TempString)) - { - panel* FileBrowser = PanelSystem_PushPanel(&State->PanelSystem, PanelType_FileView, State, Context); - Panel_PushModalOverride(Panel, FileBrowser, LoadAssemblyCallback); - } - } -#endif ui_PopLayout(&State->Interface); } diff --git a/src/app/interface.h b/src/app/interface.h index 3cd2772..6f90a18 100644 --- a/src/app/interface.h +++ b/src/app/interface.h @@ -534,11 +534,19 @@ ui_CommitBounds(ui_widget* Parent, rect2 Bounds) case LayoutDirection_BottomUp: { Parent->RowYAt = Bounds.Max.y; + if (ui_WidgetIsFlagSet(*Parent, UIWidgetFlag_ExpandsToFitChildren)) + { + Parent->Bounds.Max.y = Parent->RowYAt; + } }break; case LayoutDirection_TopDown: { Parent->RowYAt = Bounds.Min.y - Parent->RowHeight; + if (ui_WidgetIsFlagSet(*Parent, UIWidgetFlag_ExpandsToFitChildren)) + { + Parent->Bounds.Min.y = Bounds.Min.y; + } }break; } } @@ -589,7 +597,7 @@ internal ui_widget* ui_CreateLayoutWidget(ui_interface* Interface, rect2 Bounds, gs_string Name, ui_layout_direction FillDir = LayoutDirection_Inherit) { ui_widget* Result = ui_CreateWidget(Interface, Name); - ui_WidgetSetFlag(Result, UIWidgetFlag_DrawOutline); + //ui_WidgetSetFlag(Result, UIWidgetFlag_DrawOutline); Result->Bounds = Bounds; Result->Margin = Interface->Style.Margin; @@ -1021,8 +1029,8 @@ ui_EvaluateDropdown(ui_interface* Interface, ui_widget* Widget, ui_eval_result E { ui_widget ParentLayout = *Interface->ActiveLayout; - r32 SpaceAbove = ParentLayout.Bounds.Max.y - Widget->Bounds.Max.y; - r32 SpaceBelow = Widget->Bounds.Min.y - ParentLayout.Bounds.Min.y; + r32 SpaceAbove = Interface->WindowBounds.Max.y - Widget->Bounds.Max.y; + r32 SpaceBelow = Widget->Bounds.Min.y - Interface->WindowBounds.Min.y; ui_layout_direction Direction = LayoutDirection_TopDown; rect2 MenuBounds = {}; From 71547b05dcbe96e087489ce19c88745ea44df528 Mon Sep 17 00:00:00 2001 From: PS Date: Sun, 10 Jan 2021 16:25:35 -0800 Subject: [PATCH 16/44] Interface fixes. Fixed the problem with strip LUT tables where substrips were stamping over previous substrips. Some pattern building too. --- build/build_app_msvc_win32_debug.bat | 2 + debug.bat | 2 + src/app/editor/foldhaus_editor.cpp | 194 ++++++------ src/app/editor/foldhaus_operation_mode.h | 2 +- .../foldhaus_panel_animation_timeline.h | 130 ++++++-- .../editor/panels/foldhaus_panel_profiler.h | 7 +- .../panels/foldhaus_panel_sculpture_view.h | 8 +- src/app/engine/animation/foldhaus_animation.h | 68 ++++- .../animation/foldhaus_animation_renderer.cpp | 10 +- .../foldhaus_animation_serializer.cpp | 18 +- src/app/engine/assembly/foldhaus_assembly.cpp | 8 +- src/app/foldhaus_app.cpp | 42 ++- src/app/foldhaus_app.h | 161 +++++++++- src/app/interface.h | 282 +++++++++++++++++- src/app/interface_test.cpp | 102 +++++++ src/app/platform_win32/win32_foldhaus.cpp | 28 +- src/gs_libs/gs_input.h | 248 +++++++++++++++ src/gs_libs/gs_types.cpp | 178 ++++++++--- src/sculpture_gen/gen_blumen_lumen.cpp | 217 ++++++++++++++ src/sculpture_gen/sculpture_gen.h | 102 +++++++ 20 files changed, 1562 insertions(+), 247 deletions(-) create mode 100644 debug.bat create mode 100644 src/app/interface_test.cpp create mode 100644 src/sculpture_gen/gen_blumen_lumen.cpp create mode 100644 src/sculpture_gen/sculpture_gen.h diff --git a/build/build_app_msvc_win32_debug.bat b/build/build_app_msvc_win32_debug.bat index a60ed6c..25c45bd 100644 --- a/build/build_app_msvc_win32_debug.bat +++ b/build/build_app_msvc_win32_debug.bat @@ -29,6 +29,8 @@ cl %CommonCompilerFlags% %SourceCodePath%\platform_win32\win32_foldhaus.cpp /lin cl %CommonCompilerFlags% %ProjectDevPath%\src\serial_monitor\first.cpp /Feserial_monitor.exe /link %CommonLinkerFlags% user32.lib winmm.lib gdi32.lib +cl %CommonCompilerFlags% %ProjectDevPath%\src\sculpture_gen\gen_blumen_lumen.cpp /Fegen_blumen_lumen.exe /link %CommonLinkerFlags% user32.lib winmm.lib gdi32.lib + popd call %MyPath%\_postbuild_win32.bat \ No newline at end of file diff --git a/debug.bat b/debug.bat new file mode 100644 index 0000000..ecdc8cc --- /dev/null +++ b/debug.bat @@ -0,0 +1,2 @@ +@echo off +call remedybg.bat ./app_run_tree/win32_msvc/debug/session.rdbg \ No newline at end of file diff --git a/src/app/editor/foldhaus_editor.cpp b/src/app/editor/foldhaus_editor.cpp index 9d3b1a6..38f7590 100644 --- a/src/app/editor/foldhaus_editor.cpp +++ b/src/app/editor/foldhaus_editor.cpp @@ -12,6 +12,8 @@ Editor_HandleInput (app_state* State, rect2 WindowBounds, input_queue InputQueue b32 MouseInputHandled = HandleMousePanelInteraction(&State->PanelSystem, State->WindowBounds, Mouse, State); + gs_string TextInputString = PushString(State->Transient, 32); + panel* ActivePanel = PanelSystem_GetPanelContainingPoint(&State->PanelSystem, Mouse.Pos); if (ActivePanel) { @@ -47,7 +49,14 @@ Editor_HandleInput (app_state* State, rect2 WindowBounds, input_queue InputQueue // 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); + if (!FindAndPushExistingCommand(ActiveCommands, Event, Command_Began, &State->CommandQueue)) + { + char KeyASCII = KeyCodeToChar(Event.Key); + if (KeyASCII) + { + OutChar(&TextInputString, KeyASCII); + } + } } else if (KeyTransitionedUp(Event)) { @@ -55,7 +64,14 @@ Editor_HandleInput (app_state* State, rect2 WindowBounds, input_queue InputQueue } else if (KeyHeldDown(Event)) { - FindAndPushExistingCommand(ActiveCommands, Event, Command_Held, &State->CommandQueue); + if (!FindAndPushExistingCommand(ActiveCommands, Event, Command_Held, &State->CommandQueue)) + { + char KeyASCII = KeyCodeToChar(Event.Key); + if (KeyASCII) + { + OutChar(&TextInputString, KeyASCII); + } + } } } } @@ -74,6 +90,8 @@ Editor_HandleInput (app_state* State, rect2 WindowBounds, input_queue InputQueue } } + State->Interface.TempInputString = TextInputString.ConstString; + ClearCommandQueue(&State->CommandQueue); } @@ -84,6 +102,12 @@ Editor_Update(app_state* State, context* Context, input_queue InputQueue) State->WindowBounds = Context->WindowBounds; State->Interface.Mouse = Context->Mouse; + State->Interface.HotWidgetFramesSinceUpdate += 1; + if (State->Interface.HotWidgetFramesSinceUpdate > 1) + { + State->Interface.HotWidget = {}; + } + PanelSystem_UpdateLayout(&State->PanelSystem, State->WindowBounds); Editor_HandleInput(State, State->WindowBounds, InputQueue, Context->Mouse, *Context); } @@ -91,6 +115,8 @@ Editor_Update(app_state* State, context* Context, input_queue InputQueue) internal void Editor_DrawWidgetString(app_state* State, context* Context, render_command_buffer* RenderBuffer, ui_widget Widget, rect2 ClippingBox, v4 Color) { + gs_string Temp = PushString(State->Transient, 256); + PrintF(&Temp, "%d", Widget.Id.Id); render_quad_batch_constructor BatchConstructor = PushRenderTexture2DBatch(RenderBuffer, Widget.String.Length, State->Interface.Style.Font->BitmapMemory, @@ -199,14 +225,14 @@ Editor_DrawWidget(app_state* State, context* Context, render_command_buffer* Ren FillBounds.Max.y = FillToPoint; } } - PushRenderQuad2DClipped(RenderBuffer, FillBounds, WidgetParentUnion, Color); + rect2 ClippedFillBounds = Rect2Union(FillBounds, WidgetParentUnion); + PushRenderQuad2D(RenderBuffer, ClippedFillBounds, Color); if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawString) && Widget.String.Length > 0) { - // TODO(pjs): Mask this text by the horizontal fill // TODO(pjs): add this color to the style v4 TextColor = BlackV4; - Editor_DrawWidgetString(State, Context, RenderBuffer, Widget, WidgetParentUnion, TextColor); + Editor_DrawWidgetString(State, Context, RenderBuffer, Widget, ClippedFillBounds, TextColor); } } @@ -231,120 +257,67 @@ Editor_DrawWidget(app_state* State, context* Context, render_command_buffer* Ren } } -global r32 TestSlider_Value = 5; -global r32 TestSlider_Min = 0; -global r32 TestSlider_Max = 10; -global bool TestToggle = true; +#include "../interface_test.cpp" -internal void -TestRender(app_state* State, context* Context, render_command_buffer* RenderBuffer) +FOLDHAUS_INPUT_COMMAND_PROC(ActiveWidget_TypeCharacter) { - ui_InterfaceReset(&State->Interface); - State->Interface.RenderBuffer = RenderBuffer; - State->Interface.WindowBounds = Context->WindowBounds; - - gs_string A = MakeString("TestRender Layout"); - - ui_PushLayout(&State->Interface, A); + ui_widget* ActiveWidget = ui_InterfaceGetWidgetWithId(&State->Interface, State->Interface.ActiveWidget); + ui_widget_retained_state* WidgetState = ui_GetRetainedState(&State->Interface, ActiveWidget->Id); + if (WidgetState) { -#if 0 - ui_Label(&State->Interface, MakeString("Spacer")); - ui_Label(&State->Interface, MakeString("Spacer")); - ui_Label(&State->Interface, MakeString("Spacer")); - ui_Label(&State->Interface, MakeString("Spacer")); - ui_Label(&State->Interface, MakeString("Spacer")); - - ui_BeginList(&State->Interface, MakeString("TestList"), 5, 16); + char AsciiValue = CharacterFromKeyCode(Event.Key); + if (AsciiValue) { - ui_BeginRow(&State->Interface, 3); - for (u32 i = 0; i < 16; i++) - { - - ui_Button(&State->Interface, MakeString("B")); - ui_Button(&State->Interface, MakeString("C")); - ui_Button(&State->Interface, MakeString("D")); - } - ui_EndRow(&State->Interface); + OutChar(&WidgetState->EditString, AsciiValue); } - ui_EndList(&State->Interface); - //ui_Button(&State->Interface, MakeString("B")); - //ui_Button(&State->Interface, MakeString("C")); - //TestSlider_Value = ui_RangeSlider(&State->Interface, MakeString("TestSlider"), TestSlider_Value, TestSlider_Min, TestSlider_Max); -#elif 1 - ui_PushLayout(&State->Interface, MakeString("Outer")); - { - for (u32 i = 0; i < 3; i++) - { - ui_Button(&State->Interface, MakeString("A")); - } - } - ui_PopLayout(&State->Interface); - - ui_BeginRow(&State->Interface, 2); - { - ui_PushLayout(&State->Interface, MakeString("TestLayout")); - { - for (u32 i = 0; i < 5; i++) - { - ui_Button(&State->Interface, MakeString("TestButon")); - } - } - ui_PopLayout(&State->Interface); - - ui_PushLayout(&State->Interface, MakeString("TestLayout")); - { - ui_Button(&State->Interface, MakeString("TestButon")); - TestToggle = ui_Toggle(&State->Interface, MakeString("Toggle"), TestToggle); - TestSlider_Value = ui_RangeSlider(&State->Interface, MakeString("TestSlider"), TestSlider_Value, TestSlider_Min, TestSlider_Max); - if (ui_BeginDropdown(&State->Interface, MakeString("TestDropdown"))) - { - ui_Button(&State->Interface, MakeString("TestButon")); - ui_Button(&State->Interface, MakeString("TestButon")); - ui_Button(&State->Interface, MakeString("TestButon")); - } - ui_EndDropdown(&State->Interface); - } - ui_PopLayout(&State->Interface); - } - ui_EndRow(&State->Interface); - - ui_PushLayout(&State->Interface, MakeString("Outer")); - { - for (u32 i = 0; i < 3; i++) - { - ui_Button(&State->Interface, MakeString("B")); - } - } - ui_PopLayout(&State->Interface); - - - ui_PushOverlayLayout(&State->Interface, rect2{25, 25, 200, 200}, LayoutDirection_TopDown, MakeString("t")); - { - ui_Label(&State->Interface, PushStringF(State->Interface.PerFrameMemory, 256, "Mouse Pos - %f %f", State->Interface.Mouse.Pos.x, State->Interface.Mouse.Pos.y)); - } - ui_PopLayout(&State->Interface); -#else - ui_BeginList(&State->Interface, MakeString("Test List"), 10); - { - for (u32 i = 0; i < 32; i++) - { - ui_Button(&State->Interface, MakeString("Option")); - } - } - ui_EndList(&State->Interface); -#endif } - ui_PopLayout(&State->Interface); } +FOLDHAUS_INPUT_COMMAND_PROC(ActiveWidget_DeleteBackwards) +{ + ui_widget* ActiveWidget = ui_InterfaceGetWidgetWithId(&State->Interface, State->Interface.ActiveWidget); + ui_widget_retained_state* WidgetState = ui_GetRetainedState(&State->Interface, ActiveWidget->Id); + if (WidgetState) + { + WidgetState->EditString.Length -= 1; + } +} + +FOLDHAUS_INPUT_COMMAND_PROC(ActiveWidget_EndTypingMode) +{ + DeactivateCurrentOperationMode(&State->Modes); +} + +OPERATION_RENDER_PROC(ActiveWidget_EndTypingMode) +{ + ui_widget* ActiveWidget = ui_InterfaceGetWidgetWithId(&State->Interface, State->Interface.ActiveWidget); + ui_widget* LastActiveWidget = ui_InterfaceGetWidgetWithId(&State->Interface, State->Interface.LastActiveWidget); + if (ActiveWidget == 0 && LastActiveWidget != 0) + { + // if there was an active widget last frame that was typable, we want to deactivate the typing mode + DeactivateCurrentOperationMode(&State->Modes); + } +} + +input_command InterfaceTypingCommands [] = { + { KeyCode_A, KeyCode_Invalid, Command_Began | Command_Held, ActiveWidget_TypeCharacter }, + { KeyCode_B, KeyCode_Invalid, Command_Began | Command_Held, ActiveWidget_TypeCharacter }, + { KeyCode_C, KeyCode_Invalid, Command_Began | Command_Held, ActiveWidget_TypeCharacter }, + { KeyCode_D, KeyCode_Invalid, Command_Began | Command_Held, ActiveWidget_TypeCharacter }, + { KeyCode_E, KeyCode_Invalid, Command_Began | Command_Held, ActiveWidget_TypeCharacter }, + { KeyCode_Enter, KeyCode_Invalid, Command_Began, ActiveWidget_EndTypingMode }, + { KeyCode_Backspace, KeyCode_Invalid, Command_Began | Command_Held, ActiveWidget_DeleteBackwards }, +}; + internal void Editor_Render(app_state* State, context* Context, render_command_buffer* RenderBuffer) { + State->Interface.WindowBounds = Context->WindowBounds; PushRenderOrthographic(RenderBuffer, State->WindowBounds); PushRenderClearScreen(RenderBuffer); #if 0 - TestRender(State, Context, RenderBuffer); + InterfaceTest_Render(State, Context, RenderBuffer); #else ui_InterfaceReset(&State->Interface); State->Interface.RenderBuffer = RenderBuffer; @@ -369,6 +342,19 @@ Editor_Render(app_state* State, context* Context, render_command_buffer* RenderB { ui_widget Widget = *State->Interface.DrawOrderRoot; Editor_DrawWidget(State, Context, RenderBuffer, Widget, Context->WindowBounds); + +#if 0 + // TODO(pjs): got distracted halfway through getting typing input into the interface + if (ui_WidgetIdsEqual(State->Interface.ActiveWidget, State->Interface.LastActiveWidget)) + { + ui_widget* ActiveWidget = ui_InterfaceGetWidgetWithId(&State->Interface, State->Interface.ActiveWidget); + if (ActiveWidget != 0 && + ui_WidgetIsFlagSet(*ActiveWidget, UIWidgetFlag_Typable)) + { + operation_mode* TypingMode = ActivateOperationModeWithCommands(&State->Modes, InterfaceTypingCommands, ActiveWidget_EndTypingMode); + } + } +#endif } Context->GeneralWorkQueue->CompleteQueueWork(Context->GeneralWorkQueue, Context->ThreadContext); diff --git a/src/app/editor/foldhaus_operation_mode.h b/src/app/editor/foldhaus_operation_mode.h index e45606a..81e12fe 100644 --- a/src/app/editor/foldhaus_operation_mode.h +++ b/src/app/editor/foldhaus_operation_mode.h @@ -40,7 +40,7 @@ OperationModeSystemInit(gs_memory_arena* Storage, gs_thread_context ThreadContex // TODO(Peter): Do we really need an arena? Can this just operate in constant memory footprint? Result.Arena.Allocator = ThreadContext.Allocator; - Result.ModeMemoryPagesFreeList.CountMax = 16; // TODO(Peter): Static number of modes that can be active simultaneously + Result.ModeMemoryPagesFreeList.CountMax = 32; // TODO(Peter): Static number of modes that can be active simultaneously Result.ModeMemoryPagesFreeList.Data = PushArray(Storage, gs_data, Result.ModeMemoryPagesFreeList.CountMax); for (u32 Page = 0; Page < Result.ModeMemoryPagesFreeList.CountMax; Page++) { diff --git a/src/app/editor/panels/foldhaus_panel_animation_timeline.h b/src/app/editor/panels/foldhaus_panel_animation_timeline.h index 3c9d375..0a32fc4 100644 --- a/src/app/editor/panels/foldhaus_panel_animation_timeline.h +++ b/src/app/editor/panels/foldhaus_panel_animation_timeline.h @@ -34,7 +34,7 @@ GetXPositionFromFrameInAnimationPanel (u32 Frame, rect2 PanelBounds, frame_range } internal handle -AddAnimationBlockAtCurrentTime (u32 AnimationProcHandle, u32 LayerHandle, animation_system* System) +AddAnimationBlockAtCurrentTime (animation_pattern_handle AnimationProcHandle, u32 LayerHandle, animation_system* System) { u32 NewBlockStart = System->CurrentFrame; u32 NewBlockEnd = NewBlockStart + SecondsToFrames(3, *System); @@ -260,7 +260,8 @@ FOLDHAUS_INPUT_COMMAND_PROC(AddAnimationBlockCommand) frame_range Range = ActiveAnim->PlayableRange; u32 MouseDownFrame = GetFrameFromPointInAnimationPanel(Mouse.Pos, Panel->Bounds, Range); - handle NewBlockHandle = Animation_AddBlock(ActiveAnim, MouseDownFrame, MouseDownFrame + SecondsToFrames(3, State->AnimationSystem), 4, TimelineState->SelectedAnimationLayer); + animation_pattern_handle PatternHandle = Patterns_IndexToHandle(4); + handle NewBlockHandle = Animation_AddBlock(ActiveAnim, MouseDownFrame, MouseDownFrame + SecondsToFrames(3, State->AnimationSystem), PatternHandle, TimelineState->SelectedAnimationLayer); TimelineState->SelectedBlockHandle = NewBlockHandle; } @@ -575,8 +576,10 @@ PANEL_MODAL_OVERRIDE_CALLBACK(LoadAnimationFileCallback) 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, GlobalAnimationPatternsCount, GlobalAnimationPatterns); + animation NewAnim = AnimParser_Parse(AnimFileString, State->AnimationSystem.Storage, State->Patterns); + NewAnim.FileInfo = AnimFile.FileInfo; u32 NewAnimIndex = AnimationArray_Push(&State->AnimationSystem.Animations, NewAnim); State->AnimationSystem.ActiveAnimationIndex = NewAnimIndex; @@ -584,16 +587,17 @@ PANEL_MODAL_OVERRIDE_CALLBACK(LoadAnimationFileCallback) } internal void -DrawAnimationPatternList(rect2 PanelBounds, ui_interface* Interface, u32 SelectedAnimationLayerHandle, animation_system* AnimationSystem) +DrawAnimationPatternList(rect2 PanelBounds, ui_interface* Interface, u32 SelectedAnimationLayerHandle, animation_system* AnimationSystem, animation_pattern_array Patterns) { ui_PushLayout(Interface, PanelBounds, LayoutDirection_TopDown, MakeString("AnimClips Layout")); - for (s32 i = 0; i < GlobalAnimationPatternsCount; i++) + for (u32 i = 0; i < Patterns.Count; i++) { - animation_pattern Pattern = GlobalAnimationPatterns[i]; + animation_pattern Pattern = Patterns.Values[i]; gs_string PatternName = MakeString(Pattern.Name, Pattern.NameLength); if (ui_Button(Interface, PatternName)) { - AddAnimationBlockAtCurrentTime(i + 1, SelectedAnimationLayerHandle, AnimationSystem); + animation_pattern_handle PatternHandle = Patterns_IndexToHandle(i); + AddAnimationBlockAtCurrentTime(PatternHandle, SelectedAnimationLayerHandle, AnimationSystem); } } ui_PopLayout(Interface); @@ -624,12 +628,6 @@ PlayBar_Render(animation_timeline_state* TimelineState, rect2 Bounds, panel* Pan AnimSystem->TimelineShouldAdvance = false; AnimSystem->CurrentFrame = 0; } - - if (ui_Button(Interface, MakeString("Load"))) - { - panel* FileBrowser = PanelSystem_PushPanel(&State->PanelSystem, PanelType_FileView, State, Context); - Panel_PushModalOverride(Panel, FileBrowser, LoadAnimationFileCallback); - } } ui_EndRow(&State->Interface); ui_PopLayout(&State->Interface); @@ -640,7 +638,11 @@ FrameCount_Render(animation_timeline_state* TimelineState, rect2 Bounds, render_ { ui_interface* Interface = &State->Interface; gs_string TempString = PushString(State->Transient, 256); - frame_range VisibleFrames = TimelineState->VisibleRange; + // :FrameRange + // frame_range VisibleFrames = TimelineState->VisibleRange; + animation ActiveAnim = *AnimationSystem_GetActiveAnimation(&State->AnimationSystem); + frame_range VisibleFrames = ActiveAnim.PlayableRange; + s32 VisibleFrameCount = VisibleFrames.Max - VisibleFrames.Min; ui_FillRect(Interface, Bounds, Interface->Style.PanelBGColors[0]); @@ -685,7 +687,7 @@ FrameCount_Render(animation_timeline_state* TimelineState, rect2 Bounds, render_ } internal void -LayerList_Render(animation_timeline_state* TimelineState, rect2 Bounds, render_command_buffer* RenderBuffer, app_state* State, context Context) +LayerList_Render(animation_timeline_state* TimelineState, rect2 Bounds, panel* Panel, render_command_buffer* RenderBuffer, app_state* State, context Context) { ui_interface* Interface = &State->Interface; animation ActiveAnim = *AnimationSystem_GetActiveAnimation(&State->AnimationSystem); @@ -720,9 +722,15 @@ 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); + + // TODO(pjs): setting the timeline to show the entire range + // of the current animation until I reimplement the range + // slider bars + // :FrameRange + // frame_range ViewRange = TimelineState->VisibleRange; + frame_range ViewRange = ActiveAnim.PlayableRange; + handle SelectedBlockHandle = TimelineState->SelectedBlockHandle; s32 CurrentFrame = State->AnimationSystem.CurrentFrame; @@ -785,7 +793,7 @@ 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) +AnimInfoView_Render(animation_timeline_state* TimelineState, rect2 Bounds, panel* Panel, render_command_buffer* RenderBuffer, app_state* State, context Context) { animation_system* AnimSystem = &State->AnimationSystem; animation* ActiveAnim = AnimationSystem_GetActiveAnimation(AnimSystem); @@ -795,23 +803,84 @@ AnimInfoView_Render(animation_timeline_state* TimelineState, rect2 Bounds, rende ui_FillRect(&State->Interface, Bounds, Interface->Style.PanelBGColors[0]); - ui_BeginRow(&State->Interface, 2); + if (ui_BeginLabeledDropdown(Interface, MakeString("Active Animation"), ActiveAnim->Name)) { - ui_Label(Interface, MakeString("Active Animation")); - if (ui_BeginDropdown(Interface, ActiveAnim->Name)) + for (u32 i = 0; i < AnimSystem->Animations.Count; i++) { - for (u32 i = 0; i < AnimSystem->Animations.Count; i++) + animation Animation = AnimSystem->Animations.Values[i]; + if (ui_Button(Interface, Animation.Name)) { - animation Animation = AnimSystem->Animations.Values[i]; - if (ui_Button(Interface, Animation.Name)) + AnimSystem->ActiveAnimationIndex = i; + } + } + } + ui_EndLabeledDropdown(&State->Interface); + + ui_BeginRow(Interface, 3); + { + if (ui_Button(Interface, MakeString("New"))) + { + animation NewAnim = {}; + NewAnim.Name = PushString(State->AnimationSystem.Storage, 256); + + u32 NewAnimIndex = AnimationArray_Push(&State->AnimationSystem.Animations, NewAnim); + State->AnimationSystem.ActiveAnimationIndex = NewAnimIndex; + } + if (ui_Button(Interface, MakeString("Save"))) + { + // Save Animation File + // TODO(pjs): If you created the animation via the "new" button, there won't be a file attached. + // need to use the file browser to create a file + u32 ActiveAnimIndex = State->AnimationSystem.ActiveAnimationIndex; + animation ActiveAnimation = State->AnimationSystem.Animations.Values[ActiveAnimIndex]; + gs_string FileText = AnimSerializer_Serialize(ActiveAnimation, State->Patterns, State->Transient); + if (WriteEntireFile(Context.ThreadContext.FileHandler, ActiveAnimation.FileInfo.Path, StringToData(FileText))) + { + InvalidCodePath; + } + } + if (ui_Button(Interface, MakeString("Load"))) + { + panel* FileBrowser = PanelSystem_PushPanel(&State->PanelSystem, PanelType_FileView, State, Context); + Panel_PushModalOverride(Panel, FileBrowser, LoadAnimationFileCallback); + } + + } + ui_EndRow(Interface); + + ui_TextEntry(Interface, MakeString("Anim Name"), &ActiveAnim->Name); + + ui_Label(Interface, MakeString("Frame Range")); + ui_BeginRow(Interface, 3); + { + ActiveAnim->PlayableRange.Min = ui_TextEntryU64(Interface, MakeString("StartFrame"), ActiveAnim->PlayableRange.Min); + ActiveAnim->PlayableRange.Max = ui_TextEntryU64(Interface, MakeString("EndFrame"), ActiveAnim->PlayableRange.Max); + + } + ui_EndRow(Interface); + + animation_block* SelectedBlock = Animation_GetBlockFromHandle(ActiveAnim, TimelineState->SelectedBlockHandle); + if (SelectedBlock) + { + animation_pattern BlockPattern = Patterns_GetPattern(State->Patterns, SelectedBlock->AnimationProcHandle); + + ui_BeginRow(Interface, 3); + ui_Label(Interface, MakeString("Selected Pattern")); + //if (ui_BeginLabeledDropdown(Interface, MakeString("Selected Pattern"), MakeString(BlockPattern.Name, BlockPattern.NameLength))) + if (ui_BeginDropdown(Interface, MakeString(BlockPattern.Name, BlockPattern.NameLength))) + { + for (u32 i = 0; i < State->Patterns.Count; i++) + { + animation_pattern Pattern = State->Patterns.Values[i]; + if (ui_Button(Interface, MakeString(Pattern.Name, Pattern.NameLength))) { - AnimSystem->ActiveAnimationIndex = i; + SelectedBlock->AnimationProcHandle = Patterns_IndexToHandle(i); } } } - ui_EndDropdown(Interface); + ui_EndLabeledDropdown(Interface); } - ui_EndRow(&State->Interface); + ui_PopLayout(Interface); } @@ -831,8 +900,10 @@ AnimationTimeline_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* rect2 TimelineBounds, InfoBounds; RectVSplit(PanelBounds, 300, &InfoBounds, &TimelineBounds); +#if 0 rect2 AnimInfoBounds, SelectionInfoBounds; RectHSplitAtPercent(InfoBounds, .65f, &AnimInfoBounds, &SelectionInfoBounds); +#endif { // Timeline rect2 LayersPanelBounds, TimeRangePanelBounds; @@ -847,12 +918,11 @@ AnimationTimeline_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* PlayBar_Render(TimelineState, PlayBarBounds, Panel, RenderBuffer, State, Context); FrameCount_Render(TimelineState, FrameCountBounds, RenderBuffer, State, Context); - LayerList_Render(TimelineState, LayersBounds, RenderBuffer, State, Context); + LayerList_Render(TimelineState, LayersBounds, Panel, RenderBuffer, State, Context); TimeRange_Render(TimelineState, TimeRangeBounds, RenderBuffer, State, Context); } - AnimInfoView_Render(TimelineState, AnimInfoBounds, RenderBuffer, State, Context); - SelectionInfoView_Render(TimelineState, SelectionInfoBounds, RenderBuffer, State, Context); + AnimInfoView_Render(TimelineState, InfoBounds, Panel, RenderBuffer, State, Context); } #define FOLDHAUS_PANEL_ANIMATION_TIMELINE_H diff --git a/src/app/editor/panels/foldhaus_panel_profiler.h b/src/app/editor/panels/foldhaus_panel_profiler.h index 3a49177..dca590d 100644 --- a/src/app/editor/panels/foldhaus_panel_profiler.h +++ b/src/app/editor/panels/foldhaus_panel_profiler.h @@ -69,7 +69,12 @@ RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_widget* Layout, de ui_BeginMousePopup(Interface, rect2{ 25, 25, 300, 57 }, LayoutDirection_TopDown, MakeString("Hover")); { - PrintF(&String, "%S : %d - %d", Name->Name, Record->StartCycles, Record->EndCycles); + s64 Cycles = (Record->EndCycles - Record->StartCycles); + r64 PercentFrame = (r64)(Cycles) / (r64)(FrameTotalCycles); + PrintF(&String, "%S : %.2f%% frame | %dcy", + Name->Name, + PercentFrame, + Cycles); ui_Label(Interface, String); } ui_EndMousePopup(Interface); diff --git a/src/app/editor/panels/foldhaus_panel_sculpture_view.h b/src/app/editor/panels/foldhaus_panel_sculpture_view.h index ee4fecb..ba4d7c6 100644 --- a/src/app/editor/panels/foldhaus_panel_sculpture_view.h +++ b/src/app/editor/panels/foldhaus_panel_sculpture_view.h @@ -226,14 +226,10 @@ SculptureView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Ren 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); + PrintF(&Tempgs_string, "Hot Id: %u, ZIndex: %u | Active Id: %u", State->Interface.HotWidget.Id, + State->Interface.HotWidget.ZIndex,State->Interface.ActiveWidget.Id); DrawString(RenderBuffer, Tempgs_string, State->Interface.Style.Font, v2{PanelBounds.Min.x + 100, PanelBounds.Max.y - 200}, WhiteV4); - - v2 BoxHalfDim = v2{ 25, 25 }; - v2 BoxMin = LedOnScreenPosition - BoxHalfDim; - v2 BoxMax = LedOnScreenPosition + BoxHalfDim; - PushRenderBoundingBox2D(RenderBuffer, BoxMin, BoxMax, 2.0f, TealV4); } Context.GeneralWorkQueue->CompleteQueueWork(Context.GeneralWorkQueue, Context.ThreadContext); } diff --git a/src/app/engine/animation/foldhaus_animation.h b/src/app/engine/animation/foldhaus_animation.h index 0f160a0..e764ec6 100644 --- a/src/app/engine/animation/foldhaus_animation.h +++ b/src/app/engine/animation/foldhaus_animation.h @@ -14,6 +14,11 @@ struct frame_range s32 Max; }; +struct animation_pattern_handle +{ + s32 IndexPlusOne; +}; + // 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 @@ -21,7 +26,7 @@ struct frame_range struct animation_block { frame_range Range; - u32 AnimationProcHandle; + animation_pattern_handle AnimationProcHandle; u32 Layer; }; @@ -76,6 +81,9 @@ struct animation animation_block_array Blocks_; frame_range PlayableRange; + + // The information / path to the file where this animation is to be saved / where it is loaded from + gs_file_info FileInfo; }; struct animation_array @@ -132,6 +140,13 @@ struct animation_pattern animation_proc* Proc; }; +struct animation_pattern_array +{ + animation_pattern* Values; + u32 Count; + u32 CountMax; +}; + // Serialization enum animation_field @@ -185,6 +200,55 @@ global gs_const_string AnimationFieldStrings[] = { ConstString("animation_name"),// AnimField_BlockAnimName }; + +////////////////////////// +// +// Patterns List + +internal animation_pattern_array +Patterns_Create(gs_memory_arena* Arena, s32 CountMax) +{ + animation_pattern_array Result = {0}; + Result.CountMax = CountMax; + Result.Values = PushArray(Arena, animation_pattern, Result.CountMax); + return Result; +} + +#define Patterns_PushPattern(array, proc) Patterns_PushPattern_((array), (proc), Stringify(proc), sizeof(Stringify(proc))) +internal void +Patterns_PushPattern_(animation_pattern_array* Array, animation_proc* Proc, char* Name, u32 NameLength) +{ + Assert(Array->Count < Array->CountMax); + + animation_pattern Pattern = {0}; + Pattern.Name = Name; + Pattern.NameLength = NameLength; + Pattern.Proc = Proc; + + Array->Values[Array->Count++] = Pattern; +} + +internal animation_pattern_handle +Patterns_IndexToHandle(s32 Index) +{ + animation_pattern_handle Result = {}; + Result.IndexPlusOne = Index + 1; + return Result; +} + +internal animation_pattern +Patterns_GetPattern(animation_pattern_array Patterns, animation_pattern_handle Handle) +{ + animation_pattern Result = {0}; + if (Handle.IndexPlusOne > 0) + { + u32 Index = Handle.IndexPlusOne - 1; + Assert(Index < Patterns.Count); + Result = Patterns.Values[Index]; + } + return Result; +} + ////////////////////////// // // Anim Block Array @@ -291,7 +355,7 @@ AnimationArray_Push(animation_array* Array, animation Value) // Animation internal handle -Animation_AddBlock(animation* Animation, u32 StartFrame, s32 EndFrame, u32 AnimationProcHandle, u32 LayerIndex) +Animation_AddBlock(animation* Animation, u32 StartFrame, s32 EndFrame, animation_pattern_handle AnimationProcHandle, u32 LayerIndex) { Assert(LayerIndex < Animation->Layers.Count); diff --git a/src/app/engine/animation/foldhaus_animation_renderer.cpp b/src/app/engine/animation/foldhaus_animation_renderer.cpp index 83dc221..2bf58d0 100644 --- a/src/app/engine/animation/foldhaus_animation_renderer.cpp +++ b/src/app/engine/animation/foldhaus_animation_renderer.cpp @@ -81,21 +81,19 @@ LedBlend_GetProc(blend_mode BlendMode) } internal void -AnimationSystem_RenderBlockToLedBuffer(animation_system* System, animation_block Block, led_buffer* Buffer, assembly Assembly, animation_pattern* Patterns, gs_memory_arena* Transient) +AnimationSystem_RenderBlockToLedBuffer(animation_system* System, animation_block Block, led_buffer* Buffer, assembly Assembly, animation_pattern_array 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); + animation_pattern Pattern = Patterns_GetPattern(Patterns, Block.AnimationProcHandle); + Pattern.Proc(Buffer, Assembly, SecondsIntoBlock, Transient); } internal void AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Assemblies, led_system* LedSystem, - animation_pattern* Patterns, + animation_pattern_array Patterns, gs_memory_arena* Transient) { s32 CurrentFrame = System->CurrentFrame; diff --git a/src/app/engine/animation/foldhaus_animation_serializer.cpp b/src/app/engine/animation/foldhaus_animation_serializer.cpp index 8607b0f..7e688f2 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_pattern* GlobalClips, gs_memory_arena* Arena) +AnimSerializer_Serialize(animation Anim, animation_pattern_array Patterns, gs_memory_arena* Arena) { serializer Serializer = {0}; Serializer.String = PushString(Arena, 4096); @@ -45,10 +45,7 @@ AnimSerializer_Serialize(animation Anim, animation_pattern* GlobalClips, gs_memo // TODO(pjs): Handle free'd animation blocks animation_block AnimationBlockAt = Anim.Blocks_.Values[i]; - // TODO(pjs): Systematize the AnimationProcHandle - // :AnimProcHandle - u32 AnimationProcIndex = AnimationBlockAt.AnimationProcHandle - 1; - animation_pattern Animation = GlobalClips[AnimationProcIndex]; + animation_pattern Animation = Patterns_GetPattern(Patterns, AnimationBlockAt.AnimationProcHandle); Serializer_OpenStruct(&Serializer, AnimField_Block); { @@ -70,7 +67,7 @@ AnimSerializer_Serialize(animation Anim, animation_pattern* GlobalClips, gs_memo } internal animation -AnimParser_Parse(gs_string File, gs_memory_arena* Arena, u32 AnimClipsCount, animation_pattern* AnimClips) +AnimParser_Parse(gs_string File, gs_memory_arena* Arena, animation_pattern_array AnimPatterns) { animation Result = {0}; @@ -162,12 +159,13 @@ AnimParser_Parse(gs_string File, gs_memory_arena* Arena, u32 AnimClipsCount, ani // TODO(pjs): AnimName -> Animation Proc Handle gs_string AnimName = Parser_ReadStringValue(&Parser, AnimField_BlockAnimName); - Block.AnimationProcHandle = 0; - for (u32 i = 0; i < AnimClipsCount; i++) + Block.AnimationProcHandle = {0}; + for (u32 i = 0; i < AnimPatterns.Count; i++) { - if (StringEqualsCharArray(AnimName.ConstString, AnimClips[i].Name, CStringLength(AnimClips[i].Name))) + animation_pattern Pattern = AnimPatterns.Values[i]; + if (StringEqualsCharArray(AnimName.ConstString, Pattern.Name, Pattern.NameLength)) { - Block.AnimationProcHandle = i + 1; + Block.AnimationProcHandle = Patterns_IndexToHandle(i); break; } } diff --git a/src/app/engine/assembly/foldhaus_assembly.cpp b/src/app/engine/assembly/foldhaus_assembly.cpp index 1d68fdb..8c88276 100644 --- a/src/app/engine/assembly/foldhaus_assembly.cpp +++ b/src/app/engine/assembly/foldhaus_assembly.cpp @@ -136,7 +136,7 @@ LedBufferSetLed(led_buffer* Buffer, u32 Led, v4 Position) } internal u32 -Assembly_ConstructStrip(assembly* Assembly, led_buffer* LedBuffer, v2_strip* StripAt, strip_gen_data GenData, v4 RootPosition, u32 LedStartIndex) +Assembly_ConstructStrip(assembly* Assembly, led_buffer* LedBuffer, v2_strip* StripAt, strip_gen_data GenData, v4 RootPosition, u32 LedStartIndex, u32 LedLUTStartIndex) { u32 LedsAdded = 0; @@ -154,7 +154,7 @@ Assembly_ConstructStrip(assembly* Assembly, led_buffer* LedBuffer, v2_strip* Str s32 LedIndex = LedStartIndex + LedsAdded++; v4 LedPosition = WS_StripStart + (SingleStep * Step); LedBufferSetLed(LedBuffer, LedIndex, LedPosition); - StripAt->LedLUT[Step] = LedIndex; + StripAt->LedLUT[Step + LedLUTStartIndex] = LedIndex; } }break; @@ -164,7 +164,7 @@ Assembly_ConstructStrip(assembly* Assembly, led_buffer* LedBuffer, v2_strip* Str for (u32 i = 0; i < Sequence.ElementsCount; i++) { strip_gen_data SegmentGenData = Sequence.Elements[i]; - LedsAdded += Assembly_ConstructStrip(Assembly, LedBuffer, StripAt, SegmentGenData, RootPosition, LedStartIndex + LedsAdded); + LedsAdded += Assembly_ConstructStrip(Assembly, LedBuffer, StripAt, SegmentGenData, RootPosition, LedStartIndex + LedsAdded, LedsAdded); } }break; @@ -190,7 +190,7 @@ ConstructAssemblyFromDefinition (assembly* Assembly, led_system* LedSystem) StripAt->LedLUT = PushArray(&Assembly->Arena, u32, StripAt->LedCount); strip_gen_data GenData = StripAt->GenerationData; - LedsAdded += Assembly_ConstructStrip(Assembly, LedBuffer, StripAt, GenData, RootPosition, LedsAdded); + LedsAdded += Assembly_ConstructStrip(Assembly, LedBuffer, StripAt, GenData, RootPosition, LedsAdded, 0); } } diff --git a/src/app/foldhaus_app.cpp b/src/app/foldhaus_app.cpp index 3d74388..ba190b9 100644 --- a/src/app/foldhaus_app.cpp +++ b/src/app/foldhaus_app.cpp @@ -10,6 +10,23 @@ //////////////////////////////////////////////////////////////////////// +internal void +ClearAndPushPatterns(animation_pattern_array* Patterns) +{ + if (Patterns->CountMax == 0) { return; } + + Patterns->Count = 0; + Patterns_PushPattern(Patterns, TestPatternOne); + Patterns_PushPattern(Patterns, TestPatternTwo); + Patterns_PushPattern(Patterns, TestPatternThree); + Patterns_PushPattern(Patterns, Pattern_AllGreen); + Patterns_PushPattern(Patterns, Pattern_HueShift); + Patterns_PushPattern(Patterns, Pattern_HueFade); + Patterns_PushPattern(Patterns, Pattern_Spots); + Patterns_PushPattern(Patterns, Pattern_LighthouseRainbow); + Patterns_PushPattern(Patterns, Pattern_SmoothGrowRainbow); +} + RELOAD_STATIC_DATA(ReloadStaticData) { app_state* State = (app_state*)Context.MemoryBase; @@ -17,6 +34,8 @@ RELOAD_STATIC_DATA(ReloadStaticData) GlobalDebugServices = DebugServices; State->PanelSystem.PanelDefs = GlobalPanelDefs; State->PanelSystem.PanelDefsCount = GlobalPanelDefsCount; + + ClearAndPushPatterns(&State->Patterns); } INITIALIZE_APPLICATION(InitializeApplication) @@ -34,6 +53,9 @@ INITIALIZE_APPLICATION(InitializeApplication) State->CommandQueue = CommandQueue_Create(&State->Permanent, 32); + State->Patterns = Patterns_Create(&State->Permanent, 10); + ClearAndPushPatterns(&State->Patterns); + // TODO(Peter): put in InitializeInterface? r32 FontSize = 14; { @@ -112,13 +134,14 @@ INITIALIZE_APPLICATION(InitializeApplication) State->Interface.Widgets = PushArray(&State->Permanent, ui_widget, State->Interface.WidgetsCountMax); State->Interface.PerFrameMemory = PushStruct(&State->Permanent, gs_memory_arena); *State->Interface.PerFrameMemory = CreateMemoryArena(Context.ThreadContext.Allocator); + State->Interface.Permanent = &State->Permanent; State->SACN = SACN_Initialize(Context); State->LedSystem = LedSystemInitialize(Context.ThreadContext.Allocator, 128); #if 1 - gs_const_string SculpturePath = ConstString("data/blumen_lumen_silver_spring.fold"); + gs_const_string SculpturePath = ConstString("data/test_blumen.fold"); LoadAssembly(&State->Assemblies, &State->LedSystem, State->Transient, Context, SculpturePath, State->GlobalLog); #endif @@ -147,7 +170,7 @@ INITIALIZE_APPLICATION(InitializeApplication) Animation_AddLayer(&Anim, MakeString("Color Layer"), BlendMode_Multiply, &State->AnimationSystem); Animation_AddLayer(&Anim, MakeString("Sparkles"), BlendMode_Add, &State->AnimationSystem); - Animation_AddBlock(&Anim, 0, Anim.PlayableRange.Max, 4, 0); + Animation_AddBlock(&Anim, 0, Anim.PlayableRange.Max, Patterns_IndexToHandle(5), 0); AnimationArray_Push(&State->AnimationSystem.Animations, Anim); @@ -178,7 +201,7 @@ UPDATE_AND_RENDER(UpdateAndRender) AnimationSystem_RenderToLedBuffers(&State->AnimationSystem, State->Assemblies, &State->LedSystem, - GlobalAnimationPatterns, + State->Patterns, State->Transient); } @@ -192,19 +215,6 @@ UPDATE_AND_RENDER(UpdateAndRender) } Editor_Render(State, Context, RenderBuffer); - - // Checking for overflows -#if 0 - { - DEBUG_TRACK_SCOPE(OverflowChecks); - AssertAllocationsNoOverflow(State->Permanent); - for (u32 i = 0; i < State->Assemblies.Count; i++) - { - assembly* Assembly = &State->Assemblies.Values[i]; - AssertAllocationsNoOverflow(Assembly->Arena); - } - } -#endif } CLEANUP_APPLICATION(CleanupApplication) diff --git a/src/app/foldhaus_app.h b/src/app/foldhaus_app.h index df2d3d9..24a98d0 100644 --- a/src/app/foldhaus_app.h +++ b/src/app/foldhaus_app.h @@ -53,6 +53,7 @@ struct app_state assembly_array Assemblies; animation_system AnimationSystem; event_log* GlobalLog; + animation_pattern_array Patterns; // Interface // @@ -205,8 +206,15 @@ TestPatternThree(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* v4 HSVToRGB (v4 In) { float Hue = In.x; - while (Hue > 360.0f) { Hue -= 360.0f; } + /* +while (Hue > 360.0f) { Hue -= 360.0f; } while (Hue < 0.0f) { Hue += 360.0f; } + */ + Hue = ModR32(Hue, 360.0f); + if (Hue < 0) { Hue += 360.0f; } + if (Hue == MinR32) { Hue = 0; } + if (Hue == MaxR32) { Hue = 360; } + Assert(Hue >= 0 && Hue < 360); float Sat = In.y; float Value = In.z; @@ -279,9 +287,8 @@ v4 HSVToRGB (v4 In) } internal void -Pattern_AllGreen(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient) +Pattern_HueShift(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient) { -#if 1 r32 Height = SinR32(Time) * 25; r32 CycleLength = 5.0f; @@ -304,7 +311,41 @@ Pattern_AllGreen(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Leds->Colors[LedIndex].G = G; Leds->Colors[LedIndex].B = B; } -#else +} + +internal pixel +V4ToRGBPixel(v4 C) +{ + pixel Result = {}; + Result.R = (u8)(C.x * 255); + Result.G = (u8)(C.y * 255); + Result.B = (u8)(C.z * 255); + return Result; +} + +internal void +Pattern_HueFade(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient) +{ + r32 HueBase = ModR32(Time * 50, 360); + + r32 CycleLength = 5.0f; + r32 CycleProgress = FractR32(Time / CycleLength); + r32 CycleBlend = (SinR32(Time) * .5f) + .5f; + + for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) + { + v4 Pos = Leds->Positions[LedIndex]; + r32 Hue = HueBase + Pos.y + Pos.x; + v4 HSV = { Hue, 1, 1, 1 }; + v4 RGB = HSVToRGB(HSV); + + Leds->Colors[LedIndex] = V4ToRGBPixel(RGB); + } +} + +internal void +Pattern_AllGreen(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient) +{ for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) { u32 I = LedIndex + 1; @@ -322,6 +363,110 @@ Pattern_AllGreen(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Leds->Colors[LedIndex].B = 255; } + } +} + +internal r32 +PatternHash(r32 Seed) +{ + return FractR32(Seed * 17.0 * FractR32(Seed * 0.3183099)); +} + +internal void +Pattern_Spots(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient) +{ + pixel ColorA = { 0, 255, 255 }; + pixel ColorB = { 255, 0, 255 }; + + r32 Speed = .5f; + Time *= Speed; + r32 ScaleA = 2 * SinR32(Time / 5); + r32 ScaleB = 2.4f * CosR32(Time / 2.5f); + for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) + { + v4 P = Leds->Positions[LedIndex]; + r32 V = P.y; + r32 Noise = .3f * PatternHash(V); + r32 ThetaY = (Leds->Positions[LedIndex].y / 10) + Time + Noise; + r32 ThetaX = (Leds->Positions[LedIndex].x / 13) + Time + Noise; + r32 Fade = (ScaleA * SinR32(ThetaY)) + (ScaleB * CosR32(3 * ThetaX)); + Fade = RemapClampedR32(Fade, -1, 1, 0, 1); + + Leds->Colors[LedIndex].R = (u8)LerpR32(Fade, ColorA.R, ColorB.R); + Leds->Colors[LedIndex].G = (u8)LerpR32(Fade, ColorA.G, ColorB.G); + Leds->Colors[LedIndex].B = (u8)LerpR32(Fade, ColorA.B, ColorB.B); + } +} + +internal void +Pattern_LighthouseRainbow(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient) +{ + v2 RefVector = V2Normalize(v2{ SinR32(Time), CosR32(Time) }); + for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) + { + v2 Vector = v2{ + Leds->Positions[LedIndex].x, + Leds->Positions[LedIndex].z + }; + Vector = V2Normalize(Vector); + + r32 Angle = V2Dot(RefVector, Vector); + +#if 0 + r32 Fade = RemapR32(Angle, -1, 1, 0, 1); + Leds->Colors[LedIndex].R = (u8)(Fade * 255); + Leds->Colors[LedIndex].G = (u8)(Fade * 255); + Leds->Colors[LedIndex].B = (u8)(Fade * 255); +#endif + + v4 HSV = { (Angle * 30) + (Time * 10) + Leds->Positions[LedIndex].y, 1, 1, 1 }; + v4 RGB = HSVToRGB(HSV); + + Leds->Colors[LedIndex] = V4ToRGBPixel(RGB); + } +} + +internal r32 +Smoothstep(r32 T) +{ + r32 Result = (T * T * (3 - (2 * T))); + return Result; +} + +internal void +Pattern_SmoothGrowRainbow(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient) +{ + r32 FillCycleTime = ModR32(Time, 7.0f) / 7.0f; + r32 ColorCycleTime = ModR32(Time, 21.0f) / 21.0f; + + //v4 HSV = { ColorCycleTime * 360, 1, 1, 1 }; + //v4 RGB0 = HSVToRGB(HSV); + //HSV.x += ; + //v4 RGB1 = HSVToRGB(HSV); + + v4 HSV = { 0, 1, 1, 1 }; + for (u32 s = 0; s < Assembly.StripCount; s++) + { + v2_strip Strip = Assembly.Strips[s]; + + v4 RGB0 = HSVToRGB(HSV); + for (u32 l = 0; l < Strip.LedCount; l++) + { + u32 LedIndex = Strip.LedLUT[l]; + Leds->Colors[LedIndex] = V4ToRGBPixel(RGB0); + } + + HSV.x += 15; + } + +#if 0 + for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) + { + v4 P = Leds->Positions[LedIndex]; + + Leds->Colors[LedIndex] = V4ToRGBPixel(RGB0); + + } #endif } @@ -334,14 +479,6 @@ EndCurrentOperationMode(app_state* State) DeactivateCurrentOperationMode(&State->Modes); } -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" #include "editor/panels/foldhaus_panel_file_view.h" diff --git a/src/app/interface.h b/src/app/interface.h index 6f90a18..7ef4f07 100644 --- a/src/app/interface.h +++ b/src/app/interface.h @@ -231,20 +231,24 @@ DrawStringWithCursor (render_command_buffer* RenderBuffer, gs_string String, s32 enum ui_widget_flag { UIWidgetFlag_ExpandsToFitChildren, + UIWidgetFlag_DrawBackground, UIWidgetFlag_DrawString, UIWidgetFlag_DrawOutline, - UIWidgetFlag_Clickable, UIWidgetFlag_DrawHorizontalFill, UIWidgetFlag_DrawVerticalFill, UIWidgetFlag_DrawFillReversed, UIWidgetFlag_DrawFillAsHandle, + + UIWidgetFlag_Clickable, + UIWidgetFlag_Selectable, + UIWidgetFlag_Typable, }; struct ui_widget_id { u64 Id; - u64 ParentId; + u64 ZIndex; }; enum ui_layout_direction @@ -293,6 +297,8 @@ struct ui_widget // we can check the retained state of that dropdown ui_widget_id WidgetReference; + u64 ChildZIndexOffset; + ui_widget* ChildrenRoot; ui_widget* ChildrenHead; u32 ChildCount; @@ -334,6 +340,8 @@ struct ui_widget_retained_state // For use in layouts that allow you to scroll / pan v2 ChildrenDrawOffset; + + gs_string EditString; }; struct ui_interface @@ -343,6 +351,9 @@ struct ui_interface mouse_state Mouse; rect2 WindowBounds; + // A per-frame string of the characters which have been typed + gs_const_string TempInputString; + render_command_buffer* RenderBuffer; ui_widget* Widgets; @@ -353,7 +364,11 @@ struct ui_interface ui_widget* DrawOrderRoot; ui_widget_id HotWidget; + // This should really never get higher than 1 or 2 + u8 HotWidgetFramesSinceUpdate; + ui_widget_id ActiveWidget; + ui_widget_id LastActiveWidget; ui_widget* ActiveLayout; @@ -362,6 +377,12 @@ struct ui_interface u64 RetainedStateCount; gs_memory_arena* PerFrameMemory; + + // TODO(pjs): DONT USE THIS + // Right now you only need this to create EditStrings for ui_widget_retained_state's + // and even for those, you eventually want a better solution than "create a string and it lives forever" + // TODO(pjs): Get rid of the need for this vvv + gs_memory_arena* Permanent; }; internal void @@ -380,12 +401,14 @@ ui_InterfaceReset(ui_interface* Interface) Interface->RetainedState[i] = {0}; } } + + Interface->LastActiveWidget = Interface->ActiveWidget; } internal bool ui_WidgetIdsEqual(ui_widget_id A, ui_widget_id B) { - bool Result = (A.Id == B.Id) && (A.ParentId == B.ParentId); + bool Result = (A.Id == B.Id);// && (A.ParentId == B.ParentId); return Result; } @@ -411,6 +434,53 @@ ui_WidgetIsFlagSet(ui_widget Widget, u64 Flag) return Result; } +internal void +ui_WidgetSetChildrenPopover(ui_widget* Widget) +{ + Widget->ChildZIndexOffset = 1000; +} + +internal ui_widget* +ui_WidgetGetWidgetWithId(ui_widget* Parent, ui_widget_id Id) +{ + ui_widget* Result = 0; + + if (ui_WidgetIdsEqual(Parent->Id, Id)) + { + Result = Parent; + } + else if (Parent->ChildrenRoot != 0) + { + for (ui_widget* At = Parent->ChildrenRoot; At != 0; At = At->Next) + { + Result = ui_WidgetGetWidgetWithId(At, Id); + if (Result != 0) + { + break; + } + } + } + + return Result; +} + +internal ui_widget* +ui_InterfaceGetWidgetWithId(ui_interface* Interface, ui_widget_id Id) +{ + ui_widget* Result = 0; + + for (ui_widget* At = Interface->DrawOrderRoot; At != 0; At = At->Next) + { + Result = ui_WidgetGetWidgetWithId(At, Id); + if (Result != 0) + { + break; + } + } + + return Result; +} + internal ui_widget_retained_state* ui_GetRetainedState(ui_interface* Interface, ui_widget_id Id) { @@ -433,6 +503,7 @@ ui_CreateRetainedState(ui_interface* Interface, ui_widget* Widget) u64 Index = Interface->RetainedStateCount++; ui_widget_retained_state* Result = Interface->RetainedState + Index; Result->Id = Widget->Id; + Result->EditString = PushString(Interface->Permanent, 256); return Result; } @@ -451,7 +522,8 @@ internal ui_widget* ui_CreateWidget(ui_interface* Interface, gs_string String) { Assert(Interface->WidgetsCount < Interface->WidgetsCountMax); - ui_widget* Result = Interface->Widgets + Interface->WidgetsCount++; + u64 Index = Interface->WidgetsCount++; + ui_widget* Result = Interface->Widgets + Index; ZeroStruct(Result); Result->Parent = Interface->ActiveLayout; @@ -461,10 +533,18 @@ ui_CreateWidget(ui_interface* Interface, gs_string String) { Id = HashAppendDJB2ToU32(Id, Result->Parent->Id.Id); Id = HashAppendDJB2ToU32(Id, Result->Parent->ChildCount); - Result->Id.ParentId = Result->Parent->Id.Id; + //Result->Id.ParentId = Result->Parent->Id.Id; } Result->Id.Id = Id; + u64 ZIndex = Index + 1; + if (Result->Parent) + { + Result->ChildZIndexOffset += Result->Parent->ChildZIndexOffset; + ZIndex += Result->Parent->ChildZIndexOffset; + } + Result->Id.ZIndex = ZIndex; + Result->String = PushStringCopy(Interface->PerFrameMemory, String.ConstString); Result->Alignment = Align_Left; Result->Next = 0; @@ -859,20 +939,81 @@ ui_EvaluateWidget(ui_interface* Interface, ui_widget* Widget, rect2 Bounds) Interface->ActiveLayout->ChildCount += 1; ui_CommitBounds(Widget->Parent, Widget->Bounds); + if (PointIsInRect(Widget->Parent->Bounds, Interface->Mouse.Pos) && + PointIsInRect(Widget->Bounds, Interface->Mouse.Pos)) + { + if (MouseButtonTransitionedDown(Interface->Mouse.LeftButtonState)) + { + if (ui_WidgetIdsEqual(Interface->HotWidget, Widget->Id)) + { + Result.Clicked = true; + Interface->ActiveWidget = Widget->Id; + } + } + + if (Interface->HotWidget.ZIndex == 0 || + Interface->HotWidget.ZIndex <= Widget->Id.ZIndex) + { + Interface->HotWidget = Widget->Id; + Interface->HotWidgetFramesSinceUpdate = 0; + } + } + else + { + if (ui_WidgetIdsEqual(Interface->ActiveWidget, Widget->Id) && + MouseButtonTransitionedDown(Interface->Mouse.LeftButtonState)) + { + Interface->ActiveWidget = {}; + } + } + + if (ui_WidgetIdsEqual(Interface->ActiveWidget, Widget->Id)) + { + // click & drag + if (MouseButtonHeldDown(Interface->Mouse.LeftButtonState)) + { + Result.Held = true; + Result.DragDelta = Interface->Mouse.Pos - Interface->Mouse.DownPos; + } + + if (ui_WidgetIsFlagSet(*Widget, UIWidgetFlag_Typable) && + Interface->TempInputString.Length > 0) + { + ui_widget_retained_state* State = ui_GetRetainedState(Interface, Widget->Id); + + // TODO(pjs): Backspace? + for (u32 i = 0; i < Interface->TempInputString.Length; i++) + { + if (Interface->TempInputString.Str[i] == '\b') + { + State->EditString.Length -= 1; + } + else + { + OutChar(&State->EditString, Interface->TempInputString.Str[i]); + } + } + } + } + +#if 0 + // if you can click it if (ui_WidgetIsFlagSet(*Widget, UIWidgetFlag_Clickable)) { + // updating hot widget, and handling mouse clicks if (PointIsInRect(Widget->Parent->Bounds, Interface->Mouse.Pos) && PointIsInRect(Widget->Bounds, Interface->Mouse.Pos)) { if (ui_WidgetIdsEqual(Interface->HotWidget, Widget->Id) && MouseButtonTransitionedDown(Interface->Mouse.LeftButtonState)) { - Assert(!ui_WidgetIdsEqual(Interface->ActiveWidget, Widget->Id)); Result.Clicked = true; Interface->ActiveWidget = Widget->Id; } + Interface->HotWidget = Widget->Id; } + // click and drag if (MouseButtonHeldDown(Interface->Mouse.LeftButtonState) && PointIsInRect(Widget->Bounds, Interface->Mouse.DownPos)) { @@ -880,13 +1021,45 @@ ui_EvaluateWidget(ui_interface* Interface, ui_widget* Widget, rect2 Bounds) Result.DragDelta = Interface->Mouse.Pos - Interface->Mouse.DownPos; } - if (ui_WidgetIdsEqual(Interface->ActiveWidget, Widget->Id) && - MouseButtonTransitionedUp(Interface->Mouse.LeftButtonState)) + // if this is the active widget (its been clicked) + if (ui_WidgetIdsEqual(Interface->ActiveWidget, Widget->Id)) { - Interface->ActiveWidget = {}; + // if you can select it + if (ui_WidgetIsFlagSet(*Widget, UIWidgetFlag_Selectable)) + { + // + if (MouseButtonTransitionedDown(Interface->Mouse.LeftButtonState) && + !PointIsInRect(Widget->Bounds, Interface->Mouse.Pos)) + { + Interface->ActiveWidget = {}; + } + + if (ui_WidgetIsFlagSet(*Widget, UIWidgetFlag_Typable) && + Interface->TempInputString.Length > 0) + { + ui_widget_retained_state* State = ui_GetRetainedState(Interface, Widget->Id); + + // TODO(pjs): Backspace? + for (u32 i = 0; i < Interface->TempInputString.Length; i++) + { + if (Interface->TempInputString.Str[i] == '\b') + { + State->EditString.Length -= 1; + } + else + { + OutChar(&State->EditString, Interface->TempInputString.Str[i]); + } + } + } + } + else if (MouseButtonTransitionedUp(Interface->Mouse.LeftButtonState)) + { + Interface->ActiveWidget = {}; + } } - } +#endif Assert(Widget->Parent != 0); return Result; @@ -941,6 +1114,77 @@ ui_Label(ui_interface* Interface, gs_string String, gs_string_alignment Alignmen ui_EvaluateWidget(Interface, Widget); } +internal void +ui_TextEntrySetFlags(ui_widget* Widget, gs_string EditString) +{ + Widget->String = EditString; + ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawString); + ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawBackground); + ui_WidgetSetFlag(Widget, UIWidgetFlag_Clickable); + ui_WidgetSetFlag(Widget, UIWidgetFlag_Selectable); + ui_WidgetSetFlag(Widget, UIWidgetFlag_Typable); +} + +internal void +ui_TextEntry(ui_interface* Interface, gs_string Identifier, gs_string* Value) +{ + ui_widget* Widget = ui_CreateWidget(Interface, Identifier); + ui_widget_retained_state* State = ui_GetRetainedState(Interface, Widget->Id); + if (!State) + { + State = ui_CreateRetainedState(Interface, Widget); + } + PrintF(&State->EditString, "%S", *Value); + + ui_TextEntrySetFlags(Widget, State->EditString); + + ui_eval_result Result = ui_EvaluateWidget(Interface, Widget); + PrintF(Value, "%S", State->EditString); +} + +internal u64 +ui_TextEntryU64(ui_interface* Interface, gs_string String, u64 CurrentValue) +{ + ui_widget* Widget = ui_CreateWidget(Interface, String); + ui_widget_retained_state* State = ui_GetRetainedState(Interface, Widget->Id); + if (!State) + { + State = ui_CreateRetainedState(Interface, Widget); + PrintF(&State->EditString, "%u", CurrentValue); + } + ui_TextEntrySetFlags(Widget, State->EditString); + + ui_eval_result Result = ui_EvaluateWidget(Interface, Widget); + parse_uint_result ParseResult = ValidateAndParseUInt(State->EditString.ConstString); + u64 ValueResult = CurrentValue; + if (ParseResult.Success) + { + ValueResult = ParseResult.Value; + } + return ValueResult; +} + +internal r64 +ui_TextEntryR64(ui_interface* Interface, gs_string String, r64 CurrentValue) +{ + ui_widget* Widget = ui_CreateWidget(Interface, String); + ui_widget_retained_state* State = ui_GetRetainedState(Interface, Widget->Id); + if (!State) + { + State = ui_CreateRetainedState(Interface, Widget); + PrintF(&State->EditString, "%f", CurrentValue); + } + ui_TextEntrySetFlags(Widget, State->EditString); + ui_eval_result Result = ui_EvaluateWidget(Interface, Widget); + parse_float_result ParseResult = ValidateAndParseFloat(State->EditString.ConstString); + r64 ValueResult = CurrentValue; + if (ParseResult.Success) + { + ValueResult = ParseResult.Value; + } + return ValueResult; +} + internal ui_widget* ui_CreateButtonWidget(ui_interface* Interface, gs_string Text) { @@ -1057,6 +1301,7 @@ ui_EvaluateDropdown(ui_interface* Interface, ui_widget* Widget, ui_eval_result E Layout->Margin.y = 0; Layout->WidgetReference = Widget->Id; ui_WidgetClearFlag(Layout, UIWidgetFlag_DrawOutline); + ui_WidgetSetChildrenPopover(Layout); } return State->Value; @@ -1070,6 +1315,7 @@ ui_BeginDropdown(ui_interface* Interface, gs_string Text, rect2 Bounds) ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawBackground); ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawString); ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawOutline); + ui_eval_result Result = ui_EvaluateWidget(Interface, Widget, Bounds); return ui_EvaluateDropdown(Interface, Widget, Result); } @@ -1266,5 +1512,21 @@ ui_EndMousePopup(ui_interface* Interface) ui_PopLayout(Interface); } +// +internal bool +ui_BeginLabeledDropdown(ui_interface* Interface, gs_string Label, gs_string DropdownValue) +{ + ui_BeginRow(Interface, 2); + ui_Label(Interface, Label); + return ui_BeginDropdown(Interface, DropdownValue); +} + +internal void +ui_EndLabeledDropdown(ui_interface* Interface) +{ + ui_EndDropdown(Interface); + ui_EndRow(Interface); +} + #define INTERFACE_H #endif // INTERFACE_H \ No newline at end of file diff --git a/src/app/interface_test.cpp b/src/app/interface_test.cpp new file mode 100644 index 0000000..84f2d41 --- /dev/null +++ b/src/app/interface_test.cpp @@ -0,0 +1,102 @@ +// +// File: interface_test.cpp +// Author: Peter Slattery +// Creation Date: 2020-11-15 +// +#ifndef INTERFACE_TEST_CPP + +global r32 TestSlider_Value = 5; +global r32 TestSlider_Min = 0; +global r32 TestSlider_Max = 10; +global bool TestToggle = true; +global r64 TestTextEntry = 3.1415f; + +internal void +InterfaceTest_Render(app_state* State, context* Context, render_command_buffer* RenderBuffer) +{ + ui_InterfaceReset(&State->Interface); + State->Interface.RenderBuffer = RenderBuffer; + State->Interface.WindowBounds = Context->WindowBounds; + + gs_string A = MakeString("TestRender Layout"); + + ui_PushLayout(&State->Interface, A); + { +#if 1 + TestTextEntry = ui_TextEntryR64(&State->Interface, MakeString("Spacer"), TestTextEntry); + ui_Button(&State->Interface, MakeString("A")); + TestSlider_Value = ui_RangeSlider(&State->Interface, MakeString("TestSlider"), TestSlider_Value, TestSlider_Min, TestSlider_Max); +#elif 0 + ui_PushLayout(&State->Interface, MakeString("Outer")); + { + for (u32 i = 0; i < 3; i++) + { + ui_Button(&State->Interface, MakeString("A")); + } + } + ui_PopLayout(&State->Interface); + + ui_BeginRow(&State->Interface, 2); + { + ui_PushLayout(&State->Interface, MakeString("TestLayout")); + { + for (u32 i = 0; i < 5; i++) + { + ui_Button(&State->Interface, MakeString("TestButon")); + } + } + ui_PopLayout(&State->Interface); + + ui_PushLayout(&State->Interface, MakeString("TestLayout")); + { + ui_Button(&State->Interface, MakeString("TestButon")); + TestToggle = ui_Toggle(&State->Interface, MakeString("Toggle"), TestToggle); + TestSlider_Value = ui_RangeSlider(&State->Interface, MakeString("TestSlider"), TestSlider_Value, TestSlider_Min, TestSlider_Max); + if (ui_BeginDropdown(&State->Interface, MakeString("TestDropdown"))) + { + ui_Button(&State->Interface, MakeString("TestButon")); + ui_Button(&State->Interface, MakeString("TestButon")); + ui_Button(&State->Interface, MakeString("TestButon")); + } + ui_EndDropdown(&State->Interface); + } + ui_PopLayout(&State->Interface); + } + ui_EndRow(&State->Interface); + + ui_PushLayout(&State->Interface, MakeString("Outer")); + { + for (u32 i = 0; i < 3; i++) + { + ui_Button(&State->Interface, MakeString("B")); + } + } + ui_PopLayout(&State->Interface); + +#else + ui_BeginList(&State->Interface, MakeString("Test List"), 10); + { + for (u32 i = 0; i < 32; i++) + { + ui_Button(&State->Interface, MakeString("Option")); + } + } + ui_EndList(&State->Interface); +#endif + + ui_PushOverlayLayout(&State->Interface, rect2{25, 25, 400, 200}, LayoutDirection_TopDown, MakeString("t")); + { + ui_Label(&State->Interface, PushStringF(State->Interface.PerFrameMemory, 256, "Mouse Pos - %f %f", State->Interface.Mouse.Pos.x, State->Interface.Mouse.Pos.y)); + ui_Label(&State->Interface, PushStringF(State->Interface.PerFrameMemory, 256, "Hot - %lld | Active - %lld", + State->Interface.HotWidget.Id, State->Interface.ActiveWidget.Id)); + ui_Label(&State->Interface, PushStringF(State->Interface.PerFrameMemory, 256, "Last Active - %lld", + State->Interface.LastActiveWidget.Id)); + } + ui_PopLayout(&State->Interface); + } + ui_PopLayout(&State->Interface); +} + + +#define INTERFACE_TEST_CPP +#endif // INTERFACE_TEST_CPP \ No newline at end of file diff --git a/src/app/platform_win32/win32_foldhaus.cpp b/src/app/platform_win32/win32_foldhaus.cpp index 6f58fbb..7a11bf0 100644 --- a/src/app/platform_win32/win32_foldhaus.cpp +++ b/src/app/platform_win32/win32_foldhaus.cpp @@ -276,6 +276,7 @@ HandleWindowMessage (MSG Message, window* Window, input_queue* InputQueue, mouse case WM_KEYDOWN: case WM_KEYUP: { +#if 0 int VirtualKey = (int)Message.wParam; key_code Key = Win32GetKeyCode(VirtualKey, true, false); s32 KeyIndex = (int)Key; @@ -287,6 +288,27 @@ HandleWindowMessage (MSG Message, window* Window, input_queue* InputQueue, mouse b32 AltDown = GetKeyState(VK_MENU) & 0x8000; b32 CtrlDown = GetKeyState(VK_CONTROL) & 0x8000; + // New Input Queue + AddInputEventEntry(InputQueue, Key, KeyWasDown, KeyIsDown, + ShiftDown, AltDown, CtrlDown, false); +#endif + TranslateMessage(&Message); + DispatchMessage(&Message); + }break; + + case WM_CHAR: + { + char VirtualKey = (char)Message.wParam; + key_code Key = CharToKeyCode(VirtualKey); + s32 KeyIndex = (int)Key; + + b32 KeyWasDown = (Message.lParam & (1 << 30)) != 0; + b32 KeyIsDown = (Message.lParam & (1 << 31)) == 0; + + b32 ShiftDown = GetKeyState(VK_SHIFT) & 0x8000; + b32 AltDown = GetKeyState(VK_MENU) & 0x8000; + b32 CtrlDown = GetKeyState(VK_CONTROL) & 0x8000; + // New Input Queue AddInputEventEntry(InputQueue, Key, KeyWasDown, KeyIsDown, ShiftDown, AltDown, CtrlDown, false); @@ -370,6 +392,7 @@ Win32_SendAddressedDataBuffers(gs_thread_context Context, addressed_data_buffer_ DEBUG_TRACK_FUNCTION; u32 BuffersSent = 0; + u32 DataSizeSent = 0; for (addressed_data_buffer* BufferAt = OutputData.Root; BufferAt != 0; @@ -397,6 +420,7 @@ Win32_SendAddressedDataBuffers(gs_thread_context Context, addressed_data_buffer_ if (Win32SerialPort_Write(SerialPort, BufferAt->Data)) { BuffersSent += 1; + DataSizeSent += BufferAt->Data.Size; } } } @@ -411,9 +435,9 @@ Win32_SendAddressedDataBuffers(gs_thread_context Context, addressed_data_buffer_ } gs_string OutputStr = AllocatorAllocString(Context.Allocator, 256); - PrintF(&OutputStr, "Buffers Sent: %d\n", BuffersSent); + PrintF(&OutputStr, "Buffers Sent: %d | Size Sent: %d\n", BuffersSent, DataSizeSent); NullTerminate(&OutputStr); - //OutputDebugStringA(OutputStr.Str); + OutputDebugStringA(OutputStr.Str); } internal void diff --git a/src/gs_libs/gs_input.h b/src/gs_libs/gs_input.h index daabf05..2586c03 100644 --- a/src/gs_libs/gs_input.h +++ b/src/gs_libs/gs_input.h @@ -407,5 +407,253 @@ GetMouseButtonStateAdvanced (b32 ButtonState) return Result; } +internal char +KeyCodeToChar(key_code Code) +{ + char Result = 0; + + switch (Code) + { + case KeyCode_Space: { Result = ' '; } break; + case KeyCode_Tab: { Result = '\t'; } break; + case KeyCode_Enter: { Result = '\n'; } break; + case KeyCode_Backspace: { Result = '\b'; } break; + + case KeyCode_a: { Result = 'a'; } break; + case KeyCode_b: { Result = 'b'; } break; + case KeyCode_c: { Result = 'c'; } break; + case KeyCode_d: { Result = 'd'; } break; + case KeyCode_e: { Result = 'e'; } break; + case KeyCode_f: { Result = 'f'; } break; + case KeyCode_g: { Result = 'g'; } break; + case KeyCode_h: { Result = 'h'; } break; + case KeyCode_i: { Result = 'i'; } break; + case KeyCode_j: { Result = 'j'; } break; + case KeyCode_k: { Result = 'k'; } break; + case KeyCode_l: { Result = 'l'; } break; + case KeyCode_m: { Result = 'm'; } break; + case KeyCode_n: { Result = 'n'; } break; + case KeyCode_o: { Result = 'o'; } break; + case KeyCode_p: { Result = 'p'; } break; + case KeyCode_q: { Result = 'q'; } break; + case KeyCode_r: { Result = 'r'; } break; + case KeyCode_s: { Result = 's'; } break; + case KeyCode_t: { Result = 't'; } break; + case KeyCode_u: { Result = 'u'; } break; + case KeyCode_v: { Result = 'v'; } break; + case KeyCode_w: { Result = 'w'; } break; + case KeyCode_x: { Result = 'x'; } break; + case KeyCode_y: { Result = 'y'; } break; + case KeyCode_z: { Result = 'z'; } break; + case KeyCode_A: { Result = 'A'; } break; + case KeyCode_B: { Result = 'B'; } break; + case KeyCode_C: { Result = 'C'; } break; + case KeyCode_D: { Result = 'D'; } break; + case KeyCode_E: { Result = 'E'; } break; + case KeyCode_F: { Result = 'F'; } break; + case KeyCode_G: { Result = 'G'; } break; + case KeyCode_H: { Result = 'H'; } break; + case KeyCode_I: { Result = 'I'; } break; + case KeyCode_J: { Result = 'J'; } break; + case KeyCode_K: { Result = 'K'; } break; + case KeyCode_L: { Result = 'L'; } break; + case KeyCode_M: { Result = 'M'; } break; + case KeyCode_N: { Result = 'N'; } break; + case KeyCode_O: { Result = 'O'; } break; + case KeyCode_P: { Result = 'P'; } break; + case KeyCode_Q: { Result = 'Q'; } break; + case KeyCode_R: { Result = 'R'; } break; + case KeyCode_S: { Result = 'S'; } break; + case KeyCode_T: { Result = 'T'; } break; + case KeyCode_U: { Result = 'U'; } break; + case KeyCode_V: { Result = 'V'; } break; + case KeyCode_W: { Result = 'W'; } break; + case KeyCode_X: { Result = 'X'; } break; + case KeyCode_Y: { Result = 'Y'; } break; + case KeyCode_Z: { Result = 'Z'; } break; + + case KeyCode_Num0: + case KeyCode_0: { Result = '0'; } break; + case KeyCode_Num1: + case KeyCode_1: { Result = '1'; } break; + case KeyCode_Num2: + case KeyCode_2: { Result = '2'; } break; + case KeyCode_Num3: + case KeyCode_3: { Result = '3'; } break; + case KeyCode_Num4: + case KeyCode_4: { Result = '4'; } break; + case KeyCode_Num5: + case KeyCode_5: { Result = '5'; } break; + case KeyCode_Num6: + case KeyCode_6: { Result = '6'; } break; + case KeyCode_Num7: + case KeyCode_7: { Result = '7'; } break; + case KeyCode_Num8: + case KeyCode_8: { Result = '8'; } break; + case KeyCode_Num9: + case KeyCode_9: { Result = '9'; } break; + + case KeyCode_Bang: { Result = '!'; } break; + case KeyCode_At: { Result = '@'; } break; + case KeyCode_Pound: { Result = '#'; } break; + case KeyCode_Dollar: { Result = '$'; } break; + case KeyCode_Percent: { Result = '%'; } break; + case KeyCode_Carrot: { Result = '^'; } break; + case KeyCode_Ampersand: { Result = '&'; } break; + case KeyCode_Star: { Result = '*'; } break; + case KeyCode_LeftParen: { Result = '('; } break; + case KeyCode_RightParen: { Result = ')'; } break; + case KeyCode_Minus: { Result = '-'; } break; + case KeyCode_Plus: { Result = '+'; } break; + case KeyCode_Equals: { Result = '='; } break; + case KeyCode_Underscore: { Result = '_'; } break; + case KeyCode_LeftBrace: { Result = '{'; } break; + case KeyCode_RightBrace: { Result = '}'; } break; + case KeyCode_LeftBracket: { Result = '['; } break; + case KeyCode_RightBracket: { Result = ']'; } break; + case KeyCode_Colon: { Result = ':'; } break; + case KeyCode_SemiColon: { Result = ';'; } break; + case KeyCode_SingleQuote: { Result = '\''; } break; + case KeyCode_DoubleQuote: { Result = '"'; } break; + case KeyCode_ForwardSlash: { Result = '/'; } break; + case KeyCode_Backslash: { Result = '\\'; } break; + case KeyCode_Pipe: { Result = '|'; } break; + case KeyCode_Comma: { Result = ','; } break; + case KeyCode_Period: { Result = '.'; } break; + case KeyCode_QuestionMark: { Result = '?'; } break; + case KeyCode_LessThan: { Result = '<'; } break; + case KeyCode_GreaterThan: { Result = '>'; } break; + case KeyCode_Tilde: { Result = '~'; } break; + case KeyCode_BackQuote: { Result = '`'; } break; + + default: { Result = 0; } break; + } + + return Result; +} + +internal bool +KeyCodeHasChar(key_code Code) +{ + bool Result = KeyCodeToChar(Code) != 0; + return Result; +} + + +internal key_code +CharToKeyCode(char C) +{ + key_code Result = KeyCode_Invalid; + + switch (C) + { + case ' ': { Result = KeyCode_Space; } break; + case '\t': { Result = KeyCode_Tab; } break; + case '\n': { Result = KeyCode_Enter; } break; + case '\b': { Result = KeyCode_Backspace; } break; + + case 'a': { Result = KeyCode_a; } break; + case 'b': { Result = KeyCode_b; } break; + case 'c': { Result = KeyCode_c; } break; + case 'd': { Result = KeyCode_d; } break; + case 'e': { Result = KeyCode_e; } break; + case 'f': { Result = KeyCode_f; } break; + case 'g': { Result = KeyCode_g; } break; + case 'h': { Result = KeyCode_h; } break; + case 'i': { Result = KeyCode_i; } break; + case 'j': { Result = KeyCode_j; } break; + case 'k': { Result = KeyCode_k; } break; + case 'l': { Result = KeyCode_l; } break; + case 'm': { Result = KeyCode_m; } break; + case 'n': { Result = KeyCode_n; } break; + case 'o': { Result = KeyCode_o; } break; + case 'p': { Result = KeyCode_p; } break; + case 'q': { Result = KeyCode_q; } break; + case 'r': { Result = KeyCode_r; } break; + case 's': { Result = KeyCode_s; } break; + case 't': { Result = KeyCode_t; } break; + case 'u': { Result = KeyCode_u; } break; + case 'v': { Result = KeyCode_v; } break; + case 'w': { Result = KeyCode_w; } break; + case 'x': { Result = KeyCode_x; } break; + case 'y': { Result = KeyCode_y; } break; + case 'z': { Result = KeyCode_z; } break; + case 'A': { Result = KeyCode_A; } break; + case 'B': { Result = KeyCode_B; } break; + case 'C': { Result = KeyCode_C; } break; + case 'D': { Result = KeyCode_D; } break; + case 'E': { Result = KeyCode_E; } break; + case 'F': { Result = KeyCode_F; } break; + case 'G': { Result = KeyCode_G; } break; + case 'H': { Result = KeyCode_H; } break; + case 'I': { Result = KeyCode_I; } break; + case 'J': { Result = KeyCode_J; } break; + case 'K': { Result = KeyCode_K; } break; + case 'L': { Result = KeyCode_L; } break; + case 'M': { Result = KeyCode_M; } break; + case 'N': { Result = KeyCode_N; } break; + case 'O': { Result = KeyCode_O; } break; + case 'P': { Result = KeyCode_P; } break; + case 'Q': { Result = KeyCode_Q; } break; + case 'R': { Result = KeyCode_R; } break; + case 'S': { Result = KeyCode_S; } break; + case 'T': { Result = KeyCode_T; } break; + case 'U': { Result = KeyCode_U; } break; + case 'V': { Result = KeyCode_V; } break; + case 'W': { Result = KeyCode_W; } break; + case 'X': { Result = KeyCode_X; } break; + case 'Y': { Result = KeyCode_Y; } break; + case 'Z': { Result = KeyCode_Z; } break; + + case '0': { Result = KeyCode_0; } break; + case '1': { Result = KeyCode_1; } break; + case '2': { Result = KeyCode_2; } break; + case '3': { Result = KeyCode_3; } break; + case '4': { Result = KeyCode_4; } break; + case '5': { Result = KeyCode_5; } break; + case '6': { Result = KeyCode_6; } break; + case '7': { Result = KeyCode_7; } break; + case '8': { Result = KeyCode_8; } break; + case '9': { Result = KeyCode_9; } break; + + case '!': { Result = KeyCode_Bang; } break; + case '@': { Result = KeyCode_At; } break; + case '#': { Result = KeyCode_Pound; } break; + case '$': { Result = KeyCode_Dollar; } break; + case '%': { Result = KeyCode_Percent; } break; + case '^': { Result = KeyCode_Carrot; } break; + case '&': { Result = KeyCode_Ampersand; } break; + case '*': { Result = KeyCode_Star; } break; + case '(': { Result = KeyCode_LeftParen; } break; + case ')': { Result = KeyCode_RightParen; } break; + case '-': { Result = KeyCode_Minus; } break; + case '+': { Result = KeyCode_Plus; } break; + case '=': { Result = KeyCode_Equals; } break; + case '_': { Result = KeyCode_Underscore; } break; + case '{': { Result = KeyCode_LeftBrace; } break; + case '}': { Result = KeyCode_RightBrace; } break; + case '[': { Result = KeyCode_LeftBracket; } break; + case ']': { Result = KeyCode_RightBracket; } break; + case ':': { Result = KeyCode_Colon; } break; + case ';': { Result = KeyCode_SemiColon; } break; + case '\'': { Result = KeyCode_SingleQuote; } break; + case '"': { Result = KeyCode_DoubleQuote; } break; + case '/': { Result = KeyCode_ForwardSlash; } break; + case '\\': { Result = KeyCode_Backslash; } break; + case '|': { Result = KeyCode_Pipe; } break; + case ',': { Result = KeyCode_Comma; } break; + case '.': { Result = KeyCode_Period; } break; + case '?': { Result = KeyCode_QuestionMark; } break; + case '<': { Result = KeyCode_LessThan; } break; + case '>': { Result = KeyCode_GreaterThan; } break; + case '~': { Result = KeyCode_Tilde; } break; + case '`': { Result = KeyCode_BackQuote; } break; + + default: { Result = KeyCode_Invalid; } break; + } + + return Result; +} + #define GS_INPUT_H #endif // GS_INPUT_H \ No newline at end of file diff --git a/src/gs_libs/gs_types.cpp b/src/gs_libs/gs_types.cpp index 28d57b0..8bd4dc0 100644 --- a/src/gs_libs/gs_types.cpp +++ b/src/gs_libs/gs_types.cpp @@ -1592,6 +1592,21 @@ FindLastFromSet(gs_const_string String, char* SetArray) return Result; } +internal bool +StringContains(gs_const_string Str, char C) +{ + bool Result = false; + for (u32 i = 0; i < Str.Length; i++) + { + if (Str.Str[i] == C) + { + Result = true; + break; + } + } + return Result; +} + internal bool StringsEqualUpToLength(gs_const_string A, gs_const_string B, u64 Length) { @@ -1695,30 +1710,66 @@ CharToUInt(char C, u64 Base) return CharToUInt(C, GetCharSetForBase(Base)); } -internal u64 -ParseUInt(gs_const_string String, u64 Base = 10, u64* ParsedLength = 0) +struct parse_uint_result { - u64 Result = 0; + b8 Success; + u64 Value; + u32 ParsedLength; +}; + +internal parse_uint_result +ValidateAndParseUInt(gs_const_string String, u64 Base = 10) +{ + parse_uint_result Result = {0}; + gs_const_string CharSet = GetCharSetForBase(Base); - u64 i = 0; - for (; i < String.Length; i++) + + bool StringIsValid = true; + for (u32 i = 0; i < String.Length; i++) { - u64 CharIndex = FindFirst(CharSet, String.Str[i]); - if (CharIndex < CharSet.Length) - { - Result = CharToUInt(String.Str[i], CharSet) + (Result * Base); - } - else + if (!StringContains(CharSet, String.Str[i])) { + StringIsValid = false; break; } } - if (ParsedLength != 0) + + if (StringIsValid) { - *ParsedLength = i; + u64 Acc = 0; + u64 i = 0; + for (; i < String.Length; i++) + { + u64 CharIndex = FindFirst(CharSet, String.Str[i]); + if (CharIndex < CharSet.Length) + { + Acc = CharToUInt(String.Str[i], CharSet) + (Acc * Base); + } + else + { + break; + } + } + + Result.Success = true; + Result.Value = Acc; + Result.ParsedLength = i; } + return Result; } + +internal u64 +ParseUInt(gs_const_string String, u64 Base = 10, u64* ParsedLength = 0) +{ + parse_uint_result ParseResult = ValidateAndParseUInt(String, Base); + Assert(ParseResult.Success); + if (ParsedLength) + { + *ParsedLength = ParseResult.ParsedLength; + } + return ParseResult.Value; +} internal u64 ParseUInt(u64 Length, char* String, u64 Base = 10, u64* ParsedLength = 0) { @@ -1756,39 +1807,75 @@ ParseInt(char* String, u64 Base = 10, u64* ParsedLength = 0) return ParseInt(LitString(String), Base, ParsedLength); } +struct parse_float_result +{ + b8 Success; + r64 Value; + u64 ParsedLength; +}; + +internal parse_float_result +ValidateAndParseFloat(gs_const_string String) +{ + parse_float_result Result = {0}; + Result.Success = false; + + // Validate + bool StringIsValid = true; + for (u64 i = 0; i < String.Length; i++) + { + if (!IsNumericDecimal(String.Str[i]) && String.Str[i] != '-') + { + StringIsValid = false; + break; + } + } + + if (StringIsValid) + { + u64 DecimalIndex = FindFirst(String, '.'); + u64 TempParsedLength = 0; + u64 PlacesAfterPoint = 0; + + gs_const_string IntegerString = GetStringBefore(String, DecimalIndex); + gs_const_string DecimalString = GetStringAfter(String, DecimalIndex + 1); + + r32 Polarity = 1; + if (IntegerString.Str[0] == '-') + { + IntegerString = GetStringAfter(IntegerString, 1); + Polarity = -1; + } + + Result.Value = (r64)ParseInt(IntegerString, 10, &TempParsedLength); + + if (TempParsedLength == IntegerString.Length) + { + r64 AfterPoint = (r64)ParseUInt(DecimalString, 10, &PlacesAfterPoint); + r64 Decimal = (AfterPoint / PowR64(10, PlacesAfterPoint)); + Result.Value = Result.Value + Decimal; + Result.Value *= Polarity; + } + + Result.ParsedLength = TempParsedLength + PlacesAfterPoint; + if (DecimalIndex < String.Length) { Result.ParsedLength += 1; } + + Result.Success = true; + } + + return Result; +} + internal r64 ParseFloat(gs_const_string String, u64* ParsedLength = 0) { - - u64 DecimalIndex = FindFirst(String, '.'); - u64 TempParsedLength = 0; - u64 PlacesAfterPoint = 0; - - gs_const_string IntegerString = GetStringBefore(String, DecimalIndex); - gs_const_string DecimalString = GetStringAfter(String, DecimalIndex + 1); - - r32 Polarity = 1; - if (IntegerString.Str[0] == '-') - { - IntegerString = GetStringAfter(IntegerString, 1); - Polarity = -1; - } - r64 Result = (r64)ParseInt(IntegerString, 10, &TempParsedLength); - - if (TempParsedLength == IntegerString.Length) - { - r64 AfterPoint = (r64)ParseUInt(DecimalString, 10, &PlacesAfterPoint); - r64 Decimal = (AfterPoint / PowR64(10, PlacesAfterPoint)); - Result = Result + Decimal; - Result *= Polarity; - } - + parse_float_result Result = ValidateAndParseFloat(String); + Assert(Result.Success); if (ParsedLength != 0) { - *ParsedLength = TempParsedLength + PlacesAfterPoint; - if (DecimalIndex < String.Length) { *ParsedLength += 1; } + *ParsedLength = Result.ParsedLength; } - return Result; + return Result.Value; } internal r64 ParseFloat(char* String, u64* ParsedLength = 0) @@ -2010,11 +2097,16 @@ PrintFArgsList (gs_string* String, char* Format, va_list Args) FormatAt++; if (IsBase10(FormatAt[0])) { - PrecisionSpecified = true; + + gs_const_string PrecisionStr = {}; + PrecisionStr.Str = FormatAt; + for (char* C = FormatAt; *FormatAt && IsBase10(*C); C++) + { + PrecisionStr.Length++; + } u64 Parsed = 0; - AssertMessage("ParseInt assumes whole string is an integer"); - Precision = (s32)ParseInt(FormatAt, 10, &Parsed); + Precision = (s32)ParseInt(PrecisionStr, 10, &Parsed); FormatAt += Parsed; } else if (FormatAt[0] == '*') diff --git a/src/sculpture_gen/gen_blumen_lumen.cpp b/src/sculpture_gen/gen_blumen_lumen.cpp new file mode 100644 index 0000000..b269cb2 --- /dev/null +++ b/src/sculpture_gen/gen_blumen_lumen.cpp @@ -0,0 +1,217 @@ +// +// File: gen_blumen_lumen.cpp +// Author: Peter Slattery +// Creation Date: 2021-01-06 +// +#ifndef GEN_BLUMEN_LUMEN_CPP + +#include +#include + +#include "../gs_libs/gs_types.h" +#include "../gs_libs/gs_types.cpp" +#include "../app/platform_win32/win32_foldhaus_utils.h" +#include "../app/platform_win32/win32_foldhaus_memory.h" +#include "../app/platform_win32/win32_foldhaus_fileio.h" +#include "../app/platform_win32/win32_foldhaus_work_queue.h" + +#include "sculpture_gen.h" + +typedef struct +{ + v3 CenterStart; + v3 CenterEnd; + r32 Radius; + u32 SegmentsCount; + u32 SubsegmentsCount; + u32 SubsegmentLeds; + + // Only one of these two values is needed. + // If ChannelsArray != 0, then it will be used, and assumed to + // have SegmentsCount values + // Otherwise, each segment will increment from ChannelStart + u32 ChannelStart; + u32* ChannelsArray; + + char* ComPort; + char* SectionTagValue; + char* FlowerTagValue; +} loop_desc; + +internal void +BuildLoop(gs_string* OutputBuffer, loop_desc Desc) +{ + r32 SegmentsArc = TauR32 / Desc.SegmentsCount; + r32 SubsegmentsArc = SegmentsArc / Desc.SubsegmentsCount; + + for (u32 i = 0; i < Desc.SegmentsCount; i++) + { + r32 ArcBase = SegmentsArc * i; + + u32 Channel = 0; + if (Desc.ChannelsArray != 0) + { + Channel = Desc.ChannelsArray[i]; + } + else + { + Channel = Desc.ChannelStart + i; + } + + WriteLedStripOpen(OutputBuffer, Channel, Desc.ComPort); + WriteSegmentSequenceOpen(OutputBuffer, Desc.SubsegmentsCount); + + for (u32 j = 0; j < Desc.SubsegmentsCount; j++) + { + r32 Arc = ArcBase + (SubsegmentsArc * j); + v3 Offset = v3{ SinR32(Arc), 0, CosR32(Arc) } * Desc.Radius; + v3 P0 = Desc.CenterStart + Offset; + v3 P1 = Desc.CenterEnd + Offset; + + // Swap directions on the middle strip + if (j%2 != 0) + { + v3 Temp = P0; + P0 = P1; + P1 = Temp; + } + + WriteSegmentSequenceSegment(OutputBuffer, P0, P1, Desc.SubsegmentLeds); + } + + WriteSegmentSequenceClose(OutputBuffer); + WriteSegmentTagsOpen(OutputBuffer, 2); + WriteSegmentTag(OutputBuffer, "section", Desc.SectionTagValue); + WriteSegmentTag(OutputBuffer, "flower", Desc.FlowerTagValue); + WriteSegmentTagsClose(OutputBuffer); + WriteLedStripClose(OutputBuffer); + } + +} + +typedef struct +{ + v3 Pos; + char* ComPort; + char* FlowerTagValue; + u32* StemChannels; + u32* BloomOuterChannels; + u32* BloomInnerChannels; +} flower_desc; + +internal void +BuildFlower(gs_string* OutputBuffer, flower_desc Desc) +{ + // the flower stem + loop_desc FlowerStem = {}; + FlowerStem.CenterStart = v3{0, -1.5f, 0} + Desc.Pos; + FlowerStem.CenterEnd = v3{0, .5f, 0} + Desc.Pos; + FlowerStem.Radius = .05f; + FlowerStem.SegmentsCount = 6; + FlowerStem.SubsegmentsCount = 1; + FlowerStem.SubsegmentLeds = 300; + //FlowerStem.ChannelStart = 0; + FlowerStem.ChannelsArray = Desc.StemChannels; + FlowerStem.ComPort = Desc.ComPort; + FlowerStem.SectionTagValue = "stem"; + FlowerStem.FlowerTagValue = Desc.FlowerTagValue; + BuildLoop(OutputBuffer, FlowerStem); + + // the bloom stem outer + loop_desc BloomStemOuter = {}; + BloomStemOuter.CenterStart = v3{0, .5f, 0} + Desc.Pos; + BloomStemOuter.CenterEnd = v3{0, .9f, 0} + Desc.Pos; + BloomStemOuter.Radius = .07f; + BloomStemOuter.SegmentsCount = 9; + BloomStemOuter.SubsegmentsCount = 3; + BloomStemOuter.SubsegmentLeds = 41; + //BloomStemOuter.ChannelStart = 7; + BloomStemOuter.ChannelsArray = Desc.BloomOuterChannels; + BloomStemOuter.ComPort = Desc.ComPort; + BloomStemOuter.SectionTagValue = "outer_bloom"; + BloomStemOuter.FlowerTagValue = Desc.FlowerTagValue; + BuildLoop(OutputBuffer, BloomStemOuter); + + // the bloom stem inner + loop_desc BloomStemInner = {}; + BloomStemInner.CenterStart = v3{0, 1.4f, 0} + Desc.Pos; + BloomStemInner.CenterEnd = v3{0, .9f, 0} + Desc.Pos; + BloomStemInner.Radius = .05f; + BloomStemInner.SegmentsCount = 6; + BloomStemInner.SubsegmentsCount = 3; + BloomStemInner.SubsegmentLeds = 35; + //BloomStemInner.ChannelStart = 17; + BloomStemInner.ChannelsArray = Desc.BloomInnerChannels; + BloomStemInner.ComPort = Desc.ComPort; + BloomStemInner.SectionTagValue = "inner_bloom"; + BloomStemInner.FlowerTagValue = Desc.FlowerTagValue; + BuildLoop(OutputBuffer, BloomStemInner); +} + +// Just for brevity, no real function provided +#define FSC(f,c) FlowerStripToChannel((f), (c)) +internal u8 +FlowerStripToChannel(u8 Flower, u8 Channel) +{ + Assert(Flower < 3); + Assert(Channel < 8); + + u8 Result = 0; + Result |= (Flower & 0x03) << 3; + Result |= (Channel & 0x07); + + return Result; +} + +int main(int ArgCount, char** Args) +{ + gs_thread_context Ctx = Win32CreateThreadContext(); + + gs_string OutputBuffer = PushString(Ctx.Transient, MB(4)); + + char* ComPort = "\\\\.\\COM8"; + WriteAssemblyUARTOpen(&OutputBuffer, + "Blumen Lumen - Silver Spring", + 100, + v3{0, 0, 0}, + 69, + ComPort); + + u32 StemChannels[] = { FSC(2, 1), FSC(2, 2), FSC(2, 3), FSC(2, 4), FSC(2, 5), FSC(2, 6) }; + u32 BloomOuterChannels[] = { FSC(1, 0), FSC(1, 1), FSC(1, 2), FSC(1, 3), FSC(1, 4), FSC(1, 5), FSC(1, 6), FSC(1, 7), FSC(2, 0) }; + u32 BloomInnerChannels[] = { FSC(0, 0), FSC(0, 1), FSC(0, 2), FSC(0, 3), FSC(0, 4), FSC(0, 5) }; + flower_desc F0 = {}; + F0.Pos = v3{-1, 0, 0}; + F0.ComPort = ComPort; + F0.FlowerTagValue = "left"; + F0.StemChannels = StemChannels; + F0.BloomOuterChannels = BloomOuterChannels; + F0.BloomInnerChannels = BloomInnerChannels; + BuildFlower(&OutputBuffer, F0); + + /* + flower_desc F1 = {}; + F1.Pos = v3{0, 0, 0}; + F1.FlowerTagValue = "center"; + F1.StemChannels = StemChannels; + F1.BloomInnerChannels = BloomInnerChannels; + F1.BloomOuterChannels = BloomOuterChannels; + BuildFlower(&OutputBuffer, F1); + + flower_desc F2 = {}; + F2.Pos = v3{1, 0, 0}; + F2.FlowerTagValue = "right"; + F2.StemChannels = StemChannels; + F2.BloomInnerChannels = BloomInnerChannels; + F2.BloomOuterChannels = BloomOuterChannels; + BuildFlower(&OutputBuffer, F2); + */ + + printf("%.*s\n", (u32)OutputBuffer.Length, OutputBuffer.Str); + + return 0; +} + + +#define GEN_BLUMEN_LUMEN_CPP +#endif // GEN_BLUMEN_LUMEN_CPP \ No newline at end of file diff --git a/src/sculpture_gen/sculpture_gen.h b/src/sculpture_gen/sculpture_gen.h new file mode 100644 index 0000000..2b2a702 --- /dev/null +++ b/src/sculpture_gen/sculpture_gen.h @@ -0,0 +1,102 @@ +// +// File: sculpture_gen.h +// Author: Peter Slattery +// Creation Date: 2021-01-06 +// +#ifndef SCULPTURE_GEN_H + +internal void +WriteIndented(gs_string* Buffer, u32 Indent, char* Format, ...) +{ + va_list Args; + va_start(Args, Format); + + for (u32 i = 0; i < Indent; i++) + { + OutChar(Buffer, '\t'); + } + + PrintFArgsList(Buffer, Format, Args); + va_end(Args); +} + +internal void +WriteAssemblyUARTOpen(gs_string* Buffer, char* Name, u32 Scale, v3 Center, u32 StripCount, char* ComPort) +{ + WriteIndented(Buffer, 0, "assembly_name: \"%s\";\n", Name); + WriteIndented(Buffer, 0, "assembly_scale: %d;\n", Scale); + WriteIndented(Buffer, 0, "assembly_center: (%f, %f, %f);\n", Center.x, Center.y, Center.z); + WriteIndented(Buffer, 0, "led_strip_count: %d;\n", StripCount); + WriteIndented(Buffer, 0, "output_mode: \"UART\";\n"); + WriteIndented(Buffer, 0, "com_port: \"%s\";\n", ComPort); +} + +internal void +WriteLedStripOpen(gs_string* Buffer, u32 Channel, char* ComPort) +{ + WriteIndented(Buffer, 0, "led_strip:\n{\n"); + WriteIndented(Buffer, 1, "output_uart: {\n"); + WriteIndented(Buffer, 2, "channel: %d;\n", Channel); + WriteIndented(Buffer, 2, "com_port: \"%s\";\n", ComPort); + WriteIndented(Buffer, 1, "};\n\n"); +} + +internal void +WriteSegmentSequenceOpen(gs_string* Buffer, u32 SegmentCount) +{ + WriteIndented(Buffer, 1, "segment: {\n"); + WriteIndented(Buffer, 2, "point_placement_type: \"SegmentSequence\";\n"); + WriteIndented(Buffer, 2, "segment_sequence:\n"); + WriteIndented(Buffer, 2, "{\n"); + WriteIndented(Buffer, 3, "segment_count: %d;\n", SegmentCount); +} + +internal void +WriteSegmentSequenceSegment(gs_string* Buffer, v3 P0, v3 P1, u32 LedCount) +{ + WriteIndented(Buffer, 3, "segment: {\n"); + WriteIndented(Buffer, 4, "point_placement_type: \"InterpolatePoints\";\n"); + WriteIndented(Buffer, 4, "interpolate_points: {\n"); + WriteIndented(Buffer, 5, "start: (%f, %f, %f);\n", P0.x, P0.y, P0.z); + WriteIndented(Buffer, 5, "end: (%f, %f, %f);\n", P1.x, P1.y, P1.z); + WriteIndented(Buffer, 5, "led_count: %d;\n", LedCount); + WriteIndented(Buffer, 4, "};\n"); + WriteIndented(Buffer, 3, "};\n"); +} + +internal void +WriteSegmentSequenceClose(gs_string* Buffer) +{ + WriteIndented(Buffer, 2, "};\n"); + WriteIndented(Buffer, 1, "};\n"); +} + +internal void +WriteSegmentTagsOpen(gs_string* Buffer, u32 TagCount) +{ + WriteIndented(Buffer, 1, "tags_count: %d;\n", TagCount); +} + +internal void +WriteSegmentTag(gs_string* Buffer, char* TagName, char* TagValue) +{ + WriteIndented(Buffer, 1, "tag: {\n"); + WriteIndented(Buffer, 2, "name: \"%s\";\n", TagName); + WriteIndented(Buffer, 2, "value: \"%s\";\n", TagValue); + WriteIndented(Buffer, 1, "};\n"); + +} + +internal void +WriteSegmentTagsClose(gs_string* Buffer) +{ +} + +internal void +WriteLedStripClose(gs_string* Buffer) +{ + WriteIndented(Buffer, 0, "};\n"); +} + +#define SCULPTURE_GEN_H +#endif // SCULPTURE_GEN_H \ No newline at end of file From 914523cb60af9cda9e496eae7766f256904801f0 Mon Sep 17 00:00:00 2001 From: PS Date: Mon, 11 Jan 2021 00:02:42 -0800 Subject: [PATCH 17/44] Cleaned up system start up, update, and cleanup --- src/app/editor/foldhaus_editor.cpp | 2 +- src/app/editor/foldhaus_interface.cpp | 8 +- .../panels/foldhaus_panel_sculpture_view.h | 10 +- .../animation/foldhaus_animation_renderer.cpp | 2 + src/app/engine/assembly/foldhaus_assembly.cpp | 2 +- src/app/engine/foldhaus_addressed_data.h | 9 + src/app/foldhaus_app.cpp | 136 +++------- src/app/foldhaus_app.h | 2 - src/app/foldhaus_renderer.cpp | 8 + src/app/interface.h | 21 ++ src/app/platform_win32/win32_foldhaus.cpp | 248 +++--------------- src/app/platform_win32/win32_foldhaus_mouse.h | 118 +++++++++ .../platform_win32/win32_foldhaus_socket.h | 39 ++- .../win32_foldhaus_work_queue.h | 47 ++++ src/app/platform_win32/win32_test_code.cpp | 53 ++++ src/gs_libs/gs_font.h | 70 +++-- src/gs_libs/gs_input.h | 22 +- src/gs_libs/gs_types.h | 1 - 18 files changed, 446 insertions(+), 352 deletions(-) create mode 100644 src/app/platform_win32/win32_foldhaus_mouse.h create mode 100644 src/app/platform_win32/win32_test_code.cpp diff --git a/src/app/editor/foldhaus_editor.cpp b/src/app/editor/foldhaus_editor.cpp index 38f7590..f00000d 100644 --- a/src/app/editor/foldhaus_editor.cpp +++ b/src/app/editor/foldhaus_editor.cpp @@ -358,7 +358,7 @@ Editor_Render(app_state* State, context* Context, render_command_buffer* RenderB } Context->GeneralWorkQueue->CompleteQueueWork(Context->GeneralWorkQueue, Context->ThreadContext); - Context->GeneralWorkQueue->ResetWorkQueue(Context->GeneralWorkQueue); + ResetWorkQueue(Context->GeneralWorkQueue); } diff --git a/src/app/editor/foldhaus_interface.cpp b/src/app/editor/foldhaus_interface.cpp index e86b30b..f29babb 100644 --- a/src/app/editor/foldhaus_interface.cpp +++ b/src/app/editor/foldhaus_interface.cpp @@ -353,28 +353,28 @@ DrawPanelBorder(panel Panel, v2 PanelMin, v2 PanelMax, v4 Color, mouse_state* Mo v2 LeftEdgeMin = PanelMin; v2 LeftEdgeMax = v2{PanelMin.x + HighlightThickness, PanelMax.y}; PushRenderQuad2D(RenderBuffer, LeftEdgeMin, LeftEdgeMax, HighlightColor); - Mouse->CursorType = CursorType_HorizontalArrows; + Mouse->CursorType = CursorType_HArrows; } else if (MouseRightEdgeDistance < PANEL_EDGE_CLICK_MAX_DISTANCE) { v2 RightEdgeMin = v2{PanelMax.x - HighlightThickness, PanelMin.y}; v2 RightEdgeMax = PanelMax; PushRenderQuad2D(RenderBuffer, RightEdgeMin, RightEdgeMax, HighlightColor); - Mouse->CursorType = CursorType_HorizontalArrows; + Mouse->CursorType = CursorType_HArrows; } else if (MouseTopEdgeDistance < PANEL_EDGE_CLICK_MAX_DISTANCE) { v2 TopEdgeMin = v2{PanelMin.x, PanelMax.y - HighlightThickness}; v2 TopEdgeMax = PanelMax; PushRenderQuad2D(RenderBuffer, TopEdgeMin, TopEdgeMax, HighlightColor); - Mouse->CursorType = CursorType_VerticalArrows; + Mouse->CursorType = CursorType_VArrows; } else if (MouseBottomEdgeDistance < PANEL_EDGE_CLICK_MAX_DISTANCE) { v2 BottomEdgeMin = PanelMin; v2 BottomEdgeMax = v2{PanelMax.x, PanelMin.y + HighlightThickness}; PushRenderQuad2D(RenderBuffer, BottomEdgeMin, BottomEdgeMax, HighlightColor); - Mouse->CursorType = CursorType_VerticalArrows; + Mouse->CursorType = CursorType_VArrows; } } diff --git a/src/app/editor/panels/foldhaus_panel_sculpture_view.h b/src/app/editor/panels/foldhaus_panel_sculpture_view.h index ba4d7c6..6d4c803 100644 --- a/src/app/editor/panels/foldhaus_panel_sculpture_view.h +++ b/src/app/editor/panels/foldhaus_panel_sculpture_view.h @@ -5,6 +5,12 @@ // #ifndef FOLDHAUS_PANEL_SCULPTURE_VIEW_H +// Definitions + +#define PIXEL_TO_WORLD_SCALE 0.01f + +// + struct sculpture_view_panel_state { camera Camera; @@ -24,8 +30,8 @@ OPERATION_RENDER_PROC(Update3DViewMouseRotate) v2 TotalDeltaPos = Mouse.Pos - Mouse.DownPos; - m44 XRotation = M44RotationX(-TotalDeltaPos.y * State->PixelsToWorldScale); - m44 YRotation = M44RotationY(TotalDeltaPos.x * State->PixelsToWorldScale); + m44 XRotation = M44RotationX(-TotalDeltaPos.y * PIXEL_TO_WORLD_SCALE); + m44 YRotation = M44RotationY(TotalDeltaPos.x * PIXEL_TO_WORLD_SCALE); m44 Combined = XRotation * YRotation; OpState->Camera->Position = (Combined * OpState->CameraStartPos).xyz; diff --git a/src/app/engine/animation/foldhaus_animation_renderer.cpp b/src/app/engine/animation/foldhaus_animation_renderer.cpp index 2bf58d0..44075be 100644 --- a/src/app/engine/animation/foldhaus_animation_renderer.cpp +++ b/src/app/engine/animation/foldhaus_animation_renderer.cpp @@ -192,6 +192,8 @@ AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Asse } } } + + System->LastUpdatedFrame = System->CurrentFrame; } #define FOLDHAUS_ANIMATION_RENDERER_CPP diff --git a/src/app/engine/assembly/foldhaus_assembly.cpp b/src/app/engine/assembly/foldhaus_assembly.cpp index 8c88276..e2fd231 100644 --- a/src/app/engine/assembly/foldhaus_assembly.cpp +++ b/src/app/engine/assembly/foldhaus_assembly.cpp @@ -72,7 +72,7 @@ AssemblyArray_Filter(assembly_array Array, assembly_array_filter_proc* Filter, g /////////////////////////// internal led_system -LedSystemInitialize(gs_allocator PlatformMemory, u32 BuffersMax) +LedSystem_Create(gs_allocator PlatformMemory, u32 BuffersMax) { led_system Result = {}; Result.PlatformMemory = PlatformMemory; diff --git a/src/app/engine/foldhaus_addressed_data.h b/src/app/engine/foldhaus_addressed_data.h index 47b70d7..c27bd59 100644 --- a/src/app/engine/foldhaus_addressed_data.h +++ b/src/app/engine/foldhaus_addressed_data.h @@ -95,5 +95,14 @@ AddressedDataBuffer_SetCOMPort(addressed_data_buffer* Buffer, gs_const_string Co Buffer->ComPort = ComPort; } +internal addressed_data_buffer_list +AddressedDataBufferList_Create(gs_thread_context TC) +{ + addressed_data_buffer_list Result = {}; + Result.Arena = AllocatorAllocStruct(TC.Allocator, gs_memory_arena); + *Result.Arena = CreateMemoryArena(TC.Allocator); + return Result; +} + #define FOLDHAUS_ADDRESSED_DATA_H #endif // FOLDHAUS_ADDRESSED_DATA_H \ No newline at end of file diff --git a/src/app/foldhaus_app.cpp b/src/app/foldhaus_app.cpp index ba190b9..09b526c 100644 --- a/src/app/foldhaus_app.cpp +++ b/src/app/foldhaus_app.cpp @@ -45,114 +45,49 @@ INITIALIZE_APPLICATION(InitializeApplication) State->Permanent = CreateMemoryArena(Context.ThreadContext.Allocator); State->Transient = Context.ThreadContext.Transient; - State->Assemblies = AssemblyArray_Create(8, &State->Permanent); - State->GlobalLog = PushStruct(State->Transient, event_log); - *State->GlobalLog = {0}; + State->GlobalLog = PushStruct(&State->Permanent, event_log); State->CommandQueue = CommandQueue_Create(&State->Permanent, 32); State->Patterns = Patterns_Create(&State->Permanent, 10); ClearAndPushPatterns(&State->Patterns); - // TODO(Peter): put in InitializeInterface? - r32 FontSize = 14; - { - gs_file FontFile = ReadEntireFile(Context.ThreadContext.FileHandler, ConstString("data/Anonymous Pro.ttf")); - if (FileNoError(FontFile)) - { - bitmap_font* Font = PushStruct(&State->Permanent, bitmap_font); - - Font->BitmapWidth = 512; - Font->BitmapHeight = 512; - Font->BitmapBytesPerPixel = 4; - Font->BitmapMemory = PushArray(&State->Permanent, u8, Font->BitmapWidth * Font->BitmapHeight * Font->BitmapBytesPerPixel); - Font->BitmapStride = Font->BitmapWidth * Font->BitmapBytesPerPixel; - ZeroMemoryBlock(Font->BitmapMemory, Font->BitmapStride * Font->BitmapHeight); - - platform_font_info FontInfo = Context.PlatformGetFontInfo("Anonymous Pro", FontSize, FontWeight_Normal, false, false, false); - Font->PixelHeight = FontInfo.PixelHeight; - Font->Ascent = FontInfo.Ascent; - Font->Descent = FontInfo.Descent; - Font->Leading = FontInfo.Leading; - Font->MaxCharWidth = FontInfo.MaxCharWidth; - - Font->CodepointDictionarySize = (FontInfo.CodepointOnePastLast - FontInfo.CodepointStart); - Font->CodepointDictionaryCount = 0; - Font->CodepointKeys = PushArray(&State->Permanent, char, Font->CodepointDictionarySize); - Font->CodepointValues = PushArray(&State->Permanent, codepoint_bitmap, Font->CodepointDictionarySize); - - for (s32 Codepoint = FontInfo.CodepointStart; - Codepoint < FontInfo.CodepointOnePastLast; - Codepoint++) - { - - u32 CodepointX, CodepointY; - GetNextCodepointOffset(Font, &CodepointX, &CodepointY); - - u32 CodepointW, CodepointH; - Context.PlatformDrawFontCodepoint( - Font->BitmapMemory, - Font->BitmapWidth, - Font->BitmapHeight, - CodepointX, CodepointY, - Codepoint, FontInfo, - &CodepointW, &CodepointH); - - AddCodepointToFont(Font, Codepoint, 0, 0, CodepointW, CodepointH, CodepointX, CodepointY); - } - - State->Interface.Style.Font = Font; - - Font->BitmapTextureHandle = Context.PlatformGetGPUTextureHandle(Font->BitmapMemory, - Font->BitmapWidth, Font->BitmapHeight); - } - else - { - LogError(State->GlobalLog, "Unable to load font"); - } - } - - State->Interface.Style.FontSize = FontSize; - State->Interface.Style.PanelBGColors[0] = v4{.3f, .3f, .3f, 1}; - State->Interface.Style.PanelBGColors[1] = v4{.4f, .4f, .4f, 1}; - State->Interface.Style.PanelBGColors[2] = v4{.5f, .5f, .5f, 1}; - 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{.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 }; - State->Interface.Style.ListBGHover = v4{ .22f, .22f, .22f, 1.f }; - State->Interface.Style.ListBGSelected = v4{.44f, .44f, .44f, 1.f }; - State->Interface.Style.Margin = v2{5, 5}; - State->Interface.Style.RowHeight = ui_GetTextLineHeight(State->Interface) + (2 * State->Interface.Style.Margin.y); - - State->Interface.WidgetsCountMax = 4096; - State->Interface.Widgets = PushArray(&State->Permanent, ui_widget, State->Interface.WidgetsCountMax); - State->Interface.PerFrameMemory = PushStruct(&State->Permanent, gs_memory_arena); - *State->Interface.PerFrameMemory = CreateMemoryArena(Context.ThreadContext.Allocator); - State->Interface.Permanent = &State->Permanent; + interface_config IConfig = {0}; + IConfig.FontSize = 14; + IConfig.PanelBGColors[0] = v4{.3f, .3f, .3f, 1}; + IConfig.PanelBGColors[1] = v4{.4f, .4f, .4f, 1}; + IConfig.PanelBGColors[2] = v4{.5f, .5f, .5f, 1}; + IConfig.PanelBGColors[3] = v4{.6f, .6f, .6f, 1}; + IConfig.ButtonColor_Inactive = BlackV4; + IConfig.ButtonColor_Active = v4{.1f, .1f, .1f, 1}; + IConfig.ButtonColor_Selected = v4{.3f, .3f, .3f, 1}; + IConfig.TextColor = WhiteV4; + IConfig.ListBGColors[0] = v4{ .16f, .16f, .16f, 1.f }; + IConfig.ListBGColors[1] = v4{ .18f, .18f, .18f, 1.f }; + IConfig.ListBGHover = v4{ .22f, .22f, .22f, 1.f }; + IConfig.ListBGSelected = v4{.44f, .44f, .44f, 1.f }; + IConfig.Margin = v2{5, 5}; + State->Interface = ui_InterfaceCreate(Context, IConfig, &State->Permanent); State->SACN = SACN_Initialize(Context); - State->LedSystem = LedSystemInitialize(Context.ThreadContext.Allocator, 128); + State->LedSystem = LedSystem_Create(Context.ThreadContext.Allocator, 128); + + GlobalDebugServices->Interface.RenderSculpture = true; + + PanelSystem_Init(&State->PanelSystem, GlobalPanelDefs, GlobalPanelDefsCount, &State->Permanent); + PanelSystem_PushPanel(&State->PanelSystem, PanelType_SculptureView, State, Context); + State->Modes = OperationModeSystemInit(&State->Permanent, Context.ThreadContext); + + ReloadStaticData(Context, GlobalDebugServices); #if 1 gs_const_string SculpturePath = ConstString("data/test_blumen.fold"); LoadAssembly(&State->Assemblies, &State->LedSystem, State->Transient, Context, SculpturePath, State->GlobalLog); #endif - State->PixelsToWorldScale = .01f; - - GlobalDebugServices->Interface.RenderSculpture = true; - - ReloadStaticData(Context, GlobalDebugServices); - - State->Modes = OperationModeSystemInit(&State->Permanent, Context.ThreadContext); - { // Animation PLAYGROUND State->AnimationSystem = {}; State->AnimationSystem.Storage = &State->Permanent; @@ -176,9 +111,6 @@ INITIALIZE_APPLICATION(InitializeApplication) State->AnimationSystem.TimelineShouldAdvance = true; } // End Animation Playground - - PanelSystem_Init(&State->PanelSystem, GlobalPanelDefs, GlobalPanelDefsCount, &State->Permanent); - PanelSystem_PushPanel(&State->PanelSystem, PanelType_SculptureView, State, Context); } UPDATE_AND_RENDER(UpdateAndRender) @@ -197,7 +129,6 @@ UPDATE_AND_RENDER(UpdateAndRender) AnimationSystem_Update(&State->AnimationSystem); if (AnimationSystem_NeedsRender(State->AnimationSystem)) { - State->AnimationSystem.LastUpdatedFrame = State->AnimationSystem.CurrentFrame; AnimationSystem_RenderToLedBuffers(&State->AnimationSystem, State->Assemblies, &State->LedSystem, @@ -205,14 +136,13 @@ UPDATE_AND_RENDER(UpdateAndRender) State->Transient); } - { - // NOTE(pjs): Building data buffers to be sent out to the sculpture - // This array is used on the platform side to actually send the information - assembly_array SACNAssemblies = AssemblyArray_Filter(State->Assemblies, AssemblyFilter_OutputsViaSACN, State->Transient); - assembly_array UARTAssemblies = AssemblyArray_Filter(State->Assemblies, AssemblyFilter_OutputsViaUART, State->Transient); - SACN_BuildOutputData(&State->SACN, OutputData, SACNAssemblies, &State->LedSystem); - UART_BuildOutputData(OutputData, UARTAssemblies, &State->LedSystem); - } + + // NOTE(pjs): Building data buffers to be sent out to the sculpture + // This array is used on the platform side to actually send the information + assembly_array SACNAssemblies = AssemblyArray_Filter(State->Assemblies, AssemblyFilter_OutputsViaSACN, State->Transient); + assembly_array UARTAssemblies = AssemblyArray_Filter(State->Assemblies, AssemblyFilter_OutputsViaUART, State->Transient); + SACN_BuildOutputData(&State->SACN, OutputData, SACNAssemblies, &State->LedSystem); + UART_BuildOutputData(OutputData, UARTAssemblies, &State->LedSystem); Editor_Render(State, Context, RenderBuffer); } diff --git a/src/app/foldhaus_app.h b/src/app/foldhaus_app.h index 24a98d0..7f4d380 100644 --- a/src/app/foldhaus_app.h +++ b/src/app/foldhaus_app.h @@ -65,8 +65,6 @@ struct app_state ui_interface Interface; panel_system PanelSystem; panel* HotPanel; - - r32 PixelsToWorldScale; }; internal void OpenColorPicker(app_state* State, v4* Address); diff --git a/src/app/foldhaus_renderer.cpp b/src/app/foldhaus_renderer.cpp index ece4ee7..bfd6522 100644 --- a/src/app/foldhaus_renderer.cpp +++ b/src/app/foldhaus_renderer.cpp @@ -15,6 +15,14 @@ AllocateRenderCommandBuffer (u8* Memory, s32 Size, renderer_realloc* Realloc) Result.Realloc = Realloc; return Result; } +internal render_command_buffer +AllocateRenderCommandBuffer(u32 MemorySize, + gs_memory_arena* Arena, + renderer_realloc* Realloc) +{ + u8* Memory = PushSize(Arena, MemorySize); + return AllocateRenderCommandBuffer(Memory, MemorySize, Realloc); +} internal void Render3DQuadBatch (u8* CommandData, s32 TriCount) diff --git a/src/app/interface.h b/src/app/interface.h index 7ef4f07..d112c1c 100644 --- a/src/app/interface.h +++ b/src/app/interface.h @@ -1528,5 +1528,26 @@ ui_EndLabeledDropdown(ui_interface* Interface) ui_EndRow(Interface); } +internal ui_interface +ui_InterfaceCreate(context Context, interface_config Style, gs_memory_arena* Permanent) +{ + ui_interface Result = {0}; + Result.Style = Style; + + gs_file FontFile = ReadEntireFile(Context.ThreadContext.FileHandler, ConstString("data/Anonymous Pro.ttf")); + Result.Style.Font = PushStruct(Permanent, bitmap_font); + *Result.Style.Font = TextFont_Create(FontFile, 512, Style.FontSize, Context, Permanent); + + Result.Style.RowHeight = ui_GetTextLineHeight(Result) + (2 * Result.Style.Margin.y); + + Result.WidgetsCountMax = 4096; + Result.Widgets = PushArray(Permanent, ui_widget, Result.WidgetsCountMax); + Result.PerFrameMemory = PushStruct(Permanent, gs_memory_arena); + *Result.PerFrameMemory = CreateMemoryArena(Context.ThreadContext.Allocator); + Result.Permanent = Permanent; + + return Result; +} + #define INTERFACE_H #endif // INTERFACE_H \ No newline at end of file diff --git a/src/app/platform_win32/win32_foldhaus.cpp b/src/app/platform_win32/win32_foldhaus.cpp index 7a11bf0..47b625a 100644 --- a/src/app/platform_win32/win32_foldhaus.cpp +++ b/src/app/platform_win32/win32_foldhaus.cpp @@ -23,6 +23,7 @@ #include "win32_foldhaus_work_queue.h" #include "win32_foldhaus_serial.h" #include "win32_foldhaus_socket.h" +#include "win32_foldhaus_mouse.h" #include "../foldhaus_renderer.cpp" @@ -369,23 +370,6 @@ Win32Realloc(u8* Buf, s32 OldSize, s32 NewSize) return NewMemory; } -// NOTE(Peter): Only meant to take one of the values specified below: -// IDC_APPSTARTING, IDC_ARROW, IDC_CROSS, IDC_HAND, IDC_HELP, IDC_IBEAM, -// IDC_ICON, IDC_NO, IDC_SIZE, IDC_SIZEALL, IDC_SIZENESW, IDC_SIZENS, IDC_SIZENWSE, -// IDC_SIZEWE, IDC_UPARROW, IDC_WAIT -internal HCURSOR -Win32LoadSystemCursor(char* CursorIdentifier) -{ - u32 Error = 0; - HCURSOR Result = LoadCursorA(NULL, CursorIdentifier); - if (Result == NULL) - { - Error = GetLastError(); - InvalidCodePath; - } - return Result; -} - internal void Win32_SendAddressedDataBuffers(gs_thread_context Context, addressed_data_buffer_list OutputData) { @@ -467,6 +451,23 @@ UpackB4(const u8* ptr) return (u32)(ptr[3] | (ptr[2] << 8) | (ptr[1] << 16) | (ptr[0] << 24)); } +internal bool +ReloadAndLinkDLL(win32_dll_refresh* DLL, context* Context, gs_work_queue* WorkQueue, bool ShouldError) +{ + bool Success = false; + if (HotLoadDLL(DLL)) + { + SetApplicationLinks(Context, *DLL, WorkQueue); + Context->ReloadStaticData(*Context, GlobalDebugServices); + Success = true; + } + else if(ShouldError) + { + OutputDebugStringA("Unable to load application DLL at startup.\nAborting\n"); + } + return Success; +} + int WINAPI WinMain ( HINSTANCE HInstance, @@ -477,36 +478,6 @@ 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; - gs_data MessageBuffer = PushSizeToData(ThreadContext.Transient); - - gs_memory_cursor WriteCursor = CreateMemoryCursor(MessageBuffer); - - uart_header* Header = PushStructOnCursor(WriteCursor, uart_header); - UART_FillHeader(Header, Strip.UARTAddr.Channel, UART_SET_CHANNEL_WS2812); - uart_channel* Channel = PushStructOnCursor(WriteCursor, uart_channel); - *Channel = ChannelSettings; - - for (u32 i = 0; i < LedCount; i++) - { - u8* OutputPixel = PushArrayOnCursor(WriteCursor, u8, 3); - OutputPixel[Channel->RedIndex] = (u8)(i); - OutputPixel[Channel->GreenIndex] = 0; - OutputPixel[Channel->BlueIndex] = 0; - } - - uart_footer* Footer = PushStructOnCursor(WriteCursor, uart_footer); - UART_FillFooter(Footer, (u8*)Header); - -#endif - MainWindow = Win32CreateWindow (HInstance, "Foldhaus", 1440, 768, HandleWindowEvents); Win32UpdateWindowDimension(&MainWindow); @@ -516,14 +487,10 @@ WinMain ( OpenGLWindowInfo.DepthBits = 0; CreateOpenGLWindowContext(OpenGLWindowInfo, &MainWindow); - s32 InitialMemorySize = MB(64); - u8* InitialMemory = (u8*)Win32Alloc(InitialMemorySize, 0); context Context = {}; Context.ThreadContext = ThreadContext; - Context.MemorySize = InitialMemorySize; - Context.MemoryBase = InitialMemory; - Context.WindowBounds = rect2{v2{0, 0}, v2{(r32)MainWindow.Width, (r32)MainWindow.Height}}; - Context.Mouse = {0}; + Context.MemorySize = MB(64); + Context.MemoryBase = (u8*)Win32Alloc(Context.MemorySize, 0); gs_memory_arena PlatformPermanent = CreateMemoryArena(Context.ThreadContext.Allocator); @@ -533,109 +500,37 @@ WinMain ( r32 LastFrameSecondsElapsed = 0.0f; GlobalDebugServices = PushStruct(&PlatformPermanent, debug_services); - s32 DebugThreadCount = PLATFORM_THREAD_COUNT + 1; InitDebugServices(GlobalDebugServices, PerformanceCountFrequency, DEBUGAlloc, Win32Realloc, GetWallClock, Win32GetThreadId, - DebugThreadCount); + PLATFORM_THREAD_COUNT + 1); - input_queue InputQueue; - { - s32 InputQueueMemorySize = sizeof(input_entry) * 32; - u8* InputQueueMemory = (u8*)Win32Alloc(InputQueueMemorySize, 0); - InputQueue = InitializeInputQueue(InputQueueMemory, InputQueueMemorySize); - } + input_queue InputQueue = InputQueue_Create(&PlatformPermanent, 32); - // - // Set up worker threads - const s32 WorkerThreadCount = PLATFORM_THREAD_COUNT; - worker_thread_info* WorkerThreads = 0; - if (PLATFORM_THREAD_COUNT > 0) - { - WorkerThreads = PushArray(&PlatformPermanent, worker_thread_info, PLATFORM_THREAD_COUNT); - } - - HANDLE WorkQueueSemaphoreHandle = CreateSemaphoreEx(0, 0, PLATFORM_THREAD_COUNT, 0, 0, SEMAPHORE_ALL_ACCESS); - - gs_work_queue WorkQueue = {}; - WorkQueue.SemaphoreHandle = &WorkQueueSemaphoreHandle; - WorkQueue.JobsMax = 512; - WorkQueue.Jobs = PushArray(&PlatformPermanent, gs_threaded_job, WorkQueue.JobsMax); - WorkQueue.NextJobIndex = 0; - WorkQueue.PushWorkOnQueue = Win32PushWorkOnQueue; - WorkQueue.CompleteQueueWork = Win32DoQueueWorkUntilDone; - WorkQueue.ResetWorkQueue = ResetWorkQueue; - - for (s32 i = 0; i < PLATFORM_THREAD_COUNT; i++) - { - // ID = 0 is reserved for this thread - WorkerThreads[i].Queue = &WorkQueue; - WorkerThreads[i].Handle = CreateThread(0, 0, &WorkerThreadProc, (void*)&WorkerThreads[i], 0, 0); - } - - // Cursors - HCURSOR CursorArrow = Win32LoadSystemCursor(IDC_ARROW); - HCURSOR CursorPointer = Win32LoadSystemCursor(IDC_HAND); - HCURSOR CursorLoading = Win32LoadSystemCursor(IDC_WAIT); - HCURSOR CursorHorizontalArrows = Win32LoadSystemCursor(IDC_SIZEWE); - HCURSOR CursorVerticalArrows = Win32LoadSystemCursor(IDC_SIZENS); - HCURSOR CursorDiagonalTopLeftArrows = Win32LoadSystemCursor(IDC_SIZENWSE); - HCURSOR CursorDiagonalTopRightArrows = Win32LoadSystemCursor(IDC_SIZENESW); + Win32WorkQueue_Init(&PlatformPermanent, PLATFORM_THREAD_COUNT); // Platform functions - Context.GeneralWorkQueue = &WorkQueue; + Context.GeneralWorkQueue = &Win32WorkQueue.WorkQueue; Context.PlatformGetGPUTextureHandle = Win32GetGPUTextureHandle; Context.PlatformGetSocketHandle = Win32GetSocketHandle; Context.PlatformGetFontInfo = Win32GetFontInfo; Context.PlatformDrawFontCodepoint = Win32DrawFontCodepoint; win32_dll_refresh DLLRefresh = InitializeDLLHotReloading(DLLName, WorkingDLLName, DLLLockFileName); - if (HotLoadDLL(&DLLRefresh)) - { - SetApplicationLinks(&Context, DLLRefresh, &WorkQueue); - Context.ReloadStaticData(Context, GlobalDebugServices); - } - else - { - MessageBox(MainWindow.Handle, "Unable to load application DLL at startup.\nAborting\n", "Set Up Error", MB_OK); - return -1; - } + if (!ReloadAndLinkDLL(&DLLRefresh, &Context, &Win32WorkQueue.WorkQueue, true)) { return -1; } - WSADATA WSAData; - WSAStartup(MAKEWORD(2, 2), &WSAData); - Win32Sockets = Win32SocketArray_Create(16, &PlatformPermanent); + Mouse_Init(); -#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; - 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); - } -#endif + Win32SocketSystem_Init(&PlatformPermanent); Win32SerialArray_Create(ThreadContext); - s32 RenderMemorySize = MB(12); - u8* RenderMemory = PushSize(&PlatformPermanent, RenderMemorySize); - render_command_buffer RenderBuffer = AllocateRenderCommandBuffer(RenderMemory, RenderMemorySize, Win32Realloc); + render_command_buffer RenderBuffer = AllocateRenderCommandBuffer(MB(12), &PlatformPermanent, Win32Realloc); - addressed_data_buffer_list OutputData = {}; - OutputData.Arena = AllocatorAllocStruct(Context.ThreadContext.Allocator, gs_memory_arena); - *OutputData.Arena = CreateMemoryArena(Context.ThreadContext.Allocator); + addressed_data_buffer_list OutputData = AddressedDataBufferList_Create(ThreadContext); Context.InitializeApplication(Context); @@ -650,33 +545,12 @@ WinMain ( DEBUG_TRACK_SCOPE(MainLoop); ResetInputQueue(&InputQueue); - if (HotLoadDLL(&DLLRefresh)) - { - SetApplicationLinks(&Context, DLLRefresh, &WorkQueue); - Context.ReloadStaticData(Context, GlobalDebugServices); - } + + ReloadAndLinkDLL(&DLLRefresh, &Context, &Win32WorkQueue.WorkQueue, false); AddressedDataBufferList_Clear(&OutputData); - { // Mouse - POINT MousePos; - GetCursorPos (&MousePos); - ScreenToClient(MainWindow.Handle, &MousePos); - - Context.Mouse.Scroll = 0; - Context.Mouse.OldPos = Context.Mouse.Pos; - Context.Mouse.Pos = v2{(r32)MousePos.x, (r32)MainWindow.Height - MousePos.y}; - Context.Mouse.DeltaPos = Context.Mouse.Pos - Context.Mouse.OldPos; - - if (KeyIsDown(Context.Mouse.LeftButtonState)) - { - SetKeyWasDown(Context.Mouse.LeftButtonState); - } - else - { - SetKeyWasUp(Context.Mouse.LeftButtonState); - } - } + Mouse_Update(MainWindow, &Context); MSG Message; while (PeekMessageA(&Message, MainWindow.Handle, 0, 0, PM_REMOVE)) @@ -700,45 +574,10 @@ WinMain ( gs_data ProcArg = {}; ProcArg.Memory = (u8*)&OutputData; ProcArg.Size = sizeof(OutputData); - Win32PushWorkOnQueue(&WorkQueue, Win32_SendAddressedDataBuffers_Job, ProcArg, ConstString("Send UART Data")); + Win32PushWorkOnQueue(&Win32WorkQueue.WorkQueue, Win32_SendAddressedDataBuffers_Job, ProcArg, ConstString("Send UART Data")); } - Context.Mouse.LeftButtonState = GetMouseButtonStateAdvanced(Context.Mouse.LeftButtonState); - Context.Mouse.MiddleButtonState = GetMouseButtonStateAdvanced(Context.Mouse.MiddleButtonState); - Context.Mouse.RightButtonState = GetMouseButtonStateAdvanced(Context.Mouse.RightButtonState); - - switch (Context.Mouse.CursorType) - { - case CursorType_Arrow: - { - SetCursor(CursorArrow); - }break; - case CursorType_Pointer: - { - SetCursor(CursorPointer); - }break; - case CursorType_Loading: - { - SetCursor(CursorLoading); - }break; - case CursorType_HorizontalArrows: - { - SetCursor(CursorHorizontalArrows); - }break; - case CursorType_VerticalArrows: - { - SetCursor(CursorVerticalArrows); - }break; - case CursorType_DiagonalTopLeftArrows: - { - SetCursor(CursorDiagonalTopLeftArrows); - }break; - case CursorType_DiagonalTopRightArrows: - { - SetCursor(CursorDiagonalTopRightArrows); - }break; - InvalidDefaultCase; - } + Mouse_Advance(&Context); HDC DeviceContext = GetDC(MainWindow.Handle); SwapBuffers(DeviceContext); @@ -759,28 +598,13 @@ WinMain ( LastFrameSecondsElapsed = SecondsElapsed; LastFrameEnd = GetWallClock(); - - - //OutputDebugStringA("-- Frame END -- \n"); - } Context.CleanupApplication(Context); - for (s32 SocketIdx = 0; SocketIdx < Win32Sockets.Count; SocketIdx++) - { - Win32Socket_Close(Win32Sockets.Values + SocketIdx); - } + Win32SocketSystem_Cleanup(); - s32 CleanupResult = 0; - do { - CleanupResult = WSACleanup(); - }while(CleanupResult == SOCKET_ERROR); - - for (s32 Thread = 0; Thread < PLATFORM_THREAD_COUNT; Thread++) - { - TerminateThread(WorkerThreads[Thread].Handle, 0); - } + Win32WorkQueue_Cleanup(); return 0; } diff --git a/src/app/platform_win32/win32_foldhaus_mouse.h b/src/app/platform_win32/win32_foldhaus_mouse.h new file mode 100644 index 0000000..0dbc3d4 --- /dev/null +++ b/src/app/platform_win32/win32_foldhaus_mouse.h @@ -0,0 +1,118 @@ +// +// File: win32_mouse.h +// Author: Peter Slattery +// Creation Date: 2021-01-10 +// +#ifndef WIN32_MOUSE_H + +HCURSOR CursorArrow; +HCURSOR CursorPointer; +HCURSOR CursorLoading; +HCURSOR CursorHArrows; +HCURSOR CursorVArrows; +HCURSOR CursorDTopLeftArrows; +HCURSOR CursorDTopRightArrows; + +HCURSOR CurrentCursor; + +// NOTE(Peter): Only meant to take one of the values specified below: +// IDC_APPSTARTING, IDC_ARROW, IDC_CROSS, IDC_HAND, IDC_HELP, IDC_IBEAM, +// IDC_ICON, IDC_NO, IDC_SIZE, IDC_SIZEALL, IDC_SIZENESW, IDC_SIZENS, IDC_SIZENWSE, +// IDC_SIZEWE, IDC_UPARROW, IDC_WAIT +internal HCURSOR +Win32LoadSystemCursor(char* CursorIdentifier) +{ + u32 Error = 0; + HCURSOR Result = LoadCursorA(NULL, CursorIdentifier); + if (Result == NULL) + { + Error = GetLastError(); + InvalidCodePath; + } + return Result; +} + +internal void +Mouse_Init() +{ + CursorArrow = Win32LoadSystemCursor(IDC_ARROW); + CursorPointer = Win32LoadSystemCursor(IDC_HAND); + CursorLoading = Win32LoadSystemCursor(IDC_WAIT); + CursorHArrows = Win32LoadSystemCursor(IDC_SIZEWE); + CursorVArrows = Win32LoadSystemCursor(IDC_SIZENS); + CursorDTopLeftArrows = Win32LoadSystemCursor(IDC_SIZENWSE); + CursorDTopRightArrows = Win32LoadSystemCursor(IDC_SIZENESW); +} + +internal void +Mouse_Update(window Window, context* Context) +{ + POINT Pos; + GetCursorPos (&Pos); + ScreenToClient(Window.Handle, &Pos); + + Context->Mouse.Scroll = 0; + Context->Mouse.OldPos = Context->Mouse.Pos; + Context->Mouse.Pos = v2{(r32)Pos.x, (r32)Window.Height - Pos.y}; + Context->Mouse.DeltaPos = Context->Mouse.Pos - Context->Mouse.OldPos; + + if (KeyIsDown(Context->Mouse.LeftButtonState)) + { + SetKeyWasDown(Context->Mouse.LeftButtonState); + } + else + { + SetKeyWasUp(Context->Mouse.LeftButtonState); + } + + if (KeyIsDown(Context->Mouse.MiddleButtonState)) + { + SetKeyWasDown(Context->Mouse.MiddleButtonState); + } + else + { + SetKeyWasUp(Context->Mouse.MiddleButtonState); + } + + + if (KeyIsDown(Context->Mouse.RightButtonState)) + { + SetKeyWasDown(Context->Mouse.RightButtonState); + } + else + { + SetKeyWasUp(Context->Mouse.RightButtonState); + } +} + + +internal void +Mouse_Advance(context* Context) +{ + Context->Mouse.LeftButtonState = GetMouseButtonStateAdvanced(Context->Mouse.LeftButtonState); + Context->Mouse.MiddleButtonState = GetMouseButtonStateAdvanced(Context->Mouse.MiddleButtonState); + Context->Mouse.RightButtonState = GetMouseButtonStateAdvanced(Context->Mouse.RightButtonState); + + HCURSOR NewCursor = 0; + switch (Context->Mouse.CursorType) + { + case CursorType_Arrow: { NewCursor = CursorArrow; } break; + case CursorType_Pointer: { NewCursor = CursorPointer; }break; + case CursorType_Loading: { NewCursor = CursorLoading; }break; + case CursorType_HArrows: { NewCursor = CursorHArrows; }break; + case CursorType_VArrows: { NewCursor = CursorVArrows; }break; + case CursorType_DTopLeftArrows: { NewCursor = CursorDTopLeftArrows; }break; + case CursorType_DTopRightArrows: { NewCursor = CursorDTopRightArrows; }break; + + InvalidDefaultCase; + } + if (NewCursor != CurrentCursor) + { + CurrentCursor = NewCursor; + SetCursor(NewCursor); + } +} + + +#define WIN32_MOUSE_H +#endif // WIN32_MOUSE_H \ No newline at end of file diff --git a/src/app/platform_win32/win32_foldhaus_socket.h b/src/app/platform_win32/win32_foldhaus_socket.h index a95b806..65fb1a2 100644 --- a/src/app/platform_win32/win32_foldhaus_socket.h +++ b/src/app/platform_win32/win32_foldhaus_socket.h @@ -17,6 +17,9 @@ struct win32_socket_array s32 Count; }; +global WSADATA WSAData; +global win32_socket_array Win32Sockets; + ////////////////////// // // Win32 Socket Array @@ -50,9 +53,7 @@ Win32SocketArray_Get(win32_socket_array Array, s32 Index) ////////////////////// // -// Win32 Socket System - -global win32_socket_array Win32Sockets; +// Win32 Sockets internal win32_socket Win32Socket_Create(s32 AddressFamily, s32 Type, s32 Protocol) @@ -241,6 +242,38 @@ Win32Socket_Close(win32_socket* Socket) Socket->Socket = INVALID_SOCKET; } +internal void +Win32Socket_CloseArray(win32_socket_array Array) +{ + for (s32 i = 0; i < Array.Count; i++) + { + win32_socket* Socket = Array.Values + i; + Win32Socket_Close(Socket); + } +} + +////////////////////// +// +// Win32 Socket System + +internal void +Win32SocketSystem_Init(gs_memory_arena* Arena) +{ + WSAStartup(MAKEWORD(2, 2), &WSAData); + Win32Sockets = Win32SocketArray_Create(16, Arena); +} + +internal void +Win32SocketSystem_Cleanup() +{ + Win32Socket_CloseArray(Win32Sockets); + + s32 CleanupResult = 0; + do { + CleanupResult = WSACleanup(); + }while(CleanupResult == SOCKET_ERROR); +} + PLATFORM_GET_SOCKET_HANDLE(Win32GetSocketHandle) { s32 Result = Win32SocketArray_Take(&Win32Sockets); diff --git a/src/app/platform_win32/win32_foldhaus_work_queue.h b/src/app/platform_win32/win32_foldhaus_work_queue.h index 0b31fa6..2388798 100644 --- a/src/app/platform_win32/win32_foldhaus_work_queue.h +++ b/src/app/platform_win32/win32_foldhaus_work_queue.h @@ -18,6 +18,16 @@ struct worker_thread_info gs_work_queue* Queue; }; +struct win32_work_queue +{ + u32 ThreadCount; + worker_thread_info* Threads; + gs_work_queue WorkQueue; +}; + +worker_thread_info* WorkerThreads; +win32_work_queue Win32WorkQueue; + internal s32 Win32GetThreadId() { @@ -153,5 +163,42 @@ WorkerThreadProc (LPVOID InputThreadInfo) return 0; } +internal void +Win32WorkQueue_Init(gs_memory_arena* Arena, u32 ThreadCount) +{ + if (ThreadCount > 0) + { + Win32WorkQueue.ThreadCount = ThreadCount; + Win32WorkQueue.Threads = PushArray(Arena, worker_thread_info, ThreadCount); + } + + gs_work_queue WQ = {}; + WQ.SemaphoreHandle = CreateSemaphoreEx(0, 0, ThreadCount, 0, 0, SEMAPHORE_ALL_ACCESS);; + WQ.JobsMax = 512; + WQ.Jobs = PushArray(Arena, gs_threaded_job, WQ.JobsMax); + WQ.NextJobIndex = 0; + WQ.PushWorkOnQueue = Win32PushWorkOnQueue; + WQ.CompleteQueueWork = Win32DoQueueWorkUntilDone; + + Win32WorkQueue.WorkQueue = WQ; + + // ID = 0 is reserved for this thread + for (u32 i = 0; i < ThreadCount; i++) + { + worker_thread_info* T = Win32WorkQueue.Threads + i; + T->Queue = &Win32WorkQueue.WorkQueue; + T->Handle = CreateThread(0, 0, &WorkerThreadProc, (void*)T, 0, 0); + } +} + +internal void +Win32WorkQueue_Cleanup() +{ + for (u32 Thread = 0; Thread < Win32WorkQueue.ThreadCount; Thread++) + { + TerminateThread(Win32WorkQueue.Threads[Thread].Handle, 0); + } +} + #define WIN32_FOLDHAUS_WORK_QUEUE_H #endif // WIN32_FOLDHAUS_WORK_QUEUE_H \ No newline at end of file diff --git a/src/app/platform_win32/win32_test_code.cpp b/src/app/platform_win32/win32_test_code.cpp new file mode 100644 index 0000000..b9fa377 --- /dev/null +++ b/src/app/platform_win32/win32_test_code.cpp @@ -0,0 +1,53 @@ +// +// File: win32_test_code.cpp +// Author: Peter Slattery +// Creation Date: 2021-01-10 +// +#ifndef WIN32_TEST_CODE_CPP + +internal void +Win32_TestCode_UART(gs_thread_context ThreadContext) +{ + u32 LedCount = 48; + u32 MessageBaseSize = sizeof(uart_header) + sizeof(uart_channel) + sizeof(uart_footer); + MessageBaseSize += sizeof(u8) * 3 * LedCount; + gs_data MessageBuffer = PushSizeToData(ThreadContext.Transient); + + gs_memory_cursor WriteCursor = CreateMemoryCursor(MessageBuffer); + + uart_header* Header = PushStructOnCursor(WriteCursor, uart_header); + UART_FillHeader(Header, Strip.UARTAddr.Channel, UART_SET_CHANNEL_WS2812); + uart_channel* Channel = PushStructOnCursor(WriteCursor, uart_channel); + *Channel = ChannelSettings; + + for (u32 i = 0; i < LedCount; i++) + { + u8* OutputPixel = PushArrayOnCursor(WriteCursor, u8, 3); + OutputPixel[Channel->RedIndex] = (u8)(i); + OutputPixel[Channel->GreenIndex] = 0; + OutputPixel[Channel->BlueIndex] = 0; + } + + uart_footer* Footer = PushStructOnCursor(WriteCursor, uart_footer); + UART_FillFooter(Footer, (u8*)Header); +} + +internal void +Win32_TestCode_SocketReading(gs_thread_context ThreadContext) +{ + 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); + } +} + +#define WIN32_TEST_CODE_CPP +#endif // WIN32_TEST_CODE_CPP \ No newline at end of file diff --git a/src/gs_libs/gs_font.h b/src/gs_libs/gs_font.h index c901bf7..e26a681 100644 --- a/src/gs_libs/gs_font.h +++ b/src/gs_libs/gs_font.h @@ -5,8 +5,6 @@ // #ifndef GS_FONT_H -#ifndef GS_FONT_H - struct codepoint_bitmap { s32 XOffset, YOffset; @@ -37,20 +35,6 @@ struct bitmap_font s32 BitmapTextureHandle; }; -internal bitmap_font -InitializeTextFont (s32 CodepointCount, u8* CodepointMemory, s32 CodepointMemorySize) -{ - bitmap_font Result = {}; - - Result.CodepointDictionarySize = CodepointCount; - Result.CodepointDictionaryCount = 0; - Assert(CodepointMemorySize >= (sizeof(char) + sizeof(codepoint_bitmap)) * CodepointCount); - Result.CodepointKeys = (char*)CodepointMemory; - Result.CodepointValues = (codepoint_bitmap*)(CodepointMemory + (sizeof(char) * CodepointCount)); - - return Result; -} - #define GLYPH_SKIRT 1 internal void GetNextCodepointOffset (bitmap_font* Font, u32* X, u32* Y) @@ -126,8 +110,58 @@ NewLineYOffset (bitmap_font Font) return Result; } -#define GS_FONT_H -#endif + +internal bitmap_font +TextFont_Create(gs_file FontFile, u32 BitmapDim, u32 FontSize, context Context, gs_memory_arena* Arena) +{ + bitmap_font Result = {}; + Assert(FileNoError(FontFile)); + + Result.BitmapWidth = BitmapDim; + Result.BitmapHeight = BitmapDim; + Result.BitmapBytesPerPixel = 4; + Result.BitmapStride = Result.BitmapWidth * Result.BitmapBytesPerPixel; + u32 BitmapSize = Result.BitmapWidth * Result.BitmapHeight * Result.BitmapBytesPerPixel; + Result.BitmapMemory = PushArray(Arena, u8, BitmapSize); + ZeroMemoryBlock(Result.BitmapMemory, BitmapSize); + + platform_font_info FontInfo = Context.PlatformGetFontInfo("Anonymous Pro", FontSize, FontWeight_Normal, false, false, false); + Result.PixelHeight = FontInfo.PixelHeight; + Result.Ascent = FontInfo.Ascent; + Result.Descent = FontInfo.Descent; + Result.Leading = FontInfo.Leading; + Result.MaxCharWidth = FontInfo.MaxCharWidth; + + Result.CodepointDictionarySize = (FontInfo.CodepointOnePastLast - FontInfo.CodepointStart); + Result.CodepointDictionaryCount = 0; + Result.CodepointKeys = PushArray(Arena, char, Result.CodepointDictionarySize); + Result.CodepointValues = PushArray(Arena, codepoint_bitmap, Result.CodepointDictionarySize); + + for (s32 Codepoint = FontInfo.CodepointStart; + Codepoint < FontInfo.CodepointOnePastLast; + Codepoint++) + { + + u32 CodepointX, CodepointY; + GetNextCodepointOffset(&Result, &CodepointX, &CodepointY); + + u32 CodepointW, CodepointH; + Context.PlatformDrawFontCodepoint( + Result.BitmapMemory, + Result.BitmapWidth, + Result.BitmapHeight, + CodepointX, CodepointY, + Codepoint, FontInfo, + &CodepointW, &CodepointH); + + AddCodepointToFont(&Result, Codepoint, 0, 0, CodepointW, CodepointH, CodepointX, CodepointY); + } + + Result.BitmapTextureHandle = Context.PlatformGetGPUTextureHandle(Result.BitmapMemory, + Result.BitmapWidth, Result.BitmapHeight); + + return Result; +} #define GS_FONT_H #endif // GS_FONT_H \ No newline at end of file diff --git a/src/gs_libs/gs_input.h b/src/gs_libs/gs_input.h index 2586c03..4a696b3 100644 --- a/src/gs_libs/gs_input.h +++ b/src/gs_libs/gs_input.h @@ -251,10 +251,10 @@ enum cursor_type CursorType_Arrow, CursorType_Pointer, CursorType_Loading, - CursorType_HorizontalArrows, - CursorType_VerticalArrows, - CursorType_DiagonalTopLeftArrows, - CursorType_DiagonalTopRightArrows, + CursorType_HArrows, + CursorType_VArrows, + CursorType_DTopLeftArrows, + CursorType_DTopRightArrows, CursorType_Count, }; @@ -277,7 +277,7 @@ struct mouse_state }; internal input_queue -InitializeInputQueue (u8* Memory, s32 MemorySize) +InputQueue_Create (u8* Memory, s32 MemorySize) { input_queue Result = {}; s32 EntriesCount = MemorySize / sizeof(input_entry); @@ -286,6 +286,18 @@ InitializeInputQueue (u8* Memory, s32 MemorySize) Result.Entries = (input_entry*)Memory; return Result; } +internal input_queue +InputQueue_Create(gs_memory_arena* Arena, u32 CountMax) +{ + input_queue Result = {0}; + if (CountMax > 0) + { + s32 Size = sizeof(input_entry) * 32; + u8* Memory = PushSize(Arena, Size); + Result = InputQueue_Create(Memory, Size); + } + return Result; +} internal void ResetInputQueue (input_queue* Queue) diff --git a/src/gs_libs/gs_types.h b/src/gs_libs/gs_types.h index e647f5c..82c9246 100644 --- a/src/gs_libs/gs_types.h +++ b/src/gs_libs/gs_types.h @@ -1047,7 +1047,6 @@ struct gs_work_queue // Work Queue push_work_on_queue* PushWorkOnQueue; complete_queue_work* CompleteQueueWork; - reset_work_queue* ResetWorkQueue; }; #define GS_TYPES_H From 4798002dfc00bf56962fe93b883b121e5ee0a959 Mon Sep 17 00:00:00 2001 From: PS Date: Sat, 16 Jan 2021 14:02:25 -0800 Subject: [PATCH 18/44] debug and profiler improvements. implemented sending data to multiple destinations on a per strip basis, rather than a full sculpture basis. new patterns. Added user data to patterns. --- src/app/blumen_lumen.h | 15 + .../foldhaus_panel_animation_timeline.h | 2 + .../panels/foldhaus_panel_assembly_debug.h | 51 +++ .../editor/panels/foldhaus_panel_profiler.h | 90 ++-- .../editor/panels/foldhaus_panel_types.cpp | 3 +- src/app/editor/panels/foldhaus_panel_types.h | 1 + src/app/engine/animation/foldhaus_animation.h | 2 +- .../animation/foldhaus_animation_renderer.cpp | 12 +- src/app/engine/assembly/foldhaus_assembly.h | 1 - .../engine/assembly/foldhaus_assembly_debug.h | 134 ++++++ src/app/engine/uart/foldhaus_uart.cpp | 86 +++- src/app/foldhaus_app.cpp | 9 +- src/app/foldhaus_app.h | 407 +----------------- src/app/foldhaus_platform.h | 2 +- src/app/interface.h | 28 +- src/app/patterns/blumen_patterns.h | 395 +++++++++++++++++ src/app/platform_win32/win32_foldhaus.cpp | 87 ++-- src/sculpture_gen/gen_blumen_lumen.cpp | 21 +- src/sculpture_gen/sculpture_gen.h | 6 +- test_motor_header.h | 19 + test_sound_interface_packet.h | 29 ++ 21 files changed, 885 insertions(+), 515 deletions(-) create mode 100644 src/app/blumen_lumen.h create mode 100644 src/app/editor/panels/foldhaus_panel_assembly_debug.h create mode 100644 src/app/engine/assembly/foldhaus_assembly_debug.h create mode 100644 src/app/patterns/blumen_patterns.h create mode 100644 test_motor_header.h create mode 100644 test_sound_interface_packet.h diff --git a/src/app/blumen_lumen.h b/src/app/blumen_lumen.h new file mode 100644 index 0000000..e93c247 --- /dev/null +++ b/src/app/blumen_lumen.h @@ -0,0 +1,15 @@ +// +// File: blumen_lumen.h +// Author: Peter Slattery +// Creation Date: 2021-01-15 +// +#ifndef BLUMEN_LUMEN_H + +typedef struct motor_packet +{ + u8 FlowerPositions[3]; +} motor_packet; + + +#define BLUMEN_LUMEN_H +#endif // BLUMEN_LUMEN_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 0a32fc4..ca358a6 100644 --- a/src/app/editor/panels/foldhaus_panel_animation_timeline.h +++ b/src/app/editor/panels/foldhaus_panel_animation_timeline.h @@ -897,6 +897,8 @@ AnimationTimeline_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* { animation_timeline_state* TimelineState = Panel_GetStateStruct(Panel, animation_timeline_state); + ui_FillRect(&State->Interface, PanelBounds, v4{.1f,.1f,.1f,1.f}); + rect2 TimelineBounds, InfoBounds; RectVSplit(PanelBounds, 300, &InfoBounds, &TimelineBounds); diff --git a/src/app/editor/panels/foldhaus_panel_assembly_debug.h b/src/app/editor/panels/foldhaus_panel_assembly_debug.h new file mode 100644 index 0000000..d118e19 --- /dev/null +++ b/src/app/editor/panels/foldhaus_panel_assembly_debug.h @@ -0,0 +1,51 @@ +// +// File: foldhaus_panel_assembly_debug.h +// Author: Peter Slattery +// Creation Date: 2021-01-15 +// +#ifndef FOLDHAUS_PANEL_ASSEMBLY_DEBUG_H + +GSMetaTag(panel_init); +GSMetaTag(panel_type_file_view); +internal void +AssemblyDebug_Init(panel* Panel, app_state* State, context Context) +{ +} + +GSMetaTag(panel_cleanup); +GSMetaTag(panel_type_file_view); +internal void +AssemblyDebug_Cleanup(panel* Panel, app_state* State) +{ + +} + +GSMetaTag(panel_render); +GSMetaTag(panel_type_file_view); +internal void +AssemblyDebug_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context) +{ + ui_interface* Interface = &State->Interface; + ui_PushLayout(Interface, PanelBounds, LayoutDirection_TopDown, MakeString("Assembly Debug Layout")); + + State->AssemblyDebugState.TargetAssembly = ui_LabeledTextEntryU64(Interface, MakeString("Assembly"), State->AssemblyDebugState.TargetAssembly); + + State->AssemblyDebugState.TargetStrip = ui_LabeledTextEntryU64(Interface, MakeString("Strip"), State->AssemblyDebugState.TargetStrip); + + + gs_string OverrideStr = MakeString(OverrideTypeStrings[State->AssemblyDebugState.Override]); + if (ui_BeginLabeledDropdown(Interface, MakeString("Override"), OverrideStr)) + { + for (u32 i = 0; i < ADS_Override_Count; i++) + { + if (ui_Button(Interface, MakeString(OverrideTypeStrings[i]))) + { + State->AssemblyDebugState.Override = (override_type)i; + } + } + } + ui_EndLabeledDropdown(Interface); +} + +#define FOLDHAUS_PANEL_ASSEMBLY_DEBUG_H +#endif // FOLDHAUS_PANEL_ASSEMBLY_DEBUG_H \ No newline at end of file diff --git a/src/app/editor/panels/foldhaus_panel_profiler.h b/src/app/editor/panels/foldhaus_panel_profiler.h index dca590d..a54827e 100644 --- a/src/app/editor/panels/foldhaus_panel_profiler.h +++ b/src/app/editor/panels/foldhaus_panel_profiler.h @@ -37,52 +37,68 @@ RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_widget* Layout, de rect2 Bounds = ui_LayoutRemaining(*Layout); r32 Width = Rect2Width(Bounds); - r32 DepthHeight = 64; + r32 DepthHeight = 32; s64 FrameStartCycles = VisibleFrame->FrameStartCycles; - s64 FrameTotalCycles = VisibleFrame->FrameEndCycles - VisibleFrame->FrameStartCycles; + r32 FrameTotalCycles = (r32)(VisibleFrame->FrameEndCycles - VisibleFrame->FrameStartCycles); - debug_scope_record_list* ThreadScopeCalls = GetScopeListForThreadInFrame(GlobalDebugServices, - VisibleFrame); + r32 NextThreadTop = Bounds.Max.y; - gs_string String = PushString(Transient, 256); - for (s32 i = 0; i < ThreadScopeCalls->Count; i++) + for (s32 t = 0; t < VisibleFrame->ThreadCount; t++) { - scope_record* Record = ThreadScopeCalls->Calls + i; - scope_name* Name = GetOrAddNameHashEntry(VisibleFrame, Record->NameHash); - r32 PercentStart = (r32)(Record->StartCycles - FrameStartCycles) / (r32)FrameTotalCycles; - r32 PercentEnd = (r32)(Record->EndCycles - FrameStartCycles) / (r32)FrameTotalCycles; + debug_scope_record_list ThreadCalls = VisibleFrame->ThreadCalls[t]; - r32 PixelStart = Bounds.Min.x + (Width * PercentStart); - r32 PixelEnd = Bounds.Min.x + (Width * PercentEnd); - r32 MinY = Bounds.Max.y - ((Record->CallDepth + 1) * DepthHeight); - rect2 ScopeBounds = { - v2{ PixelStart, MinY }, - v2{ PixelEnd, MinY + (DepthHeight - 4) } - }; - if (Rect2Width(ScopeBounds) >= 1) + gs_string String = PushString(Transient, 256); + + r32 ThreadScopeMin = Bounds.Max.y; + + for (s32 i = 0; i < ThreadCalls.Count; i++) { - v4 Color = ThreadColors[0]; - if (PointIsInRect(ScopeBounds, Interface->Mouse.Pos)) - { - Color = GreenV4; - - ui_BeginMousePopup(Interface, rect2{ 25, 25, 300, 57 }, LayoutDirection_TopDown, MakeString("Hover")); - { - s64 Cycles = (Record->EndCycles - Record->StartCycles); - r64 PercentFrame = (r64)(Cycles) / (r64)(FrameTotalCycles); - PrintF(&String, "%S : %.2f%% frame | %dcy", - Name->Name, - PercentFrame, - Cycles); - ui_Label(Interface, String); - } - ui_EndMousePopup(Interface); - } + scope_record* Record = ThreadCalls.Calls + i; + scope_name* Name = GetOrAddNameHashEntry(VisibleFrame, Record->NameHash); + s64 OffsetStart = Record->StartCycles - FrameStartCycles; + s64 OffsetEnd = Record->EndCycles - FrameStartCycles; + r32 PercentStart = (r32)(OffsetStart) / FrameTotalCycles; + r32 PercentEnd = (r32)(OffsetEnd) / FrameTotalCycles; + r32 PercentWidth = PercentEnd - PercentStart; - ui_FillRect(Interface, ScopeBounds, Color); - ui_OutlineRect(Interface, ScopeBounds, 1, BlackV4); + rect2 ScopeBounds = { + v2{0, 0}, + v2{PercentWidth * Width, DepthHeight - 4}, + }; + v2 Offset = { + Bounds.Min.x + (PercentStart * Width), + NextThreadTop - ((Record->CallDepth + 1) * DepthHeight) + }; + ScopeBounds = Rect2Translate(ScopeBounds, Offset); + ThreadScopeMin = Min(ScopeBounds.Min.y, ThreadScopeMin); + + if (Rect2Width(ScopeBounds) >= 1) + { + v4 Color = ThreadColors[t]; + if (PointIsInRect(ScopeBounds, Interface->Mouse.Pos)) + { + Color = GreenV4; + + ui_BeginMousePopup(Interface, rect2{ 25, 25, 300, 57 }, LayoutDirection_TopDown, MakeString("Hover")); + { + s64 Cycles = (Record->EndCycles - Record->StartCycles); + r32 PercentFrame = (r32)(Cycles) / FrameTotalCycles; + PrintF(&String, "%S : %.2f%% frame | %dcy", + Name->Name, + PercentFrame, + Cycles); + ui_Label(Interface, String); + } + ui_EndMousePopup(Interface); + } + + ui_FillRect(Interface, ScopeBounds, Color); + ui_OutlineRect(Interface, ScopeBounds, 1, BlackV4); + } } + + NextThreadTop = ThreadScopeMin; } } diff --git a/src/app/editor/panels/foldhaus_panel_types.cpp b/src/app/editor/panels/foldhaus_panel_types.cpp index 9c006fa..ea56618 100644 --- a/src/app/editor/panels/foldhaus_panel_types.cpp +++ b/src/app/editor/panels/foldhaus_panel_types.cpp @@ -4,7 +4,7 @@ // Creation Date: 2020-10-17 // #ifndef FOLDHAUS_PANEL_TYPES_CPP -global s32 GlobalPanelDefsCount = 6; +global s32 GlobalPanelDefsCount = 7; global panel_definition GlobalPanelDefs[] = { { "File View", 9, FileView_Init, FileView_Cleanup, FileView_Render, FileView_Commands, FileView_CommandsCount }, { "Sculpture View", 14, SculptureView_Init, SculptureView_Cleanup, SculptureView_Render, SculptureView_Commands, SculptureView_CommandsCount }, @@ -12,6 +12,7 @@ global panel_definition GlobalPanelDefs[] = { { "Dmx View", 8, DMXView_Init, DMXView_Cleanup, DMXView_Render, DMXView_Commands, DMXView_CommandsCount }, { "Hierarchy", 9, HierarchyView_Init, HierarchyView_Cleanup, HierarchyView_Render, HierarchyView_Commands, HierarchyView_CommandsCount }, { "Profiler", 8, ProfilerView_Init, ProfilerView_Cleanup, ProfilerView_Render, ProfilerView_Commands, ProfilerView_CommandsCount }, + { "Assembly Debug", 14, AssemblyDebug_Init, AssemblyDebug_Cleanup, AssemblyDebug_Render, 0, 0 }, }; #define FOLDHAUS_PANEL_TYPES_CPP #endif // FOLDHAUS_PANEL_TYPES_CPP \ No newline at end of file diff --git a/src/app/editor/panels/foldhaus_panel_types.h b/src/app/editor/panels/foldhaus_panel_types.h index 7b1164b..85c93ed 100644 --- a/src/app/editor/panels/foldhaus_panel_types.h +++ b/src/app/editor/panels/foldhaus_panel_types.h @@ -12,6 +12,7 @@ enum panel_type { PanelType_HierarchyView, PanelType_NodeGraph, PanelType_ProfilerView, + PanelType_AssemblyDebug, }; #define FOLDHAUS_PANEL_TYPES_H #endif // FOLDHAUS_PANEL_TYPES_H \ No newline at end of file diff --git a/src/app/engine/animation/foldhaus_animation.h b/src/app/engine/animation/foldhaus_animation.h index e764ec6..9309c0b 100644 --- a/src/app/engine/animation/foldhaus_animation.h +++ b/src/app/engine/animation/foldhaus_animation.h @@ -5,7 +5,7 @@ // #ifndef FOLDHAUS_ANIMATION -#define ANIMATION_PROC(name) void name(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient) +#define ANIMATION_PROC(name) void name(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) typedef ANIMATION_PROC(animation_proc); struct frame_range diff --git a/src/app/engine/animation/foldhaus_animation_renderer.cpp b/src/app/engine/animation/foldhaus_animation_renderer.cpp index 44075be..8915d59 100644 --- a/src/app/engine/animation/foldhaus_animation_renderer.cpp +++ b/src/app/engine/animation/foldhaus_animation_renderer.cpp @@ -81,20 +81,22 @@ LedBlend_GetProc(blend_mode BlendMode) } internal void -AnimationSystem_RenderBlockToLedBuffer(animation_system* System, animation_block Block, led_buffer* Buffer, assembly Assembly, animation_pattern_array Patterns, gs_memory_arena* Transient) +AnimationSystem_RenderBlockToLedBuffer(animation_system* System, animation_block Block, led_buffer* Buffer, assembly Assembly, animation_pattern_array Patterns, gs_memory_arena* Transient, + u8* UserData) { u32 FramesIntoBlock = System->CurrentFrame - Block.Range.Min; r32 SecondsIntoBlock = FramesIntoBlock * System->SecondsPerFrame; animation_pattern Pattern = Patterns_GetPattern(Patterns, Block.AnimationProcHandle); - Pattern.Proc(Buffer, Assembly, SecondsIntoBlock, Transient); + Pattern.Proc(Buffer, Assembly, SecondsIntoBlock, Transient, UserData); } internal void AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Assemblies, led_system* LedSystem, animation_pattern_array Patterns, - gs_memory_arena* Transient) + gs_memory_arena* Transient, + u8* UserData) { s32 CurrentFrame = System->CurrentFrame; r32 FrameTime = CurrentFrame * System->SecondsPerFrame; @@ -148,14 +150,14 @@ AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Asse { led_buffer TempBuffer = LayerBuffers[Layer].HotBuffer; animation_block Block = LayerFrame.Hot; - AnimationSystem_RenderBlockToLedBuffer(System, Block, &TempBuffer, *Assembly, Patterns, Transient); + AnimationSystem_RenderBlockToLedBuffer(System, Block, &TempBuffer, *Assembly, Patterns, Transient, UserData); } if (LayerFrame.HasNextHot) { led_buffer TempBuffer = LayerBuffers[Layer].NextHotBuffer; animation_block Block = LayerFrame.NextHot; - AnimationSystem_RenderBlockToLedBuffer(System, Block, &TempBuffer, *Assembly, Patterns, Transient); + AnimationSystem_RenderBlockToLedBuffer(System, Block, &TempBuffer, *Assembly, Patterns, Transient, UserData); } } diff --git a/src/app/engine/assembly/foldhaus_assembly.h b/src/app/engine/assembly/foldhaus_assembly.h index f1d7ba9..90694d1 100644 --- a/src/app/engine/assembly/foldhaus_assembly.h +++ b/src/app/engine/assembly/foldhaus_assembly.h @@ -160,7 +160,6 @@ struct assembly_array assembly* Values; }; - internal led_buffer* LedSystemGetBuffer(led_system* System, u32 Index) { diff --git a/src/app/engine/assembly/foldhaus_assembly_debug.h b/src/app/engine/assembly/foldhaus_assembly_debug.h new file mode 100644 index 0000000..bb385d2 --- /dev/null +++ b/src/app/engine/assembly/foldhaus_assembly_debug.h @@ -0,0 +1,134 @@ +// +// File: foldhaus_assembly_debug.h +// Author: Peter Slattery +// Creation Date: 2021-01-15 +// +#ifndef FOLDHAUS_ASSEMBLY_DEBUG_H + +enum override_type +{ + ADS_Override_None, + + ADS_Override_Strip, + ADS_Override_SoloStrip, + ADS_Override_AllRed, + ADS_Override_AllGreen, + ADS_Override_AllBlue, + + ADS_Override_Count, +}; + +global gs_const_string OverrideTypeStrings[] = { + LitString("Override_None"), + LitString("Override_Strip"), + LitString("Override_SoloStrip" ), + LitString("Override_AllRed" ), + LitString("Override_AllGreen" ), + LitString("Override_AllBlue" ), + LitString("Override_Count"), +}; + +struct assembly_debug_state +{ + override_type Override; + u32 TargetAssembly; + u32 TargetStrip; + pixel TargetColor; +}; + +internal void +AssemblyDebug_OverrideOutput(assembly_debug_state State, assembly_array Assemblies, led_system LedSystem) +{ + if (State.Override == ADS_Override_None) return; + State.TargetColor = pixel{255,255,255}; + + assembly Assembly = Assemblies.Values[State.TargetAssembly]; + led_buffer LedBuffer = LedSystem.Buffers[Assembly.LedBufferIndex]; + + switch (State.Override) + { + case ADS_Override_Strip: + { + v2_strip Strip = Assembly.Strips[State.TargetStrip]; + for (u32 i = 0; i < Strip.LedCount; i++) + { + u32 LedIdx = Strip.LedLUT[i]; + LedBuffer.Colors[LedIdx] = State.TargetColor; + } + }break; + + case ADS_Override_SoloStrip: + { + for (u32 s = 0; s < Assembly.StripCount; s++) + { + v2_strip Strip = Assembly.Strips[s]; + + pixel Color = pixel{0,0,0}; + if (s == State.TargetStrip) + { + Color = State.TargetColor; + } + + for (u32 i = 0; i < Strip.LedCount; i++) + { + u32 LedIdx = Strip.LedLUT[i]; + LedBuffer.Colors[LedIdx] = Color; + } + } + }break; + + case ADS_Override_AllRed: + { + for (u32 s = 0; s < Assembly.StripCount; s++) + { + v2_strip Strip = Assembly.Strips[s]; + for (u32 i = 0; i < Strip.LedCount; i++) + { + u32 LedIdx = Strip.LedLUT[i]; + LedBuffer.Colors[LedIdx] = pixel{255, 0, 0}; + } + } + }break; + + case ADS_Override_AllGreen: + { + for (u32 s = 0; s < Assembly.StripCount; s++) + { + v2_strip Strip = Assembly.Strips[s]; + for (u32 i = 0; i < Strip.LedCount; i++) + { + u32 LedIdx = Strip.LedLUT[i]; + LedBuffer.Colors[LedIdx] = pixel{0, 255, 0}; + } + } + }break; + + case ADS_Override_AllBlue: + { + for (u32 s = 0; s < Assembly.StripCount; s++) + { + v2_strip Strip = Assembly.Strips[s]; + for (u32 i = 0; i < Strip.LedCount; i++) + { + u32 LedIdx = Strip.LedLUT[i]; + LedBuffer.Colors[LedIdx] = pixel{0, 0, 255}; + } + } + }break; + + case ADS_Override_None: + { + }break; + + InvalidDefaultCase; + } + + if (State.Override ) + { + + } +} + + +#define FOLDHAUS_ASSEMBLY_DEBUG_H +#endif // FOLDHAUS_ASSEMBLY_DEBUG_H \ No newline at end of file diff --git a/src/app/engine/uart/foldhaus_uart.cpp b/src/app/engine/uart/foldhaus_uart.cpp index d523f6d..c158412 100644 --- a/src/app/engine/uart/foldhaus_uart.cpp +++ b/src/app/engine/uart/foldhaus_uart.cpp @@ -56,7 +56,7 @@ UART_DrawAll_Create(gs_memory_cursor* WriteCursor) } internal void -UART_BuildOutputData(addressed_data_buffer_list* Output, assembly_array Assemblies, led_system* LedSystem) +UART_BuildOutputData(addressed_data_buffer_list* Output, assembly_array Assemblies, led_system* LedSystem, gs_memory_arena* Transient) { uart_channel ChannelSettings = {0}; ChannelSettings.ElementsCount = 3; @@ -71,22 +71,88 @@ UART_BuildOutputData(addressed_data_buffer_list* Output, assembly_array Assembli assembly Assembly = Assemblies.Values[AssemblyIdx]; led_buffer* LedBuffer = LedSystemGetBuffer(LedSystem, Assembly.LedBufferIndex); - u32 TotalBufferSize = MessageBaseSize * Assembly.StripCount; // SetChannelBuffer messages - TotalBufferSize += MessageBaseSize; // DrawAll message - TotalBufferSize += ChannelSettings.ElementsCount * Assembly.LedCountTotal; // pixels * channels per pixel + struct strips_to_data_buffer + { + gs_const_string ComPort; + u32* StripIndices; + u32 StripIndicesCount; + u32 StripIndicesCountMax; + + u64 LedCount; + + strips_to_data_buffer* Next; + }; - addressed_data_buffer* Buffer = AddressedDataBufferList_Push(Output, TotalBufferSize); - AddressedDataBuffer_SetCOMPort(Buffer, Assembly.UARTComPort.ConstString); - gs_memory_cursor WriteCursor = CreateMemoryCursor(Buffer->Data); + strips_to_data_buffer* BuffersNeededHead = 0; + strips_to_data_buffer* BuffersNeededTail = 0; for (u32 StripIdx = 0; StripIdx < Assembly.StripCount; StripIdx++) { v2_strip StripAt = Assembly.Strips[StripIdx]; - ChannelSettings.PixelsCount = StripAt.LedCount; - UART_SetChannelBuffer_Create(&WriteCursor, ChannelSettings, StripAt, *LedBuffer); + + // If there is a buffer for this com port already created + // we use that + strips_to_data_buffer* BufferSelected = 0; + for (strips_to_data_buffer* At = BuffersNeededHead; + At!= 0; + At = At->Next) + { + if (StringsEqual(At->ComPort, StripAt.UARTAddr.ComPort.ConstString)) + { + BufferSelected = At; + break; + } + } + + // if no existing buffer for this com port + // create a new one + if (!BufferSelected) + { + BufferSelected = PushStruct(Transient, strips_to_data_buffer); + *BufferSelected = {}; + BufferSelected->ComPort = StripAt.UARTAddr.ComPort.ConstString; + // we don't know at this point how many indices per + // com port so just make enough room to fit all the strips + // if necessary + BufferSelected->StripIndicesCountMax = Assembly.StripCount; + BufferSelected->StripIndices = PushArray(Transient, u32, BufferSelected->StripIndicesCountMax); + BufferSelected->LedCount = 0; + BufferSelected->Next = 0; + + SLLPushOrInit(BuffersNeededHead, BuffersNeededTail, BufferSelected); + } + + Assert(BufferSelected->StripIndicesCount < BufferSelected->StripIndicesCountMax); + u32 Index = BufferSelected->StripIndicesCount++; + BufferSelected->StripIndices[Index] = StripIdx; + BufferSelected->LedCount += StripAt.LedCount; } - UART_DrawAll_Create(&WriteCursor); + for (strips_to_data_buffer* At = BuffersNeededHead; + At!= 0; + At = At->Next) + { + u32 TotalBufferSize = MessageBaseSize * Assembly.StripCount; // SetChannelBuffer messages + TotalBufferSize += MessageBaseSize; // DrawAll message + TotalBufferSize += ChannelSettings.ElementsCount * At->LedCount; // pixels * channels per pixel + + addressed_data_buffer* Buffer = AddressedDataBufferList_Push(Output, TotalBufferSize); + gs_const_string ComPort = At->ComPort; + AddressedDataBuffer_SetCOMPort(Buffer, ComPort); + + gs_memory_cursor WriteCursor = CreateMemoryCursor(Buffer->Data); + + for (u32 i = 0; i < At->StripIndicesCount; i++) + { + u32 StripIdx = At->StripIndices[i]; + v2_strip StripAt = Assembly.Strips[StripIdx]; + + ChannelSettings.PixelsCount = StripAt.LedCount; + UART_SetChannelBuffer_Create(&WriteCursor, ChannelSettings, StripAt, *LedBuffer); + } + + UART_DrawAll_Create(&WriteCursor); + } } } diff --git a/src/app/foldhaus_app.cpp b/src/app/foldhaus_app.cpp index 09b526c..900f228 100644 --- a/src/app/foldhaus_app.cpp +++ b/src/app/foldhaus_app.cpp @@ -25,6 +25,7 @@ ClearAndPushPatterns(animation_pattern_array* Patterns) Patterns_PushPattern(Patterns, Pattern_Spots); Patterns_PushPattern(Patterns, Pattern_LighthouseRainbow); Patterns_PushPattern(Patterns, Pattern_SmoothGrowRainbow); + Patterns_PushPattern(Patterns, Pattern_GrowAndFade); } RELOAD_STATIC_DATA(ReloadStaticData) @@ -133,16 +134,20 @@ UPDATE_AND_RENDER(UpdateAndRender) State->Assemblies, &State->LedSystem, State->Patterns, - State->Transient); + State->Transient, + State->UserData.Memory); } + AssemblyDebug_OverrideOutput(State->AssemblyDebugState, + State->Assemblies, + State->LedSystem); // NOTE(pjs): Building data buffers to be sent out to the sculpture // This array is used on the platform side to actually send the information assembly_array SACNAssemblies = AssemblyArray_Filter(State->Assemblies, AssemblyFilter_OutputsViaSACN, State->Transient); assembly_array UARTAssemblies = AssemblyArray_Filter(State->Assemblies, AssemblyFilter_OutputsViaUART, State->Transient); SACN_BuildOutputData(&State->SACN, OutputData, SACNAssemblies, &State->LedSystem); - UART_BuildOutputData(OutputData, UARTAssemblies, &State->LedSystem); + UART_BuildOutputData(OutputData, UARTAssemblies, &State->LedSystem, State->Transient); Editor_Render(State, Context, RenderBuffer); } diff --git a/src/app/foldhaus_app.h b/src/app/foldhaus_app.h index 7f4d380..af5b98e 100644 --- a/src/app/foldhaus_app.h +++ b/src/app/foldhaus_app.h @@ -19,6 +19,7 @@ #include "engine/assembly/foldhaus_assembly.h" #include "engine/assembly/foldhaus_assembly_parser.cpp" +#include "engine/assembly/foldhaus_assembly_debug.h" #include "engine/sacn/foldhaus_sacn.h" #include "engine/uart/foldhaus_uart.h" @@ -51,6 +52,7 @@ struct app_state streaming_acn SACN; led_system LedSystem; assembly_array Assemblies; + assembly_debug_state AssemblyDebugState; animation_system AnimationSystem; event_log* GlobalLog; animation_pattern_array Patterns; @@ -65,411 +67,17 @@ struct app_state ui_interface Interface; panel_system PanelSystem; panel* HotPanel; + + // User Space + // + gs_data UserData; }; internal void OpenColorPicker(app_state* State, v4* Address); #include "engine/assembly/foldhaus_assembly.cpp" -// BEGIN TEMPORARY PATTERNS -internal void -TestPatternOne(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient) -{ - led_strip_list BlumenStrips = AssemblyStripsGetWithTagValue(Assembly, ConstString("assembly"), ConstString("Blumen Lumen"), Transient); - led_strip_list RadiaStrips = AssemblyStripsGetWithTagValue(Assembly, ConstString("assembly"), ConstString("Radialumia"), Transient); - - for (u32 i = 0; i < BlumenStrips.Count; i++) - { - u32 StripIndex = BlumenStrips.StripIndices[i]; - v2_strip StripAt = Assembly.Strips[StripIndex]; - - for (u32 j = 0; j < StripAt.LedCount; j++) - { - u32 LedIndex = StripAt.LedLUT[j]; - Leds->Colors[LedIndex] = { 255, 0, 0 }; - - } - } - - for (u32 i = 0; i < RadiaStrips.Count; i++) - { - u32 StripIndex = RadiaStrips.StripIndices[i]; - v2_strip StripAt = Assembly.Strips[StripIndex]; - - for (u32 j = 0; j < StripAt.LedCount; j++) - { - u32 LedIndex = StripAt.LedLUT[j]; - Leds->Colors[LedIndex] = { 0, 255, 0 }; - } - } -#if 0 - for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) - { - v4 LedPosition = Leds->Positions[LedIndex]; - float PercentX = RemapClampedR32(LedPosition.x, -150.0f, 150.0f, 0.0f, 1.0f); - float PercentY = RemapClampedR32(LedPosition.y, -150.0f, 150.0f, 0.0f, 1.0f); - Leds->Colors[LedIndex].R = (u8)(PercentX * 255); - Leds->Colors[LedIndex].G = (u8)(PercentY * 255); - } -#endif - -} - -internal void -TestPatternTwo(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient) -{ - r32 PeriodicTime = (Time / PiR32) * 2; - - r32 ZeroOneSin = (SinR32(PeriodicTime) * .5f) + .5f; - r32 ZeroOneCos = (CosR32(PeriodicTime) * .5f) + .5f; - pixel Color = { (u8)(ZeroOneSin * 255), 0, (u8)(ZeroOneCos * 255) }; - - v4 Center = v4{0, 0, 0, 1}; - r32 ThetaZ = Time / 2; - v4 Normal = v4{CosR32(ThetaZ), 0, SinR32(ThetaZ), 0}; // NOTE(Peter): dont' need to normalize. Should always be 1 - v4 Right = V4Cross(Normal, v4{0, 1, 0, 0}); - - v4 FrontCenter = Center + (Normal * 25); - v4 BackCenter = Center - (Normal * 25); - - r32 OuterRadiusSquared = 1000000; - r32 InnerRadiusSquared = 0; - - for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) - { - v4 Position = Leds->Positions[LedIndex]; - - v4 ToFront = Position + FrontCenter; - v4 ToBack = Position + BackCenter; - - r32 ToFrontDotNormal = V4Dot(ToFront, Normal); - r32 ToBackDotNormal = V4Dot(ToBack, Normal); - - ToFrontDotNormal = Clamp01(ToFrontDotNormal * 1000); - ToBackDotNormal = Clamp01(ToBackDotNormal * 1000); - - r32 SqDistToCenter = V4MagSquared(Position); - if (SqDistToCenter < OuterRadiusSquared && SqDistToCenter > InnerRadiusSquared) - { - if (XOR(ToFrontDotNormal > 0, ToBackDotNormal > 0)) - { - Leds->Colors[LedIndex] = Color; - } - else - { - //Leds->Colors[LedIndex] = {}; - } - } - else - { - //Leds->Colors[LedIndex] = {}; - } - } -} - -internal void -TestPatternThree(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient) -{ - v4 GreenCenter = v4{0, 0, 150, 1}; - r32 GreenRadius = Abs(SinR32(Time)) * 200; - - v4 TealCenter = v4{0, 0, 150, 1}; - r32 TealRadius = Abs(SinR32(Time + 1.5)) * 200; - - r32 FadeDist = 35; - - - for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) - { - v4 LedPosition = Leds->Positions[LedIndex]; - u8 Red = 0; - u8 Green = 0; - u8 Blue = 0; - - r32 GreenDist = Abs(V4Mag(LedPosition - GreenCenter) - GreenRadius); - r32 GreenBrightness = Clamp(0.f, FadeDist - Abs(GreenDist), FadeDist); - Green = (u8)(GreenBrightness * 255); - - r32 TealDist = Abs(V4Mag(LedPosition - TealCenter) - TealRadius); - r32 TealBrightness = Clamp(0.f, FadeDist - Abs(TealDist), FadeDist); - Red = (u8)(TealBrightness * 255); - Blue = (u8)(TealBrightness * 255); - - Leds->Colors[LedIndex].R = Red; - Leds->Colors[LedIndex].B = Green; - Leds->Colors[LedIndex].G = Green; - } -} - -v4 HSVToRGB (v4 In) -{ - float Hue = In.x; - /* -while (Hue > 360.0f) { Hue -= 360.0f; } - while (Hue < 0.0f) { Hue += 360.0f; } - */ - Hue = ModR32(Hue, 360.0f); - if (Hue < 0) { Hue += 360.0f; } - if (Hue == MinR32) { Hue = 0; } - if (Hue == MaxR32) { Hue = 360; } - Assert(Hue >= 0 && Hue < 360); - - float Sat = In.y; - float Value = In.z; - - float hh, p, q, t, ff; - long i; - v4 Result = {}; - Result.a = In.a; - - if(Sat <= 0.0f) { // < is bogus, just shuts up warnings - Result.r = Value; - Result.g = Value; - Result.b = Value; - return Result; - } - hh = Hue; - if(hh >= 360.0f) hh = 0.0f; - hh /= 60.0f; - i = (long)hh; - ff = hh - i; - p = Value * (1.0f - Sat); - q = Value * (1.0f - (Sat * ff)); - t = Value * (1.0f - (Sat * (1.0f - ff))); - - switch(i) { - case 0: - {Result.r = Value; - Result.g = t; - Result.b = p; - }break; - - case 1: - { - Result.r = q; - Result.g = Value; - Result.b = p; - }break; - - case 2: - { - Result.r = p; - Result.g = Value; - Result.b = t; - }break; - - case 3: - { - Result.r = p; - Result.g = q; - Result.b = Value; - }break; - - case 4: - { - Result.r = t; - Result.g = p; - Result.b = Value; - }break; - - case 5: - default: - { - Result.r = Value; - Result.g = p; - Result.b = q; - }break; - } - - return Result; -} - -internal void -Pattern_HueShift(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient) -{ - r32 Height = SinR32(Time) * 25; - - r32 CycleLength = 5.0f; - r32 CycleProgress = FractR32(Time / CycleLength); - r32 CycleBlend = (SinR32(Time) * .5f) + .5f; - - for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) - { - v4 Pos = Leds->Positions[LedIndex]; - r32 Dist = Pos.y - Height; - - v4 HSV = { (ModR32(Dist, 25) / 25) * 360, 1, 1, 1 }; - v4 RGB = HSVToRGB(HSV); - - u8 R = (u8)(RGB.x * 255); - u8 G = (u8)(RGB.y * 255); - u8 B = (u8)(RGB.z * 255); - - Leds->Colors[LedIndex].R = R; - Leds->Colors[LedIndex].G = G; - Leds->Colors[LedIndex].B = B; - } -} - -internal pixel -V4ToRGBPixel(v4 C) -{ - pixel Result = {}; - Result.R = (u8)(C.x * 255); - Result.G = (u8)(C.y * 255); - Result.B = (u8)(C.z * 255); - return Result; -} - -internal void -Pattern_HueFade(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient) -{ - r32 HueBase = ModR32(Time * 50, 360); - - r32 CycleLength = 5.0f; - r32 CycleProgress = FractR32(Time / CycleLength); - r32 CycleBlend = (SinR32(Time) * .5f) + .5f; - - for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) - { - v4 Pos = Leds->Positions[LedIndex]; - r32 Hue = HueBase + Pos.y + Pos.x; - v4 HSV = { Hue, 1, 1, 1 }; - v4 RGB = HSVToRGB(HSV); - - Leds->Colors[LedIndex] = V4ToRGBPixel(RGB); - } -} - -internal void -Pattern_AllGreen(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient) -{ - for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) - { - u32 I = LedIndex + 1; - Leds->Colors[LedIndex] = {}; - if (I % 3 == 0) - { - Leds->Colors[LedIndex].R = 255; - } - else if (I % 3 == 1) - { - Leds->Colors[LedIndex].G = 255; - } - else if (I % 3 == 2) - { - Leds->Colors[LedIndex].B = 255; - } - - } -} - -internal r32 -PatternHash(r32 Seed) -{ - return FractR32(Seed * 17.0 * FractR32(Seed * 0.3183099)); -} - -internal void -Pattern_Spots(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient) -{ - pixel ColorA = { 0, 255, 255 }; - pixel ColorB = { 255, 0, 255 }; - - r32 Speed = .5f; - Time *= Speed; - r32 ScaleA = 2 * SinR32(Time / 5); - r32 ScaleB = 2.4f * CosR32(Time / 2.5f); - for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) - { - v4 P = Leds->Positions[LedIndex]; - r32 V = P.y; - r32 Noise = .3f * PatternHash(V); - r32 ThetaY = (Leds->Positions[LedIndex].y / 10) + Time + Noise; - r32 ThetaX = (Leds->Positions[LedIndex].x / 13) + Time + Noise; - r32 Fade = (ScaleA * SinR32(ThetaY)) + (ScaleB * CosR32(3 * ThetaX)); - Fade = RemapClampedR32(Fade, -1, 1, 0, 1); - - Leds->Colors[LedIndex].R = (u8)LerpR32(Fade, ColorA.R, ColorB.R); - Leds->Colors[LedIndex].G = (u8)LerpR32(Fade, ColorA.G, ColorB.G); - Leds->Colors[LedIndex].B = (u8)LerpR32(Fade, ColorA.B, ColorB.B); - } -} - -internal void -Pattern_LighthouseRainbow(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient) -{ - v2 RefVector = V2Normalize(v2{ SinR32(Time), CosR32(Time) }); - for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) - { - v2 Vector = v2{ - Leds->Positions[LedIndex].x, - Leds->Positions[LedIndex].z - }; - Vector = V2Normalize(Vector); - - r32 Angle = V2Dot(RefVector, Vector); - -#if 0 - r32 Fade = RemapR32(Angle, -1, 1, 0, 1); - Leds->Colors[LedIndex].R = (u8)(Fade * 255); - Leds->Colors[LedIndex].G = (u8)(Fade * 255); - Leds->Colors[LedIndex].B = (u8)(Fade * 255); -#endif - - v4 HSV = { (Angle * 30) + (Time * 10) + Leds->Positions[LedIndex].y, 1, 1, 1 }; - v4 RGB = HSVToRGB(HSV); - - Leds->Colors[LedIndex] = V4ToRGBPixel(RGB); - } -} - -internal r32 -Smoothstep(r32 T) -{ - r32 Result = (T * T * (3 - (2 * T))); - return Result; -} - -internal void -Pattern_SmoothGrowRainbow(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient) -{ - r32 FillCycleTime = ModR32(Time, 7.0f) / 7.0f; - r32 ColorCycleTime = ModR32(Time, 21.0f) / 21.0f; - - //v4 HSV = { ColorCycleTime * 360, 1, 1, 1 }; - //v4 RGB0 = HSVToRGB(HSV); - //HSV.x += ; - //v4 RGB1 = HSVToRGB(HSV); - - v4 HSV = { 0, 1, 1, 1 }; - for (u32 s = 0; s < Assembly.StripCount; s++) - { - v2_strip Strip = Assembly.Strips[s]; - - v4 RGB0 = HSVToRGB(HSV); - for (u32 l = 0; l < Strip.LedCount; l++) - { - u32 LedIndex = Strip.LedLUT[l]; - Leds->Colors[LedIndex] = V4ToRGBPixel(RGB0); - } - - HSV.x += 15; - } - -#if 0 - for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) - { - v4 P = Leds->Positions[LedIndex]; - - Leds->Colors[LedIndex] = V4ToRGBPixel(RGB0); - - - } -#endif -} - -// END TEMPORARY PATTERNS +#include "patterns/blumen_patterns.h" internal void EndCurrentOperationMode(app_state* State) @@ -485,6 +93,7 @@ EndCurrentOperationMode(app_state* State) #include "editor/panels/foldhaus_panel_dmx_view.h" #include "editor/panels/foldhaus_panel_animation_timeline.h" #include "editor/panels/foldhaus_panel_hierarchy.h" +#include "editor/panels/foldhaus_panel_assembly_debug.h" #include "editor/panels/foldhaus_panel_types.cpp" diff --git a/src/app/foldhaus_platform.h b/src/app/foldhaus_platform.h index d40a71a..5778c7f 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 0 +#define PLATFORM_THREAD_COUNT 3 RESET_WORK_QUEUE(ResetWorkQueue) { diff --git a/src/app/interface.h b/src/app/interface.h index d112c1c..3fada9f 100644 --- a/src/app/interface.h +++ b/src/app/interface.h @@ -1513,11 +1513,35 @@ ui_EndMousePopup(ui_interface* Interface) } // +internal void +ui_BeginLabelRow(ui_interface* Interface, gs_string Label, u32 Count = 2) +{ + ui_BeginRow(Interface, Count); + ui_Label(Interface, Label); +} + +internal bool +ui_LabeledToggle(ui_interface* Interface, gs_string Label, bool Value) +{ + ui_BeginLabelRow(Interface, Label); + bool Result = ui_Toggle(Interface, Label, Value); + ui_EndRow(Interface); + return Result; +} + +internal u64 +ui_LabeledTextEntryU64(ui_interface* Interface, gs_string Label, u32 Value) +{ + ui_BeginLabelRow(Interface, Label); + u64 Result = ui_TextEntryU64(Interface, Label, Value); + ui_EndRow(Interface); + return Result; +} + internal bool ui_BeginLabeledDropdown(ui_interface* Interface, gs_string Label, gs_string DropdownValue) { - ui_BeginRow(Interface, 2); - ui_Label(Interface, Label); + ui_BeginLabelRow(Interface, Label); return ui_BeginDropdown(Interface, DropdownValue); } diff --git a/src/app/patterns/blumen_patterns.h b/src/app/patterns/blumen_patterns.h new file mode 100644 index 0000000..a8940f9 --- /dev/null +++ b/src/app/patterns/blumen_patterns.h @@ -0,0 +1,395 @@ +// +// File: blumen_patterns.h +// Author: Peter Slattery +// Creation Date: 2021-01-15 +// +#ifndef BLUMEN_PATTERNS_H + +internal void +TestPatternOne(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +{ + led_strip_list BlumenStrips = AssemblyStripsGetWithTagValue(Assembly, ConstString("assembly"), ConstString("Blumen Lumen"), Transient); + led_strip_list RadiaStrips = AssemblyStripsGetWithTagValue(Assembly, ConstString("assembly"), ConstString("Radialumia"), Transient); + + for (u32 i = 0; i < BlumenStrips.Count; i++) + { + u32 StripIndex = BlumenStrips.StripIndices[i]; + v2_strip StripAt = Assembly.Strips[StripIndex]; + + for (u32 j = 0; j < StripAt.LedCount; j++) + { + u32 LedIndex = StripAt.LedLUT[j]; + Leds->Colors[LedIndex] = { 255, 0, 0 }; + + } + } + + for (u32 i = 0; i < RadiaStrips.Count; i++) + { + u32 StripIndex = RadiaStrips.StripIndices[i]; + v2_strip StripAt = Assembly.Strips[StripIndex]; + + for (u32 j = 0; j < StripAt.LedCount; j++) + { + u32 LedIndex = StripAt.LedLUT[j]; + Leds->Colors[LedIndex] = { 0, 255, 0 }; + } + } +} + +internal void +TestPatternTwo(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +{ + r32 PeriodicTime = (Time / PiR32) * 2; + + r32 ZeroOneSin = (SinR32(PeriodicTime) * .5f) + .5f; + r32 ZeroOneCos = (CosR32(PeriodicTime) * .5f) + .5f; + pixel Color = { (u8)(ZeroOneSin * 255), 0, (u8)(ZeroOneCos * 255) }; + + v4 Center = v4{0, 0, 0, 1}; + r32 ThetaZ = Time / 2; + v4 Normal = v4{CosR32(ThetaZ), 0, SinR32(ThetaZ), 0}; // NOTE(Peter): dont' need to normalize. Should always be 1 + v4 Right = V4Cross(Normal, v4{0, 1, 0, 0}); + + v4 FrontCenter = Center + (Normal * 25); + v4 BackCenter = Center - (Normal * 25); + + r32 OuterRadiusSquared = 1000000; + r32 InnerRadiusSquared = 0; + + for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) + { + v4 Position = Leds->Positions[LedIndex]; + + v4 ToFront = Position + FrontCenter; + v4 ToBack = Position + BackCenter; + + r32 ToFrontDotNormal = V4Dot(ToFront, Normal); + r32 ToBackDotNormal = V4Dot(ToBack, Normal); + + ToFrontDotNormal = Clamp01(ToFrontDotNormal * 1000); + ToBackDotNormal = Clamp01(ToBackDotNormal * 1000); + + r32 SqDistToCenter = V4MagSquared(Position); + if (SqDistToCenter < OuterRadiusSquared && SqDistToCenter > InnerRadiusSquared) + { + if (XOR(ToFrontDotNormal > 0, ToBackDotNormal > 0)) + { + Leds->Colors[LedIndex] = Color; + } + else + { + //Leds->Colors[LedIndex] = {}; + } + } + else + { + //Leds->Colors[LedIndex] = {}; + } + } +} + +internal void +TestPatternThree(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +{ + v4 GreenCenter = v4{0, 0, 150, 1}; + r32 GreenRadius = Abs(SinR32(Time)) * 200; + + v4 TealCenter = v4{0, 0, 150, 1}; + r32 TealRadius = Abs(SinR32(Time + 1.5)) * 200; + + r32 FadeDist = 35; + + + for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) + { + v4 LedPosition = Leds->Positions[LedIndex]; + u8 Red = 0; + u8 Green = 0; + u8 Blue = 0; + + r32 GreenDist = Abs(V4Mag(LedPosition - GreenCenter) - GreenRadius); + r32 GreenBrightness = Clamp(0.f, FadeDist - Abs(GreenDist), FadeDist); + Green = (u8)(GreenBrightness * 255); + + r32 TealDist = Abs(V4Mag(LedPosition - TealCenter) - TealRadius); + r32 TealBrightness = Clamp(0.f, FadeDist - Abs(TealDist), FadeDist); + Red = (u8)(TealBrightness * 255); + Blue = (u8)(TealBrightness * 255); + + Leds->Colors[LedIndex].R = Red; + Leds->Colors[LedIndex].B = Green; + Leds->Colors[LedIndex].G = Green; + } +} + +v4 HSVToRGB (v4 In) +{ + float Hue = In.x; + /* +while (Hue > 360.0f) { Hue -= 360.0f; } + while (Hue < 0.0f) { Hue += 360.0f; } + */ + Hue = ModR32(Hue, 360.0f); + if (Hue < 0) { Hue += 360.0f; } + if (Hue == MinR32) { Hue = 0; } + if (Hue == MaxR32) { Hue = 360; } + Assert(Hue >= 0 && Hue < 360); + + float Sat = In.y; + float Value = In.z; + + float hh, p, q, t, ff; + long i; + v4 Result = {}; + Result.a = In.a; + + if(Sat <= 0.0f) { // < is bogus, just shuts up warnings + Result.r = Value; + Result.g = Value; + Result.b = Value; + return Result; + } + hh = Hue; + if(hh >= 360.0f) hh = 0.0f; + hh /= 60.0f; + i = (long)hh; + ff = hh - i; + p = Value * (1.0f - Sat); + q = Value * (1.0f - (Sat * ff)); + t = Value * (1.0f - (Sat * (1.0f - ff))); + + switch(i) { + case 0: + {Result.r = Value; + Result.g = t; + Result.b = p; + }break; + + case 1: + { + Result.r = q; + Result.g = Value; + Result.b = p; + }break; + + case 2: + { + Result.r = p; + Result.g = Value; + Result.b = t; + }break; + + case 3: + { + Result.r = p; + Result.g = q; + Result.b = Value; + }break; + + case 4: + { + Result.r = t; + Result.g = p; + Result.b = Value; + }break; + + case 5: + default: + { + Result.r = Value; + Result.g = p; + Result.b = q; + }break; + } + + return Result; +} + +internal void +Pattern_HueShift(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +{ + r32 Height = SinR32(Time) * 25; + + r32 CycleLength = 5.0f; + r32 CycleProgress = FractR32(Time / CycleLength); + r32 CycleBlend = (SinR32(Time) * .5f) + .5f; + + for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) + { + v4 Pos = Leds->Positions[LedIndex]; + r32 Dist = Pos.y - Height; + + v4 HSV = { (ModR32(Dist, 25) / 25) * 360, 1, 1, 1 }; + v4 RGB = HSVToRGB(HSV); + + u8 R = (u8)(RGB.x * 255); + u8 G = (u8)(RGB.y * 255); + u8 B = (u8)(RGB.z * 255); + + Leds->Colors[LedIndex].R = R; + Leds->Colors[LedIndex].G = G; + Leds->Colors[LedIndex].B = B; + } +} + +internal pixel +V4ToRGBPixel(v4 C) +{ + pixel Result = {}; + Result.R = (u8)(C.x * 255); + Result.G = (u8)(C.y * 255); + Result.B = (u8)(C.z * 255); + return Result; +} + +internal void +Pattern_HueFade(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +{ + r32 HueBase = ModR32(Time * 50, 360); + + r32 CycleLength = 5.0f; + r32 CycleProgress = FractR32(Time / CycleLength); + r32 CycleBlend = (SinR32(Time) * .5f) + .5f; + + for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) + { + v4 Pos = Leds->Positions[LedIndex]; + r32 Hue = HueBase + Pos.y + Pos.x; + v4 HSV = { Hue, 1, 1, 1 }; + v4 RGB = HSVToRGB(HSV); + + Leds->Colors[LedIndex] = V4ToRGBPixel(RGB); + } +} + +internal void +Pattern_AllGreen(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +{ + for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) + { + u32 I = LedIndex + 1; + Leds->Colors[LedIndex] = {}; + if (I % 3 == 0) + { + Leds->Colors[LedIndex].R = 255; + } + else if (I % 3 == 1) + { + Leds->Colors[LedIndex].G = 255; + } + else if (I % 3 == 2) + { + Leds->Colors[LedIndex].B = 255; + } + + } +} + +internal r32 +PatternHash(r32 Seed) +{ + return FractR32(Seed * 17.0 * FractR32(Seed * 0.3183099)); +} + +internal void +Pattern_Spots(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +{ + pixel ColorA = { 0, 255, 255 }; + pixel ColorB = { 255, 0, 255 }; + + r32 Speed = .5f; + Time *= Speed; + r32 ScaleA = 2 * SinR32(Time / 5); + r32 ScaleB = 2.4f * CosR32(Time / 2.5f); + for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) + { + v4 P = Leds->Positions[LedIndex]; + r32 V = P.y; + r32 Noise = .3f * PatternHash(V); + r32 ThetaY = (Leds->Positions[LedIndex].y / 10) + Time + Noise; + r32 ThetaX = (Leds->Positions[LedIndex].x / 13) + Time + Noise; + r32 Fade = (ScaleA * SinR32(ThetaY)) + (ScaleB * CosR32(3 * ThetaX)); + Fade = RemapClampedR32(Fade, -1, 1, 0, 1); + + Leds->Colors[LedIndex].R = (u8)LerpR32(Fade, ColorA.R, ColorB.R); + Leds->Colors[LedIndex].G = (u8)LerpR32(Fade, ColorA.G, ColorB.G); + Leds->Colors[LedIndex].B = (u8)LerpR32(Fade, ColorA.B, ColorB.B); + } +} + +internal void +Pattern_LighthouseRainbow(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +{ + v2 RefVector = V2Normalize(v2{ SinR32(Time), CosR32(Time) }); + for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) + { + v2 Vector = v2{ + Leds->Positions[LedIndex].x, + Leds->Positions[LedIndex].z + }; + Vector = V2Normalize(Vector); + + r32 Angle = V2Dot(RefVector, Vector); + + v4 HSV = { (Angle * 30) + (Time * 10) + Leds->Positions[LedIndex].y, 1, 1, 1 }; + v4 RGB = HSVToRGB(HSV); + + Leds->Colors[LedIndex] = V4ToRGBPixel(RGB); + } +} + +internal r32 +Smoothstep(r32 T) +{ + r32 Result = (T * T * (3 - (2 * T))); + return Result; +} + +internal void +Pattern_SmoothGrowRainbow(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +{ + r32 FillCycleTime = ModR32(Time, 7.0f) / 7.0f; + r32 ColorCycleTime = ModR32(Time, 21.0f) / 21.0f; + + v4 HSV = { 0, 1, 1, 1 }; + for (u32 s = 0; s < Assembly.StripCount; s++) + { + v2_strip Strip = Assembly.Strips[s]; + + v4 RGB0 = HSVToRGB(HSV); + for (u32 l = 0; l < Strip.LedCount; l++) + { + u32 LedIndex = Strip.LedLUT[l]; + Leds->Colors[LedIndex] = V4ToRGBPixel(RGB0); + } + + HSV.x += 15; + } +} + +internal void +Pattern_GrowAndFade(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +{ + r32 PercentCycle = ModR32(Time, 10) / 10; + v4 HSV = { PercentCycle * 360, 1, 1, 1 }; + v4 RGB = HSVToRGB(HSV); + + r32 RefHeight = -100 + (Smoothstep(PercentCycle * 1.4f) * 400); + r32 RefBrightness = 1.0f - Smoothstep(PercentCycle); + + for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) + { + v4 P = Leds->Positions[LedIndex]; + + v4 RgbFaded = v4{}; + if (P.y < RefHeight) + { + RgbFaded = RGB * RefBrightness; + } + Leds->Colors[LedIndex] = V4ToRGBPixel(RgbFaded); + } +} + +#define BLUMEN_PATTERNS_H +#endif // BLUMEN_PATTERNS_H \ No newline at end of file diff --git a/src/app/platform_win32/win32_foldhaus.cpp b/src/app/platform_win32/win32_foldhaus.cpp index 47b625a..1e1dd7b 100644 --- a/src/app/platform_win32/win32_foldhaus.cpp +++ b/src/app/platform_win32/win32_foldhaus.cpp @@ -371,64 +371,56 @@ Win32Realloc(u8* Buf, s32 OldSize, s32 NewSize) } internal void -Win32_SendAddressedDataBuffers(gs_thread_context Context, addressed_data_buffer_list OutputData) +Win32_SendAddressedDataBuffer(gs_thread_context Context, addressed_data_buffer* BufferAt) { DEBUG_TRACK_FUNCTION; u32 BuffersSent = 0; u32 DataSizeSent = 0; - for (addressed_data_buffer* BufferAt = OutputData.Root; - BufferAt != 0; - BufferAt = BufferAt->Next) + switch(BufferAt->AddressType) { - switch(BufferAt->AddressType) + case AddressType_NetworkIP: { - case AddressType_NetworkIP: + Win32Socket_SendTo(BufferAt->SendSocket, + BufferAt->V4SendAddress, + BufferAt->SendPort, + (const char*)BufferAt->Memory, + BufferAt->MemorySize, + 0); + }break; + + case AddressType_ComPort: + { + if (BufferAt->ComPort.Length > 0) { - Win32Socket_SendTo(BufferAt->SendSocket, - BufferAt->V4SendAddress, - BufferAt->SendPort, - (const char*)BufferAt->Memory, - BufferAt->MemorySize, - 0); - }break; - - case AddressType_ComPort: - { - if (BufferAt->ComPort.Length > 0) + HANDLE SerialPort = Win32SerialArray_GetOrOpen(BufferAt->ComPort, 2000000, 8, NOPARITY, 1); + if (SerialPort != INVALID_HANDLE_VALUE) { - HANDLE SerialPort = Win32SerialArray_GetOrOpen(BufferAt->ComPort, 2000000, 8, NOPARITY, 1); - if (SerialPort != INVALID_HANDLE_VALUE) + if (Win32SerialPort_Write(SerialPort, BufferAt->Data)) { - if (Win32SerialPort_Write(SerialPort, BufferAt->Data)) - { - BuffersSent += 1; - DataSizeSent += BufferAt->Data.Size; - } + BuffersSent += 1; + DataSizeSent += BufferAt->Data.Size; } } - else - { - OutputDebugStringA("Skipping data buffer because its COM Port isn't set"); - } - }break; - - InvalidDefaultCase; - } + } + else + { +#if 0 + OutputDebugStringA("Skipping data buffer because its COM Port isn't set"); +#endif + } + }break; + + InvalidDefaultCase; } - - gs_string OutputStr = AllocatorAllocString(Context.Allocator, 256); - PrintF(&OutputStr, "Buffers Sent: %d | Size Sent: %d\n", BuffersSent, DataSizeSent); - NullTerminate(&OutputStr); - OutputDebugStringA(OutputStr.Str); } internal void -Win32_SendAddressedDataBuffers_Job(gs_thread_context Context, gs_data Arg) +Win32_SendAddressedDataBuffer_Job(gs_thread_context Context, gs_data Arg) { - addressed_data_buffer_list* OutputData = (addressed_data_buffer_list*)Arg.Memory; - Win32_SendAddressedDataBuffers(Context, *OutputData); + addressed_data_buffer* OutputData = (addressed_data_buffer*)Arg.Memory; + Win32_SendAddressedDataBuffer(Context, OutputData); } #pragma pack(push, 1) @@ -571,10 +563,15 @@ WinMain ( if (true) { - gs_data ProcArg = {}; - ProcArg.Memory = (u8*)&OutputData; - ProcArg.Size = sizeof(OutputData); - Win32PushWorkOnQueue(&Win32WorkQueue.WorkQueue, Win32_SendAddressedDataBuffers_Job, ProcArg, ConstString("Send UART Data")); + for (addressed_data_buffer* At = OutputData.Root; + At != 0; + At = At->Next) + { + gs_data ProcArg = {}; + ProcArg.Memory = (u8*)At; + ProcArg.Size = sizeof(addressed_data_buffer); + Win32PushWorkOnQueue(&Win32WorkQueue.WorkQueue, Win32_SendAddressedDataBuffer_Job, ProcArg, ConstString("Send UART Data")); + } } Mouse_Advance(&Context); @@ -583,7 +580,7 @@ WinMain ( SwapBuffers(DeviceContext); ReleaseDC(MainWindow.Handle, DeviceContext); - //Win32DoQueueWorkUntilDone(&WorkQueue, Context.ThreadContext); + Win32DoQueueWorkUntilDone(&Win32WorkQueue.WorkQueue, Context.ThreadContext); s64 FinishedWorkTime = GetWallClock(); r32 SecondsElapsed = GetSecondsElapsed(LastFrameEnd, FinishedWorkTime, PerformanceCountFrequency); diff --git a/src/sculpture_gen/gen_blumen_lumen.cpp b/src/sculpture_gen/gen_blumen_lumen.cpp index b269cb2..a1fb63f 100644 --- a/src/sculpture_gen/gen_blumen_lumen.cpp +++ b/src/sculpture_gen/gen_blumen_lumen.cpp @@ -175,7 +175,7 @@ int main(int ArgCount, char** Args) 100, v3{0, 0, 0}, 69, - ComPort); + ""); u32 StemChannels[] = { FSC(2, 1), FSC(2, 2), FSC(2, 3), FSC(2, 4), FSC(2, 5), FSC(2, 6) }; u32 BloomOuterChannels[] = { FSC(1, 0), FSC(1, 1), FSC(1, 2), FSC(1, 3), FSC(1, 4), FSC(1, 5), FSC(1, 6), FSC(1, 7), FSC(2, 0) }; @@ -189,23 +189,24 @@ int main(int ArgCount, char** Args) F0.BloomInnerChannels = BloomInnerChannels; BuildFlower(&OutputBuffer, F0); - /* flower_desc F1 = {}; F1.Pos = v3{0, 0, 0}; + F1.ComPort = "\\\\.\\COM9"; F1.FlowerTagValue = "center"; F1.StemChannels = StemChannels; F1.BloomInnerChannels = BloomInnerChannels; F1.BloomOuterChannels = BloomOuterChannels; BuildFlower(&OutputBuffer, F1); - flower_desc F2 = {}; - F2.Pos = v3{1, 0, 0}; - F2.FlowerTagValue = "right"; - F2.StemChannels = StemChannels; - F2.BloomInnerChannels = BloomInnerChannels; - F2.BloomOuterChannels = BloomOuterChannels; - BuildFlower(&OutputBuffer, F2); - */ + /* + flower_desc F2 = {}; + F2.Pos = v3{1, 0, 0}; + F2.FlowerTagValue = "right"; + F2.StemChannels = StemChannels; + F2.BloomInnerChannels = BloomInnerChannels; + F2.BloomOuterChannels = BloomOuterChannels; + BuildFlower(&OutputBuffer, F2); + */ printf("%.*s\n", (u32)OutputBuffer.Length, OutputBuffer.Str); diff --git a/src/sculpture_gen/sculpture_gen.h b/src/sculpture_gen/sculpture_gen.h index 2b2a702..bbba18c 100644 --- a/src/sculpture_gen/sculpture_gen.h +++ b/src/sculpture_gen/sculpture_gen.h @@ -28,7 +28,11 @@ WriteAssemblyUARTOpen(gs_string* Buffer, char* Name, u32 Scale, v3 Center, u32 S WriteIndented(Buffer, 0, "assembly_center: (%f, %f, %f);\n", Center.x, Center.y, Center.z); WriteIndented(Buffer, 0, "led_strip_count: %d;\n", StripCount); WriteIndented(Buffer, 0, "output_mode: \"UART\";\n"); - WriteIndented(Buffer, 0, "com_port: \"%s\";\n", ComPort); + + if (ComPort) + { + WriteIndented(Buffer, 0, "com_port: \"%s\";\n", ComPort); + } } internal void diff --git a/test_motor_header.h b/test_motor_header.h new file mode 100644 index 0000000..3a443b3 --- /dev/null +++ b/test_motor_header.h @@ -0,0 +1,19 @@ +// +// File: test_motor_header.h +// Author: Peter Slattery +// Creation Date: 2021-01-14 +// +#ifndef TEST_MOTOR_HEADER_H + +struct +{ + u8 MotorOnePos; + u8 MotorTwoPos; + u8 MotorThreePos; +} typedef packet; + +static packet +UnpackPacket + +#define TEST_MOTOR_HEADER_H +#endif // TEST_MOTOR_HEADER_H \ No newline at end of file diff --git a/test_sound_interface_packet.h b/test_sound_interface_packet.h new file mode 100644 index 0000000..a046c21 --- /dev/null +++ b/test_sound_interface_packet.h @@ -0,0 +1,29 @@ +// +// File: test_sound_interface_packet.h +// Author: Peter Slattery +// Creation Date: 2021-01-14 +// +#ifndef TEST_SOUND_INTERFACE_PACKET_H + +enum selectable_patterns +{ +}; + +typedef struct +{ + u8 PrimaryColor[3]; + u8 SecondaryColor[3]; + u32 PatternIndex; // Set via selectable_patterns + u8 Speed; // +} sound_interface_packet; + +// expects V to be in the range -1:1 +u8 FloatToSpeed (float V) +{ + u8 Result = (u8)(((V + 1) / 2) * 255); + return Result; +} + + +#define TEST_SOUND_INTERFACE_PACKET_H +#endif // TEST_SOUND_INTERFACE_PACKET_H \ No newline at end of file From 35a37930152e8e9ba2f4b18a7fc0b4e35acef6cd Mon Sep 17 00:00:00 2001 From: PS Date: Sat, 16 Jan 2021 16:37:56 -0800 Subject: [PATCH 19/44] more debug functionality. --- .../panels/foldhaus_panel_assembly_debug.h | 52 ++++++- .../editor/panels/foldhaus_panel_profiler.h | 18 +-- src/app/engine/assembly/foldhaus_assembly.cpp | 13 +- src/app/engine/assembly/foldhaus_assembly.h | 21 +++ .../engine/assembly/foldhaus_assembly_debug.h | 137 ++++++++++++++---- src/app/foldhaus_app.cpp | 1 + src/app/interface.h | 13 +- src/sculpture_gen/gen_blumen_lumen.cpp | 69 +++++---- 8 files changed, 233 insertions(+), 91 deletions(-) diff --git a/src/app/editor/panels/foldhaus_panel_assembly_debug.h b/src/app/editor/panels/foldhaus_panel_assembly_debug.h index d118e19..5d07449 100644 --- a/src/app/editor/panels/foldhaus_panel_assembly_debug.h +++ b/src/app/editor/panels/foldhaus_panel_assembly_debug.h @@ -20,6 +20,21 @@ AssemblyDebug_Cleanup(panel* Panel, app_state* State) } +// TODO(pjs): This is really blumen specific +#define FSC(f,c) FlowerStripToChannel((f), (c)) +internal u8 +FlowerStripToChannel(u8 Flower, u8 Channel) +{ + Assert(Flower < 3); + Assert(Channel < 8); + + u8 Result = 0; + Result |= (Flower & 0x03) << 3; + Result |= (Channel & 0x07); + + return Result; +} + GSMetaTag(panel_render); GSMetaTag(panel_type_file_view); internal void @@ -28,11 +43,6 @@ AssemblyDebug_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Ren ui_interface* Interface = &State->Interface; ui_PushLayout(Interface, PanelBounds, LayoutDirection_TopDown, MakeString("Assembly Debug Layout")); - State->AssemblyDebugState.TargetAssembly = ui_LabeledTextEntryU64(Interface, MakeString("Assembly"), State->AssemblyDebugState.TargetAssembly); - - State->AssemblyDebugState.TargetStrip = ui_LabeledTextEntryU64(Interface, MakeString("Strip"), State->AssemblyDebugState.TargetStrip); - - gs_string OverrideStr = MakeString(OverrideTypeStrings[State->AssemblyDebugState.Override]); if (ui_BeginLabeledDropdown(Interface, MakeString("Override"), OverrideStr)) { @@ -44,7 +54,37 @@ AssemblyDebug_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Ren } } } - ui_EndLabeledDropdown(Interface); + + if (State->AssemblyDebugState.Override == ADS_Override_TagWhite || + State->AssemblyDebugState.Override == ADS_Override_TagStripWhite) + { + ui_LabeledTextEntry(Interface, MakeString("Tag Name"), &State->AssemblyDebugState.TagName); + ui_LabeledTextEntry(Interface, MakeString("Tag Value"), &State->AssemblyDebugState.TagValue); + + if (State->AssemblyDebugState.Override == ADS_Override_TagStripWhite) + { + ui_EndLabeledDropdown(Interface); + State->AssemblyDebugState.TargetAssembly = ui_LabeledTextEntryU64(Interface, MakeString("Assembly"), State->AssemblyDebugState.TargetAssembly); + + State->AssemblyDebugState.TargetStrip = ui_LabeledTextEntryU64(Interface, MakeString("Strip"), State->AssemblyDebugState.TargetStrip); + } + } + else if (State->AssemblyDebugState.Override == ADS_Override_ChannelWhite) + { + u64 Board = 0; + u64 Strip = 0; + Board = ui_LabeledTextEntryU64(Interface, MakeString("Board"), Board); + Strip = ui_LabeledTextEntryU64(Interface, MakeString("Strip"), Strip); + + State->AssemblyDebugState.TargetChannel = FSC(Board, Strip); + } + else + { + ui_EndLabeledDropdown(Interface); + State->AssemblyDebugState.TargetAssembly = ui_LabeledTextEntryU64(Interface, MakeString("Assembly"), State->AssemblyDebugState.TargetAssembly); + + State->AssemblyDebugState.TargetStrip = ui_LabeledTextEntryU64(Interface, MakeString("Strip"), State->AssemblyDebugState.TargetStrip); + } } #define FOLDHAUS_PANEL_ASSEMBLY_DEBUG_H diff --git a/src/app/editor/panels/foldhaus_panel_profiler.h b/src/app/editor/panels/foldhaus_panel_profiler.h index a54827e..0af6138 100644 --- a/src/app/editor/panels/foldhaus_panel_profiler.h +++ b/src/app/editor/panels/foldhaus_panel_profiler.h @@ -27,14 +27,6 @@ ProfilerView_Cleanup(panel* Panel, app_state* State) internal void RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_widget* Layout, debug_frame* VisibleFrame, gs_memory_arena* Transient) { - v4 ThreadColors[] = { - v4{.73f, .33f, .83f, 1}, - v4{0, .50f, .50f, 1}, - v4{.83f, 0, 0, 1}, - v4{.33f, .49f, .83f, 1}, - v4{.74f, .40f, .25f, 1}, - }; - rect2 Bounds = ui_LayoutRemaining(*Layout); r32 Width = Rect2Width(Bounds); r32 DepthHeight = 32; @@ -52,6 +44,14 @@ RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_widget* Layout, de r32 ThreadScopeMin = Bounds.Max.y; + //PrintF(&String, "Thread %d", ThreadCalls.ThreadId); + //ui_Label(Interface, String, rect2{ThreadScopeMin); + + r32 Hue = (r32)(t) / (r32)(VisibleFrame->ThreadCount); + Hue += (.5f * (t % 2)); + v4 ThreadHSV = v4{ 360.0f * Hue, .5f, 1.0f, 1.0f }; + v4 ThreadRGB = HSVToRGB(ThreadHSV); + for (s32 i = 0; i < ThreadCalls.Count; i++) { scope_record* Record = ThreadCalls.Calls + i; @@ -75,7 +75,7 @@ RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_widget* Layout, de if (Rect2Width(ScopeBounds) >= 1) { - v4 Color = ThreadColors[t]; + v4 Color = ThreadRGB; if (PointIsInRect(ScopeBounds, Interface->Mouse.Pos)) { Color = GreenV4; diff --git a/src/app/engine/assembly/foldhaus_assembly.cpp b/src/app/engine/assembly/foldhaus_assembly.cpp index e2fd231..fd060d4 100644 --- a/src/app/engine/assembly/foldhaus_assembly.cpp +++ b/src/app/engine/assembly/foldhaus_assembly.cpp @@ -256,18 +256,9 @@ AssemblyStripsGetWithTagValue(assembly Assembly, gs_const_string TagName, gs_con for (u32 StripIndex = 0; StripIndex < Assembly.StripCount; StripIndex++) { v2_strip StripAt = Assembly.Strips[StripIndex]; - for (u32 j = 0; j < StripAt.TagsCount; j++) + if (AssemblyStrip_HasTagValue(StripAt, NameHash, ValueHash)) { - v2_tag TagAt = StripAt.Tags[j]; - if (TagAt.NameHash == NameHash) - { - // NOTE(pjs): We can pass an empty string to the Value parameter, - // and it will match all values of Tag - if (ValueHash == 0 || ValueHash == TagAt.ValueHash) - { - Result.StripIndices[Result.Count++] = StripIndex; - } - } + Result.StripIndices[Result.Count++] = StripIndex; } } diff --git a/src/app/engine/assembly/foldhaus_assembly.h b/src/app/engine/assembly/foldhaus_assembly.h index 90694d1..3378cc5 100644 --- a/src/app/engine/assembly/foldhaus_assembly.h +++ b/src/app/engine/assembly/foldhaus_assembly.h @@ -204,5 +204,26 @@ StripGenData_CountLeds(strip_gen_data Data) return Result; } +internal bool +AssemblyStrip_HasTagValue(v2_strip Strip, u64 NameHash, u64 ValueHash) +{ + bool Result = false; + for (u32 i = 0; i < Strip.TagsCount; i++) + { + v2_tag TagAt = Strip.Tags[i]; + if (TagAt.NameHash == NameHash) + { + // NOTE(pjs): We can pass an empty string to the Value parameter, + // and it will match all values of Tag + if (ValueHash == 0 || ValueHash == TagAt.ValueHash) + { + Result = true; + break; + } + } + } + return Result; +} + #define FOLDHAUS_ASSEMBLY_H #endif // FOLDHAUS_ASSEMBLY_H \ No newline at end of file diff --git a/src/app/engine/assembly/foldhaus_assembly_debug.h b/src/app/engine/assembly/foldhaus_assembly_debug.h index bb385d2..9a1cc12 100644 --- a/src/app/engine/assembly/foldhaus_assembly_debug.h +++ b/src/app/engine/assembly/foldhaus_assembly_debug.h @@ -14,6 +14,11 @@ enum override_type ADS_Override_AllRed, ADS_Override_AllGreen, ADS_Override_AllBlue, + ADS_Override_AllOff, + ADS_Override_AllWhite, + ADS_Override_TagWhite, + ADS_Override_TagStripWhite, + ADS_Override_ChannelWhite, ADS_Override_Count, }; @@ -25,17 +30,74 @@ global gs_const_string OverrideTypeStrings[] = { LitString("Override_AllRed" ), LitString("Override_AllGreen" ), LitString("Override_AllBlue" ), + LitString("ADS_Override_AllOff" ), + LitString("ADS_Override_AllWhite" ), + LitString("ADS_Override_TagWhite" ), + LitString("ADS_Override_TagStripWhite" ), + LitString("ADS_Override_ChannelWhite," ), LitString("Override_Count"), }; struct assembly_debug_state { override_type Override; + u32 TargetAssembly; u32 TargetStrip; + + gs_string TagName; + gs_string TagValue; + pixel TargetColor; + + u32 TargetChannel; }; +internal assembly_debug_state +AssemblyDebug_Create(gs_memory_arena* Storage) +{ + assembly_debug_state Result = {}; + Result.TagName = PushString(Storage, 256); + Result.TagValue = PushString(Storage, 256); + return Result; +} + +internal void +AssemblyDebug_OverrideStripWithColor(v2_strip Strip, led_buffer LedBuffer, pixel Color) +{ + for (u32 i = 0; i < Strip.LedCount; i++) + { + u32 LedIdx = Strip.LedLUT[i]; + LedBuffer.Colors[LedIdx] = Color; + } +} + +internal void +AssemblyDebug_OverrideWithColor(assembly Assembly, led_buffer LedBuffer, pixel Color) +{ + for (u32 s = 0; s < Assembly.StripCount; s++) + { + v2_strip Strip = Assembly.Strips[s]; + AssemblyDebug_OverrideStripWithColor(Strip, LedBuffer, Color); + } +} + +internal void +AssemblyDebug_OverrideTagValueWithColor(assembly Assembly, led_buffer LedBuffer, pixel Color, gs_string TagName, gs_string TagValue) +{ + u64 NameHash = HashDJB2ToU32(StringExpand(TagName)); + u64 ValueHash = HashDJB2ToU32(StringExpand(TagValue)); + + for (u32 s = 0; s < Assembly.StripCount; s++) + { + v2_strip Strip = Assembly.Strips[s]; + if (AssemblyStrip_HasTagValue(Strip, NameHash, ValueHash)) + { + AssemblyDebug_OverrideStripWithColor(Strip, LedBuffer, Color); + } + } +} + internal void AssemblyDebug_OverrideOutput(assembly_debug_state State, assembly_array Assemblies, led_system LedSystem) { @@ -50,11 +112,7 @@ AssemblyDebug_OverrideOutput(assembly_debug_state State, assembly_array Assembli case ADS_Override_Strip: { v2_strip Strip = Assembly.Strips[State.TargetStrip]; - for (u32 i = 0; i < Strip.LedCount; i++) - { - u32 LedIdx = Strip.LedLUT[i]; - LedBuffer.Colors[LedIdx] = State.TargetColor; - } + AssemblyDebug_OverrideStripWithColor(Strip, LedBuffer, State.TargetColor); }break; case ADS_Override_SoloStrip: @@ -69,49 +127,66 @@ AssemblyDebug_OverrideOutput(assembly_debug_state State, assembly_array Assembli Color = State.TargetColor; } - for (u32 i = 0; i < Strip.LedCount; i++) - { - u32 LedIdx = Strip.LedLUT[i]; - LedBuffer.Colors[LedIdx] = Color; - } + AssemblyDebug_OverrideStripWithColor(Strip, LedBuffer, Color); } }break; case ADS_Override_AllRed: { - for (u32 s = 0; s < Assembly.StripCount; s++) - { - v2_strip Strip = Assembly.Strips[s]; - for (u32 i = 0; i < Strip.LedCount; i++) - { - u32 LedIdx = Strip.LedLUT[i]; - LedBuffer.Colors[LedIdx] = pixel{255, 0, 0}; - } - } + AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{255, 0, 0}); }break; case ADS_Override_AllGreen: { - for (u32 s = 0; s < Assembly.StripCount; s++) - { - v2_strip Strip = Assembly.Strips[s]; - for (u32 i = 0; i < Strip.LedCount; i++) - { - u32 LedIdx = Strip.LedLUT[i]; - LedBuffer.Colors[LedIdx] = pixel{0, 255, 0}; - } - } + AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{0, 255, 0}); }break; case ADS_Override_AllBlue: { + AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{0, 0, 255}); + }break; + + case ADS_Override_AllOff: + { + AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{0, 0, 0}); + }break; + + case ADS_Override_AllWhite: + { + AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{255, 255, 255}); + }break; + + case ADS_Override_TagWhite: + { + AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{0, 0, 0}); + AssemblyDebug_OverrideTagValueWithColor(Assembly, LedBuffer, pixel{255, 255, 255}, State.TagName, State.TagValue); + + }break; + + case ADS_Override_TagStripWhite: + { + u64 NameHash = HashDJB2ToU32(StringExpand(State.TagName)); + u64 ValueHash = HashDJB2ToU32(StringExpand(State.TagValue)); + + AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{0, 0, 0}); + + v2_strip Strip = Assembly.Strips[State.TargetStrip]; + if (AssemblyStrip_HasTagValue(Strip, NameHash, ValueHash)) + { + AssemblyDebug_OverrideStripWithColor(Strip, LedBuffer, + pixel{255, 255, 255}); + } + }break; + + case ADS_Override_ChannelWhite: + { + AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{0, 0, 0}); for (u32 s = 0; s < Assembly.StripCount; s++) { v2_strip Strip = Assembly.Strips[s]; - for (u32 i = 0; i < Strip.LedCount; i++) + if (Strip.UARTAddr.Channel == State.TargetChannel) { - u32 LedIdx = Strip.LedLUT[i]; - LedBuffer.Colors[LedIdx] = pixel{0, 0, 255}; + AssemblyDebug_OverrideStripWithColor(Strip, LedBuffer, pixel{255, 255, 255}); } } }break; diff --git a/src/app/foldhaus_app.cpp b/src/app/foldhaus_app.cpp index 900f228..ade4707 100644 --- a/src/app/foldhaus_app.cpp +++ b/src/app/foldhaus_app.cpp @@ -75,6 +75,7 @@ INITIALIZE_APPLICATION(InitializeApplication) State->SACN = SACN_Initialize(Context); State->LedSystem = LedSystem_Create(Context.ThreadContext.Allocator, 128); + State->AssemblyDebugState = AssemblyDebug_Create(&State->Permanent); GlobalDebugServices->Interface.RenderSculpture = true; diff --git a/src/app/interface.h b/src/app/interface.h index 3fada9f..4eeb355 100644 --- a/src/app/interface.h +++ b/src/app/interface.h @@ -981,10 +981,10 @@ ui_EvaluateWidget(ui_interface* Interface, ui_widget* Widget, rect2 Bounds) { ui_widget_retained_state* State = ui_GetRetainedState(Interface, Widget->Id); - // TODO(pjs): Backspace? for (u32 i = 0; i < Interface->TempInputString.Length; i++) { - if (Interface->TempInputString.Str[i] == '\b') + if (Interface->TempInputString.Str[i] == '\b' && + State->EditString.Length > 0) { State->EditString.Length -= 1; } @@ -1529,6 +1529,15 @@ ui_LabeledToggle(ui_interface* Interface, gs_string Label, bool Value) return Result; } +internal void +ui_LabeledTextEntry(ui_interface* Interface, gs_string Label, gs_string* Value) +{ + ui_BeginLabelRow(Interface, Label); + ui_TextEntry(Interface, Label, Value); + ui_EndRow(Interface); +} + + internal u64 ui_LabeledTextEntryU64(ui_interface* Interface, gs_string Label, u32 Value) { diff --git a/src/sculpture_gen/gen_blumen_lumen.cpp b/src/sculpture_gen/gen_blumen_lumen.cpp index a1fb63f..5a1bb04 100644 --- a/src/sculpture_gen/gen_blumen_lumen.cpp +++ b/src/sculpture_gen/gen_blumen_lumen.cpp @@ -102,20 +102,21 @@ typedef struct internal void BuildFlower(gs_string* OutputBuffer, flower_desc Desc) { - // the flower stem - loop_desc FlowerStem = {}; - FlowerStem.CenterStart = v3{0, -1.5f, 0} + Desc.Pos; - FlowerStem.CenterEnd = v3{0, .5f, 0} + Desc.Pos; - FlowerStem.Radius = .05f; - FlowerStem.SegmentsCount = 6; - FlowerStem.SubsegmentsCount = 1; - FlowerStem.SubsegmentLeds = 300; - //FlowerStem.ChannelStart = 0; - FlowerStem.ChannelsArray = Desc.StemChannels; - FlowerStem.ComPort = Desc.ComPort; - FlowerStem.SectionTagValue = "stem"; - FlowerStem.FlowerTagValue = Desc.FlowerTagValue; - BuildLoop(OutputBuffer, FlowerStem); + +#if 1 + // the bloom stem inner + loop_desc BloomStemInner = {}; + BloomStemInner.CenterStart = v3{0, 1.4f, 0} + Desc.Pos; + BloomStemInner.CenterEnd = v3{0, .9f, 0} + Desc.Pos; + BloomStemInner.Radius = .05f; + BloomStemInner.SegmentsCount = 6; + BloomStemInner.SubsegmentsCount = 3; + BloomStemInner.SubsegmentLeds = 35; + BloomStemInner.ChannelsArray = Desc.BloomInnerChannels; + BloomStemInner.ComPort = Desc.ComPort; + BloomStemInner.SectionTagValue = "inner_bloom"; + BloomStemInner.FlowerTagValue = Desc.FlowerTagValue; + BuildLoop(OutputBuffer, BloomStemInner); // the bloom stem outer loop_desc BloomStemOuter = {}; @@ -125,27 +126,29 @@ BuildFlower(gs_string* OutputBuffer, flower_desc Desc) BloomStemOuter.SegmentsCount = 9; BloomStemOuter.SubsegmentsCount = 3; BloomStemOuter.SubsegmentLeds = 41; - //BloomStemOuter.ChannelStart = 7; BloomStemOuter.ChannelsArray = Desc.BloomOuterChannels; BloomStemOuter.ComPort = Desc.ComPort; BloomStemOuter.SectionTagValue = "outer_bloom"; BloomStemOuter.FlowerTagValue = Desc.FlowerTagValue; BuildLoop(OutputBuffer, BloomStemOuter); +#endif + +#if 1 + // the flower stem + loop_desc FlowerStem = {}; + FlowerStem.CenterStart = v3{0, -1.5f, 0} + Desc.Pos; + FlowerStem.CenterEnd = v3{0, .5f, 0} + Desc.Pos; + FlowerStem.Radius = .05f; + FlowerStem.SegmentsCount = 6; + FlowerStem.SubsegmentsCount = 1; + FlowerStem.SubsegmentLeds = 300; + FlowerStem.ChannelsArray = Desc.StemChannels; + FlowerStem.ComPort = Desc.ComPort; + FlowerStem.SectionTagValue = "stem"; + FlowerStem.FlowerTagValue = Desc.FlowerTagValue; + BuildLoop(OutputBuffer, FlowerStem); +#endif - // the bloom stem inner - loop_desc BloomStemInner = {}; - BloomStemInner.CenterStart = v3{0, 1.4f, 0} + Desc.Pos; - BloomStemInner.CenterEnd = v3{0, .9f, 0} + Desc.Pos; - BloomStemInner.Radius = .05f; - BloomStemInner.SegmentsCount = 6; - BloomStemInner.SubsegmentsCount = 3; - BloomStemInner.SubsegmentLeds = 35; - //BloomStemInner.ChannelStart = 17; - BloomStemInner.ChannelsArray = Desc.BloomInnerChannels; - BloomStemInner.ComPort = Desc.ComPort; - BloomStemInner.SectionTagValue = "inner_bloom"; - BloomStemInner.FlowerTagValue = Desc.FlowerTagValue; - BuildLoop(OutputBuffer, BloomStemInner); } // Just for brevity, no real function provided @@ -169,7 +172,7 @@ int main(int ArgCount, char** Args) gs_string OutputBuffer = PushString(Ctx.Transient, MB(4)); - char* ComPort = "\\\\.\\COM8"; + char* ComPort = "\\\\.\\COM3"; WriteAssemblyUARTOpen(&OutputBuffer, "Blumen Lumen - Silver Spring", 100, @@ -178,7 +181,7 @@ int main(int ArgCount, char** Args) ""); u32 StemChannels[] = { FSC(2, 1), FSC(2, 2), FSC(2, 3), FSC(2, 4), FSC(2, 5), FSC(2, 6) }; - u32 BloomOuterChannels[] = { FSC(1, 0), FSC(1, 1), FSC(1, 2), FSC(1, 3), FSC(1, 4), FSC(1, 5), FSC(1, 6), FSC(1, 7), FSC(2, 0) }; + u32 BloomOuterChannels[] = { FSC(1, 0), FSC(1, 1), FSC(1, 2), FSC(1, 3), FSC(1, 4), FSC(1, 5), FSC(1, 6), FSC(1, 7), FSC(2, 7) }; u32 BloomInnerChannels[] = { FSC(0, 0), FSC(0, 1), FSC(0, 2), FSC(0, 3), FSC(0, 4), FSC(0, 5) }; flower_desc F0 = {}; F0.Pos = v3{-1, 0, 0}; @@ -189,14 +192,16 @@ int main(int ArgCount, char** Args) F0.BloomInnerChannels = BloomInnerChannels; BuildFlower(&OutputBuffer, F0); +#if 1 flower_desc F1 = {}; F1.Pos = v3{0, 0, 0}; - F1.ComPort = "\\\\.\\COM9"; + F1.ComPort = "\\\\.\\COM6"; F1.FlowerTagValue = "center"; F1.StemChannels = StemChannels; F1.BloomInnerChannels = BloomInnerChannels; F1.BloomOuterChannels = BloomOuterChannels; BuildFlower(&OutputBuffer, F1); +#endif /* flower_desc F2 = {}; From 3c1110adfd03310f829cfd79667503829c0da166 Mon Sep 17 00:00:00 2001 From: PS Date: Sat, 16 Jan 2021 18:55:31 -0800 Subject: [PATCH 20/44] Layout push/pop pairing is now checked for and asserted on --- src/app/editor/foldhaus_editor.cpp | 5 ++- .../foldhaus_panel_animation_timeline.h | 6 ++-- .../panels/foldhaus_panel_assembly_debug.h | 14 ++++++-- .../editor/panels/foldhaus_panel_file_view.h | 2 +- .../editor/panels/foldhaus_panel_hierarchy.h | 2 +- .../editor/panels/foldhaus_panel_profiler.h | 2 +- src/app/interface.h | 34 ++++++++++++++----- src/app/interface_test.cpp | 5 +++ 8 files changed, 53 insertions(+), 17 deletions(-) diff --git a/src/app/editor/foldhaus_editor.cpp b/src/app/editor/foldhaus_editor.cpp index f00000d..441dc6a 100644 --- a/src/app/editor/foldhaus_editor.cpp +++ b/src/app/editor/foldhaus_editor.cpp @@ -108,6 +108,9 @@ Editor_Update(app_state* State, context* Context, input_queue InputQueue) State->Interface.HotWidget = {}; } + Assert(State->Interface.PerFrameMemory && + (u64)State->Interface.PerFrameMemory != 0x5); + PanelSystem_UpdateLayout(&State->PanelSystem, State->WindowBounds); Editor_HandleInput(State, State->WindowBounds, InputQueue, Context->Mouse, *Context); } @@ -334,7 +337,7 @@ Editor_Render(app_state* State, context* Context, render_command_buffer* RenderB } } - ui_PopLayout(&State->Interface); + ui_PopLayout(&State->Interface, MakeString("Editor Layout")); #endif // Draw the Interface diff --git a/src/app/editor/panels/foldhaus_panel_animation_timeline.h b/src/app/editor/panels/foldhaus_panel_animation_timeline.h index ca358a6..b8f3ef3 100644 --- a/src/app/editor/panels/foldhaus_panel_animation_timeline.h +++ b/src/app/editor/panels/foldhaus_panel_animation_timeline.h @@ -600,7 +600,7 @@ DrawAnimationPatternList(rect2 PanelBounds, ui_interface* Interface, u32 Selecte AddAnimationBlockAtCurrentTime(PatternHandle, SelectedAnimationLayerHandle, AnimationSystem); } } - ui_PopLayout(Interface); + ui_PopLayout(Interface, MakeString("AnimClips Layout")); } internal void @@ -630,7 +630,7 @@ PlayBar_Render(animation_timeline_state* TimelineState, rect2 Bounds, panel* Pan } } ui_EndRow(&State->Interface); - ui_PopLayout(&State->Interface); + ui_PopLayout(&State->Interface, MakeString("PlayBar Layout")); } internal void @@ -881,7 +881,7 @@ AnimInfoView_Render(animation_timeline_state* TimelineState, rect2 Bounds, panel ui_EndLabeledDropdown(Interface); } - ui_PopLayout(Interface); + ui_PopLayout(Interface, MakeString("AnimInfo Layout")); } internal void diff --git a/src/app/editor/panels/foldhaus_panel_assembly_debug.h b/src/app/editor/panels/foldhaus_panel_assembly_debug.h index 5d07449..2abfda6 100644 --- a/src/app/editor/panels/foldhaus_panel_assembly_debug.h +++ b/src/app/editor/panels/foldhaus_panel_assembly_debug.h @@ -43,6 +43,8 @@ AssemblyDebug_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Ren ui_interface* Interface = &State->Interface; ui_PushLayout(Interface, PanelBounds, LayoutDirection_TopDown, MakeString("Assembly Debug Layout")); + InterfaceAssert(Interface->PerFrameMemory); + gs_string OverrideStr = MakeString(OverrideTypeStrings[State->AssemblyDebugState.Override]); if (ui_BeginLabeledDropdown(Interface, MakeString("Override"), OverrideStr)) { @@ -54,6 +56,8 @@ AssemblyDebug_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Ren } } } + ui_EndLabeledDropdown(Interface); + InterfaceAssert(Interface->PerFrameMemory); if (State->AssemblyDebugState.Override == ADS_Override_TagWhite || State->AssemblyDebugState.Override == ADS_Override_TagStripWhite) @@ -63,7 +67,6 @@ AssemblyDebug_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Ren if (State->AssemblyDebugState.Override == ADS_Override_TagStripWhite) { - ui_EndLabeledDropdown(Interface); State->AssemblyDebugState.TargetAssembly = ui_LabeledTextEntryU64(Interface, MakeString("Assembly"), State->AssemblyDebugState.TargetAssembly); State->AssemblyDebugState.TargetStrip = ui_LabeledTextEntryU64(Interface, MakeString("Strip"), State->AssemblyDebugState.TargetStrip); @@ -80,11 +83,18 @@ AssemblyDebug_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Ren } else { - ui_EndLabeledDropdown(Interface); + InterfaceAssert(Interface->PerFrameMemory); + State->AssemblyDebugState.TargetAssembly = ui_LabeledTextEntryU64(Interface, MakeString("Assembly"), State->AssemblyDebugState.TargetAssembly); + InterfaceAssert(Interface->PerFrameMemory); + State->AssemblyDebugState.TargetStrip = ui_LabeledTextEntryU64(Interface, MakeString("Strip"), State->AssemblyDebugState.TargetStrip); + + InterfaceAssert(Interface->PerFrameMemory); } + + ui_PopLayout(Interface, MakeString("Assembly Debug Layout")); } #define FOLDHAUS_PANEL_ASSEMBLY_DEBUG_H diff --git a/src/app/editor/panels/foldhaus_panel_file_view.h b/src/app/editor/panels/foldhaus_panel_file_view.h index 8183829..55105bd 100644 --- a/src/app/editor/panels/foldhaus_panel_file_view.h +++ b/src/app/editor/panels/foldhaus_panel_file_view.h @@ -121,7 +121,7 @@ FileView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBu } } - ui_PopLayout(&State->Interface); + ui_PopLayout(&State->Interface, MakeString("FileView Layout")); } diff --git a/src/app/editor/panels/foldhaus_panel_hierarchy.h b/src/app/editor/panels/foldhaus_panel_hierarchy.h index d2f9804..380596c 100644 --- a/src/app/editor/panels/foldhaus_panel_hierarchy.h +++ b/src/app/editor/panels/foldhaus_panel_hierarchy.h @@ -66,7 +66,7 @@ HierarchyView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Ren ui_EndRow(&State->Interface); } ui_EndList(&State->Interface); - ui_PopLayout(&State->Interface); + ui_PopLayout(&State->Interface, MakeString("Hierarchy Layout")); } diff --git a/src/app/editor/panels/foldhaus_panel_profiler.h b/src/app/editor/panels/foldhaus_panel_profiler.h index 0af6138..405b50f 100644 --- a/src/app/editor/panels/foldhaus_panel_profiler.h +++ b/src/app/editor/panels/foldhaus_panel_profiler.h @@ -254,7 +254,7 @@ ProfilerView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Rend RenderProfiler_ListVisualization(&State->Interface, Layout, VisibleFrame, Memory); } - ui_PopLayout(&State->Interface); + ui_PopLayout(&State->Interface, MakeString("Profiler Layout")); } diff --git a/src/app/interface.h b/src/app/interface.h index 4eeb355..1c1b304 100644 --- a/src/app/interface.h +++ b/src/app/interface.h @@ -5,6 +5,8 @@ // #ifndef INTERFACE_H +#define InterfaceAssert(IMemPtr) Assert(IMemPtr && (u64)IMemPtr != 0x5 && (u64)IMemPtr != 0xC) + enum gs_string_alignment { Align_Left, @@ -342,6 +344,10 @@ struct ui_widget_retained_state v2 ChildrenDrawOffset; gs_string EditString; + + // For dropdowns and rows to be able to error check not closing + // a layout you open + u32 MaxChildren; }; struct ui_interface @@ -392,6 +398,7 @@ ui_InterfaceReset(ui_interface* Interface) Interface->DrawOrderHead = 0; Interface->DrawOrderRoot = 0; ClearArena(Interface->PerFrameMemory); + InterfaceAssert(Interface->PerFrameMemory); for (u32 i = 0; i < Interface->RetainedStateCount; i++) { @@ -521,6 +528,7 @@ ui_GetOrCreateRetainedState(ui_interface* Interface, ui_widget* Widget) internal ui_widget* ui_CreateWidget(ui_interface* Interface, gs_string String) { + InterfaceAssert(Interface->PerFrameMemory); Assert(Interface->WidgetsCount < Interface->WidgetsCountMax); u64 Index = Interface->WidgetsCount++; ui_widget* Result = Interface->Widgets + Index; @@ -546,6 +554,7 @@ ui_CreateWidget(ui_interface* Interface, gs_string String) Result->Id.ZIndex = ZIndex; Result->String = PushStringCopy(Interface->PerFrameMemory, String.ConstString); + InterfaceAssert(Interface->PerFrameMemory); Result->Alignment = Align_Left; Result->Next = 0; Result->ChildrenRoot = 0; @@ -656,6 +665,7 @@ internal void ui_WidgetCreateColumns(ui_widget* Widget, u32 ColumnsCount, ui_interface* Interface) { Widget->Columns = PushArray(Interface->PerFrameMemory, ui_column, ColumnsCount); + InterfaceAssert(Interface->PerFrameMemory); Widget->ColumnsCount = ColumnsCount; Widget->ColumnsFilled = 0; } @@ -799,11 +809,17 @@ ui_ExpandToFitChildren(ui_widget* Parent) } static void -ui_PopLayout(ui_interface* Interface) +ui_PopLayout(ui_interface* Interface, gs_string LayoutName) { Assert(Interface->ActiveLayout != 0); ui_widget* Layout = Interface->ActiveLayout; + + // NOTE(pjs): If this isn't true then a layout was opened without being closed + // Go check for ui_PushLayout, ui_BeginDropdown, ui_BeginRow, etc that don't have + // a corresponding ui_Pop/ui_End* + Assert(StringsEqual(Layout->String, LayoutName)); + ui_ExpandToFitChildren(Layout); Interface->ActiveLayout = Interface->ActiveLayout->Parent; @@ -916,7 +932,7 @@ ui_BeginRow(ui_interface* Interface, u32 ColumnsMax, ui_column_spec* ColumnRules static void ui_EndRow(ui_interface* Interface) { - ui_PopLayout(Interface); + ui_PopLayout(Interface, MakeString("Row")); } static rect2 @@ -1297,7 +1313,7 @@ ui_EvaluateDropdown(ui_interface* Interface, ui_widget* Widget, ui_eval_result E }; } - ui_widget* Layout = ui_PushOverlayLayout(Interface, MenuBounds, Direction, MakeString("WidgetLayout")); + ui_widget* Layout = ui_PushOverlayLayout(Interface, MenuBounds, Direction, MakeString("DropdownLayout")); Layout->Margin.y = 0; Layout->WidgetReference = Widget->Id; ui_WidgetClearFlag(Layout, UIWidgetFlag_DrawOutline); @@ -1341,7 +1357,7 @@ ui_EndDropdown(ui_interface* Interface) { if (State->Value) { - ui_PopLayout(Interface); + ui_PopLayout(Interface, MakeString("DropdownLayout")); } } } @@ -1378,6 +1394,7 @@ ui_CreateRangeSliderWidget(ui_interface* Interface, gs_string Text, r32 Value) ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawHorizontalFill); ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawOutline); Widget->String = PushStringF(Interface->PerFrameMemory, 128, "%f", Value); + InterfaceAssert(Interface->PerFrameMemory); return Widget; } @@ -1492,8 +1509,7 @@ internal void ui_EndList(ui_interface* Interface) { // Pop the Viewport Layout - ui_PopLayout(Interface); - // TODO(pjs): Ensure that the active layout is the row layout we started in begin list + ui_PopLayout(Interface, MakeString("Contents")); // Pop the actual list layout ui_EndRow(Interface); } @@ -1502,14 +1518,14 @@ internal void ui_BeginMousePopup(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir, gs_string Text) { rect2 FollowMouseBounds = Rect2Translate(Bounds, Interface->Mouse.Pos); - ui_widget* Layout = ui_PushOverlayLayout(Interface, FollowMouseBounds, FillDir, Text); + ui_widget* Layout = ui_PushOverlayLayout(Interface, FollowMouseBounds, FillDir, MakeString("MousePopup")); ui_WidgetSetFlag(Layout, UIWidgetFlag_DrawBackground); } internal void ui_EndMousePopup(ui_interface* Interface) { - ui_PopLayout(Interface); + ui_PopLayout(Interface, MakeString("MousePopup")); } // @@ -1577,6 +1593,8 @@ ui_InterfaceCreate(context Context, interface_config Style, gs_memory_arena* Per Result.Widgets = PushArray(Permanent, ui_widget, Result.WidgetsCountMax); Result.PerFrameMemory = PushStruct(Permanent, gs_memory_arena); *Result.PerFrameMemory = CreateMemoryArena(Context.ThreadContext.Allocator); + InterfaceAssert(Result.PerFrameMemory); + Result.Permanent = Permanent; return Result; diff --git a/src/app/interface_test.cpp b/src/app/interface_test.cpp index 84f2d41..6eba9aa 100644 --- a/src/app/interface_test.cpp +++ b/src/app/interface_test.cpp @@ -20,6 +20,7 @@ InterfaceTest_Render(app_state* State, context* Context, render_command_buffer* gs_string A = MakeString("TestRender Layout"); +#if 0 ui_PushLayout(&State->Interface, A); { #if 1 @@ -87,14 +88,18 @@ InterfaceTest_Render(app_state* State, context* Context, render_command_buffer* ui_PushOverlayLayout(&State->Interface, rect2{25, 25, 400, 200}, LayoutDirection_TopDown, MakeString("t")); { ui_Label(&State->Interface, PushStringF(State->Interface.PerFrameMemory, 256, "Mouse Pos - %f %f", State->Interface.Mouse.Pos.x, State->Interface.Mouse.Pos.y)); + Assert(State->Interface.PerFrameMemory->CursorList); ui_Label(&State->Interface, PushStringF(State->Interface.PerFrameMemory, 256, "Hot - %lld | Active - %lld", State->Interface.HotWidget.Id, State->Interface.ActiveWidget.Id)); + Assert(State->Interface.PerFrameMemory->CursorList); ui_Label(&State->Interface, PushStringF(State->Interface.PerFrameMemory, 256, "Last Active - %lld", State->Interface.LastActiveWidget.Id)); + Assert(State->Interface.PerFrameMemory->CursorList); } ui_PopLayout(&State->Interface); } ui_PopLayout(&State->Interface); +#endif } From 99c62292a45e29e2516ab0aa411b36a129eb34b0 Mon Sep 17 00:00:00 2001 From: PS Date: Sat, 16 Jan 2021 19:45:13 -0800 Subject: [PATCH 21/44] fixed error causing crashes when you exit the file viewer without selecting a file. Issue was when we tried to check if a string that had no data pointer was null terminated --- src/app/editor/foldhaus_editor.cpp | 232 +----------------- src/app/editor/foldhaus_editor_draw.h | 151 ++++++++++++ src/app/editor/foldhaus_interface.cpp | 11 +- .../panels/foldhaus_panel_assembly_debug.h | 2 + .../editor/panels/foldhaus_panel_file_view.h | 55 +++-- src/app/foldhaus_app.h | 6 +- src/gs_libs/gs_types.cpp | 7 +- 7 files changed, 205 insertions(+), 259 deletions(-) create mode 100644 src/app/editor/foldhaus_editor_draw.h diff --git a/src/app/editor/foldhaus_editor.cpp b/src/app/editor/foldhaus_editor.cpp index 441dc6a..6d71ca3 100644 --- a/src/app/editor/foldhaus_editor.cpp +++ b/src/app/editor/foldhaus_editor.cpp @@ -115,203 +115,6 @@ Editor_Update(app_state* State, context* Context, input_queue InputQueue) Editor_HandleInput(State, State->WindowBounds, InputQueue, Context->Mouse, *Context); } -internal void -Editor_DrawWidgetString(app_state* State, context* Context, render_command_buffer* RenderBuffer, ui_widget Widget, rect2 ClippingBox, v4 Color) -{ - gs_string Temp = PushString(State->Transient, 256); - PrintF(&Temp, "%d", Widget.Id.Id); - 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, ClippingBox, Color); - }break; - - case Align_Right: - { - RegisterPosition = DrawStringRightAligned(&BatchConstructor, StringExpand(Widget.String), RegisterPosition, State->Interface.Style.Font, ClippingBox, Color); - }break; - - InvalidDefaultCase; - } -} - -internal void -Editor_DrawWidget(app_state* State, context* Context, render_command_buffer* RenderBuffer, ui_widget Widget, rect2 ParentClipBounds) -{ - rect2 WidgetParentUnion = Widget.Bounds; - WidgetParentUnion = Rect2Union(Widget.Bounds, ParentClipBounds); - - if (!Widget.Parent || (Rect2Area(WidgetParentUnion) > 0)) - { - 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; - } - PushRenderQuad2DClipped(RenderBuffer, Widget.Bounds, WidgetParentUnion, Color); - } - - if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawString) && Widget.String.Length > 0) - { - v4 Color = State->Interface.Style.TextColor; - Editor_DrawWidgetString(State, Context, RenderBuffer, Widget, WidgetParentUnion, Color); - } - - if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawHorizontalFill) || - ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawVerticalFill)) - { - v4 Color = State->Interface.Style.ButtonColor_Selected; - if (ui_WidgetIdsEqual(Widget.Id, State->Interface.HotWidget) || - ui_WidgetIdsEqual(Widget.Id, State->Interface.ActiveWidget)) - { - Color = WhiteV4; - } - - rect2 FillBounds = {}; - if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawHorizontalFill)) - { - FillBounds.Min.y = Widget.Bounds.Min.y; - FillBounds.Max.y = Widget.Bounds.Max.y; - r32 FillToPoint = LerpR32(Widget.FillPercent, Widget.Bounds.Min.x, Widget.Bounds.Max.x); - if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawFillReversed)) - { - FillBounds.Min.x = FillToPoint; - FillBounds.Max.x = Widget.Bounds.Max.x; - } - else if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawFillAsHandle)) - { - FillBounds.Min.x = FillToPoint - 5; - FillBounds.Max.x = FillToPoint + 5; - } - else - { - FillBounds.Min.x = Widget.Bounds.Min.x; - FillBounds.Max.x = FillToPoint; - } - } - else if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawVerticalFill)) - { - FillBounds.Min.x = Widget.Bounds.Min.x; - FillBounds.Max.x = Widget.Bounds.Max.x; - r32 FillToPoint = LerpR32(Widget.FillPercent, Widget.Bounds.Min.y, Widget.Bounds.Max.y); - if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawFillReversed)) - { - FillBounds.Min.y = FillToPoint; - FillBounds.Max.y = Widget.Bounds.Max.y; - } - else if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawFillAsHandle)) - { - FillBounds.Min.y = FillToPoint - 5; - FillBounds.Max.y = FillToPoint + 5; - } - else - { - FillBounds.Min.y = Widget.Bounds.Min.y; - FillBounds.Max.y = FillToPoint; - } - } - rect2 ClippedFillBounds = Rect2Union(FillBounds, WidgetParentUnion); - PushRenderQuad2D(RenderBuffer, ClippedFillBounds, Color); - - if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawString) && Widget.String.Length > 0) - { - // TODO(pjs): add this color to the style - v4 TextColor = BlackV4; - Editor_DrawWidgetString(State, Context, RenderBuffer, Widget, ClippedFillBounds, TextColor); - } - } - - - if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawOutline)) - { - // TODO(pjs): replace these with values from the style - r32 Thickness = 1.0f; - v4 Color = WhiteV4; - PushRenderBoundingBox2D(RenderBuffer, WidgetParentUnion.Min, WidgetParentUnion.Max, Thickness, Color); - } - } - - if (Widget.ChildrenRoot) - { - Editor_DrawWidget(State, Context, RenderBuffer, *Widget.ChildrenRoot, WidgetParentUnion); - } - - if (Widget.Next) - { - Editor_DrawWidget(State, Context, RenderBuffer, *Widget.Next, ParentClipBounds); - } -} - -#include "../interface_test.cpp" - -FOLDHAUS_INPUT_COMMAND_PROC(ActiveWidget_TypeCharacter) -{ - ui_widget* ActiveWidget = ui_InterfaceGetWidgetWithId(&State->Interface, State->Interface.ActiveWidget); - ui_widget_retained_state* WidgetState = ui_GetRetainedState(&State->Interface, ActiveWidget->Id); - if (WidgetState) - { - char AsciiValue = CharacterFromKeyCode(Event.Key); - if (AsciiValue) - { - OutChar(&WidgetState->EditString, AsciiValue); - } - } -} - -FOLDHAUS_INPUT_COMMAND_PROC(ActiveWidget_DeleteBackwards) -{ - ui_widget* ActiveWidget = ui_InterfaceGetWidgetWithId(&State->Interface, State->Interface.ActiveWidget); - ui_widget_retained_state* WidgetState = ui_GetRetainedState(&State->Interface, ActiveWidget->Id); - if (WidgetState) - { - WidgetState->EditString.Length -= 1; - } -} - -FOLDHAUS_INPUT_COMMAND_PROC(ActiveWidget_EndTypingMode) -{ - DeactivateCurrentOperationMode(&State->Modes); -} - -OPERATION_RENDER_PROC(ActiveWidget_EndTypingMode) -{ - ui_widget* ActiveWidget = ui_InterfaceGetWidgetWithId(&State->Interface, State->Interface.ActiveWidget); - ui_widget* LastActiveWidget = ui_InterfaceGetWidgetWithId(&State->Interface, State->Interface.LastActiveWidget); - if (ActiveWidget == 0 && LastActiveWidget != 0) - { - // if there was an active widget last frame that was typable, we want to deactivate the typing mode - DeactivateCurrentOperationMode(&State->Modes); - } -} - -input_command InterfaceTypingCommands [] = { - { KeyCode_A, KeyCode_Invalid, Command_Began | Command_Held, ActiveWidget_TypeCharacter }, - { KeyCode_B, KeyCode_Invalid, Command_Began | Command_Held, ActiveWidget_TypeCharacter }, - { KeyCode_C, KeyCode_Invalid, Command_Began | Command_Held, ActiveWidget_TypeCharacter }, - { KeyCode_D, KeyCode_Invalid, Command_Began | Command_Held, ActiveWidget_TypeCharacter }, - { KeyCode_E, KeyCode_Invalid, Command_Began | Command_Held, ActiveWidget_TypeCharacter }, - { KeyCode_Enter, KeyCode_Invalid, Command_Began, ActiveWidget_EndTypingMode }, - { KeyCode_Backspace, KeyCode_Invalid, Command_Began | Command_Held, ActiveWidget_DeleteBackwards }, -}; - internal void Editor_Render(app_state* State, context* Context, render_command_buffer* RenderBuffer) { @@ -319,45 +122,30 @@ Editor_Render(app_state* State, context* Context, render_command_buffer* RenderB PushRenderOrthographic(RenderBuffer, State->WindowBounds); PushRenderClearScreen(RenderBuffer); -#if 0 - InterfaceTest_Render(State, Context, RenderBuffer); -#else + ui_InterfaceReset(&State->Interface); State->Interface.RenderBuffer = RenderBuffer; ui_PushLayout(&State->Interface, Context->WindowBounds, LayoutDirection_TopDown, MakeString("Editor Layout")); - - 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) + DrawAllPanels(State->PanelSystem, RenderBuffer, &Context->Mouse, State, *Context); + + for (s32 m = 0; m < State->Modes.ActiveModesCount; m++) { - OperationMode.Render(State, RenderBuffer, OperationMode, Context->Mouse, *Context); + operation_mode OperationMode = State->Modes.ActiveModes[m]; + if (OperationMode.Render != 0) + { + OperationMode.Render(State, RenderBuffer, OperationMode, Context->Mouse, *Context); + } } } - ui_PopLayout(&State->Interface, MakeString("Editor Layout")); -#endif + // Draw the Interface if (State->Interface.DrawOrderRoot != 0) { ui_widget Widget = *State->Interface.DrawOrderRoot; Editor_DrawWidget(State, Context, RenderBuffer, Widget, Context->WindowBounds); - -#if 0 - // TODO(pjs): got distracted halfway through getting typing input into the interface - if (ui_WidgetIdsEqual(State->Interface.ActiveWidget, State->Interface.LastActiveWidget)) - { - ui_widget* ActiveWidget = ui_InterfaceGetWidgetWithId(&State->Interface, State->Interface.ActiveWidget); - if (ActiveWidget != 0 && - ui_WidgetIsFlagSet(*ActiveWidget, UIWidgetFlag_Typable)) - { - operation_mode* TypingMode = ActivateOperationModeWithCommands(&State->Modes, InterfaceTypingCommands, ActiveWidget_EndTypingMode); - } - } -#endif } Context->GeneralWorkQueue->CompleteQueueWork(Context->GeneralWorkQueue, Context->ThreadContext); diff --git a/src/app/editor/foldhaus_editor_draw.h b/src/app/editor/foldhaus_editor_draw.h new file mode 100644 index 0000000..00c7949 --- /dev/null +++ b/src/app/editor/foldhaus_editor_draw.h @@ -0,0 +1,151 @@ +// +// File: foldhaus_editor_draw.h +// Author: Peter Slattery +// Creation Date: 2021-01-16 +// +#ifndef FOLDHAUS_EDITOR_DRAW_H + +internal void +Editor_DrawWidgetString(app_state* State, context* Context, render_command_buffer* RenderBuffer, ui_widget Widget, rect2 ClippingBox, v4 Color) +{ + gs_string Temp = PushString(State->Transient, 256); + PrintF(&Temp, "%d", Widget.Id.Id); + 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, ClippingBox, Color); + }break; + + case Align_Right: + { + RegisterPosition = DrawStringRightAligned(&BatchConstructor, StringExpand(Widget.String), RegisterPosition, State->Interface.Style.Font, ClippingBox, Color); + }break; + + InvalidDefaultCase; + } +} + +enum widget_fill_dir +{ + WidgetFill_Horizontal = 0, + WidgetFill_Vertical = 1, +}; + +internal rect2 +Editor_GetWidgetFillBounds(ui_widget Widget) +{ + Assert(ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawHorizontalFill) || ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawVerticalFill)); + + rect2 Result = {}; + + widget_fill_dir Dir = WidgetFill_Horizontal; + if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawHorizontalFill)) { Dir = WidgetFill_Vertical; } + widget_fill_dir OtherDir = (widget_fill_dir)(WidgetFill_Vertical - Dir); + + Result.Min.E[Dir] = Widget.Bounds.Min.E[Dir]; + Result.Max.E[Dir] = Widget.Bounds.Max.E[Dir]; + r32 FillToPoint = LerpR32(Widget.FillPercent, Widget.Bounds.Min.E[OtherDir], Widget.Bounds.Max.E[OtherDir]); + if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawFillReversed)) + { + Result.Min.E[OtherDir] = FillToPoint; + Result.Max.E[OtherDir] = Widget.Bounds.Max.E[OtherDir]; + } + else if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawFillAsHandle)) + { + Result.Min.E[OtherDir] = FillToPoint - 5; + Result.Max.E[OtherDir] = FillToPoint + 5; + } + else + { + Result.Min.E[OtherDir] = Widget.Bounds.Min.E[OtherDir]; + Result.Max.E[OtherDir] = FillToPoint; + } + + return Result; +} + +internal void +Editor_DrawWidget(app_state* State, context* Context, render_command_buffer* RenderBuffer, ui_widget Widget, rect2 ParentClipBounds) +{ + rect2 WidgetParentUnion = Widget.Bounds; + WidgetParentUnion = Rect2Union(Widget.Bounds, ParentClipBounds); + + if (!Widget.Parent || (Rect2Area(WidgetParentUnion) > 0)) + { + 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; + } + PushRenderQuad2DClipped(RenderBuffer, Widget.Bounds, WidgetParentUnion, Color); + } + + if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawString) && Widget.String.Length > 0) + { + v4 Color = State->Interface.Style.TextColor; + Editor_DrawWidgetString(State, Context, RenderBuffer, Widget, WidgetParentUnion, Color); + } + + if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawHorizontalFill) || + ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawVerticalFill)) + { + v4 Color = State->Interface.Style.ButtonColor_Selected; + if (ui_WidgetIdsEqual(Widget.Id, State->Interface.HotWidget) || + ui_WidgetIdsEqual(Widget.Id, State->Interface.ActiveWidget)) + { + Color = WhiteV4; + } + + rect2 FillBounds = Editor_GetWidgetFillBounds(Widget); + rect2 ClippedFillBounds = Rect2Union(FillBounds, WidgetParentUnion); + PushRenderQuad2D(RenderBuffer, ClippedFillBounds, Color); + + if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawString) && Widget.String.Length > 0) + { + // TODO(pjs): add this color to the style + v4 TextColor = BlackV4; + Editor_DrawWidgetString(State, Context, RenderBuffer, Widget, ClippedFillBounds, TextColor); + } + } + + if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawOutline)) + { + // TODO(pjs): replace these with values from the style + r32 Thickness = 1.0f; + v4 Color = WhiteV4; + PushRenderBoundingBox2D(RenderBuffer, WidgetParentUnion.Min, WidgetParentUnion.Max, Thickness, Color); + } + } + + if (Widget.ChildrenRoot) + { + Editor_DrawWidget(State, Context, RenderBuffer, *Widget.ChildrenRoot, WidgetParentUnion); + } + + if (Widget.Next) + { + Editor_DrawWidget(State, Context, RenderBuffer, *Widget.Next, ParentClipBounds); + } +} + + +#define FOLDHAUS_EDITOR_DRAW_H +#endif // FOLDHAUS_EDITOR_DRAW_H \ No newline at end of file diff --git a/src/app/editor/foldhaus_interface.cpp b/src/app/editor/foldhaus_interface.cpp index f29babb..d194260 100644 --- a/src/app/editor/foldhaus_interface.cpp +++ b/src/app/editor/foldhaus_interface.cpp @@ -338,14 +338,16 @@ HandleMousePanelInteraction(panel_system* PanelSystem, rect2 WindowBounds, mouse } internal void -DrawPanelBorder(panel Panel, v2 PanelMin, v2 PanelMax, v4 Color, mouse_state* Mouse, render_command_buffer* RenderBuffer) +DrawPanelBorder(panel Panel, v2 PanelMin, v2 PanelMax, mouse_state* Mouse, render_command_buffer* RenderBuffer) { r32 MouseLeftEdgeDistance = Abs(Mouse->Pos.x - PanelMin.x); r32 MouseRightEdgeDistance = Abs(Mouse->Pos.x - PanelMax.x); r32 MouseTopEdgeDistance = Abs(Mouse->Pos.y - PanelMax.y); r32 MouseBottomEdgeDistance = Abs(Mouse->Pos.y - PanelMin.y); + v4 Color = BlackV4; PushRenderBoundingBox2D(RenderBuffer, PanelMin, PanelMax, 1, Color); + v4 HighlightColor = v4{.3f, .3f, .3f, 1.f}; r32 HighlightThickness = 1; if (MouseLeftEdgeDistance < PANEL_EDGE_CLICK_MAX_DISTANCE) @@ -428,6 +430,7 @@ RenderPanel(panel* Panel, rect2 PanelBounds, rect2 WindowBounds, render_command_ internal void DrawPanelRecursive(panel* Panel, render_command_buffer* RenderBuffer, mouse_state* Mouse, app_state* State, context Context) { + rect2 Bounds = Panel->Bounds; switch (Panel->SplitDirection) { case PanelSplit_Horizontal: @@ -440,11 +443,9 @@ DrawPanelRecursive(panel* Panel, render_command_buffer* RenderBuffer, mouse_stat case PanelSplit_NoSplit: { panel* OverridePanel = Panel_GetModalOverride(Panel); - RenderPanel(OverridePanel, OverridePanel->Bounds, State->WindowBounds, RenderBuffer, State, Context, *Mouse); - v4 BorderColor = v4{0, 0, 0, 1}; - + RenderPanel(OverridePanel, Bounds, State->WindowBounds, RenderBuffer, State, Context, *Mouse); PushRenderOrthographic(RenderBuffer, State->WindowBounds); - DrawPanelBorder(*OverridePanel, OverridePanel->Bounds.Min, OverridePanel->Bounds.Max, BorderColor, Mouse, RenderBuffer); + DrawPanelBorder(*OverridePanel, Bounds.Min, Bounds.Max, Mouse, RenderBuffer); }break; InvalidDefaultCase; diff --git a/src/app/editor/panels/foldhaus_panel_assembly_debug.h b/src/app/editor/panels/foldhaus_panel_assembly_debug.h index 2abfda6..5bdb699 100644 --- a/src/app/editor/panels/foldhaus_panel_assembly_debug.h +++ b/src/app/editor/panels/foldhaus_panel_assembly_debug.h @@ -94,6 +94,8 @@ AssemblyDebug_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Ren InterfaceAssert(Interface->PerFrameMemory); } + ui_RangeSlider(Interface, MakeString("Test"), .5f, 0, 1); + ui_PopLayout(Interface, MakeString("Assembly Debug Layout")); } diff --git a/src/app/editor/panels/foldhaus_panel_file_view.h b/src/app/editor/panels/foldhaus_panel_file_view.h index 55105bd..fc3b4cd 100644 --- a/src/app/editor/panels/foldhaus_panel_file_view.h +++ b/src/app/editor/panels/foldhaus_panel_file_view.h @@ -89,38 +89,41 @@ FileView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBu { file_view_state* FileViewState = Panel_GetStateStruct(Panel, file_view_state); ui_PushLayout(&State->Interface, PanelBounds, LayoutDirection_TopDown, MakeString("FileView Layout")); - - if (ui_Button(&State->Interface, MakeString("Exit"))) { - FileView_Exit_(Panel, State, Context); - } - - // Header - ui_Label(&State->Interface, FileViewState->WorkingDirectory); - - // File Display - for (u32 i = 0; i < FileViewState->FileNames.Count; i++) - { - gs_file_info File = FileViewState->FileNames.Values[i]; - - u32 LastSlashIndex = FindLast(File.Path, '\\'); - gs_const_string FileName = Substring(File.Path, LastSlashIndex + 1, File.Path.Length); - gs_string PathString = PushString(State->Transient, FileName.Length); - PrintF(&PathString, "%S", FileName); - if (ui_LayoutListButton(&State->Interface, PathString, i)) + if (ui_Button(&State->Interface, MakeString("Exit"))) { - if (File.IsDirectory) + FileView_Exit_(Panel, State, Context); + } + + // Header + ui_Label(&State->Interface, FileViewState->WorkingDirectory); + + // File Display + ui_BeginList(&State->Interface, MakeString("Files"), 10, FileViewState->FileNames.Count); + for (u32 i = 0; i < FileViewState->FileNames.Count; i++) + { + gs_file_info File = FileViewState->FileNames.Values[i]; + + u32 LastSlashIndex = FindLast(File.Path, '\\'); + gs_const_string FileName = Substring(File.Path, LastSlashIndex + 1, File.Path.Length); + gs_string PathString = PushString(State->Transient, FileName.Length); + PrintF(&PathString, "%S", FileName); + + if (ui_LayoutListButton(&State->Interface, PathString, i)) { - FileViewUpdateWorkingDirectory(File.Path, FileViewState, Context); - } - else - { - FileViewState->SelectedFile = File; - FileView_Exit_(Panel, State, Context); + if (File.IsDirectory) + { + FileViewUpdateWorkingDirectory(File.Path, FileViewState, Context); + } + else + { + FileViewState->SelectedFile = File; + FileView_Exit_(Panel, State, Context); + } } } + ui_EndList(&State->Interface); } - ui_PopLayout(&State->Interface, MakeString("FileView Layout")); } diff --git a/src/app/foldhaus_app.h b/src/app/foldhaus_app.h index af5b98e..bf99bf6 100644 --- a/src/app/foldhaus_app.h +++ b/src/app/foldhaus_app.h @@ -95,14 +95,10 @@ EndCurrentOperationMode(app_state* State) #include "editor/panels/foldhaus_panel_hierarchy.h" #include "editor/panels/foldhaus_panel_assembly_debug.h" - #include "editor/panels/foldhaus_panel_types.cpp" -//#include "generated/foldhaus_panels_generated.h" #include "editor/foldhaus_interface.cpp" - -#include "../meta/gs_meta_include.cpp" - +#include "editor/foldhaus_editor_draw.h" #include "editor/foldhaus_editor.cpp" #define FOLDHAUS_APP_H diff --git a/src/gs_libs/gs_types.cpp b/src/gs_libs/gs_types.cpp index 8bd4dc0..205ef8c 100644 --- a/src/gs_libs/gs_types.cpp +++ b/src/gs_libs/gs_types.cpp @@ -1440,7 +1440,12 @@ CharArrayLength (char* CS) internal bool IsNullTerminated(gs_const_string String) { - return (String.Str[String.Length] == 0); + bool Result = false; + if (String.Str) + { + Result = (String.Str[String.Length] == 0); + } + return Result; } internal bool IsNullTerminated(gs_string String) From 2769640adfdfeb227a25dff8eb77ae6dc8196cad Mon Sep 17 00:00:00 2001 From: PS Date: Sat, 16 Jan 2021 23:01:08 -0800 Subject: [PATCH 22/44] updated the build system to get it to work out of the box on more systems --- build/_postbuild_win32.bat | 4 +- build/_prebuild_win32.bat | 6 +- build/build_app_clang_win32_debug.bat | 24 +++---- build/build_app_msvc_win32_debug.bat | 18 +++--- build/setup_cl.bat | 37 +++++++++++ .../foldhaus_panel_animation_timeline.h | 34 ++++------ .../editor/panels/foldhaus_panel_file_view.h | 64 ++++++++++++++----- .../editor/panels/foldhaus_panel_hierarchy.h | 1 + .../assembly/foldhaus_assembly_parser.cpp | 2 +- src/app/interface.h | 5 +- .../platform_win32/win32_foldhaus_fileio.h | 14 ++++ src/gs_libs/gs_types.h | 1 + 12 files changed, 144 insertions(+), 66 deletions(-) create mode 100644 build/setup_cl.bat diff --git a/build/_postbuild_win32.bat b/build/_postbuild_win32.bat index 32c9169..ebc3e0a 100644 --- a/build/_postbuild_win32.bat +++ b/build/_postbuild_win32.bat @@ -2,8 +2,8 @@ IF NOT "%PrebuildCalled%"=="1" GOTO error -C:\apps\ctime\ctime.exe -end %StatsPath%\%StatsFile% %LastError% -C:\apps\ctime\ctime.exe -stats %StatsPath%\%StatsFile% +IF EXIST %CTIMEPATH% ( call C:\apps\ctime\ctime.exe -end %StatsPath%\%StatsFile% %LastError% ) +IF EXIST %CTIMEPATH% ( call C:\apps\ctime\ctime.exe -stats %StatsPath%\%StatsFile% ) set PrebuildCalled=0 GOTO:eof diff --git a/build/_prebuild_win32.bat b/build/_prebuild_win32.bat index 9d8c31e..9680699 100644 --- a/build/_prebuild_win32.bat +++ b/build/_prebuild_win32.bat @@ -1,6 +1,6 @@ @echo off -REM This file takes two arguments +REM This file takes three arguments REM 1 = "app" or "meta" REM 2 = "debug" or "release" REM 3 = "msvc" or "clang" @@ -22,7 +22,9 @@ set StatsFile=%1_win32_%3_%2_build_time.ctm IF NOT EXIST %BuildPath% mkdir %BuildPath% IF NOT EXIST %StatsPath% mkdir %StatsPath% -C:\apps\ctime\ctime.exe -begin %StatsPath%\%StatsFile% +set CTimePath=C:\apps\ctime +IF EXIST %CTIMEPATH% ( call C:\apps\ctime\ctime.exe -begin %StatsPath%\%StatsFile% ) + echo. echo BUILDING TO %BuildPath% echo STATS IN %StatsPath%\%StatsFile% diff --git a/build/build_app_clang_win32_debug.bat b/build/build_app_clang_win32_debug.bat index 30c5b8b..20a1746 100644 --- a/build/build_app_clang_win32_debug.bat +++ b/build/build_app_clang_win32_debug.bat @@ -1,32 +1,26 @@ @echo off -set ProjectDevFolder=%~dp0 -set ProjectDevPath=%ProjectDevFolder:~0,-1% - -pushd %ProjectDevPath% - -IF NOT EXIST .\build_clang\ mkdir .\build_clang - -C:\programs\ctime\ctime.exe -begin %ProjectDevPath%\build\win32_foldhaus_clang_build_time.ctm +SET MyPath=%~dp0 +SET MyPath=%MyPath:~0,-1% +call %MyPath%\_prebuild_win32.bat app debug clang set CommonCompilerFlags=-std=c++11 -Wno-writable-strings -Wno-unused-value -Wno-varargs -Wno-switch -Wno-microsoft-enum-forward-reference -DDEBUG=1 -pushd .\build_clang\ +pushd %BuildPath% -REM Run the Preprocessor -foldhaus_meta.exe ..\src\foldhaus_app.cpp +del *.pdb > NUL 2> NUL echo WAITING FOR PDB TO WRITE > lock.tmp -clang %CommonCompilerFlags% ..\src\foldhaus_app.cpp -shared +clang++ %CommonCompilerFlags% %SourceCodePath%\foldhaus_app.cpp -shared -o set LastError=%ERRORLEVEL% del lock.tmp -clang %CommonCompilerFlags% ..\src\win32_foldhaus.cpp -o win32_foldhaus.exe user32.lib winmm.lib gdi32.lib opengl32.lib dsound.lib Ws2_32.lib Comdlg32.lib +clang++ -c %CommonCompilerFlags% %SourceCodePath%\platform_win32\win32_foldhaus.cpp +link win32_foldhaus.o user32.lib winmm.lib gdi32.lib opengl32.lib dsound.lib Ws2_32.lib Comdlg32.lib -C:\programs\ctime\ctime.exe -end %ProjectDevPath%\build\win32_foldhaus_clang_build_time.ctm %LastError% -REM C:\programs\ctime\ctime.exe -stats %ProjectDevPath%\build\win32_foldhaus_clang_build_time.ctm popd +call %MyPath%\_postbuild_win32.bat diff --git a/build/build_app_msvc_win32_debug.bat b/build/build_app_msvc_win32_debug.bat index 25c45bd..0819a48 100644 --- a/build/build_app_msvc_win32_debug.bat +++ b/build/build_app_msvc_win32_debug.bat @@ -3,30 +3,32 @@ SET MyPath=%~dp0 SET MyPath=%MyPath:~0,-1% call %MyPath%\_prebuild_win32.bat app debug msvc +call %MyPath%\setup_cl.bat -set CommonCompilerFlags=-nologo -DDEBUG=1 -DPLATFORM_WINDOWS -FC -WX -W4 -Z7 -Oi -GR- -EHsc -EHa- -MTd -fp:fast -fp:except- -IC:\programs-dev\gs_libs\src -set CommonCompilerFlags=-wd4127 -wd4702 -wd4101 -wd4505 -wd4100 -wd4189 -wd4244 -wd4201 -wd4996 -I%CommonLibs% -O2 %CommonCompilerFlags% +SET CommonCompilerFlags=-nologo -DDEBUG=1 -DPLATFORM_WINDOWS -FC -WX -W4 -Z7 -Oi -GR- -EHsc -EHa- -MTd -fp:fast -fp:except- -IC:\programs-dev\gs_libs\src -set CommonLinkerFlags= -opt:ref -incremental:no +SET CommonCompilerFlags=-wd4127 -wd4702 -wd4101 -wd4505 -wd4100 -wd4189 -wd4244 -wd4201 -wd4996 -I%CommonLibs% -O2 %CommonCompilerFlags% -set DLLExports=/EXPORT:InitializeApplication /EXPORT:UpdateAndRender /EXPORT:CleanupApplication /EXPORT:ReloadStaticData +SET CommonLinkerFlags= -opt:ref -incremental:no + +SET DLLExports=/EXPORT:InitializeApplication /EXPORT:UpdateAndRender /EXPORT:CleanupApplication /EXPORT:ReloadStaticData pushd %BuildPath% del *.pdb > NUL 2> NUL -REM Run the Preprocessor -REM %MetaProgramPath%\foldhaus_meta.exe %SourceCodePath%\foldhaus_app.cpp - echo WAITING FOR PDB TO WRITE > lock.tmp cl %CommonCompilerFlags% %SourceCodePath%\foldhaus_app.cpp /Fefoldhaus.dll /LD /link %CommonLinkerFlags% %DLLExports% -set LastError=%ERRORLEVEL% +SET LastError=%ERRORLEVEL% del lock.tmp cl %CommonCompilerFlags% %SourceCodePath%\platform_win32\win32_foldhaus.cpp /link %CommonLinkerFlags% user32.lib winmm.lib gdi32.lib opengl32.lib dsound.lib Ws2_32.lib Comdlg32.lib + +REM COMPILE UTILITY EXES + cl %CommonCompilerFlags% %ProjectDevPath%\src\serial_monitor\first.cpp /Feserial_monitor.exe /link %CommonLinkerFlags% user32.lib winmm.lib gdi32.lib cl %CommonCompilerFlags% %ProjectDevPath%\src\sculpture_gen\gen_blumen_lumen.cpp /Fegen_blumen_lumen.exe /link %CommonLinkerFlags% user32.lib winmm.lib gdi32.lib diff --git a/build/setup_cl.bat b/build/setup_cl.bat new file mode 100644 index 0000000..faf7fe6 --- /dev/null +++ b/build/setup_cl.bat @@ -0,0 +1,37 @@ +@echo off + +SET "LIB=" + +SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio 12.0 +IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\vcvarsall.bat" x64)) + +SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio 11.0 +IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\vcvarsall.bat" x64)) + +SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio 10.0 +IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\vcvarsall.bat" x64)) + +SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio 13.0 +IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\vcvarsall.bat" x64)) + +SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio 14.0 +IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\vcvarsall.bat" x64)) + +SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools +IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\Auxiliary\Build\vcvarsall.bat" x64)) + +SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio\2017\Community +IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\Auxiliary\Build\vcvarsall.bat" x64)) + +SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional +IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\Auxiliary\Build\vcvarsall.bat" x64)) + +SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools +IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\Auxiliary\Build\vcvarsall.bat" x64)) + +SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio\2019\Community +IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\Auxiliary\Build\vcvarsall.bat" x64)) + +SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional +IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\Auxiliary\Build\vcvarsall.bat" x64)) + diff --git a/src/app/editor/panels/foldhaus_panel_animation_timeline.h b/src/app/editor/panels/foldhaus_panel_animation_timeline.h index b8f3ef3..1fb550a 100644 --- a/src/app/editor/panels/foldhaus_panel_animation_timeline.h +++ b/src/app/editor/panels/foldhaus_panel_animation_timeline.h @@ -900,30 +900,22 @@ AnimationTimeline_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* ui_FillRect(&State->Interface, PanelBounds, v4{.1f,.1f,.1f,1.f}); rect2 TimelineBounds, InfoBounds; - RectVSplit(PanelBounds, 300, &InfoBounds, &TimelineBounds); + RectVSplitAtDistanceFromLeft(PanelBounds, 300, &InfoBounds, &TimelineBounds); -#if 0 - rect2 AnimInfoBounds, SelectionInfoBounds; - RectHSplitAtPercent(InfoBounds, .65f, &AnimInfoBounds, &SelectionInfoBounds); -#endif + rect2 LayersPanelBounds, TimeRangePanelBounds; + RectVSplitAtDistanceFromLeft(TimelineBounds, 200, &LayersPanelBounds, &TimeRangePanelBounds); - { // Timeline - rect2 LayersPanelBounds, TimeRangePanelBounds; - RectVSplitAtDistanceFromLeft(TimelineBounds, 200, &LayersPanelBounds, &TimeRangePanelBounds); - - 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); - - PlayBar_Render(TimelineState, PlayBarBounds, Panel, RenderBuffer, State, Context); - FrameCount_Render(TimelineState, FrameCountBounds, RenderBuffer, State, Context); - LayerList_Render(TimelineState, LayersBounds, Panel, RenderBuffer, State, Context); - TimeRange_Render(TimelineState, TimeRangeBounds, RenderBuffer, State, Context); - } + 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); + PlayBar_Render(TimelineState, PlayBarBounds, Panel, RenderBuffer, State, Context); + FrameCount_Render(TimelineState, FrameCountBounds, RenderBuffer, State, Context); + LayerList_Render(TimelineState, LayersBounds, Panel, RenderBuffer, State, Context); + TimeRange_Render(TimelineState, TimeRangeBounds, RenderBuffer, State, Context); AnimInfoView_Render(TimelineState, InfoBounds, Panel, RenderBuffer, State, Context); } diff --git a/src/app/editor/panels/foldhaus_panel_file_view.h b/src/app/editor/panels/foldhaus_panel_file_view.h index fc3b4cd..eaf5013 100644 --- a/src/app/editor/panels/foldhaus_panel_file_view.h +++ b/src/app/editor/panels/foldhaus_panel_file_view.h @@ -5,8 +5,16 @@ // #ifndef FOLDHAUS_PANEL_FILE_VIEW_H +enum file_view_mode +{ + FileViewMode_Load, + FileViewMode_Save, +}; + struct file_view_state { + file_view_mode Mode; + gs_string WorkingDirectory; gs_memory_arena FileNamesArena; gs_file_info_array FileNames; @@ -14,9 +22,18 @@ struct file_view_state gs_file_info SelectedFile; }; +internal void +FileView_SetMode(panel* Panel, file_view_mode Mode) +{ + file_view_state* FileViewState = Panel_GetStateStruct(Panel, file_view_state); + FileViewState->Mode = Mode; +} + internal void FileView_Exit_(panel* FileViewPanel, app_state* State, context Context) { + // TODO(pjs): Free State->FileNamesArena + Assert(FileViewPanel->IsModalOverrideFor != 0); panel* ReturnTo = FileViewPanel->IsModalOverrideFor; if (ReturnTo->ModalOverrideCB) @@ -30,7 +47,7 @@ global input_command* FileView_Commands = 0; s32 FileView_CommandsCount = 0; internal void -FileViewUpdateWorkingDirectory(gs_const_string WorkingDirectory, file_view_state* State, context Context) +FileView_UpdateWorkingDirectory(gs_const_string WorkingDirectory, file_view_state* State, context Context) { ClearArena(&State->FileNamesArena); @@ -43,23 +60,20 @@ FileViewUpdateWorkingDirectory(gs_const_string WorkingDirectory, file_view_state u32 SecondLastSlashIndex = FindLast(SanitizedDirectory, LastSlashIndex - 1, '\\'); SanitizedDirectory = Substring(SanitizedDirectory, 0, SecondLastSlashIndex); } - else if (StringsEqual(LastDir, ConstString("."))) + else if (StringsEqual(LastDir, ConstString(".")) && LastDir.Length > 1) { SanitizedDirectory = Substring(SanitizedDirectory, 0, LastSlashIndex); } - State->WorkingDirectory = PushString(&State->FileNamesArena, WorkingDirectory.Length + 2); - PrintF(&State->WorkingDirectory, "%S", SanitizedDirectory); - if (State->WorkingDirectory.Str[State->WorkingDirectory.Length - 1] != '\\') + gs_file_info NewWorkingDirectory = GetFileInfo(Context.ThreadContext.FileHandler, SanitizedDirectory); + if (NewWorkingDirectory.IsDirectory) { - AppendPrintF(&State->WorkingDirectory, "\\"); + // NOTE(pjs): we might be printing from State->WorkingDirectory to State->WorkingDirectory + // in some cases. Shouldn't be a problem but it is unnecessary + PrintF(&State->WorkingDirectory, "%S", WorkingDirectory); + + State->FileNames = EnumerateDirectory(Context.ThreadContext.FileHandler, &State->FileNamesArena, State->WorkingDirectory.ConstString, EnumerateDirectory_IncludeDirectories); } - if (State->WorkingDirectory.Str[State->WorkingDirectory.Length - 1] != '*') - { - AppendPrintF(&State->WorkingDirectory, "*"); - } - - State->FileNames = EnumerateDirectory(Context.ThreadContext.FileHandler, &State->FileNamesArena, State->WorkingDirectory.ConstString, EnumerateDirectory_IncludeDirectories); } GSMetaTag(panel_init); @@ -71,7 +85,10 @@ FileView_Init(panel* Panel, app_state* State, context Context) file_view_state* FileViewState = PushStruct(&State->Permanent, file_view_state); Panel->StateMemory = StructToData(FileViewState, file_view_state); FileViewState->FileNamesArena = CreateMemoryArena(Context.ThreadContext.Allocator); - FileViewUpdateWorkingDirectory(ConstString("."), FileViewState, Context); + + // TODO(pjs): this shouldn't be stored in permanent + FileViewState->WorkingDirectory = PushString(&State->Permanent, 256); + FileView_UpdateWorkingDirectory(ConstString("."), FileViewState, Context); } GSMetaTag(panel_cleanup); @@ -88,6 +105,8 @@ 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); + Assert(FileViewState->Mode == FileViewMode_Save); + ui_PushLayout(&State->Interface, PanelBounds, LayoutDirection_TopDown, MakeString("FileView Layout")); { if (ui_Button(&State->Interface, MakeString("Exit"))) @@ -96,7 +115,21 @@ FileView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBu } // Header - ui_Label(&State->Interface, FileViewState->WorkingDirectory); + if (ui_TextEntry(&State->Interface, MakeString("pwd"), &FileViewState->WorkingDirectory)) + { + // if last character is a slash, update pwd, and clear the filter string + // otherwise update the filter string + gs_string Pwd = FileViewState->WorkingDirectory; + char LastChar = Pwd.Str[Pwd.Length - 1]; + if (LastChar == '\\' || LastChar == '/') + { + FileView_UpdateWorkingDirectory(Pwd.ConstString, FileViewState, Context); + } + else + { + + } + } // File Display ui_BeginList(&State->Interface, MakeString("Files"), 10, FileViewState->FileNames.Count); @@ -113,7 +146,7 @@ FileView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBu { if (File.IsDirectory) { - FileViewUpdateWorkingDirectory(File.Path, FileViewState, Context); + FileView_UpdateWorkingDirectory(File.Path, FileViewState, Context); } else { @@ -128,6 +161,5 @@ FileView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBu } - #define FOLDHAUS_PANEL_FILE_VIEW_H #endif // FOLDHAUS_PANEL_FILE_VIEW_H \ No newline at end of file diff --git a/src/app/editor/panels/foldhaus_panel_hierarchy.h b/src/app/editor/panels/foldhaus_panel_hierarchy.h index 380596c..e19cbb0 100644 --- a/src/app/editor/panels/foldhaus_panel_hierarchy.h +++ b/src/app/editor/panels/foldhaus_panel_hierarchy.h @@ -60,6 +60,7 @@ HierarchyView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Ren if (ui_Button(&State->Interface, MakeString("+ Add Assembly"))) { panel* FileBrowser = PanelSystem_PushPanel(&State->PanelSystem, PanelType_FileView, State, Context); + FileView_SetMode(FileBrowser, FileViewMode_Save); Panel_PushModalOverride(Panel, FileBrowser, LoadAssemblyCallback); } diff --git a/src/app/engine/assembly/foldhaus_assembly_parser.cpp b/src/app/engine/assembly/foldhaus_assembly_parser.cpp index ff2cbc0..26e4205 100644 --- a/src/app/engine/assembly/foldhaus_assembly_parser.cpp +++ b/src/app/engine/assembly/foldhaus_assembly_parser.cpp @@ -225,7 +225,7 @@ AssemblyParser_ReadSequence(parser* Parser, assembly* Assembly) internal strip_gen_data AssemblyParser_ReadStripGenData(parser* Parser, assembly* Assembly) { - strip_gen_data Result = {0}; + strip_gen_data Result = {}; if (Parser_ReadOpenStruct(Parser, AssemblyField_Segment)) { diff --git a/src/app/interface.h b/src/app/interface.h index 1c1b304..ee846c1 100644 --- a/src/app/interface.h +++ b/src/app/interface.h @@ -1141,7 +1141,7 @@ ui_TextEntrySetFlags(ui_widget* Widget, gs_string EditString) ui_WidgetSetFlag(Widget, UIWidgetFlag_Typable); } -internal void +internal bool ui_TextEntry(ui_interface* Interface, gs_string Identifier, gs_string* Value) { ui_widget* Widget = ui_CreateWidget(Interface, Identifier); @@ -1155,7 +1155,10 @@ ui_TextEntry(ui_interface* Interface, gs_string Identifier, gs_string* Value) ui_TextEntrySetFlags(Widget, State->EditString); ui_eval_result Result = ui_EvaluateWidget(Interface, Widget); + bool StringEdited = !StringsEqual(*Value, State->EditString); PrintF(Value, "%S", State->EditString); + + return StringEdited; } internal u64 diff --git a/src/app/platform_win32/win32_foldhaus_fileio.h b/src/app/platform_win32/win32_foldhaus_fileio.h index 2c4059c..bfb93ac 100644 --- a/src/app/platform_win32/win32_foldhaus_fileio.h +++ b/src/app/platform_win32/win32_foldhaus_fileio.h @@ -46,6 +46,20 @@ GET_FILE_INFO(Win32GetFileInfo) } CloseHandle(FileHandle); } + else + { + DWORD FileAttr = GetFileAttributes(Path.Str); + if (FileAttr != INVALID_FILE_ATTRIBUTES && + (FileAttr & FILE_ATTRIBUTE_DIRECTORY)) + { + Result.Path = Path; + Result.IsDirectory = true; + } + else + { + // Path is not a file or directory + } + } return Result; } diff --git a/src/gs_libs/gs_types.h b/src/gs_libs/gs_types.h index 82c9246..c9cfdbe 100644 --- a/src/gs_libs/gs_types.h +++ b/src/gs_libs/gs_types.h @@ -9,6 +9,7 @@ # pragma GCC diagnostic ignored "-Wunused-value" # pragma GCC diagnostic ignored "-Wvarargs" # pragma GCC diagnostic ignored "-Wwritable-strings" +# pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif #if defined(_MSC_VER) From 6d8d642dfbd1af6bc2c743d3e19109c1984cebdf Mon Sep 17 00:00:00 2001 From: PS Date: Sat, 23 Jan 2021 12:46:46 -0800 Subject: [PATCH 23/44] cleaning up build system. added animation_system_desc --- build/build_app_msvc_win32_debug.bat | 1 + build/setup_cl.bat | 3 +++ src/app/engine/animation/foldhaus_animation.h | 18 ++++++++++++++++++ src/app/foldhaus_app.cpp | 11 ++++++----- 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/build/build_app_msvc_win32_debug.bat b/build/build_app_msvc_win32_debug.bat index 0819a48..d69d5db 100644 --- a/build/build_app_msvc_win32_debug.bat +++ b/build/build_app_msvc_win32_debug.bat @@ -2,6 +2,7 @@ SET MyPath=%~dp0 SET MyPath=%MyPath:~0,-1% + call %MyPath%\_prebuild_win32.bat app debug msvc call %MyPath%\setup_cl.bat diff --git a/build/setup_cl.bat b/build/setup_cl.bat index faf7fe6..bae8867 100644 --- a/build/setup_cl.bat +++ b/build/setup_cl.bat @@ -1,5 +1,7 @@ @echo off +ECHO SETUP CL + SET "LIB=" SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio 12.0 @@ -35,3 +37,4 @@ IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\Auxiliary\Build\vcv SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\Auxiliary\Build\vcvarsall.bat" x64)) +ECHO SETUP CL COMPLETE \ No newline at end of file diff --git a/src/app/engine/animation/foldhaus_animation.h b/src/app/engine/animation/foldhaus_animation.h index 9309c0b..d93f3f1 100644 --- a/src/app/engine/animation/foldhaus_animation.h +++ b/src/app/engine/animation/foldhaus_animation.h @@ -484,6 +484,24 @@ ClampFrameToRange(s32 Frame, frame_range Range) // System +struct animation_system_desc +{ + gs_memory_arena* Storage; + u32 AnimArrayCount; + r32 SecondsPerFrame; +}; + +internal animation_system +AnimationSystem_Init(animation_system_desc Desc) +{ + animation_system Result = {}; + Result.Storage = Desc.Storage; + Result.Animations = AnimationArray_Create(Result.Storage, Desc.AnimArrayCount); + Result.SecondsPerFrame = Desc.SecondsPerFrame; + + return Result; +} + internal animation* AnimationSystem_GetActiveAnimation(animation_system* System) { diff --git a/src/app/foldhaus_app.cpp b/src/app/foldhaus_app.cpp index ade4707..f879b98 100644 --- a/src/app/foldhaus_app.cpp +++ b/src/app/foldhaus_app.cpp @@ -91,11 +91,11 @@ INITIALIZE_APPLICATION(InitializeApplication) #endif { // Animation PLAYGROUND - State->AnimationSystem = {}; - State->AnimationSystem.Storage = &State->Permanent; - State->AnimationSystem.Animations = AnimationArray_Create(State->AnimationSystem.Storage, 32); - - State->AnimationSystem.SecondsPerFrame = 1.f / 24.f; + animation_system_desc AnimSysDesc = {}; + AnimSysDesc.Storage = &State->Permanent; + AnimSysDesc.AnimArrayCount = 32; + AnimSysDesc.SecondsPerFrame = 1.0f / 24.0f; + State->AnimationSystem = AnimationSystem_Init(AnimSysDesc); animation Anim = {0}; Anim.Name = PushStringF(&State->Permanent, 256, "test_anim_one"); @@ -103,6 +103,7 @@ INITIALIZE_APPLICATION(InitializeApplication) Anim.Blocks_ = AnimBlockArray_Create(State->AnimationSystem.Storage, 8); Anim.PlayableRange.Min = 0; Anim.PlayableRange.Max = SecondsToFrames(15, State->AnimationSystem); + Animation_AddLayer(&Anim, MakeString("Base Layer"), BlendMode_Overwrite, &State->AnimationSystem); Animation_AddLayer(&Anim, MakeString("Color Layer"), BlendMode_Multiply, &State->AnimationSystem); Animation_AddLayer(&Anim, MakeString("Sparkles"), BlendMode_Add, &State->AnimationSystem); From 0916bef999b7839bf8ecdbc03ef118d5e29323bb Mon Sep 17 00:00:00 2001 From: Peter Slattery Date: Sat, 23 Jan 2021 12:48:14 -0800 Subject: [PATCH 24/44] introduced BlumenLumen_CustomUpdate and Init as proxies for an eventual user space system --- src/app/blumen_lumen.cpp | 57 ++++++++++++++++++++++++++++++++++++++++ src/app/foldhaus_app.cpp | 31 ++++++---------------- src/app/foldhaus_app.h | 1 + 3 files changed, 66 insertions(+), 23 deletions(-) create mode 100644 src/app/blumen_lumen.cpp diff --git a/src/app/blumen_lumen.cpp b/src/app/blumen_lumen.cpp new file mode 100644 index 0000000..8a9d23b --- /dev/null +++ b/src/app/blumen_lumen.cpp @@ -0,0 +1,57 @@ +// +// File: blumen_lumen.cpp +// Author: Peter Slattery +// Creation Date: 2021-01-23 +// +#ifndef BLUMEN_LUMEN_CPP + +struct foo_ +{ + u32 Heyo; +}; + +internal gs_data +BlumenLumen_CustomInit(app_state* State, context Context) +{ + // This is memory for any custom data that we want to use + // as a part of a particular sculpture. + // By returning it from here, it will be sent as an argument to + // the sculpture's CustomUpdate function; + gs_data Result = {}; + + Result = PushSizeToData(&State->Permanent, sizeof(foo_)); + foo_* MyFoo = (foo_*)Result.Memory; + MyFoo->Heyo = 5; + + { // Animation PLAYGROUND + + animation Anim = {0}; + Anim.Name = PushStringF(&State->Permanent, 256, "test_anim_one"); + Anim.Layers = AnimLayerArray_Create(State->AnimationSystem.Storage, 8); + Anim.Blocks_ = AnimBlockArray_Create(State->AnimationSystem.Storage, 8); + Anim.PlayableRange.Min = 0; + Anim.PlayableRange.Max = SecondsToFrames(15, State->AnimationSystem); + Animation_AddLayer(&Anim, MakeString("Base Layer"), BlendMode_Overwrite, &State->AnimationSystem); + Animation_AddLayer(&Anim, MakeString("Color Layer"), BlendMode_Multiply, &State->AnimationSystem); + Animation_AddLayer(&Anim, MakeString("Sparkles"), BlendMode_Add, &State->AnimationSystem); + + Animation_AddBlock(&Anim, 0, Anim.PlayableRange.Max, Patterns_IndexToHandle(5), 0); + + AnimationArray_Push(&State->AnimationSystem.Animations, Anim); + + State->AnimationSystem.TimelineShouldAdvance = true; + } // End Animation Playground + + return Result; +} + +internal void +BlumenLumen_CustomUpdate(gs_data UserData, app_state* State, context* Context) +{ + foo_* MyFoo = (foo_*)UserData.Memory; + Assert(MyFoo->Heyo == 5); +} + + +#define BLUMEN_LUMEN_CPP +#endif // BLUMEN_LUMEN_CPP \ No newline at end of file diff --git a/src/app/foldhaus_app.cpp b/src/app/foldhaus_app.cpp index ade4707..ef95275 100644 --- a/src/app/foldhaus_app.cpp +++ b/src/app/foldhaus_app.cpp @@ -90,29 +90,12 @@ INITIALIZE_APPLICATION(InitializeApplication) LoadAssembly(&State->Assemblies, &State->LedSystem, State->Transient, Context, SculpturePath, State->GlobalLog); #endif - { // Animation PLAYGROUND - State->AnimationSystem = {}; - State->AnimationSystem.Storage = &State->Permanent; - State->AnimationSystem.Animations = AnimationArray_Create(State->AnimationSystem.Storage, 32); - - State->AnimationSystem.SecondsPerFrame = 1.f / 24.f; - - animation Anim = {0}; - Anim.Name = PushStringF(&State->Permanent, 256, "test_anim_one"); - Anim.Layers = AnimLayerArray_Create(State->AnimationSystem.Storage, 8); - Anim.Blocks_ = AnimBlockArray_Create(State->AnimationSystem.Storage, 8); - Anim.PlayableRange.Min = 0; - Anim.PlayableRange.Max = SecondsToFrames(15, State->AnimationSystem); - Animation_AddLayer(&Anim, MakeString("Base Layer"), BlendMode_Overwrite, &State->AnimationSystem); - Animation_AddLayer(&Anim, MakeString("Color Layer"), BlendMode_Multiply, &State->AnimationSystem); - Animation_AddLayer(&Anim, MakeString("Sparkles"), BlendMode_Add, &State->AnimationSystem); - - Animation_AddBlock(&Anim, 0, Anim.PlayableRange.Max, Patterns_IndexToHandle(5), 0); - - AnimationArray_Push(&State->AnimationSystem.Animations, Anim); - - State->AnimationSystem.TimelineShouldAdvance = true; - } // End Animation Playground + State->AnimationSystem = {}; + State->AnimationSystem.Storage = &State->Permanent; + State->AnimationSystem.Animations = AnimationArray_Create(State->AnimationSystem.Storage, 32); + State->AnimationSystem.SecondsPerFrame = 1.f / 24.f; + + State->UserData = BlumenLumen_CustomInit(State, Context); } UPDATE_AND_RENDER(UpdateAndRender) @@ -139,6 +122,8 @@ UPDATE_AND_RENDER(UpdateAndRender) State->UserData.Memory); } + BlumenLumen_CustomUpdate(State->UserData, State, Context); + AssemblyDebug_OverrideOutput(State->AssemblyDebugState, State->Assemblies, State->LedSystem); diff --git a/src/app/foldhaus_app.h b/src/app/foldhaus_app.h index bf99bf6..a6608dc 100644 --- a/src/app/foldhaus_app.h +++ b/src/app/foldhaus_app.h @@ -78,6 +78,7 @@ internal void OpenColorPicker(app_state* State, v4* Address); #include "engine/assembly/foldhaus_assembly.cpp" #include "patterns/blumen_patterns.h" +#include "blumen_lumen.cpp" internal void EndCurrentOperationMode(app_state* State) From 26caed68a4c925608784ac9b56ba33ba817b8031 Mon Sep 17 00:00:00 2001 From: Peter Slattery Date: Sat, 23 Jan 2021 15:58:05 -0800 Subject: [PATCH 25/44] more blumen explorations --- src/app/blumen_lumen.cpp | 40 +++++++++---- src/app/engine/assembly/foldhaus_assembly.h | 8 +++ src/app/foldhaus_app.cpp | 8 +-- src/app/patterns/blumen_patterns.h | 62 +++++++++++++++++++++ src/gs_libs/gs_types.cpp | 24 ++++---- src/sculpture_gen/gen_blumen_lumen.cpp | 26 ++++----- 6 files changed, 124 insertions(+), 44 deletions(-) diff --git a/src/app/blumen_lumen.cpp b/src/app/blumen_lumen.cpp index 8a9d23b..54a21ce 100644 --- a/src/app/blumen_lumen.cpp +++ b/src/app/blumen_lumen.cpp @@ -5,6 +5,10 @@ // #ifndef BLUMEN_LUMEN_CPP +// TODO(pjs): +// - need to request opening a network port and getting messages from it pumped into CustomUpdate +// + struct foo_ { u32 Heyo; @@ -23,21 +27,35 @@ BlumenLumen_CustomInit(app_state* State, context Context) foo_* MyFoo = (foo_*)Result.Memory; MyFoo->Heyo = 5; +#if 1 + gs_const_string SculpturePath = ConstString("data/test_blumen.fold"); + LoadAssembly(&State->Assemblies, &State->LedSystem, State->Transient, Context, SculpturePath, State->GlobalLog); +#endif + { // Animation PLAYGROUND + animation Anim0 = {0}; + Anim0.Name = PushStringF(&State->Permanent, 256, "test_anim_zero"); + Anim0.Layers = AnimLayerArray_Create(State->AnimationSystem.Storage, 8); + Anim0.Blocks_ = AnimBlockArray_Create(State->AnimationSystem.Storage, 8); + Anim0.PlayableRange.Min = 0; + Anim0.PlayableRange.Max = SecondsToFrames(15, State->AnimationSystem); + Animation_AddLayer(&Anim0, MakeString("Base Layer"), BlendMode_Overwrite, &State->AnimationSystem); - animation Anim = {0}; - Anim.Name = PushStringF(&State->Permanent, 256, "test_anim_one"); - Anim.Layers = AnimLayerArray_Create(State->AnimationSystem.Storage, 8); - Anim.Blocks_ = AnimBlockArray_Create(State->AnimationSystem.Storage, 8); - Anim.PlayableRange.Min = 0; - Anim.PlayableRange.Max = SecondsToFrames(15, State->AnimationSystem); - Animation_AddLayer(&Anim, MakeString("Base Layer"), BlendMode_Overwrite, &State->AnimationSystem); - Animation_AddLayer(&Anim, MakeString("Color Layer"), BlendMode_Multiply, &State->AnimationSystem); - Animation_AddLayer(&Anim, MakeString("Sparkles"), BlendMode_Add, &State->AnimationSystem); + Animation_AddBlock(&Anim0, 0, Anim0.PlayableRange.Max, Patterns_IndexToHandle(5), 0); - Animation_AddBlock(&Anim, 0, Anim.PlayableRange.Max, Patterns_IndexToHandle(5), 0); + AnimationArray_Push(&State->AnimationSystem.Animations, Anim0); - AnimationArray_Push(&State->AnimationSystem.Animations, Anim); + animation Anim1 = {0}; + Anim1.Name = PushStringF(&State->Permanent, 256, "test_anim_one"); + Anim1.Layers = AnimLayerArray_Create(State->AnimationSystem.Storage, 8); + Anim1.Blocks_ = AnimBlockArray_Create(State->AnimationSystem.Storage, 8); + Anim1.PlayableRange.Min = 0; + Anim1.PlayableRange.Max = SecondsToFrames(15, State->AnimationSystem); + Animation_AddLayer(&Anim1, MakeString("Base Layer"), BlendMode_Overwrite, &State->AnimationSystem); + + Animation_AddBlock(&Anim1, 0, Anim0.PlayableRange.Max, Patterns_IndexToHandle(5), 0); + + AnimationArray_Push(&State->AnimationSystem.Animations, Anim1); State->AnimationSystem.TimelineShouldAdvance = true; } // End Animation Playground diff --git a/src/app/engine/assembly/foldhaus_assembly.h b/src/app/engine/assembly/foldhaus_assembly.h index 3378cc5..677d4ff 100644 --- a/src/app/engine/assembly/foldhaus_assembly.h +++ b/src/app/engine/assembly/foldhaus_assembly.h @@ -225,5 +225,13 @@ AssemblyStrip_HasTagValue(v2_strip Strip, u64 NameHash, u64 ValueHash) return Result; } +internal bool +AssemblyStrip_HasTagValueSLOW(v2_strip Strip, char* Name, char* Value) +{ + u64 NameHash = HashDJB2ToU32(Name); + u64 ValueHash = HashDJB2ToU32(Value); + return AssemblyStrip_HasTagValue(Strip, NameHash, ValueHash); +} + #define FOLDHAUS_ASSEMBLY_H #endif // FOLDHAUS_ASSEMBLY_H \ No newline at end of file diff --git a/src/app/foldhaus_app.cpp b/src/app/foldhaus_app.cpp index 8389999..f8fbe20 100644 --- a/src/app/foldhaus_app.cpp +++ b/src/app/foldhaus_app.cpp @@ -26,6 +26,7 @@ ClearAndPushPatterns(animation_pattern_array* Patterns) Patterns_PushPattern(Patterns, Pattern_LighthouseRainbow); Patterns_PushPattern(Patterns, Pattern_SmoothGrowRainbow); Patterns_PushPattern(Patterns, Pattern_GrowAndFade); + Patterns_PushPattern(Patterns, Pattern_ColorToWhite); } RELOAD_STATIC_DATA(ReloadStaticData) @@ -52,7 +53,7 @@ INITIALIZE_APPLICATION(InitializeApplication) State->CommandQueue = CommandQueue_Create(&State->Permanent, 32); - State->Patterns = Patterns_Create(&State->Permanent, 10); + State->Patterns = Patterns_Create(&State->Permanent, 32); ClearAndPushPatterns(&State->Patterns); interface_config IConfig = {0}; @@ -85,11 +86,6 @@ INITIALIZE_APPLICATION(InitializeApplication) ReloadStaticData(Context, GlobalDebugServices); -#if 1 - gs_const_string SculpturePath = ConstString("data/test_blumen.fold"); - LoadAssembly(&State->Assemblies, &State->LedSystem, State->Transient, Context, SculpturePath, State->GlobalLog); -#endif - animation_system_desc AnimSysDesc = {}; AnimSysDesc.Storage = &State->Permanent; AnimSysDesc.AnimArrayCount = 32; diff --git a/src/app/patterns/blumen_patterns.h b/src/app/patterns/blumen_patterns.h index a8940f9..0560339 100644 --- a/src/app/patterns/blumen_patterns.h +++ b/src/app/patterns/blumen_patterns.h @@ -391,5 +391,67 @@ Pattern_GrowAndFade(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_are } } +internal void +Pattern_ColorToWhite(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +{ + r32 FadeBottomBase = 50; + r32 FadeTop = 125; + + for (u32 StripIndex = 0; StripIndex < Assembly.StripCount; StripIndex++) + { + v2_strip Strip = Assembly.Strips[StripIndex]; + + r32 FlowerSpread = .8f; + r32 FlowerOffset = 0; + if (AssemblyStrip_HasTagValueSLOW(Strip, "flower", "center")) + { + FlowerOffset = 1; + } + else if (AssemblyStrip_HasTagValueSLOW(Strip, "flower", "right")) + { + FlowerOffset = 2; + } + FlowerOffset *= FlowerSpread; + + r32 PercentCycle = ModR32(Time + FlowerOffset, 10) / 10; + + r32 FadeBottom = FadeBottomBase + RemapR32(SinR32((PercentCycle * 4) * TauR32), -1, 1, -50, 50); + + v4 TopRGB = WhiteV4; + pixel TopColor = V4ToRGBPixel(TopRGB); + + for (u32 i = 0; i < Strip.LedCount; i++) + { + u32 LedIndex = Strip.LedLUT[i]; + v4 P = Leds->Positions[LedIndex]; + + pixel FinalColor = {}; + if (P.y > FadeTop) + { + FinalColor = TopColor; + } + else + { + r32 B = RemapR32(SinR32((P.y / 15.f) + (PercentCycle * TauR32)), -1, 1, .5f, 1.f); + r32 HNoise = RemapR32(SinR32((P.y / 31.f) + (PercentCycle * TauR32)), -1, 1, -32.f, 32.f); + v4 BottomRGB = HSVToRGB(v4{ (PercentCycle * 360) + HNoise, 1, B, 1 }); + + if (P.y < FadeBottom) + { + FinalColor = V4ToRGBPixel(BottomRGB); + } + else if (P.y >= FadeBottom && P.y <= FadeTop) + { + r32 FadePct = RemapR32(P.y, FadeBottom, FadeTop, 0, 1); + v4 MixRGB = V4Lerp(FadePct, BottomRGB, TopRGB); + FinalColor = V4ToRGBPixel(MixRGB); + } + } + + Leds->Colors[LedIndex] = FinalColor; + } + } +} + #define BLUMEN_PATTERNS_H #endif // BLUMEN_PATTERNS_H \ No newline at end of file diff --git a/src/gs_libs/gs_types.cpp b/src/gs_libs/gs_types.cpp index 205ef8c..fd40b0f 100644 --- a/src/gs_libs/gs_types.cpp +++ b/src/gs_libs/gs_types.cpp @@ -685,34 +685,34 @@ V4Cross(v4 A, v4 B) } internal v2 -V2Lerp(v2 A, v2 B, r32 T) +V2Lerp(r32 T, v2 A, v2 B) { v2 Result = v2{ - LerpR32(A.x, B.x, T), - LerpR32(A.y, B.y, T), + LerpR32(T, A.x, B.x), + LerpR32(T, A.y, B.y), }; return Result; } internal v3 -V3Lerp(v3 A, v3 B, r32 T) +V3Lerp(r32 T, v3 A, v3 B) { v3 Result = v3{ - LerpR32(A.x, B.x, T), - LerpR32(A.y, B.y, T), - LerpR32(A.z, B.z, T), + LerpR32(T, A.x, B.x), + LerpR32(T, A.y, B.y), + LerpR32(T, A.z, B.z), }; return Result; } internal v4 -V4Lerp(v4 A, v4 B, r32 T) +V4Lerp(r32 T, v4 A, v4 B) { v4 Result = v4{ - LerpR32(A.x, B.x, T), - LerpR32(A.y, B.y, T), - LerpR32(A.z, B.z, T), - LerpR32(A.w, B.w, T), + LerpR32(T, A.x, B.x), + LerpR32(T, A.y, B.y), + LerpR32(T, A.z, B.z), + LerpR32(T, A.w, B.w), }; return Result; } diff --git a/src/sculpture_gen/gen_blumen_lumen.cpp b/src/sculpture_gen/gen_blumen_lumen.cpp index 5a1bb04..00333da 100644 --- a/src/sculpture_gen/gen_blumen_lumen.cpp +++ b/src/sculpture_gen/gen_blumen_lumen.cpp @@ -172,7 +172,6 @@ int main(int ArgCount, char** Args) gs_string OutputBuffer = PushString(Ctx.Transient, MB(4)); - char* ComPort = "\\\\.\\COM3"; WriteAssemblyUARTOpen(&OutputBuffer, "Blumen Lumen - Silver Spring", 100, @@ -181,37 +180,34 @@ int main(int ArgCount, char** Args) ""); u32 StemChannels[] = { FSC(2, 1), FSC(2, 2), FSC(2, 3), FSC(2, 4), FSC(2, 5), FSC(2, 6) }; - u32 BloomOuterChannels[] = { FSC(1, 0), FSC(1, 1), FSC(1, 2), FSC(1, 3), FSC(1, 4), FSC(1, 5), FSC(1, 6), FSC(1, 7), FSC(2, 7) }; + u32 BloomOuterChannels[] = { FSC(1, 0), FSC(1, 1), FSC(1, 2), FSC(1, 3), FSC(1, 4), FSC(1, 5), FSC(1, 6), FSC(1, 7), FSC(2, 0) }; u32 BloomInnerChannels[] = { FSC(0, 0), FSC(0, 1), FSC(0, 2), FSC(0, 3), FSC(0, 4), FSC(0, 5) }; flower_desc F0 = {}; F0.Pos = v3{-1, 0, 0}; - F0.ComPort = ComPort; + F0.ComPort = "\\\\.\\COM4"; F0.FlowerTagValue = "left"; F0.StemChannels = StemChannels; F0.BloomOuterChannels = BloomOuterChannels; F0.BloomInnerChannels = BloomInnerChannels; BuildFlower(&OutputBuffer, F0); -#if 1 flower_desc F1 = {}; F1.Pos = v3{0, 0, 0}; - F1.ComPort = "\\\\.\\COM6"; + F1.ComPort = "\\\\.\\COM5"; F1.FlowerTagValue = "center"; F1.StemChannels = StemChannels; F1.BloomInnerChannels = BloomInnerChannels; F1.BloomOuterChannels = BloomOuterChannels; BuildFlower(&OutputBuffer, F1); -#endif - /* - flower_desc F2 = {}; - F2.Pos = v3{1, 0, 0}; - F2.FlowerTagValue = "right"; - F2.StemChannels = StemChannels; - F2.BloomInnerChannels = BloomInnerChannels; - F2.BloomOuterChannels = BloomOuterChannels; - BuildFlower(&OutputBuffer, F2); - */ + flower_desc F2 = {}; + F2.Pos = v3{1, 0, 0}; + F2.ComPort = "\\\\.\\COM6"; + F2.FlowerTagValue = "right"; + F2.StemChannels = StemChannels; + F2.BloomInnerChannels = BloomInnerChannels; + F2.BloomOuterChannels = BloomOuterChannels; + BuildFlower(&OutputBuffer, F2); printf("%.*s\n", (u32)OutputBuffer.Length, OutputBuffer.Str); From 9d1809b5e2396ab66d1d0dd23cb6cf286d371179 Mon Sep 17 00:00:00 2001 From: Peter Slattery Date: Sat, 23 Jan 2021 17:38:19 -0800 Subject: [PATCH 26/44] Got a listen loop set up for the mic --- src/app/blumen_lumen.cpp | 66 ++++++++++++++++++---- src/app/blumen_lumen.h | 20 +++++++ src/app/foldhaus_app.cpp | 6 ++ src/app/foldhaus_app.h | 2 + src/app/foldhaus_platform.h | 19 ++++++- src/app/patterns/blumen_patterns.h | 23 ++++++++ src/app/platform_win32/win32_foldhaus.cpp | 26 ++------- src/app/platform_win32/win32_test_code.cpp | 43 +++++++++++--- 8 files changed, 161 insertions(+), 44 deletions(-) diff --git a/src/app/blumen_lumen.cpp b/src/app/blumen_lumen.cpp index 54a21ce..ccc04c1 100644 --- a/src/app/blumen_lumen.cpp +++ b/src/app/blumen_lumen.cpp @@ -9,11 +9,6 @@ // - need to request opening a network port and getting messages from it pumped into CustomUpdate // -struct foo_ -{ - u32 Heyo; -}; - internal gs_data BlumenLumen_CustomInit(app_state* State, context Context) { @@ -23,9 +18,10 @@ BlumenLumen_CustomInit(app_state* State, context Context) // the sculpture's CustomUpdate function; gs_data Result = {}; - Result = PushSizeToData(&State->Permanent, sizeof(foo_)); - foo_* MyFoo = (foo_*)Result.Memory; - MyFoo->Heyo = 5; + Result = PushSizeToData(&State->Permanent, sizeof(blumen_lumen_state)); + + blumen_lumen_state* BLState = (blumen_lumen_state*)Result.Memory; + BLState->JobReq.Memory = (u8*)&BLState->MicPacketBuffer; #if 1 gs_const_string SculpturePath = ConstString("data/test_blumen.fold"); @@ -41,7 +37,7 @@ BlumenLumen_CustomInit(app_state* State, context Context) Anim0.PlayableRange.Max = SecondsToFrames(15, State->AnimationSystem); Animation_AddLayer(&Anim0, MakeString("Base Layer"), BlendMode_Overwrite, &State->AnimationSystem); - Animation_AddBlock(&Anim0, 0, Anim0.PlayableRange.Max, Patterns_IndexToHandle(5), 0); + Animation_AddBlock(&Anim0, 0, Anim0.PlayableRange.Max, Patterns_IndexToHandle(11), 0); AnimationArray_Push(&State->AnimationSystem.Animations, Anim0); @@ -53,10 +49,22 @@ BlumenLumen_CustomInit(app_state* State, context Context) Anim1.PlayableRange.Max = SecondsToFrames(15, State->AnimationSystem); Animation_AddLayer(&Anim1, MakeString("Base Layer"), BlendMode_Overwrite, &State->AnimationSystem); - Animation_AddBlock(&Anim1, 0, Anim0.PlayableRange.Max, Patterns_IndexToHandle(5), 0); + Animation_AddBlock(&Anim1, 0, Anim0.PlayableRange.Max, Patterns_IndexToHandle(12), 0); AnimationArray_Push(&State->AnimationSystem.Animations, Anim1); + animation Anim2 = {0}; + Anim2.Name = PushStringF(&State->Permanent, 256, "i_love_you"); + Anim2.Layers = AnimLayerArray_Create(State->AnimationSystem.Storage, 8); + Anim2.Blocks_ = AnimBlockArray_Create(State->AnimationSystem.Storage, 8); + Anim2.PlayableRange.Min = 0; + Anim2.PlayableRange.Max = SecondsToFrames(15, State->AnimationSystem); + Animation_AddLayer(&Anim2, MakeString("Base Layer"), BlendMode_Overwrite, &State->AnimationSystem); + + Animation_AddBlock(&Anim2, 0, Anim0.PlayableRange.Max, Patterns_IndexToHandle(10), 0); + + AnimationArray_Push(&State->AnimationSystem.Animations, Anim2); + State->AnimationSystem.TimelineShouldAdvance = true; } // End Animation Playground @@ -66,8 +74,42 @@ BlumenLumen_CustomInit(app_state* State, context Context) internal void BlumenLumen_CustomUpdate(gs_data UserData, app_state* State, context* Context) { - foo_* MyFoo = (foo_*)UserData.Memory; - Assert(MyFoo->Heyo == 5); + blumen_lumen_state* BLState = (blumen_lumen_state*)UserData.Memory; + + gs_string BlueString = MakeString("blue"); + gs_string GreenString = MakeString("green"); + gs_string ILoveYouString = MakeString("i_love_you"); + + while (BLState->MicPacketBuffer.ReadHead != BLState->MicPacketBuffer.WriteHead) + { + gs_data PacketData = BLState->MicPacketBuffer.Values[BLState->MicPacketBuffer.ReadHead++]; + microphone_packet Packet = *(microphone_packet*)PacketData.Memory; + + u32 NameLen = CStringLength(Packet.AnimationFileName); + if (StringEqualsCharArray(BlueString.ConstString, Packet.AnimationFileName, NameLen)) + { + State->AnimationSystem.ActiveAnimationIndex = 0; + } + else if (StringEqualsCharArray(GreenString.ConstString, Packet.AnimationFileName, NameLen)) + { + State->AnimationSystem.ActiveAnimationIndex = 1; + } + else if (StringEqualsCharArray(ILoveYouString.ConstString, Packet.AnimationFileName, NameLen)) + { + State->AnimationSystem.ActiveAnimationIndex = 2; + } + + gs_string TempString = PushStringF(State->Transient, 256, "%.*s", 32, Packet.AnimationFileName); + NullTerminate(&TempString); + + OutputDebugStringA("Received\n"); + OutputDebugStringA(TempString.Str); + + if (BLState->MicPacketBuffer.ReadHead >= PACKETS_MAX) + { + BLState->MicPacketBuffer.ReadHead = 0; + } + } } diff --git a/src/app/blumen_lumen.h b/src/app/blumen_lumen.h index e93c247..25220bb 100644 --- a/src/app/blumen_lumen.h +++ b/src/app/blumen_lumen.h @@ -10,6 +10,26 @@ typedef struct motor_packet u8 FlowerPositions[3]; } motor_packet; +#pragma pack(push, 1) +struct microphone_packet +{ + b8 ChangeAnimation; + char AnimationFileName[32]; + b8 SetLayer; + char LayerName[32]; + r32 LayerOpacity; + b8 SetLayerParamColor; + char LayerParamColor[7]; + r32 OverrideDuration; +}; +#pragma pack(pop) + +struct blumen_lumen_state +{ + packet_ringbuffer MicPacketBuffer; + temp_job_req JobReq; +}; + #define BLUMEN_LUMEN_H #endif // BLUMEN_LUMEN_H \ No newline at end of file diff --git a/src/app/foldhaus_app.cpp b/src/app/foldhaus_app.cpp index f8fbe20..7bec2d8 100644 --- a/src/app/foldhaus_app.cpp +++ b/src/app/foldhaus_app.cpp @@ -27,6 +27,8 @@ ClearAndPushPatterns(animation_pattern_array* Patterns) Patterns_PushPattern(Patterns, Pattern_SmoothGrowRainbow); Patterns_PushPattern(Patterns, Pattern_GrowAndFade); Patterns_PushPattern(Patterns, Pattern_ColorToWhite); + Patterns_PushPattern(Patterns, Pattern_Blue); + Patterns_PushPattern(Patterns, Pattern_Green); } RELOAD_STATIC_DATA(ReloadStaticData) @@ -93,6 +95,10 @@ INITIALIZE_APPLICATION(InitializeApplication) State->AnimationSystem = AnimationSystem_Init(AnimSysDesc); State->UserData = BlumenLumen_CustomInit(State, Context); + + // TEMP + blumen_lumen_state* BLState = (blumen_lumen_state*)State->UserData.Memory; + return (temp_job_req*)&BLState->JobReq; } UPDATE_AND_RENDER(UpdateAndRender) diff --git a/src/app/foldhaus_app.h b/src/app/foldhaus_app.h index a6608dc..43f0f84 100644 --- a/src/app/foldhaus_app.h +++ b/src/app/foldhaus_app.h @@ -41,6 +41,8 @@ typedef struct panel panel; #include "engine/animation/foldhaus_animation_serializer.cpp" #include "engine/animation/foldhaus_animation_renderer.cpp" +#include "blumen_lumen.h" + struct app_state { gs_memory_arena Permanent; diff --git a/src/app/foldhaus_platform.h b/src/app/foldhaus_platform.h index 5778c7f..459c1af 100644 --- a/src/app/foldhaus_platform.h +++ b/src/app/foldhaus_platform.h @@ -50,7 +50,23 @@ typedef struct context context; // Application Functions -#define INITIALIZE_APPLICATION(name) void name(context Context) +// TODO(pjs): TEMP +typedef void temp_job_req_proc(gs_thread_context* Ctx, u8* Memory); +struct temp_job_req +{ + temp_job_req_proc* Proc; + u8* Memory; +}; +// This isn't necessarily temp but I'm not sure it goes here +#define PACKETS_MAX 32 +struct packet_ringbuffer +{ + gs_data Values[PACKETS_MAX]; + u32 ReadHead; + u32 WriteHead; +}; + +#define INITIALIZE_APPLICATION(name) temp_job_req* name(context Context) typedef INITIALIZE_APPLICATION(initialize_application); #define UPDATE_AND_RENDER(name) void name(context* Context, input_queue InputQueue, render_command_buffer* RenderBuffer, addressed_data_buffer_list* OutputData) @@ -200,6 +216,5 @@ struct context platform_get_socket_handle* PlatformGetSocketHandle; }; - #define FOLDHAUS_PLATFORM_H #endif // FOLDHAUS_PLATFORM_H \ No newline at end of file diff --git a/src/app/patterns/blumen_patterns.h b/src/app/patterns/blumen_patterns.h index 0560339..966587a 100644 --- a/src/app/patterns/blumen_patterns.h +++ b/src/app/patterns/blumen_patterns.h @@ -5,6 +5,29 @@ // #ifndef BLUMEN_PATTERNS_H +internal void +SolidColorPattern(led_buffer* Leds, pixel Color) +{ + for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) + { + Leds->Colors[LedIndex] = Color; + } +} + +internal void +Pattern_Blue(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +{ + pixel Blue = pixel{0, 0, 255}; + SolidColorPattern(Leds, Blue); +} + +internal void +Pattern_Green(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +{ + pixel Green = pixel{0, 255, 0}; + SolidColorPattern(Leds, Green); +} + internal void TestPatternOne(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) { diff --git a/src/app/platform_win32/win32_foldhaus.cpp b/src/app/platform_win32/win32_foldhaus.cpp index 1e1dd7b..9fec14f 100644 --- a/src/app/platform_win32/win32_foldhaus.cpp +++ b/src/app/platform_win32/win32_foldhaus.cpp @@ -27,6 +27,8 @@ #include "../foldhaus_renderer.cpp" +#include "win32_test_code.cpp" + global b32 Running = false; global b32 WindowIsActive = false; @@ -423,26 +425,6 @@ Win32_SendAddressedDataBuffer_Job(gs_thread_context Context, gs_data Arg) Win32_SendAddressedDataBuffer(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)); -} - internal bool ReloadAndLinkDLL(win32_dll_refresh* DLL, context* Context, gs_work_queue* WorkQueue, bool ShouldError) { @@ -524,7 +506,9 @@ WinMain ( addressed_data_buffer_list OutputData = AddressedDataBufferList_Create(ThreadContext); - Context.InitializeApplication(Context); + temp_job_req* Req = Context.InitializeApplication(Context); + Req->Proc = BlumenLumen_MicListenJob; + Win32_TestCode_SocketReading(ThreadContext, Req); Running = true; Context.WindowIsVisible = true; diff --git a/src/app/platform_win32/win32_test_code.cpp b/src/app/platform_win32/win32_test_code.cpp index b9fa377..8173e73 100644 --- a/src/app/platform_win32/win32_test_code.cpp +++ b/src/app/platform_win32/win32_test_code.cpp @@ -5,6 +5,7 @@ // #ifndef WIN32_TEST_CODE_CPP +#if 0 internal void Win32_TestCode_UART(gs_thread_context ThreadContext) { @@ -31,21 +32,45 @@ Win32_TestCode_UART(gs_thread_context ThreadContext) uart_footer* Footer = PushStructOnCursor(WriteCursor, uart_footer); UART_FillFooter(Footer, (u8*)Header); } +#endif -internal void -Win32_TestCode_SocketReading(gs_thread_context ThreadContext) +win32_socket ListenSocket; + +DWORD WINAPI +Win32_TestCode_ListenThreadProc(LPVOID ThreadData) { - win32_socket TestSocket = Win32Socket_ConnectToAddress("127.0.0.1", "20185"); - test_microphone_packet* Recv = 0; + gs_thread_context Ctx = Win32CreateThreadContext(); + + temp_job_req* Req = (temp_job_req*)ThreadData; + while (true) { - gs_data Data = Win32Socket_Receive(&TestSocket, ThreadContext.Transient); - if (Data.Size > 0) + Req->Proc(&Ctx, Req->Memory); + } +} + +internal void +Win32_TestCode_SocketReading(gs_thread_context ThreadContext, temp_job_req* Req) +{ + ListenSocket = Win32Socket_ConnectToAddress("127.0.0.1", "20185"); + u8* Arg = (u8*)Req; + HANDLE Handle = CreateThread(0, 0, &Win32_TestCode_ListenThreadProc, Arg, 0, 0); +} + +internal void +BlumenLumen_MicListenJob(gs_thread_context* Ctx, u8* UserData) +{ + packet_ringbuffer* MicPacketBuffer = (packet_ringbuffer*)UserData; + + gs_data Data = Win32Socket_Receive(&ListenSocket, Ctx->Transient); + if (Data.Size > 0) + { + OutputDebugStringA("Listened"); + MicPacketBuffer->Values[MicPacketBuffer->WriteHead++] = Data; + if (MicPacketBuffer->WriteHead >= PACKETS_MAX) { - OutputDebugStringA("Received\n"); - Recv = (test_microphone_packet*)Data.Memory; + MicPacketBuffer->WriteHead = 0; } - ClearArena(ThreadContext.Transient); } } From b1d745aa1fd4cc77be03f5bcc3bd7479c6f3d04e Mon Sep 17 00:00:00 2001 From: PS Date: Sun, 24 Jan 2021 14:49:38 -0800 Subject: [PATCH 27/44] implemented an abstraction layer for threads so application code can run multithreaded code wihtout worrying about the platform --- src/app/blumen_lumen.cpp | 31 +++++++- src/app/blumen_lumen.h | 2 + src/app/foldhaus_app.cpp | 2 - src/app/foldhaus_platform.h | 2 + src/app/platform_win32/win32_foldhaus.cpp | 3 + .../win32_foldhaus_work_queue.h | 42 +++++++++++ src/gs_libs/gs_types.cpp | 74 +++++++++++++++++++ src/gs_libs/gs_types.h | 42 ++++++++++- 8 files changed, 189 insertions(+), 9 deletions(-) diff --git a/src/app/blumen_lumen.cpp b/src/app/blumen_lumen.cpp index ccc04c1..e58414b 100644 --- a/src/app/blumen_lumen.cpp +++ b/src/app/blumen_lumen.cpp @@ -5,9 +5,31 @@ // #ifndef BLUMEN_LUMEN_CPP -// TODO(pjs): -// - need to request opening a network port and getting messages from it pumped into CustomUpdate -// +internal void +BlumenLumen_MicListenJob(gs_thread_context* Ctx, u8* UserData) +{ + packet_ringbuffer* MicPacketBuffer = (packet_ringbuffer*)UserData; + +#if 0 + platform_socket* ListenSocket = CreateSocketAndConnect(Ctx->SocketManager, "127.0.0.1", "20185"); + + while (true) + { + gs_data Data = SocketReceive(Ctx->SocketManager, &ListenSocket, Ctx->Transient); + if (Data.Size > 0) + { + OutputDebugStringA("Listened"); + MicPacketBuffer->Values[MicPacketBuffer->WriteHead++] = Data; + if (MicPacketBuffer->WriteHead >= PACKETS_MAX) + { + MicPacketBuffer->WriteHead = 0; + } + } + } + + CloseSocket(Ctx->SocketManager, ListenSocket); +#endif +} internal gs_data BlumenLumen_CustomInit(app_state* State, context Context) @@ -21,7 +43,8 @@ BlumenLumen_CustomInit(app_state* State, context Context) Result = PushSizeToData(&State->Permanent, sizeof(blumen_lumen_state)); blumen_lumen_state* BLState = (blumen_lumen_state*)Result.Memory; - BLState->JobReq.Memory = (u8*)&BLState->MicPacketBuffer; + BLState->MicListenThread = CreateThread(Context.ThreadManager, BlumenLumen_MicListenJob, (u8*)&BLState->MicPacketBuffer); + #if 1 gs_const_string SculpturePath = ConstString("data/test_blumen.fold"); diff --git a/src/app/blumen_lumen.h b/src/app/blumen_lumen.h index 25220bb..74631d2 100644 --- a/src/app/blumen_lumen.h +++ b/src/app/blumen_lumen.h @@ -28,6 +28,8 @@ struct blumen_lumen_state { packet_ringbuffer MicPacketBuffer; temp_job_req JobReq; + + platform_thread_handle MicListenThread; }; diff --git a/src/app/foldhaus_app.cpp b/src/app/foldhaus_app.cpp index 7bec2d8..12d5bfd 100644 --- a/src/app/foldhaus_app.cpp +++ b/src/app/foldhaus_app.cpp @@ -8,8 +8,6 @@ #include "foldhaus_platform.h" #include "foldhaus_app.h" -//////////////////////////////////////////////////////////////////////// - internal void ClearAndPushPatterns(animation_pattern_array* Patterns) { diff --git a/src/app/foldhaus_platform.h b/src/app/foldhaus_platform.h index 459c1af..68762b6 100644 --- a/src/app/foldhaus_platform.h +++ b/src/app/foldhaus_platform.h @@ -206,6 +206,8 @@ struct context update_and_render* UpdateAndRender; cleanup_application* CleanupApplication; + platform_thread_manager* ThreadManager; + // Platform Services gs_work_queue* GeneralWorkQueue; diff --git a/src/app/platform_win32/win32_foldhaus.cpp b/src/app/platform_win32/win32_foldhaus.cpp index 9fec14f..0382f6d 100644 --- a/src/app/platform_win32/win32_foldhaus.cpp +++ b/src/app/platform_win32/win32_foldhaus.cpp @@ -493,6 +493,9 @@ WinMain ( Context.PlatformGetFontInfo = Win32GetFontInfo; Context.PlatformDrawFontCodepoint = Win32DrawFontCodepoint; + Context.ThreadManager = PushStruct(&PlatformPermanent, platform_thread_manager); + *Context.ThreadManager = CreatePlatformThreadManager(Win32CreateThread, Win32KillThread); + win32_dll_refresh DLLRefresh = InitializeDLLHotReloading(DLLName, WorkingDLLName, DLLLockFileName); if (!ReloadAndLinkDLL(&DLLRefresh, &Context, &Win32WorkQueue.WorkQueue, true)) { return -1; } diff --git a/src/app/platform_win32/win32_foldhaus_work_queue.h b/src/app/platform_win32/win32_foldhaus_work_queue.h index 2388798..8fa0311 100644 --- a/src/app/platform_win32/win32_foldhaus_work_queue.h +++ b/src/app/platform_win32/win32_foldhaus_work_queue.h @@ -163,6 +163,48 @@ WorkerThreadProc (LPVOID InputThreadInfo) return 0; } +DWORD WINAPI +Win32ThreadProcWrapper(LPVOID ThreadInfo) +{ + platform_thread* Thread = (platform_thread*)ThreadInfo; + gs_thread_context Ctx = Win32CreateThreadContext(); + Thread->Proc(&Ctx, Thread->UserData); + + // TODO(pjs): Destroy Thread Context + // TODO(pjs): How do we notify the thread manager this thread belongs to that it is free? + // Probaby put a pointer to the thread manager in the platform_thread struct + // so we can update the tracking structure? + + return 0; +} + +CREATE_THREAD(Win32CreateThread) +{ + Thread->Proc = Proc; + Thread->UserData = UserData; + + // TODO(pjs): ugh, allocation out in the middle of nowhere + HANDLE* ThreadHandle = (HANDLE*)Win32Alloc(sizeof(HANDLE), 0); + *ThreadHandle = CreateThread(0, 0, Win32ThreadProcWrapper, (void*)Thread, 0, 0); + // TODO(pjs): Error checking on the created thread + + Thread->PlatformHandle = (u8*)ThreadHandle; + + return true; +} + +KILL_THREAD(Win32KillThread) +{ + HANDLE* ThreadHandle = (HANDLE*)Thread->PlatformHandle; + TerminateThread(ThreadHandle, 0); + + // TODO(pjs): see allocation out in the middle of nowhere in Win32CreateThread + Win32Free((void*)Thread->PlatformHandle, sizeof(HANDLE)); + + // TODO(pjs): Error checking + return true; +} + internal void Win32WorkQueue_Init(gs_memory_arena* Arena, u32 ThreadCount) { diff --git a/src/gs_libs/gs_types.cpp b/src/gs_libs/gs_types.cpp index fd40b0f..d1e6916 100644 --- a/src/gs_libs/gs_types.cpp +++ b/src/gs_libs/gs_types.cpp @@ -3271,6 +3271,80 @@ TimeHandlerGetSecondsElapsed(gs_time_handler TimeHandler, s64 StartCycles, s64 E return Result; } +////////////////////////// +// +// Thread Manager + +CREATE_THREAD(CreateThreadStub) +{ + return {}; +} + + +KILL_THREAD(KillThreadStub) +{ + return false; +} + +internal platform_thread_manager +CreatePlatformThreadManager(platform_create_thread* CreateThreadProc, + platform_kill_thread* KillThreadProc) +{ + platform_thread_manager Result = {}; + Result.CreateThreadProc = CreateThreadProc; + Result.KillThreadProc = KillThreadProc; + + if (!CreateThreadProc) + { + Result.CreateThreadProc = CreateThreadStub; + } + if (!KillThreadProc) + { + Result.KillThreadProc = KillThreadStub; + } + + return Result; +} + +internal platform_thread_handle +CreateThread(platform_thread_manager* Manager, thread_proc_* Proc, u8* Arg) +{ + platform_thread_handle Result = {}; + + for (u32 i = 1; i < THREADS_MAX; i++) + { + if (!Manager->ThreadsUsed[i]) + { + Result.Index = i; + break; + } + } + Assert(Result.Index != 0); + + Manager->ThreadsUsed[Result.Index] = true; + Manager->CreateThreadProc(&Manager->Threads[Result.Index], Proc, Arg); + + return Result; +} + +internal bool +KillThread(platform_thread_manager* Manager, platform_thread_handle Handle) +{ + Assert(Manager->ThreadsUsed[Handle.Index]); + + platform_thread* Thread = &Manager->Threads[Handle.Index]; + bool Result = Manager->KillThreadProc(Thread); + + if (Result) + { + Manager->ThreadsUsed[Handle.Index] = false; + Manager->Threads[Handle.Index] = {}; + } + + return Result; +} + + /////////////////////////// // // Hashes diff --git a/src/gs_libs/gs_types.h b/src/gs_libs/gs_types.h index c9cfdbe..8bd7ac8 100644 --- a/src/gs_libs/gs_types.h +++ b/src/gs_libs/gs_types.h @@ -1005,16 +1005,52 @@ struct gs_thread_context gs_memory_arena* Transient; }; -// Threads & Work Queue +// Threads + +typedef struct platform_thread_handle +{ + u32 Index; +} platform_thread_handle; + +typedef struct platform_thread_manager platform_thread_manager; + +#define THREAD_PROC_(name) void name(gs_thread_context* Ctx, u8* UserData) +typedef THREAD_PROC_(thread_proc_); + +typedef struct platform_thread +{ + u8* PlatformHandle; + thread_proc_* Proc; + u8* UserData; + // TODO(pjs): Some kind of platform thread handle +} platform_thread; + +#define CREATE_THREAD(name) bool name(platform_thread* Thread, thread_proc_* Proc, u8* UserData) +typedef CREATE_THREAD(platform_create_thread); + +#define KILL_THREAD(name) bool name(platform_thread* Thread) +typedef KILL_THREAD(platform_kill_thread); + +#define THREADS_MAX 32 +typedef struct platform_thread_manager +{ + b8 ThreadsUsed[THREADS_MAX]; + platform_thread Threads[THREADS_MAX]; + + platform_create_thread* CreateThreadProc; + platform_kill_thread* KillThreadProc; +} platform_thread_manager; + +// Work Queue typedef struct gs_work_queue gs_work_queue; -struct gs_worker_thread +typedef struct gs_worker_thread { gs_thread_context Context; gs_work_queue* Queue; b32 ShouldExit; -}; +} gs_worker_thread; #define THREAD_PROC(name) void name(gs_thread_context Context, gs_data Data) typedef THREAD_PROC(thread_proc); From 070773437da2ee67469ec3cba17c53480660c7c6 Mon Sep 17 00:00:00 2001 From: PS Date: Sat, 30 Jan 2021 13:22:43 -0800 Subject: [PATCH 28/44] began working on an abstraction layer for sockets --- src/app/blumen_lumen.cpp | 24 ++--- src/app/blumen_lumen.h | 8 ++ src/app/foldhaus_platform.h | 1 + src/app/platform_win32/win32_foldhaus.cpp | 7 +- .../platform_win32/win32_foldhaus_socket.h | 95 +++++++++++++++++++ src/gs_libs/gs_types.cpp | 95 +++++++++++++++++++ src/gs_libs/gs_types.h | 31 ++++++ 7 files changed, 245 insertions(+), 16 deletions(-) diff --git a/src/app/blumen_lumen.cpp b/src/app/blumen_lumen.cpp index e58414b..0467e8a 100644 --- a/src/app/blumen_lumen.cpp +++ b/src/app/blumen_lumen.cpp @@ -8,27 +8,23 @@ internal void BlumenLumen_MicListenJob(gs_thread_context* Ctx, u8* UserData) { - packet_ringbuffer* MicPacketBuffer = (packet_ringbuffer*)UserData; - -#if 0 - platform_socket* ListenSocket = CreateSocketAndConnect(Ctx->SocketManager, "127.0.0.1", "20185"); + mic_listen_job_data* Data = (mic_listen_job_data*)UserData; while (true) { - gs_data Data = SocketReceive(Ctx->SocketManager, &ListenSocket, Ctx->Transient); - if (Data.Size > 0) + gs_data Msg = SocketRecieve(Data->SocketManager, Data->ListenSocket, Ctx->Transient); + if (Msg.Size > 0) { OutputDebugStringA("Listened"); - MicPacketBuffer->Values[MicPacketBuffer->WriteHead++] = Data; - if (MicPacketBuffer->WriteHead >= PACKETS_MAX) + Data->MicPacketBuffer->Values[Data->MicPacketBuffer->WriteHead++] = Msg; + if (Data->MicPacketBuffer->WriteHead >= PACKETS_MAX) { - MicPacketBuffer->WriteHead = 0; + Data->MicPacketBuffer->WriteHead = 0; } } } - CloseSocket(Ctx->SocketManager, ListenSocket); -#endif + CloseSocket(Data->SocketManager, Data->ListenSocket); } internal gs_data @@ -43,7 +39,11 @@ BlumenLumen_CustomInit(app_state* State, context Context) Result = PushSizeToData(&State->Permanent, sizeof(blumen_lumen_state)); blumen_lumen_state* BLState = (blumen_lumen_state*)Result.Memory; - BLState->MicListenThread = CreateThread(Context.ThreadManager, BlumenLumen_MicListenJob, (u8*)&BLState->MicPacketBuffer); + BLState->MicListenJobData.SocketManager = Context.SocketManager; + BLState->MicListenJobData.MicPacketBuffer = &BLState->MicPacketBuffer; + BLState->MicListenJobData.ListenSocket = CreateSocket(Context.SocketManager, "127.0.0.1", "20185"); + + BLState->MicListenThread = CreateThread(Context.ThreadManager, BlumenLumen_MicListenJob, (u8*)&BLState->MicListenJobData); #if 1 diff --git a/src/app/blumen_lumen.h b/src/app/blumen_lumen.h index 74631d2..a59f26d 100644 --- a/src/app/blumen_lumen.h +++ b/src/app/blumen_lumen.h @@ -24,12 +24,20 @@ struct microphone_packet }; #pragma pack(pop) +struct mic_listen_job_data +{ + platform_socket_manager* SocketManager; + packet_ringbuffer* MicPacketBuffer; + platform_socket_handle_ ListenSocket; +}; + struct blumen_lumen_state { packet_ringbuffer MicPacketBuffer; temp_job_req JobReq; platform_thread_handle MicListenThread; + mic_listen_job_data MicListenJobData; }; diff --git a/src/app/foldhaus_platform.h b/src/app/foldhaus_platform.h index 68762b6..c3cbb3e 100644 --- a/src/app/foldhaus_platform.h +++ b/src/app/foldhaus_platform.h @@ -207,6 +207,7 @@ struct context cleanup_application* CleanupApplication; platform_thread_manager* ThreadManager; + platform_socket_manager* SocketManager; // Platform Services gs_work_queue* GeneralWorkQueue; diff --git a/src/app/platform_win32/win32_foldhaus.cpp b/src/app/platform_win32/win32_foldhaus.cpp index 0382f6d..4b4a612 100644 --- a/src/app/platform_win32/win32_foldhaus.cpp +++ b/src/app/platform_win32/win32_foldhaus.cpp @@ -496,6 +496,9 @@ WinMain ( Context.ThreadManager = PushStruct(&PlatformPermanent, platform_thread_manager); *Context.ThreadManager = CreatePlatformThreadManager(Win32CreateThread, Win32KillThread); + Context.SocketManager = PushStruct(&PlatformPermanent, platform_socket_manager); + *Context.SocketManager = CreatePlatformSocketManager(Win32CreateSocket, Win32CloseSocket, Win32SocketReceive); + win32_dll_refresh DLLRefresh = InitializeDLLHotReloading(DLLName, WorkingDLLName, DLLLockFileName); if (!ReloadAndLinkDLL(&DLLRefresh, &Context, &Win32WorkQueue.WorkQueue, true)) { return -1; } @@ -509,10 +512,6 @@ WinMain ( addressed_data_buffer_list OutputData = AddressedDataBufferList_Create(ThreadContext); - temp_job_req* Req = Context.InitializeApplication(Context); - Req->Proc = BlumenLumen_MicListenJob; - Win32_TestCode_SocketReading(ThreadContext, Req); - Running = true; Context.WindowIsVisible = true; while (Running) diff --git a/src/app/platform_win32/win32_foldhaus_socket.h b/src/app/platform_win32/win32_foldhaus_socket.h index 65fb1a2..43d5dbc 100644 --- a/src/app/platform_win32/win32_foldhaus_socket.h +++ b/src/app/platform_win32/win32_foldhaus_socket.h @@ -131,6 +131,101 @@ Win32Socket_ConnectToAddress(char* Address, char* DefaultPort) return Result; } +internal bool +Win32CreateSocket(platform_socket* Socket, char* Address, char* DefaultPort) +{ + bool Result = false; + + 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) + { + SOCKET SocketHandle = socket(InfoAt->ai_family, InfoAt->ai_socktype, InfoAt->ai_protocol); + if (SocketHandle == INVALID_SOCKET) + { + Error = WSAGetLastError(); + InvalidCodePath; + } + + Error = connect(SocketHandle, InfoAt->ai_addr, (int)InfoAt->ai_addrlen); + if (Error == SOCKET_ERROR) + { + closesocket(SocketHandle); + continue; + } + else + { + Socket->PlatformHandle = (u8*)Win32Alloc(sizeof(SOCKET), 0); + *(SOCKET*)Socket->PlatformHandle = SocketHandle; + Result = true; + break; + } + } + } + else + { + Error = WSAGetLastError(); + InvalidCodePath; + } + + if (!Result) + { + Assert(Socket->PlatformHandle == 0); + } + + freeaddrinfo(PotentialConnections); + return Result; +} + +internal bool +Win32CloseSocket(platform_socket* Socket) +{ + SOCKET* Win32Sock = (SOCKET*)Socket->PlatformHandle; + closesocket(*Win32Sock); + Win32Free((u8*)Socket->PlatformHandle, sizeof(SOCKET)); + *Socket = {}; + return true; +} + +internal gs_data +Win32SocketReceive(platform_socket* Socket, gs_memory_arena* Storage) +{ + // TODO(pjs): Test this first code path when you have data running - it should + // get the actual size of the data packet being sent +#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; + SOCKET* Win32Sock = (SOCKET*)Socket->PlatformHandle; + s32 BytesReceived = recv(*Win32Sock, (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 s32 Win32Socket_SetOption(win32_socket* Socket, s32 Level, s32 Option, const char* OptionValue, s32 OptionLength) { diff --git a/src/gs_libs/gs_types.cpp b/src/gs_libs/gs_types.cpp index d1e6916..91f2b03 100644 --- a/src/gs_libs/gs_types.cpp +++ b/src/gs_libs/gs_types.cpp @@ -3345,6 +3345,101 @@ KillThread(platform_thread_manager* Manager, platform_thread_handle Handle) } +////////////////////////// +// +// Socket Manager + +CREATE_SOCKET(PlatformCreateSocket_Stub) +{ + return false; +} + +CLOSE_SOCKET(PlatformCloseSocket_Stub) +{ + return false; +} + +SOCKET_RECEIVE(PlatformSocketRecieve_Stub) +{ + return {}; +} + + +internal platform_socket_manager +CreatePlatformSocketManager(platform_create_socket* CreateSocketProc, + platform_close_socket* CloseSocketProc, + platform_socket_receive* SocketRecieveProc) +{ + platform_socket_manager Result = {}; + Result.CreateSocketProc = CreateSocketProc; + Result.CloseSocketProc = CloseSocketProc; + Result.SocketRecieveProc = SocketRecieveProc; + + if (!CreateSocketProc) + { + Result.CreateSocketProc = PlatformCreateSocket_Stub; + } + if (!CloseSocketProc) + { + Result.CloseSocketProc = PlatformCloseSocket_Stub; + } + if (!SocketRecieveProc) + { + Result.SocketRecieveProc = PlatformSocketRecieve_Stub; + } + return Result; +} + +internal platform_socket_handle_ +CreateSocket(platform_socket_manager* Manager, char* Addr, char* Port) +{ + platform_socket_handle_ Result = {}; + for (u32 i = 1; i < SOCKETS_COUNT_MAX; i++) + { + if (!Manager->SocketsUsed[i]) + { + Result.Index = i; + Manager->SocketsUsed[i] = true; + break; + } + } + + Assert(Result.Index != 0); + platform_socket* Socket = &Manager->Sockets[Result.Index]; + Manager->CreateSocketProc(Socket, Addr, Port); + + return Result; +} + +internal bool +CloseSocket(platform_socket_manager* Manager, platform_socket_handle_ Handle) +{ + bool Result = false; + platform_socket* Socket = &Manager->Sockets[Handle.Index]; + if (Manager->CloseSocketProc(Socket)) + { + Manager->SocketsUsed[Handle.Index] = false; + *Socket = {}; + Result = true; + } + return Result; +} + +internal gs_data +SocketRecieve(platform_socket_manager* Manager, platform_socket_handle_ SocketHandle, gs_memory_arena* Storage) +{ + gs_data Result = {}; + if (Manager->SocketsUsed[SocketHandle.Index]) + { + platform_socket* Socket = &Manager->Sockets[SocketHandle.Index]; + if (Socket->PlatformHandle != 0) + { + Result = Manager->SocketRecieveProc(Socket, Storage); + } + } + return Result; +} + /////////////////////////// // // Hashes diff --git a/src/gs_libs/gs_types.h b/src/gs_libs/gs_types.h index 8bd7ac8..2cdd56b 100644 --- a/src/gs_libs/gs_types.h +++ b/src/gs_libs/gs_types.h @@ -1086,5 +1086,36 @@ struct gs_work_queue complete_queue_work* CompleteQueueWork; }; +// Sockets + +typedef struct platform_socket_handle_ +{ + u32 Index; +} platform_socket_handle_; + +typedef struct platform_socket +{ + u8* PlatformHandle; +} platform_socket; + +#define CREATE_SOCKET(name) bool name(platform_socket* Socket, char* Addr, char* DefaultPort) +typedef CREATE_SOCKET(platform_create_socket); + +#define CLOSE_SOCKET(name) bool name(platform_socket* Socket) +typedef CLOSE_SOCKET(platform_close_socket); + +#define SOCKET_RECEIVE(name) gs_data name(platform_socket* Socket, gs_memory_arena* Storage) +typedef SOCKET_RECEIVE(platform_socket_receive); + +#define SOCKETS_COUNT_MAX 32 +typedef struct platform_socket_manager +{ + b8 SocketsUsed[SOCKETS_COUNT_MAX]; + platform_socket Sockets[SOCKETS_COUNT_MAX]; + + platform_create_socket* CreateSocketProc; + platform_close_socket* CloseSocketProc; + platform_socket_receive* SocketRecieveProc; +} platform_socket_manager; #define GS_TYPES_H #endif // GS_TYPES_H \ No newline at end of file From cd6bee6d7e290d61911eb9efbceaacd1efdcde52 Mon Sep 17 00:00:00 2001 From: Peter Slattery Date: Sat, 30 Jan 2021 14:01:04 -0800 Subject: [PATCH 29/44] Finished preliminary socket layer and win32 implementation. --- src/app/blumen_lumen.cpp | 62 ++++++++++++++++--- src/app/blumen_lumen.h | 14 +++++ .../foldhaus_panel_animation_timeline.h | 8 +-- src/app/foldhaus_app.cpp | 19 +++--- src/app/interface.h | 2 +- src/app/platform_win32/win32_foldhaus.cpp | 5 +- .../platform_win32/win32_foldhaus_socket.h | 41 +++++++++++- src/app/platform_win32/win32_test_code.cpp | 10 ++- src/gs_libs/gs_types.cpp | 28 ++++++++- src/gs_libs/gs_types.h | 4 ++ 10 files changed, 163 insertions(+), 30 deletions(-) diff --git a/src/app/blumen_lumen.cpp b/src/app/blumen_lumen.cpp index 0467e8a..667b997 100644 --- a/src/app/blumen_lumen.cpp +++ b/src/app/blumen_lumen.cpp @@ -10,9 +10,13 @@ BlumenLumen_MicListenJob(gs_thread_context* Ctx, u8* UserData) { mic_listen_job_data* Data = (mic_listen_job_data*)UserData; + gs_data Msg = {}; + while (true) { - gs_data Msg = SocketRecieve(Data->SocketManager, Data->ListenSocket, Ctx->Transient); +#if 0 + // TODO(pjs): Make this a peek operation + Msg = SocketRecieve(Data->SocketManager, Data->ListenSocket, Ctx->Transient); if (Msg.Size > 0) { OutputDebugStringA("Listened"); @@ -22,6 +26,23 @@ BlumenLumen_MicListenJob(gs_thread_context* Ctx, u8* UserData) Data->MicPacketBuffer->WriteHead = 0; } } +#endif + + while (Data->OutgoingMsgQueue->ReadHead != Data->OutgoingMsgQueue->WriteHead) + { + u32 ReadIndex = Data->OutgoingMsgQueue->ReadHead++; + if (Data->OutgoingMsgQueue->ReadHead >= BLUMEN_MESSAGE_QUEUE_COUNT) + { + Data->OutgoingMsgQueue->ReadHead = 0; + } + + Msg = Data->OutgoingMsgQueue->Buffers[ReadIndex]; + u32 Address = 0; + u32 Port = 0; + s32 Flags = 0; + SocketSend(Data->SocketManager, Data->ListenSocket, Address, Port, Msg, Flags); + OutputDebugStringA("Wrote\n"); + } } CloseSocket(Data->SocketManager, Data->ListenSocket); @@ -41,15 +62,13 @@ BlumenLumen_CustomInit(app_state* State, context Context) blumen_lumen_state* BLState = (blumen_lumen_state*)Result.Memory; BLState->MicListenJobData.SocketManager = Context.SocketManager; BLState->MicListenJobData.MicPacketBuffer = &BLState->MicPacketBuffer; + BLState->MicListenJobData.OutgoingMsgQueue = &BLState->OutgoingMsgQueue; BLState->MicListenJobData.ListenSocket = CreateSocket(Context.SocketManager, "127.0.0.1", "20185"); BLState->MicListenThread = CreateThread(Context.ThreadManager, BlumenLumen_MicListenJob, (u8*)&BLState->MicListenJobData); - -#if 1 gs_const_string SculpturePath = ConstString("data/test_blumen.fold"); LoadAssembly(&State->Assemblies, &State->LedSystem, State->Transient, Context, SculpturePath, State->GlobalLog); -#endif { // Animation PLAYGROUND animation Anim0 = {0}; @@ -122,17 +141,40 @@ BlumenLumen_CustomUpdate(gs_data UserData, app_state* State, context* Context) State->AnimationSystem.ActiveAnimationIndex = 2; } - gs_string TempString = PushStringF(State->Transient, 256, "%.*s", 32, Packet.AnimationFileName); - NullTerminate(&TempString); - - OutputDebugStringA("Received\n"); - OutputDebugStringA(TempString.Str); - if (BLState->MicPacketBuffer.ReadHead >= PACKETS_MAX) { BLState->MicPacketBuffer.ReadHead = 0; } } + + if ((BLState->OutgoingMsgQueue.WriteHead >= BLState->OutgoingMsgQueue.ReadHead) || + (BLState->OutgoingMsgQueue.WriteHead < BLState->OutgoingMsgQueue.ReadHead)) + { + u32 WriteIndex = BLState->OutgoingMsgQueue.WriteHead; + if (BLState->OutgoingMsgQueue.WriteHead >= BLUMEN_MESSAGE_QUEUE_COUNT) + { + BLState->OutgoingMsgQueue.WriteHead = 0; + } + + gs_data* Msg = BLState->OutgoingMsgQueue.Buffers + WriteIndex; + if (Msg->Size == 0) + { + *Msg = PushSizeToData(&State->Permanent, sizeof(motor_packet)); + } + motor_packet* Packet = (motor_packet*)Msg->Memory; + Packet->FlowerPositions[0] = 5; + Packet->FlowerPositions[0] = 4; + Packet->FlowerPositions[0] = 9; + + // NOTE(pjs): We increment the write head AFTER we've written so that + // the network thread doesn't think the buffer is ready to send before + // the data is set. We want to avoid the case of: + // 1. Main Thread increments write head to 1 + // 2. Network Thread thinks theres a new message to send at 0 + // 3. Network Thread sends the message at 0 + // 4. Main Thread sets the message at 0 + BLState->OutgoingMsgQueue.WriteHead += 1; + } } diff --git a/src/app/blumen_lumen.h b/src/app/blumen_lumen.h index a59f26d..d5ce452 100644 --- a/src/app/blumen_lumen.h +++ b/src/app/blumen_lumen.h @@ -24,18 +24,32 @@ struct microphone_packet }; #pragma pack(pop) +#define BLUMEN_MESSAGE_QUEUE_COUNT 32 +typedef struct blumen_network_msg_queue +{ + gs_data Buffers[BLUMEN_MESSAGE_QUEUE_COUNT]; + u32 WriteHead; + u32 ReadHead; +} blumen_network_msg_queue; + +// TODO(pjs): Refactor this -> blumen_network_job_state struct mic_listen_job_data { platform_socket_manager* SocketManager; packet_ringbuffer* MicPacketBuffer; platform_socket_handle_ ListenSocket; + + blumen_network_msg_queue* OutgoingMsgQueue; }; struct blumen_lumen_state { packet_ringbuffer MicPacketBuffer; + blumen_network_msg_queue OutgoingMsgQueue; + temp_job_req JobReq; + platform_thread_handle MicListenThread; mic_listen_job_data MicListenJobData; }; diff --git a/src/app/editor/panels/foldhaus_panel_animation_timeline.h b/src/app/editor/panels/foldhaus_panel_animation_timeline.h index 1fb550a..92ee12c 100644 --- a/src/app/editor/panels/foldhaus_panel_animation_timeline.h +++ b/src/app/editor/panels/foldhaus_panel_animation_timeline.h @@ -610,7 +610,7 @@ PlayBar_Render(animation_timeline_state* TimelineState, rect2 Bounds, panel* Pan ui_interface* Interface = &State->Interface; ui_PushLayout(Interface, Bounds, LayoutDirection_TopDown, MakeString("PlayBar Layout")); - ui_FillRect(Interface, Bounds, Interface->Style.PanelBGColors[0]); + ui_FillRect(Interface, Bounds, Interface->Style.PanelBG); ui_BeginRow(&State->Interface, 4); { if (ui_Button(Interface, MakeString("Pause"))) @@ -645,7 +645,7 @@ FrameCount_Render(animation_timeline_state* TimelineState, rect2 Bounds, render_ s32 VisibleFrameCount = VisibleFrames.Max - VisibleFrames.Min; - ui_FillRect(Interface, Bounds, Interface->Style.PanelBGColors[0]); + ui_FillRect(Interface, Bounds, Interface->Style.PanelBG); // Frame Ticks u32 TickCount = 10; @@ -692,7 +692,7 @@ LayerList_Render(animation_timeline_state* TimelineState, rect2 Bounds, panel* P ui_interface* Interface = &State->Interface; animation ActiveAnim = *AnimationSystem_GetActiveAnimation(&State->AnimationSystem); - ui_FillRect(Interface, Bounds, Interface->Style.PanelBGColors[0]); + ui_FillRect(Interface, Bounds, Interface->Style.PanelBG); v2 LayerDim = { Rect2Width(Bounds), LAYER_HEIGHT }; rect2 LayerBounds = {0}; @@ -801,7 +801,7 @@ AnimInfoView_Render(animation_timeline_state* TimelineState, rect2 Bounds, panel ui_interface* Interface = &State->Interface; ui_PushLayout(Interface, Bounds, LayoutDirection_TopDown, MakeString("AnimInfo Layout")); - ui_FillRect(&State->Interface, Bounds, Interface->Style.PanelBGColors[0]); + ui_FillRect(&State->Interface, Bounds, Interface->Style.PanelBG); if (ui_BeginLabeledDropdown(Interface, MakeString("Active Animation"), ActiveAnim->Name)) { diff --git a/src/app/foldhaus_app.cpp b/src/app/foldhaus_app.cpp index 12d5bfd..f53a27c 100644 --- a/src/app/foldhaus_app.cpp +++ b/src/app/foldhaus_app.cpp @@ -58,18 +58,15 @@ INITIALIZE_APPLICATION(InitializeApplication) interface_config IConfig = {0}; IConfig.FontSize = 14; - IConfig.PanelBGColors[0] = v4{.3f, .3f, .3f, 1}; - IConfig.PanelBGColors[1] = v4{.4f, .4f, .4f, 1}; - IConfig.PanelBGColors[2] = v4{.5f, .5f, .5f, 1}; - IConfig.PanelBGColors[3] = v4{.6f, .6f, .6f, 1}; + IConfig.PanelBG = v4{ .3f, .3f, .3f, 1.f }; IConfig.ButtonColor_Inactive = BlackV4; - IConfig.ButtonColor_Active = v4{.1f, .1f, .1f, 1}; - IConfig.ButtonColor_Selected = v4{.3f, .3f, .3f, 1}; - IConfig.TextColor = WhiteV4; - IConfig.ListBGColors[0] = v4{ .16f, .16f, .16f, 1.f }; - IConfig.ListBGColors[1] = v4{ .18f, .18f, .18f, 1.f }; - IConfig.ListBGHover = v4{ .22f, .22f, .22f, 1.f }; - IConfig.ListBGSelected = v4{.44f, .44f, .44f, 1.f }; + IConfig.ButtonColor_Active = v4{ .1f, .1f, .1f, 1.f }; + IConfig.ButtonColor_Selected = v4{ .3f, .3f, .3f, 1.f }; + IConfig.TextColor = WhiteV4; + IConfig.ListBGColors[0] = v4{ .16f, .16f, .16f, 1.f }; + IConfig.ListBGColors[1] = v4{ .18f, .18f, .18f, 1.f }; + IConfig.ListBGHover = v4{ .22f, .22f, .22f, 1.f }; + IConfig.ListBGSelected = v4{ .44f, .44f, .44f, 1.f }; IConfig.Margin = v2{5, 5}; State->Interface = ui_InterfaceCreate(Context, IConfig, &State->Permanent); diff --git a/src/app/interface.h b/src/app/interface.h index ee846c1..34cf505 100644 --- a/src/app/interface.h +++ b/src/app/interface.h @@ -315,7 +315,7 @@ struct ui_eval_result struct interface_config { - v4 PanelBGColors[4]; + v4 PanelBG; // TODO(pjs): Turn these into _Default, _Hot, _Active v4 ButtonColor_Inactive, ButtonColor_Active, ButtonColor_Selected; diff --git a/src/app/platform_win32/win32_foldhaus.cpp b/src/app/platform_win32/win32_foldhaus.cpp index 4b4a612..9877fa3 100644 --- a/src/app/platform_win32/win32_foldhaus.cpp +++ b/src/app/platform_win32/win32_foldhaus.cpp @@ -497,7 +497,7 @@ WinMain ( *Context.ThreadManager = CreatePlatformThreadManager(Win32CreateThread, Win32KillThread); Context.SocketManager = PushStruct(&PlatformPermanent, platform_socket_manager); - *Context.SocketManager = CreatePlatformSocketManager(Win32CreateSocket, Win32CloseSocket, Win32SocketReceive); + *Context.SocketManager = CreatePlatformSocketManager(Win32CreateSocket, Win32CloseSocket, Win32SocketReceive, Win32SocketSend); win32_dll_refresh DLLRefresh = InitializeDLLHotReloading(DLLName, WorkingDLLName, DLLLockFileName); if (!ReloadAndLinkDLL(&DLLRefresh, &Context, &Win32WorkQueue.WorkQueue, true)) { return -1; } @@ -512,6 +512,8 @@ WinMain ( addressed_data_buffer_list OutputData = AddressedDataBufferList_Create(ThreadContext); + Context.InitializeApplication(Context); + Running = true; Context.WindowIsVisible = true; while (Running) @@ -588,6 +590,7 @@ WinMain ( Win32SocketSystem_Cleanup(); Win32WorkQueue_Cleanup(); + Win32_TestCode_SocketReading_Cleanup(); return 0; } diff --git a/src/app/platform_win32/win32_foldhaus_socket.h b/src/app/platform_win32/win32_foldhaus_socket.h index 43d5dbc..adce909 100644 --- a/src/app/platform_win32/win32_foldhaus_socket.h +++ b/src/app/platform_win32/win32_foldhaus_socket.h @@ -226,6 +226,34 @@ Win32SocketReceive(platform_socket* Socket, gs_memory_arena* Storage) #endif } +internal s32 +Win32SocketSend(platform_socket* Socket, u32 Address, u32 Port, gs_data Data, s32 Flags) +{ + SOCKET* Win32Sock = (SOCKET*)Socket->PlatformHandle; + + sockaddr_in SockAddress = {}; + SockAddress.sin_family = AF_INET; + SockAddress.sin_port = HostToNetU16(Port); + SockAddress.sin_addr.s_addr = HostToNetU32(Address); + + s32 LengthSent = sendto(*Win32Sock, (char*)Data.Memory, Data.Size, Flags, (sockaddr*)&SockAddress, sizeof(sockaddr_in)); + + if (LengthSent == SOCKET_ERROR) + { + s32 Error = WSAGetLastError(); + if (Error == 10051) + { + } + else + { + // TODO(Peter): :ErrorLogging + InvalidCodePath; + } + } + + return LengthSent; +} + internal s32 Win32Socket_SetOption(win32_socket* Socket, s32 Level, s32 Option, const char* OptionValue, s32 OptionLength) { @@ -323,7 +351,18 @@ Win32Socket_Receive(win32_socket* Socket, gs_memory_arena* Storage) { // TODO(pjs): Error logging s32 Error = WSAGetLastError(); - InvalidCodePath; + if (Error == 10053) + { + // WSAECONNABORTED - aborted by the software + } + else if (Error == 10093) + { + // WSANOTINITIALISED + } + else + { + InvalidCodePath; + } } Result.Size = BytesReceived; return Result; diff --git a/src/app/platform_win32/win32_test_code.cpp b/src/app/platform_win32/win32_test_code.cpp index 8173e73..8c23153 100644 --- a/src/app/platform_win32/win32_test_code.cpp +++ b/src/app/platform_win32/win32_test_code.cpp @@ -35,6 +35,7 @@ Win32_TestCode_UART(gs_thread_context ThreadContext) #endif win32_socket ListenSocket; +HANDLE ListenThread; DWORD WINAPI Win32_TestCode_ListenThreadProc(LPVOID ThreadData) @@ -54,7 +55,7 @@ Win32_TestCode_SocketReading(gs_thread_context ThreadContext, temp_job_req* Req) { ListenSocket = Win32Socket_ConnectToAddress("127.0.0.1", "20185"); u8* Arg = (u8*)Req; - HANDLE Handle = CreateThread(0, 0, &Win32_TestCode_ListenThreadProc, Arg, 0, 0); + ListenThread = CreateThread(0, 0, &Win32_TestCode_ListenThreadProc, Arg, 0, 0); } internal void @@ -74,5 +75,12 @@ BlumenLumen_MicListenJob(gs_thread_context* Ctx, u8* UserData) } } +internal void +Win32_TestCode_SocketReading_Cleanup() +{ + TerminateThread(ListenThread, 0); + Win32Socket_Close(&ListenSocket); +} + #define WIN32_TEST_CODE_CPP #endif // WIN32_TEST_CODE_CPP \ No newline at end of file diff --git a/src/gs_libs/gs_types.cpp b/src/gs_libs/gs_types.cpp index 91f2b03..cff4d8c 100644 --- a/src/gs_libs/gs_types.cpp +++ b/src/gs_libs/gs_types.cpp @@ -3364,16 +3364,22 @@ SOCKET_RECEIVE(PlatformSocketRecieve_Stub) return {}; } +SOCKET_SEND(PlatformSocketSend_Stub) +{ + return false; +} internal platform_socket_manager CreatePlatformSocketManager(platform_create_socket* CreateSocketProc, platform_close_socket* CloseSocketProc, - platform_socket_receive* SocketRecieveProc) + platform_socket_receive* SocketRecieveProc, + platform_socket_send* SocketSendProc) { platform_socket_manager Result = {}; Result.CreateSocketProc = CreateSocketProc; Result.CloseSocketProc = CloseSocketProc; Result.SocketRecieveProc = SocketRecieveProc; + Result.SocketSendProc = SocketSendProc; if (!CreateSocketProc) { @@ -3387,6 +3393,10 @@ CreatePlatformSocketManager(platform_create_socket* CreateSocketProc, { Result.SocketRecieveProc = PlatformSocketRecieve_Stub; } + if (!SocketSendProc) + { + Result.SocketSendProc = PlatformSocketSend_Stub; + } return Result; } @@ -3440,6 +3450,22 @@ SocketRecieve(platform_socket_manager* Manager, platform_socket_handle_ SocketHa return Result; } +internal bool +SocketSend(platform_socket_manager* Manager, platform_socket_handle_ SocketHandle, u32 Address, u32 Port, gs_data Data, s32 Flags) +{ + bool Result = false; + if (Manager->SocketsUsed[SocketHandle.Index]) + { + platform_socket* Socket = &Manager->Sockets[SocketHandle.Index]; + if (Socket->PlatformHandle != 0) + { + s32 SizeSent = Manager->SocketSendProc(Socket, Address, Port, Data, Flags); + Result = (SizeSent == Data.Size); + } + } + return Result; +} + /////////////////////////// // // Hashes diff --git a/src/gs_libs/gs_types.h b/src/gs_libs/gs_types.h index 2cdd56b..3b29abe 100644 --- a/src/gs_libs/gs_types.h +++ b/src/gs_libs/gs_types.h @@ -1107,6 +1107,9 @@ typedef CLOSE_SOCKET(platform_close_socket); #define SOCKET_RECEIVE(name) gs_data name(platform_socket* Socket, gs_memory_arena* Storage) typedef SOCKET_RECEIVE(platform_socket_receive); +#define SOCKET_SEND(name) s32 name(platform_socket* Socket, u32 Address, u32 Port, gs_data Data, s32 Flags) +typedef SOCKET_SEND(platform_socket_send); + #define SOCKETS_COUNT_MAX 32 typedef struct platform_socket_manager { @@ -1116,6 +1119,7 @@ typedef struct platform_socket_manager platform_create_socket* CreateSocketProc; platform_close_socket* CloseSocketProc; platform_socket_receive* SocketRecieveProc; + platform_socket_send* SocketSendProc; } platform_socket_manager; #define GS_TYPES_H #endif // GS_TYPES_H \ No newline at end of file From 84854b2ad8ee6142ca6e18eabb5805d52968e085 Mon Sep 17 00:00:00 2001 From: PS Date: Sat, 30 Jan 2021 14:09:19 -0800 Subject: [PATCH 30/44] Fixed issue with the ring buffer's write incrementation. --- src/app/blumen_lumen.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/blumen_lumen.cpp b/src/app/blumen_lumen.cpp index 667b997..caf3147 100644 --- a/src/app/blumen_lumen.cpp +++ b/src/app/blumen_lumen.cpp @@ -151,10 +151,6 @@ BlumenLumen_CustomUpdate(gs_data UserData, app_state* State, context* Context) (BLState->OutgoingMsgQueue.WriteHead < BLState->OutgoingMsgQueue.ReadHead)) { u32 WriteIndex = BLState->OutgoingMsgQueue.WriteHead; - if (BLState->OutgoingMsgQueue.WriteHead >= BLUMEN_MESSAGE_QUEUE_COUNT) - { - BLState->OutgoingMsgQueue.WriteHead = 0; - } gs_data* Msg = BLState->OutgoingMsgQueue.Buffers + WriteIndex; if (Msg->Size == 0) @@ -174,6 +170,10 @@ BlumenLumen_CustomUpdate(gs_data UserData, app_state* State, context* Context) // 3. Network Thread sends the message at 0 // 4. Main Thread sets the message at 0 BLState->OutgoingMsgQueue.WriteHead += 1; + if (BLState->OutgoingMsgQueue.WriteHead >= BLUMEN_MESSAGE_QUEUE_COUNT) + { + BLState->OutgoingMsgQueue.WriteHead = 0; + } } } From 751ee2e27afd78cadc695cc79eeaf1d69fa42836 Mon Sep 17 00:00:00 2001 From: PS Date: Sat, 30 Jan 2021 14:25:58 -0800 Subject: [PATCH 31/44] Compressed some of the socket layer code and added a path to peek for messages --- src/app/blumen_lumen.cpp | 19 +++-- src/app/platform_win32/win32_foldhaus.cpp | 2 +- .../platform_win32/win32_foldhaus_socket.h | 25 +++++++ src/gs_libs/gs_types.cpp | 71 ++++++++++++++----- src/gs_libs/gs_types.h | 9 +++ 5 files changed, 97 insertions(+), 29 deletions(-) diff --git a/src/app/blumen_lumen.cpp b/src/app/blumen_lumen.cpp index caf3147..3525506 100644 --- a/src/app/blumen_lumen.cpp +++ b/src/app/blumen_lumen.cpp @@ -14,19 +14,19 @@ BlumenLumen_MicListenJob(gs_thread_context* Ctx, u8* UserData) while (true) { -#if 0 - // TODO(pjs): Make this a peek operation - Msg = SocketRecieve(Data->SocketManager, Data->ListenSocket, Ctx->Transient); - if (Msg.Size > 0) + if (SocketPeek(Data->SocketManager, Data->ListenSocket)) { - OutputDebugStringA("Listened"); - Data->MicPacketBuffer->Values[Data->MicPacketBuffer->WriteHead++] = Msg; - if (Data->MicPacketBuffer->WriteHead >= PACKETS_MAX) + // TODO(pjs): Make this a peek operation + Msg = SocketRecieve(Data->SocketManager, Data->ListenSocket, Ctx->Transient); + if (Msg.Size > 0) { - Data->MicPacketBuffer->WriteHead = 0; + Data->MicPacketBuffer->Values[Data->MicPacketBuffer->WriteHead++] = Msg; + if (Data->MicPacketBuffer->WriteHead >= PACKETS_MAX) + { + Data->MicPacketBuffer->WriteHead = 0; + } } } -#endif while (Data->OutgoingMsgQueue->ReadHead != Data->OutgoingMsgQueue->WriteHead) { @@ -41,7 +41,6 @@ BlumenLumen_MicListenJob(gs_thread_context* Ctx, u8* UserData) u32 Port = 0; s32 Flags = 0; SocketSend(Data->SocketManager, Data->ListenSocket, Address, Port, Msg, Flags); - OutputDebugStringA("Wrote\n"); } } diff --git a/src/app/platform_win32/win32_foldhaus.cpp b/src/app/platform_win32/win32_foldhaus.cpp index 9877fa3..f0974e3 100644 --- a/src/app/platform_win32/win32_foldhaus.cpp +++ b/src/app/platform_win32/win32_foldhaus.cpp @@ -497,7 +497,7 @@ WinMain ( *Context.ThreadManager = CreatePlatformThreadManager(Win32CreateThread, Win32KillThread); Context.SocketManager = PushStruct(&PlatformPermanent, platform_socket_manager); - *Context.SocketManager = CreatePlatformSocketManager(Win32CreateSocket, Win32CloseSocket, Win32SocketReceive, Win32SocketSend); + *Context.SocketManager = CreatePlatformSocketManager(Win32CreateSocket, Win32CloseSocket, Win32SocketPeek, Win32SocketReceive, Win32SocketSend); win32_dll_refresh DLLRefresh = InitializeDLLHotReloading(DLLName, WorkingDLLName, DLLLockFileName); if (!ReloadAndLinkDLL(&DLLRefresh, &Context, &Win32WorkQueue.WorkQueue, true)) { return -1; } diff --git a/src/app/platform_win32/win32_foldhaus_socket.h b/src/app/platform_win32/win32_foldhaus_socket.h index adce909..1795cfe 100644 --- a/src/app/platform_win32/win32_foldhaus_socket.h +++ b/src/app/platform_win32/win32_foldhaus_socket.h @@ -194,6 +194,29 @@ Win32CloseSocket(platform_socket* Socket) return true; } +internal u32 +Win32SocketPeek(platform_socket* Socket) +{ + u32 Result = 0; + s32 Flags = MSG_PEEK; + SOCKET* Win32Sock = (SOCKET*)Socket->PlatformHandle; + char Temp[4]; + u32 TempSize = 4; + + s32 BytesQueued = recv(*Win32Sock, Temp, TempSize, Flags); + if (BytesQueued != SOCKET_ERROR) + { + Result = (u32)BytesQueued; + } + else + { + // TODO(pjs): Error handling + s32 Error = WSAGetLastError(); + InvalidCodePath; + } + return Result; +} + internal gs_data Win32SocketReceive(platform_socket* Socket, gs_memory_arena* Storage) { @@ -211,6 +234,8 @@ Win32SocketReceive(platform_socket* Socket, gs_memory_arena* Storage) } return Result; #else + + gs_data Result = PushSizeToData(Storage, 1024); s32 Flags = 0; SOCKET* Win32Sock = (SOCKET*)Socket->PlatformHandle; diff --git a/src/gs_libs/gs_types.cpp b/src/gs_libs/gs_types.cpp index cff4d8c..f51a16d 100644 --- a/src/gs_libs/gs_types.cpp +++ b/src/gs_libs/gs_types.cpp @@ -3359,6 +3359,11 @@ CLOSE_SOCKET(PlatformCloseSocket_Stub) return false; } +SOCKET_PEEK(PlatformSocketPeek_Stub) +{ + return 0; +} + SOCKET_RECEIVE(PlatformSocketRecieve_Stub) { return {}; @@ -3372,12 +3377,14 @@ SOCKET_SEND(PlatformSocketSend_Stub) internal platform_socket_manager CreatePlatformSocketManager(platform_create_socket* CreateSocketProc, platform_close_socket* CloseSocketProc, + platform_socket_peek* SocketPeekProc, platform_socket_receive* SocketRecieveProc, platform_socket_send* SocketSendProc) { platform_socket_manager Result = {}; Result.CreateSocketProc = CreateSocketProc; Result.CloseSocketProc = CloseSocketProc; + Result.SocketPeekProc = SocketPeekProc; Result.SocketRecieveProc = SocketRecieveProc; Result.SocketSendProc = SocketSendProc; @@ -3389,6 +3396,10 @@ CreatePlatformSocketManager(platform_create_socket* CreateSocketProc, { Result.CloseSocketProc = PlatformCloseSocket_Stub; } + if (!SocketPeekProc) + { + Result.SocketPeekProc = PlatformSocketPeek_Stub; + } if (!SocketRecieveProc) { Result.SocketRecieveProc = PlatformSocketRecieve_Stub; @@ -3421,16 +3432,46 @@ CreateSocket(platform_socket_manager* Manager, char* Addr, char* Port) return Result; } +internal platform_socket* +SocketManagerGetSocket(platform_socket_manager* Manager, platform_socket_handle_ Handle) +{ + platform_socket* Result = 0; + if (Manager->SocketsUsed[Handle.Index]) + { + platform_socket* Socket = &Manager->Sockets[Handle.Index]; + if (Socket->PlatformHandle != 0) + { + Result = Socket; + } + } + return Result; +} + internal bool CloseSocket(platform_socket_manager* Manager, platform_socket_handle_ Handle) { bool Result = false; - platform_socket* Socket = &Manager->Sockets[Handle.Index]; - if (Manager->CloseSocketProc(Socket)) + platform_socket* Socket = SocketManagerGetSocket(Manager, Handle); + if (Socket) { - Manager->SocketsUsed[Handle.Index] = false; - *Socket = {}; - Result = true; + if (Manager->CloseSocketProc(Socket)) + { + Manager->SocketsUsed[Handle.Index] = false; + *Socket = {}; + Result = true; + } + } + return Result; +} + +internal u32 +SocketPeek(platform_socket_manager* Manager, platform_socket_handle_ SocketHandle) +{ + u32 Result = 0; + platform_socket* Socket = SocketManagerGetSocket(Manager, SocketHandle); + if (Socket) + { + Result = Manager->SocketPeekProc(Socket); } return Result; } @@ -3439,13 +3480,10 @@ internal gs_data SocketRecieve(platform_socket_manager* Manager, platform_socket_handle_ SocketHandle, gs_memory_arena* Storage) { gs_data Result = {}; - if (Manager->SocketsUsed[SocketHandle.Index]) + platform_socket* Socket = SocketManagerGetSocket(Manager, SocketHandle); + if (Socket) { - platform_socket* Socket = &Manager->Sockets[SocketHandle.Index]; - if (Socket->PlatformHandle != 0) - { - Result = Manager->SocketRecieveProc(Socket, Storage); - } + Result = Manager->SocketRecieveProc(Socket, Storage); } return Result; } @@ -3454,14 +3492,11 @@ internal bool SocketSend(platform_socket_manager* Manager, platform_socket_handle_ SocketHandle, u32 Address, u32 Port, gs_data Data, s32 Flags) { bool Result = false; - if (Manager->SocketsUsed[SocketHandle.Index]) + platform_socket* Socket = SocketManagerGetSocket(Manager, SocketHandle); + if (Socket) { - platform_socket* Socket = &Manager->Sockets[SocketHandle.Index]; - if (Socket->PlatformHandle != 0) - { - s32 SizeSent = Manager->SocketSendProc(Socket, Address, Port, Data, Flags); - Result = (SizeSent == Data.Size); - } + s32 SizeSent = Manager->SocketSendProc(Socket, Address, Port, Data, Flags); + Result = (SizeSent == Data.Size); } return Result; } diff --git a/src/gs_libs/gs_types.h b/src/gs_libs/gs_types.h index 3b29abe..04a64fb 100644 --- a/src/gs_libs/gs_types.h +++ b/src/gs_libs/gs_types.h @@ -1104,6 +1104,13 @@ typedef CREATE_SOCKET(platform_create_socket); #define CLOSE_SOCKET(name) bool name(platform_socket* Socket) typedef CLOSE_SOCKET(platform_close_socket); +#define SOCKET_PEEK(name) u32 name(platform_socket* Socket) +typedef SOCKET_PEEK(platform_socket_peek); + +// TODO(pjs): allow for a size parameter that can be zero +// if provided, that is how big the message it expects to be +// if it equals zero, the proc will peek at the message first to determine +// the needed size #define SOCKET_RECEIVE(name) gs_data name(platform_socket* Socket, gs_memory_arena* Storage) typedef SOCKET_RECEIVE(platform_socket_receive); @@ -1118,8 +1125,10 @@ typedef struct platform_socket_manager platform_create_socket* CreateSocketProc; platform_close_socket* CloseSocketProc; + platform_socket_peek* SocketPeekProc; platform_socket_receive* SocketRecieveProc; platform_socket_send* SocketSendProc; } platform_socket_manager; + #define GS_TYPES_H #endif // GS_TYPES_H \ No newline at end of file From 4836f7550dd2afe2d134c44ce7521197072af1a0 Mon Sep 17 00:00:00 2001 From: PS Date: Sat, 30 Jan 2021 15:10:46 -0800 Subject: [PATCH 32/44] Formalized a system for user space sculpture code --- src/app/blumen_lumen.cpp | 34 +++++++++++++++++++++++ src/app/engine/user_space.cpp | 36 +++++++++++++++++++++++++ src/app/engine/user_space.h | 27 +++++++++++++++++++ src/app/foldhaus_app.cpp | 51 +++++++++-------------------------- src/app/foldhaus_app.h | 7 ++--- src/app/foldhaus_platform.h | 6 ++--- 6 files changed, 117 insertions(+), 44 deletions(-) create mode 100644 src/app/engine/user_space.cpp create mode 100644 src/app/engine/user_space.h diff --git a/src/app/blumen_lumen.cpp b/src/app/blumen_lumen.cpp index 3525506..2fd647d 100644 --- a/src/app/blumen_lumen.cpp +++ b/src/app/blumen_lumen.cpp @@ -47,6 +47,31 @@ BlumenLumen_MicListenJob(gs_thread_context* Ctx, u8* UserData) CloseSocket(Data->SocketManager, Data->ListenSocket); } +internal void +BlumenLumen_LoadPatterns(app_state* State) +{ + animation_pattern_array* Patterns = &State->Patterns; + if (Patterns->CountMax == 0) + { + *Patterns = Patterns_Create(&State->Permanent, 32); + } + + Patterns->Count = 0; + Patterns_PushPattern(Patterns, TestPatternOne); + Patterns_PushPattern(Patterns, TestPatternTwo); + Patterns_PushPattern(Patterns, TestPatternThree); + Patterns_PushPattern(Patterns, Pattern_AllGreen); + Patterns_PushPattern(Patterns, Pattern_HueShift); + Patterns_PushPattern(Patterns, Pattern_HueFade); + Patterns_PushPattern(Patterns, Pattern_Spots); + Patterns_PushPattern(Patterns, Pattern_LighthouseRainbow); + Patterns_PushPattern(Patterns, Pattern_SmoothGrowRainbow); + Patterns_PushPattern(Patterns, Pattern_GrowAndFade); + Patterns_PushPattern(Patterns, Pattern_ColorToWhite); + Patterns_PushPattern(Patterns, Pattern_Blue); + Patterns_PushPattern(Patterns, Pattern_Green); +} + internal gs_data BlumenLumen_CustomInit(app_state* State, context Context) { @@ -176,6 +201,15 @@ BlumenLumen_CustomUpdate(gs_data UserData, app_state* State, context* Context) } } +internal user_space_desc +BlumenLumen_UserSpaceCreate() +{ + user_space_desc Result = {}; + Result.LoadPatterns = BlumenLumen_LoadPatterns; + Result.CustomInit = BlumenLumen_CustomInit; + Result.CustomUpdate = BlumenLumen_CustomUpdate; + return Result; +} #define BLUMEN_LUMEN_CPP #endif // BLUMEN_LUMEN_CPP \ No newline at end of file diff --git a/src/app/engine/user_space.cpp b/src/app/engine/user_space.cpp new file mode 100644 index 0000000..57ceb1c --- /dev/null +++ b/src/app/engine/user_space.cpp @@ -0,0 +1,36 @@ +// +// File: userspace.cpp +// Author: Peter Slattery +// Creation Date: 2021-01-30 +// +#ifndef USERSPACE_CPP + +internal void +US_LoadPatterns(user_space_desc* Desc, app_state* State, context Context) +{ + if (Desc->LoadPatterns) + { + Desc->LoadPatterns(State); + } +} + +internal void +US_CustomInit(user_space_desc* Desc, app_state* State, context Context) +{ + if (Desc->CustomInit) + { + Desc->UserData = Desc->CustomInit(State, Context); + } +} + +internal void +US_CustomUpdate(user_space_desc* Desc, app_state* State, context* Context) +{ + if (Desc->CustomUpdate) + { + Desc->CustomUpdate(Desc->UserData, State, Context); + } +} + +#define USERSPACE_CPP +#endif // USERSPACE_CPP \ No newline at end of file diff --git a/src/app/engine/user_space.h b/src/app/engine/user_space.h new file mode 100644 index 0000000..78b5318 --- /dev/null +++ b/src/app/engine/user_space.h @@ -0,0 +1,27 @@ +// +// File: userspace.h +// Author: Peter Slattery +// Creation Date: 2021-01-30 +// +#ifndef USERSPACE_H + +#define US_LOAD_PATTERNS(name) void name(app_state* State) +typedef US_LOAD_PATTERNS(us_load_patterns_proc); + +#define US_CUSTOM_INIT(name) gs_data name (app_state* State, context Context) +typedef US_CUSTOM_INIT(us_custom_init_proc); + +#define US_CUSTOM_UPDATE(name) void name(gs_data UserData, app_state* State, context* Context) +typedef US_CUSTOM_UPDATE(us_custom_update_proc); + +typedef struct user_space_desc +{ + us_load_patterns_proc* LoadPatterns; + us_custom_init_proc* CustomInit; + us_custom_update_proc* CustomUpdate; + + gs_data UserData; +} user_space_desc; + +#define USERSPACE_H +#endif // USERSPACE_H \ No newline at end of file diff --git a/src/app/foldhaus_app.cpp b/src/app/foldhaus_app.cpp index f53a27c..13111f7 100644 --- a/src/app/foldhaus_app.cpp +++ b/src/app/foldhaus_app.cpp @@ -8,27 +8,6 @@ #include "foldhaus_platform.h" #include "foldhaus_app.h" -internal void -ClearAndPushPatterns(animation_pattern_array* Patterns) -{ - if (Patterns->CountMax == 0) { return; } - - Patterns->Count = 0; - Patterns_PushPattern(Patterns, TestPatternOne); - Patterns_PushPattern(Patterns, TestPatternTwo); - Patterns_PushPattern(Patterns, TestPatternThree); - Patterns_PushPattern(Patterns, Pattern_AllGreen); - Patterns_PushPattern(Patterns, Pattern_HueShift); - Patterns_PushPattern(Patterns, Pattern_HueFade); - Patterns_PushPattern(Patterns, Pattern_Spots); - Patterns_PushPattern(Patterns, Pattern_LighthouseRainbow); - Patterns_PushPattern(Patterns, Pattern_SmoothGrowRainbow); - Patterns_PushPattern(Patterns, Pattern_GrowAndFade); - Patterns_PushPattern(Patterns, Pattern_ColorToWhite); - Patterns_PushPattern(Patterns, Pattern_Blue); - Patterns_PushPattern(Patterns, Pattern_Green); -} - RELOAD_STATIC_DATA(ReloadStaticData) { app_state* State = (app_state*)Context.MemoryBase; @@ -37,7 +16,7 @@ RELOAD_STATIC_DATA(ReloadStaticData) State->PanelSystem.PanelDefs = GlobalPanelDefs; State->PanelSystem.PanelDefsCount = GlobalPanelDefsCount; - ClearAndPushPatterns(&State->Patterns); + US_LoadPatterns(&State->UserSpaceDesc, State, Context); } INITIALIZE_APPLICATION(InitializeApplication) @@ -53,8 +32,11 @@ INITIALIZE_APPLICATION(InitializeApplication) State->CommandQueue = CommandQueue_Create(&State->Permanent, 32); - State->Patterns = Patterns_Create(&State->Permanent, 32); - ClearAndPushPatterns(&State->Patterns); + animation_system_desc AnimSysDesc = {}; + AnimSysDesc.Storage = &State->Permanent; + AnimSysDesc.AnimArrayCount = 32; + AnimSysDesc.SecondsPerFrame = 1.0f / 24.0f; + State->AnimationSystem = AnimationSystem_Init(AnimSysDesc); interface_config IConfig = {0}; IConfig.FontSize = 14; @@ -81,19 +63,10 @@ INITIALIZE_APPLICATION(InitializeApplication) PanelSystem_PushPanel(&State->PanelSystem, PanelType_SculptureView, State, Context); State->Modes = OperationModeSystemInit(&State->Permanent, Context.ThreadContext); + State->UserSpaceDesc = BlumenLumen_UserSpaceCreate(); + ReloadStaticData(Context, GlobalDebugServices); - - animation_system_desc AnimSysDesc = {}; - AnimSysDesc.Storage = &State->Permanent; - AnimSysDesc.AnimArrayCount = 32; - AnimSysDesc.SecondsPerFrame = 1.0f / 24.0f; - State->AnimationSystem = AnimationSystem_Init(AnimSysDesc); - - State->UserData = BlumenLumen_CustomInit(State, Context); - - // TEMP - blumen_lumen_state* BLState = (blumen_lumen_state*)State->UserData.Memory; - return (temp_job_req*)&BLState->JobReq; + US_CustomInit(&State->UserSpaceDesc, State, Context); } UPDATE_AND_RENDER(UpdateAndRender) @@ -101,6 +74,8 @@ UPDATE_AND_RENDER(UpdateAndRender) DEBUG_TRACK_FUNCTION; app_state* State = (app_state*)Context->MemoryBase; + OutputDebugStringA("Test"); + // NOTE(Peter): We do this at the beginning because all the render commands are stored in Transient, // and need to persist beyond the end of the UpdateAndRender call. In the release version, we won't // zero the Transient arena when we clear it so it wouldn't be a problem, but it is technically @@ -117,10 +92,10 @@ UPDATE_AND_RENDER(UpdateAndRender) &State->LedSystem, State->Patterns, State->Transient, - State->UserData.Memory); + State->UserSpaceDesc.UserData.Memory); } - BlumenLumen_CustomUpdate(State->UserData, State, Context); + US_CustomUpdate(&State->UserSpaceDesc, State, Context); AssemblyDebug_OverrideOutput(State->AssemblyDebugState, State->Assemblies, diff --git a/src/app/foldhaus_app.h b/src/app/foldhaus_app.h index 43f0f84..43ded68 100644 --- a/src/app/foldhaus_app.h +++ b/src/app/foldhaus_app.h @@ -41,6 +41,7 @@ typedef struct panel panel; #include "engine/animation/foldhaus_animation_serializer.cpp" #include "engine/animation/foldhaus_animation_renderer.cpp" +#include "engine/user_space.h" #include "blumen_lumen.h" struct app_state @@ -70,15 +71,15 @@ struct app_state panel_system PanelSystem; panel* HotPanel; - // User Space - // - gs_data UserData; + user_space_desc UserSpaceDesc; }; internal void OpenColorPicker(app_state* State, v4* Address); #include "engine/assembly/foldhaus_assembly.cpp" +#include "engine/user_space.cpp" + #include "patterns/blumen_patterns.h" #include "blumen_lumen.cpp" diff --git a/src/app/foldhaus_platform.h b/src/app/foldhaus_platform.h index c3cbb3e..7f10ab0 100644 --- a/src/app/foldhaus_platform.h +++ b/src/app/foldhaus_platform.h @@ -5,10 +5,10 @@ // #ifndef FOLDHAUS_PLATFORM_H +// TODO Remove +#include #include -#include // TODO Remove - #include "..\gs_libs\gs_types.h" #include "..\gs_libs\gs_types.cpp" @@ -66,7 +66,7 @@ struct packet_ringbuffer u32 WriteHead; }; -#define INITIALIZE_APPLICATION(name) temp_job_req* name(context Context) +#define INITIALIZE_APPLICATION(name) void name(context Context) typedef INITIALIZE_APPLICATION(initialize_application); #define UPDATE_AND_RENDER(name) void name(context* Context, input_queue InputQueue, render_command_buffer* RenderBuffer, addressed_data_buffer_list* OutputData) From 8a51ce2f04cf469faf56c084b5f63e1f3a61cecd Mon Sep 17 00:00:00 2001 From: PS Date: Sat, 30 Jan 2021 16:24:36 -0800 Subject: [PATCH 33/44] New patterns with the idea of pulling colors from set arrays of color patterns --- src/app/blumen_lumen.cpp | 2 + src/app/foldhaus_app.cpp | 2 - src/app/patterns/blumen_patterns.h | 127 +++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+), 2 deletions(-) diff --git a/src/app/blumen_lumen.cpp b/src/app/blumen_lumen.cpp index 2fd647d..bde1a00 100644 --- a/src/app/blumen_lumen.cpp +++ b/src/app/blumen_lumen.cpp @@ -70,6 +70,8 @@ BlumenLumen_LoadPatterns(app_state* State) Patterns_PushPattern(Patterns, Pattern_ColorToWhite); Patterns_PushPattern(Patterns, Pattern_Blue); Patterns_PushPattern(Patterns, Pattern_Green); + Patterns_PushPattern(Patterns, Pattern_FlowerColors); + Patterns_PushPattern(Patterns, Pattern_FlowerColorToWhite); } internal gs_data diff --git a/src/app/foldhaus_app.cpp b/src/app/foldhaus_app.cpp index 13111f7..6277cd4 100644 --- a/src/app/foldhaus_app.cpp +++ b/src/app/foldhaus_app.cpp @@ -74,8 +74,6 @@ UPDATE_AND_RENDER(UpdateAndRender) DEBUG_TRACK_FUNCTION; app_state* State = (app_state*)Context->MemoryBase; - OutputDebugStringA("Test"); - // NOTE(Peter): We do this at the beginning because all the render commands are stored in Transient, // and need to persist beyond the end of the UpdateAndRender call. In the release version, we won't // zero the Transient arena when we clear it so it wouldn't be a problem, but it is technically diff --git a/src/app/patterns/blumen_patterns.h b/src/app/patterns/blumen_patterns.h index 966587a..c4b3f8e 100644 --- a/src/app/patterns/blumen_patterns.h +++ b/src/app/patterns/blumen_patterns.h @@ -5,6 +5,52 @@ // #ifndef BLUMEN_PATTERNS_H +#define FLOWER_COLORS_COUNT 12 +pixel FlowerColors[FLOWER_COLORS_COUNT] = { + { 232,219,88 }, + { 232,219,88 }, + { 232,219,88 }, + { 147,75,176 }, + { 193,187,197 }, + { 223,190,49 }, + { 198,76,65 }, + { 198,76,65 }, + { 198,76,65 }, + { 226,200,17 }, + { 116,126,39 }, + { 61,62,31 } +}; + +internal pixel +PixelMix(r32 T, pixel A, pixel B) +{ + pixel Result = { + LerpU8(T, A.R, B.R), + LerpU8(T, A.G, B.G), + LerpU8(T, A.B, B.B), + }; + return Result; +} + +internal pixel +GetColor(pixel* Colors, u32 ColorsCount, r32 Percent) +{ + Percent = Clamp01(Percent); + + u32 LowerIndex = Percent * ColorsCount; + + u32 HigherIndex = LowerIndex + 1; + if (HigherIndex >= ColorsCount) HigherIndex = 0; + + r32 LowerPercent = (r32)LowerIndex / (r32)ColorsCount; + r32 StepPercent = 1.f / (r32)ColorsCount; + r32 PercentLower = (Percent - LowerPercent) / StepPercent; + + pixel Result = PixelMix(PercentLower, Colors[LowerIndex], Colors[HigherIndex]); + + return Result; +} + internal void SolidColorPattern(led_buffer* Leds, pixel Color) { @@ -28,6 +74,25 @@ Pattern_Green(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Tr SolidColorPattern(Leds, Green); } +internal void +Pattern_FlowerColors(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +{ + r32 CycleTime = 10; + r32 CyclePercent = ModR32(Time, CycleTime) / CycleTime; + + pixel CA = GetColor(FlowerColors, FLOWER_COLORS_COUNT, CyclePercent); + pixel CB = GetColor(FlowerColors, FLOWER_COLORS_COUNT, 1.0f - CyclePercent); + + for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) + { + v4 P = Leds->Positions[LedIndex]; + r32 Pct = (Abs(ModR32(P.y, 150) / 150) + CycleTime) * PiR32; + + r32 APct = RemapR32(SinR32(Pct), -1, 1, 0, 1); + Leds->Colors[LedIndex] = PixelMix(APct, CA, CB); + } +} + internal void TestPatternOne(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) { @@ -476,5 +541,67 @@ Pattern_ColorToWhite(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_ar } } +internal void +Pattern_FlowerColorToWhite(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +{ + r32 FadeBottomBase = 50; + r32 FadeTop = 125; + + for (u32 StripIndex = 0; StripIndex < Assembly.StripCount; StripIndex++) + { + v2_strip Strip = Assembly.Strips[StripIndex]; + + r32 FlowerSpread = .8f; + r32 FlowerOffset = 0; + if (AssemblyStrip_HasTagValueSLOW(Strip, "flower", "center")) + { + FlowerOffset = 1; + } + else if (AssemblyStrip_HasTagValueSLOW(Strip, "flower", "right")) + { + FlowerOffset = 2; + } + FlowerOffset *= FlowerSpread; + + r32 PercentCycle = ModR32(Time + FlowerOffset, 10) / 10; + + r32 FadeBottom = FadeBottomBase + RemapR32(SinR32((PercentCycle * 4) * TauR32), -1, 1, -50, 50); + + v4 TopRGB = WhiteV4; + pixel TopColor = V4ToRGBPixel(TopRGB); + + for (u32 i = 0; i < Strip.LedCount; i++) + { + u32 LedIndex = Strip.LedLUT[i]; + v4 P = Leds->Positions[LedIndex]; + + pixel FinalColor = {}; + if (P.y > FadeTop) + { + FinalColor = TopColor; + } + else + { + r32 B = RemapR32(SinR32((P.y / 15.f) + (PercentCycle * TauR32)), -1, 1, .5f, 1.f); + r32 HNoise = RemapR32(SinR32((P.y / 31.f) + (PercentCycle * TauR32)), -1, 1, 0.f, 1.f); + + pixel BottomColor = GetColor(FlowerColors, FLOWER_COLORS_COUNT, (PercentCycle + HNoise) / 2); + + if (P.y < FadeBottom) + { + FinalColor = BottomColor; + } + else if (P.y >= FadeBottom && P.y <= FadeTop) + { + r32 FadePct = RemapR32(P.y, FadeBottom, FadeTop, 0, 1); + FinalColor = PixelMix(FadePct, BottomColor, TopColor); + } + } + + Leds->Colors[LedIndex] = FinalColor; + } + } +} + #define BLUMEN_PATTERNS_H #endif // BLUMEN_PATTERNS_H \ No newline at end of file From c58ef9e40a37d9b55fed5e7a2b88ab7906c88606 Mon Sep 17 00:00:00 2001 From: Peter Slattery Date: Sat, 30 Jan 2021 19:33:44 -0800 Subject: [PATCH 34/44] Saturday @ Foldspace --- src/app/blumen_lumen.cpp | 50 ++++- src/app/patterns/blumen_patterns.h | 176 +++++++++++++++--- .../platform_win32/win32_foldhaus_socket.h | 7 +- 3 files changed, 196 insertions(+), 37 deletions(-) diff --git a/src/app/blumen_lumen.cpp b/src/app/blumen_lumen.cpp index bde1a00..3ea2102 100644 --- a/src/app/blumen_lumen.cpp +++ b/src/app/blumen_lumen.cpp @@ -12,8 +12,19 @@ BlumenLumen_MicListenJob(gs_thread_context* Ctx, u8* UserData) gs_data Msg = {}; + u8 WeathermanIPAddr[4] = {}; + WeathermanIPAddr[0] = 127; + WeathermanIPAddr[1] = 0; + WeathermanIPAddr[2] = 0; + WeathermanIPAddr[3] = 1; + + u32 WeathermanIPV4 = (u32)UpackB4(WeathermanIPAddr); + u32 WeathermanPort = 20185; + while (true) { +#if 0 + // TODO(pjs): Removing this block for now - nothing is wrong with it except that SocketPeek is still blocking for some reason if (SocketPeek(Data->SocketManager, Data->ListenSocket)) { // TODO(pjs): Make this a peek operation @@ -27,6 +38,7 @@ BlumenLumen_MicListenJob(gs_thread_context* Ctx, u8* UserData) } } } +#endif while (Data->OutgoingMsgQueue->ReadHead != Data->OutgoingMsgQueue->WriteHead) { @@ -37,8 +49,8 @@ BlumenLumen_MicListenJob(gs_thread_context* Ctx, u8* UserData) } Msg = Data->OutgoingMsgQueue->Buffers[ReadIndex]; - u32 Address = 0; - u32 Port = 0; + u32 Address = WeathermanIPV4; + u32 Port = WeathermanPort; s32 Flags = 0; SocketSend(Data->SocketManager, Data->ListenSocket, Address, Port, Msg, Flags); } @@ -72,6 +84,20 @@ BlumenLumen_LoadPatterns(app_state* State) Patterns_PushPattern(Patterns, Pattern_Green); Patterns_PushPattern(Patterns, Pattern_FlowerColors); Patterns_PushPattern(Patterns, Pattern_FlowerColorToWhite); + Patterns_PushPattern(Patterns, Pattern_BasicFlowers); +} + +internal pixel +TEMP_Saturate(pixel P) +{ + v4 CRGB = v4{ (r32)P.R / 255.f, (r32)P.G / 255.f, (r32)P.B / 255.f, 1.f }; + v4 CHSV = RGBToHSV(CRGB); + if (CHSV.g > .3f) + { + CHSV.g = 1; + CRGB = HSVToRGB(CHSV); + } + return V4ToRGBPixel(CRGB); } internal gs_data @@ -91,7 +117,7 @@ BlumenLumen_CustomInit(app_state* State, context Context) BLState->MicListenJobData.OutgoingMsgQueue = &BLState->OutgoingMsgQueue; BLState->MicListenJobData.ListenSocket = CreateSocket(Context.SocketManager, "127.0.0.1", "20185"); - BLState->MicListenThread = CreateThread(Context.ThreadManager, BlumenLumen_MicListenJob, (u8*)&BLState->MicListenJobData); + //BLState->MicListenThread = CreateThread(Context.ThreadManager, BlumenLumen_MicListenJob, (u8*)&BLState->MicListenJobData); gs_const_string SculpturePath = ConstString("data/test_blumen.fold"); LoadAssembly(&State->Assemblies, &State->LedSystem, State->Transient, Context, SculpturePath, State->GlobalLog); @@ -105,7 +131,7 @@ BlumenLumen_CustomInit(app_state* State, context Context) Anim0.PlayableRange.Max = SecondsToFrames(15, State->AnimationSystem); Animation_AddLayer(&Anim0, MakeString("Base Layer"), BlendMode_Overwrite, &State->AnimationSystem); - Animation_AddBlock(&Anim0, 0, Anim0.PlayableRange.Max, Patterns_IndexToHandle(11), 0); + Animation_AddBlock(&Anim0, 0, Anim0.PlayableRange.Max, Patterns_IndexToHandle(15), 0); AnimationArray_Push(&State->AnimationSystem.Animations, Anim0); @@ -136,9 +162,18 @@ BlumenLumen_CustomInit(app_state* State, context Context) State->AnimationSystem.TimelineShouldAdvance = true; } // End Animation Playground + for (u32 i = 0; i < FLOWER_COLORS_COUNT; i++) + { + FlowerAColors[i] = TEMP_Saturate(FlowerAColors[i]); + FlowerBColors[i] = TEMP_Saturate(FlowerBColors[i]); + FlowerCColors[i] = TEMP_Saturate(FlowerCColors[i]); + } + return Result; } +u8 temp = 0; + internal void BlumenLumen_CustomUpdate(gs_data UserData, app_state* State, context* Context) { @@ -184,9 +219,10 @@ BlumenLumen_CustomUpdate(gs_data UserData, app_state* State, context* Context) *Msg = PushSizeToData(&State->Permanent, sizeof(motor_packet)); } motor_packet* Packet = (motor_packet*)Msg->Memory; - Packet->FlowerPositions[0] = 5; - Packet->FlowerPositions[0] = 4; - Packet->FlowerPositions[0] = 9; + Packet->FlowerPositions[0] = temp; + Packet->FlowerPositions[1] = temp + 1; + Packet->FlowerPositions[2] = temp + 2; + temp++; // NOTE(pjs): We increment the write head AFTER we've written so that // the network thread doesn't think the buffer is ready to send before diff --git a/src/app/patterns/blumen_patterns.h b/src/app/patterns/blumen_patterns.h index c4b3f8e..bd27bfc 100644 --- a/src/app/patterns/blumen_patterns.h +++ b/src/app/patterns/blumen_patterns.h @@ -6,7 +6,8 @@ #ifndef BLUMEN_PATTERNS_H #define FLOWER_COLORS_COUNT 12 -pixel FlowerColors[FLOWER_COLORS_COUNT] = { + +pixel FlowerAColors[FLOWER_COLORS_COUNT] = { { 232,219,88 }, { 232,219,88 }, { 232,219,88 }, @@ -20,6 +21,34 @@ pixel FlowerColors[FLOWER_COLORS_COUNT] = { { 116,126,39 }, { 61,62,31 } }; +pixel FlowerBColors[FLOWER_COLORS_COUNT] = { + { 62,56,139 }, + { 93,87,164 }, + { 93,87,164 }, + { 93,87,164 }, + { 155,140,184 }, + { 191,201,204 }, + { 45,31,116 }, + { 201,196,156 }, + { 191,175,109 }, + { 186,176,107 }, + { 89,77,17 }, + { 47,49,18 }, +}; +pixel FlowerCColors[FLOWER_COLORS_COUNT] = { + { 220,217,210 }, + { 220,217,210 }, + { 220,217,210 }, + { 225,193,110 }, + { 225,193,110 }, + { 227,221,214 }, + { 227,221,214 }, + { 230,218,187 }, + { 230,218,187 }, + { 172,190,211 }, + { 172,190,211 }, + { 172,190,211 }, +}; internal pixel PixelMix(r32 T, pixel A, pixel B) @@ -80,8 +109,8 @@ Pattern_FlowerColors(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_ar r32 CycleTime = 10; r32 CyclePercent = ModR32(Time, CycleTime) / CycleTime; - pixel CA = GetColor(FlowerColors, FLOWER_COLORS_COUNT, CyclePercent); - pixel CB = GetColor(FlowerColors, FLOWER_COLORS_COUNT, 1.0f - CyclePercent); + pixel CA = GetColor(FlowerAColors, FLOWER_COLORS_COUNT, CyclePercent); + pixel CB = GetColor(FlowerAColors, FLOWER_COLORS_COUNT, 1.0f - CyclePercent); for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) { @@ -211,6 +240,54 @@ TestPatternThree(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* } } +v4 RGBToHSV(v4 In) +{ + v4 Result = {}; + + r32 Min = Min(In.r, Min(In.g, In.b)); + r32 Max = Max(In.r, Max(In.g, In.b)); + + + r32 V = Max; + r32 Delta = Max - Min; + r32 S = 0; + r32 H = 0; + if( Max != 0 ) + { + S = Delta / Max; + + if( In.r == Max ) + { + H = ( In.g - In.b ) / Delta; // between yellow & magenta + } + else if( In.g == Max ) + { + H = 2 + ( In.b - In.r ) / Delta; // between cyan & yellow + } + else + { + H = 4 + ( In.r - In.g ) / Delta; // between magenta & cyan + } + H *= 60; // degrees + if( H < 0 ) + H += 360; + Assert(H); + //if ( isNaN(h) ) + //H = 0; + Result = v4{H, S, V, 1}; + } + else + { + // r = g = b = 0 + // s = 0, v is undefined + S = 0; + H = -1; + Result = v4{H, S, 1, 1}; + } + + return Result; +} + v4 HSVToRGB (v4 In) { float Hue = In.x; @@ -551,6 +628,9 @@ Pattern_FlowerColorToWhite(led_buffer* Leds, assembly Assembly, r32 Time, gs_mem { v2_strip Strip = Assembly.Strips[StripIndex]; +#if 0 + // All flowers same flower type + pixel* Colors = &FlowerAColors[0]; r32 FlowerSpread = .8f; r32 FlowerOffset = 0; if (AssemblyStrip_HasTagValueSLOW(Strip, "flower", "center")) @@ -562,46 +642,86 @@ Pattern_FlowerColorToWhite(led_buffer* Leds, assembly Assembly, r32 Time, gs_mem FlowerOffset = 2; } FlowerOffset *= FlowerSpread; - +#else + // Each flower different + pixel* Colors = &FlowerAColors[0]; + r32 FlowerOffset = 0; + if (AssemblyStrip_HasTagValueSLOW(Strip, "flower", "center")) + { + Colors = &FlowerBColors[0]; + } + else if (AssemblyStrip_HasTagValueSLOW(Strip, "flower", "right")) + { + Colors = &FlowerCColors[0]; + } +#endif r32 PercentCycle = ModR32(Time + FlowerOffset, 10) / 10; r32 FadeBottom = FadeBottomBase + RemapR32(SinR32((PercentCycle * 4) * TauR32), -1, 1, -50, 50); - v4 TopRGB = WhiteV4; - pixel TopColor = V4ToRGBPixel(TopRGB); - for (u32 i = 0; i < Strip.LedCount; i++) { u32 LedIndex = Strip.LedLUT[i]; v4 P = Leds->Positions[LedIndex]; pixel FinalColor = {}; - if (P.y > FadeTop) - { - FinalColor = TopColor; - } - else - { - r32 B = RemapR32(SinR32((P.y / 15.f) + (PercentCycle * TauR32)), -1, 1, .5f, 1.f); - r32 HNoise = RemapR32(SinR32((P.y / 31.f) + (PercentCycle * TauR32)), -1, 1, 0.f, 1.f); - - pixel BottomColor = GetColor(FlowerColors, FLOWER_COLORS_COUNT, (PercentCycle + HNoise) / 2); - - if (P.y < FadeBottom) - { - FinalColor = BottomColor; - } - else if (P.y >= FadeBottom && P.y <= FadeTop) - { - r32 FadePct = RemapR32(P.y, FadeBottom, FadeTop, 0, 1); - FinalColor = PixelMix(FadePct, BottomColor, TopColor); - } - } + r32 B = RemapR32(SinR32((P.y / 15.f) + (PercentCycle * TauR32)), -1, 1, .5f, 1.f); + r32 HNoise = RemapR32(SinR32((P.y / 31.f) + (PercentCycle * TauR32)), -1, 1, 0.f, 1.f); + + pixel BottomColor = GetColor(Colors, FLOWER_COLORS_COUNT, (PercentCycle + HNoise) / 2); + + FinalColor = BottomColor; Leds->Colors[LedIndex] = FinalColor; } } } +r32 TLastFrame = 0; +pixel* FAC = &FlowerAColors[0]; +pixel* FBC = &FlowerBColors[0]; +pixel* FCC = &FlowerCColors[0]; + +internal void +Pattern_BasicFlowers(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +{ + if (TLastFrame > Time) + { + pixel* Temp = FAC; + FAC = FBC; + FBC = FCC; + FCC = Temp; + } + TLastFrame = Time; + + for (u32 StripIndex = 0; StripIndex < Assembly.StripCount; StripIndex++) + { + v2_strip Strip = Assembly.Strips[StripIndex]; + + // Each flower different + pixel* Colors = FAC; + if (AssemblyStrip_HasTagValueSLOW(Strip, "flower", "center")) + { + Colors = FBC; + } + else if (AssemblyStrip_HasTagValueSLOW(Strip, "flower", "right")) + { + Colors = FCC; + } + + r32 CycleT = ModR32(Time, 10) * 20; + + for (u32 i = 0; i < Strip.LedCount; i++) + { + u32 LedIndex = Strip.LedLUT[i]; + v4 P = Leds->Positions[LedIndex]; + + r32 T = ModR32(P.y + CycleT, 200) / 200.f; + T = Clamp01(T); + + Leds->Colors[LedIndex] = GetColor(Colors, FLOWER_COLORS_COUNT, T); + } + } +} #define BLUMEN_PATTERNS_H #endif // BLUMEN_PATTERNS_H \ No newline at end of file diff --git a/src/app/platform_win32/win32_foldhaus_socket.h b/src/app/platform_win32/win32_foldhaus_socket.h index 1795cfe..dcbc1e8 100644 --- a/src/app/platform_win32/win32_foldhaus_socket.h +++ b/src/app/platform_win32/win32_foldhaus_socket.h @@ -234,8 +234,6 @@ Win32SocketReceive(platform_socket* Socket, gs_memory_arena* Storage) } return Result; #else - - gs_data Result = PushSizeToData(Storage, 1024); s32 Flags = 0; SOCKET* Win32Sock = (SOCKET*)Socket->PlatformHandle; @@ -269,6 +267,11 @@ Win32SocketSend(platform_socket* Socket, u32 Address, u32 Port, gs_data Data, s3 if (Error == 10051) { } + if (Error == 10053) + { + // TODO(pjs): WSAECONNABORTED + InvalidCodePath; + } else { // TODO(Peter): :ErrorLogging From 45f0b396793ee5569b1ab4f1ac12679cd5e4d450 Mon Sep 17 00:00:00 2001 From: Peter Slattery Date: Sat, 6 Feb 2021 14:09:17 -0800 Subject: [PATCH 35/44] Fixed a strip count error in gen_blumen_lumen, and did some output data checking to ensure that we weren't sending garbage data to the sculpture. --- run.bat | 4 +++ src/app/engine/assembly/foldhaus_assembly.cpp | 11 ++++++- .../assembly/foldhaus_assembly_parser.cpp | 10 ++++-- src/app/engine/foldhaus_serializer.h | 33 ++++++++++++++++--- src/app/engine/uart/foldhaus_uart.cpp | 29 +++++++++++++--- src/app/engine/uart/foldhaus_uart.h | 2 ++ src/app/foldhaus_app.cpp | 5 +-- src/app/patterns/blumen_patterns.h | 7 ++-- src/app/platform_win32/win32_foldhaus.cpp | 21 +++++++++--- src/sculpture_gen/gen_blumen_lumen.cpp | 20 +++++++---- 10 files changed, 116 insertions(+), 26 deletions(-) create mode 100644 run.bat diff --git a/run.bat b/run.bat new file mode 100644 index 0000000..d8708cf --- /dev/null +++ b/run.bat @@ -0,0 +1,4 @@ +@echo off +pushd app_run_tree +start win32_msvc\debug\win32_foldhaus.exe +popd \ No newline at end of file diff --git a/src/app/engine/assembly/foldhaus_assembly.cpp b/src/app/engine/assembly/foldhaus_assembly.cpp index fd060d4..4ae1a6c 100644 --- a/src/app/engine/assembly/foldhaus_assembly.cpp +++ b/src/app/engine/assembly/foldhaus_assembly.cpp @@ -208,7 +208,8 @@ LoadAssembly (assembly_array* Assemblies, led_system* LedSystem, gs_memory_arena assembly* NewAssembly = AssemblyArray_Take(Assemblies); NewAssembly->Arena = CreateMemoryArena(Context.ThreadContext.Allocator); - if (ParseAssemblyFile(NewAssembly, FileName, AssemblyFileText, Scratch)) + parser AssemblyParser = ParseAssemblyFile(NewAssembly, FileName, AssemblyFileText, Scratch); + if (AssemblyParser.Success) { ConstructAssemblyFromDefinition(NewAssembly, LedSystem); } @@ -217,6 +218,14 @@ LoadAssembly (assembly_array* Assemblies, led_system* LedSystem, gs_memory_arena FreeMemoryArena(&NewAssembly->Arena); Assemblies->Count -= 1; } + + for (parser_error* ErrorAt = AssemblyParser.ErrorsRoot; + ErrorAt != 0; + ErrorAt = ErrorAt->Next) + { + OutputDebugString(ErrorAt->Message.Str); + } + } else { diff --git a/src/app/engine/assembly/foldhaus_assembly_parser.cpp b/src/app/engine/assembly/foldhaus_assembly_parser.cpp index 26e4205..5024fb6 100644 --- a/src/app/engine/assembly/foldhaus_assembly_parser.cpp +++ b/src/app/engine/assembly/foldhaus_assembly_parser.cpp @@ -258,12 +258,13 @@ AssemblyParser_ReadStripGenData(parser* Parser, assembly* Assembly) return Result; } -internal bool +internal parser ParseAssemblyFile(assembly* Assembly, gs_const_string FileName, gs_string FileText, gs_memory_arena* Transient) { Assembly->LedCountTotal = 0; parser Parser = {0}; + Parser.FileName = FileName; Parser.String = FileText; Parser.Identifiers = &AssemblyFieldIdentifiers[0]; Parser.IdentifiersCount = AssemblyField_Count; @@ -271,6 +272,7 @@ ParseAssemblyFile(assembly* Assembly, gs_const_string FileName, gs_string FileTe Parser.LineStart = Parser.At; Parser.Arena = &Assembly->Arena; Parser.Transient = Transient; + Parser.Success = true; Assembly->Name = Parser_ReadStringValue(&Parser, AssemblyField_AssemblyName); Assembly->Scale = Parser_ReadR32Value(&Parser, AssemblyField_AssemblyScale); @@ -298,6 +300,7 @@ ParseAssemblyFile(assembly* Assembly, gs_const_string FileName, gs_string FileTe else { Parser_PushErrorF(&Parser, "Invalid output mode specified for assembly."); + Parser.Success = false; } for (u32 i = 0; i < Assembly->StripCount; i++) @@ -316,16 +319,17 @@ ParseAssemblyFile(assembly* Assembly, gs_const_string FileName, gs_string FileTe if (!Parser_ReadCloseStruct(&Parser)) { Parser_PushErrorF(&Parser, "Strip struct doesn't close where expected"); + Parser.Success = false; } } else { Parser_PushErrorF(&Parser, "Expected a strip struct but none was found"); + Parser.Success = false; } } - // TODO(pjs): invalidate the file if its incorrect - return true; //Tokenizer.ParsingIsValid; + return Parser; } #define FOLDHAUS_ASSEMBLY_PARSER_CPP diff --git a/src/app/engine/foldhaus_serializer.h b/src/app/engine/foldhaus_serializer.h index 06f9d71..34ac831 100644 --- a/src/app/engine/foldhaus_serializer.h +++ b/src/app/engine/foldhaus_serializer.h @@ -135,7 +135,7 @@ struct parser_error { gs_string Message; - gs_string FileName; + gs_const_string FileName; u32 LineNumber; parser_error* Next; @@ -143,7 +143,7 @@ struct parser_error struct parser { - gs_string FileName; + gs_const_string FileName; gs_string String; @@ -160,6 +160,8 @@ struct parser parser_error* ErrorsRoot; parser_error* ErrorsHead; + + bool Success; }; internal void @@ -170,13 +172,17 @@ Parser_PushErrorF(parser* Parser, char* Format, ...) Error->LineNumber = Parser->Line; Error->Message = PushString(Parser->Transient, 1024); - PrintF(&Error->Message, "File: %S Line: %d - ", Error->FileName, Error->LineNumber); + PrintF(&Error->Message, "Error:\n"); va_list Args; va_start(Args, Format); PrintFArgsList(&Error->Message, Format, Args); va_end(Args); + AppendPrintF(&Error->Message, "\n\tFile: %S\n\tLine: %d\n", + Error->FileName, Error->LineNumber); + NullTerminate(&Error->Message); + SLLPushOrInit(Parser->ErrorsRoot, Parser->ErrorsHead, Error); } @@ -202,8 +208,27 @@ Parser_AdvanceChar(parser* P) { P->Line += 1; P->LineStart = P->At + 1; + + if ((P->At[0] == '\n' && P->At[1] == '\r') || + (P->At[0] == '\r' && P->At[1] == '\n')) + { + P->At++; + P->At++; + } + else if (P->At[0] == '\n') + { + P->At++; + } + else + { + // TODO(pjs): Not sure this is actually invalid + InvalidCodePath; + } + } + else + { + P->At++; } - P->At++; } internal void diff --git a/src/app/engine/uart/foldhaus_uart.cpp b/src/app/engine/uart/foldhaus_uart.cpp index c158412..64157fa 100644 --- a/src/app/engine/uart/foldhaus_uart.cpp +++ b/src/app/engine/uart/foldhaus_uart.cpp @@ -6,7 +6,7 @@ #ifndef FOLDHAUS_UART_CPP -internal void +internal uart_header* UART_SetChannelBuffer_Create(gs_memory_cursor* WriteCursor, uart_channel ChannelSettings, v2_strip Strip, led_buffer LedBuffer) { // NOTE(pjs): This is just here because the information is duplicated and I want to be sure @@ -27,10 +27,15 @@ UART_SetChannelBuffer_Create(gs_memory_cursor* WriteCursor, uart_channel Channel u8* OutputPixel = PushArrayOnCursor(WriteCursor, u8, 3); // TODO(pjs): Use the Output mask +#if 1 OutputPixel[0] = Color.R; OutputPixel[1] = Color.G; OutputPixel[2] = Color.B; - +#else + OutputPixel[0] = 255; + OutputPixel[1] = 255; + OutputPixel[2] = 255; +#endif if (Channel->ElementsCount == 4) { // TODO(pjs): Calculate white from the RGB components? @@ -43,6 +48,8 @@ UART_SetChannelBuffer_Create(gs_memory_cursor* WriteCursor, uart_channel Channel uart_footer* Footer = PushStructOnCursor(WriteCursor, uart_footer); UART_FillFooter(Footer, (u8*)Header); + + return Header; } internal void @@ -64,7 +71,7 @@ UART_BuildOutputData(addressed_data_buffer_list* Output, assembly_array Assembli // NOTE(pjs): This is the minimum size of every UART message. SetChannelBuffer messages will // be bigger than this, but their size is based on the number of pixels in each channel - u32 MessageBaseSize = sizeof(uart_header) + sizeof(uart_channel) + sizeof(uart_footer); + u32 MessageBaseSize = UART_MESSAGE_MIN_SIZE; for (u32 AssemblyIdx = 0; AssemblyIdx < Assemblies.Count; AssemblyIdx++) { @@ -74,15 +81,19 @@ UART_BuildOutputData(addressed_data_buffer_list* Output, assembly_array Assembli struct strips_to_data_buffer { gs_const_string ComPort; + u32* StripIndices; u32 StripIndicesCount; u32 StripIndicesCountMax; u64 LedCount; + u8** ChannelsStart; + strips_to_data_buffer* Next; }; + u32 BuffersNeededCount = 0; strips_to_data_buffer* BuffersNeededHead = 0; strips_to_data_buffer* BuffersNeededTail = 0; @@ -120,6 +131,12 @@ UART_BuildOutputData(addressed_data_buffer_list* Output, assembly_array Assembli BufferSelected->Next = 0; SLLPushOrInit(BuffersNeededHead, BuffersNeededTail, BufferSelected); + BuffersNeededCount += 1; + + gs_string Temp = PushStringF(Transient, 256, "Found Com Port: %S\n\tStrip: %d\n", StripAt.UARTAddr.ComPort.ConstString, + StripIdx); + NullTerminate(&Temp); + OutputDebugString(Temp.Str); } Assert(BufferSelected->StripIndicesCount < BufferSelected->StripIndicesCountMax); @@ -136,6 +153,8 @@ UART_BuildOutputData(addressed_data_buffer_list* Output, assembly_array Assembli TotalBufferSize += MessageBaseSize; // DrawAll message TotalBufferSize += ChannelSettings.ElementsCount * At->LedCount; // pixels * channels per pixel + At->ChannelsStart = PushArray(Transient, u8*, At->StripIndicesCount); + addressed_data_buffer* Buffer = AddressedDataBufferList_Push(Output, TotalBufferSize); gs_const_string ComPort = At->ComPort; AddressedDataBuffer_SetCOMPort(Buffer, ComPort); @@ -148,7 +167,9 @@ UART_BuildOutputData(addressed_data_buffer_list* Output, assembly_array Assembli v2_strip StripAt = Assembly.Strips[StripIdx]; ChannelSettings.PixelsCount = StripAt.LedCount; - UART_SetChannelBuffer_Create(&WriteCursor, ChannelSettings, StripAt, *LedBuffer); + uart_header* Header = UART_SetChannelBuffer_Create(&WriteCursor, ChannelSettings, StripAt, *LedBuffer); + + //At->Header[i] = Header; } UART_DrawAll_Create(&WriteCursor); diff --git a/src/app/engine/uart/foldhaus_uart.h b/src/app/engine/uart/foldhaus_uart.h index f866efc..63067ba 100644 --- a/src/app/engine/uart/foldhaus_uart.h +++ b/src/app/engine/uart/foldhaus_uart.h @@ -35,6 +35,8 @@ struct uart_footer #pragma pack(pop) +#define UART_MESSAGE_MIN_SIZE sizeof(uart_header) + sizeof(uart_channel) + sizeof(uart_footer) + global u32 UART_CRCTable[256] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d diff --git a/src/app/foldhaus_app.cpp b/src/app/foldhaus_app.cpp index 6277cd4..afb9fe2 100644 --- a/src/app/foldhaus_app.cpp +++ b/src/app/foldhaus_app.cpp @@ -56,6 +56,7 @@ INITIALIZE_APPLICATION(InitializeApplication) State->LedSystem = LedSystem_Create(Context.ThreadContext.Allocator, 128); State->AssemblyDebugState = AssemblyDebug_Create(&State->Permanent); + State->AssemblyDebugState.Override = ADS_Override_AllRed; GlobalDebugServices->Interface.RenderSculpture = true; @@ -99,14 +100,14 @@ UPDATE_AND_RENDER(UpdateAndRender) State->Assemblies, State->LedSystem); + Editor_Render(State, Context, RenderBuffer); + // NOTE(pjs): Building data buffers to be sent out to the sculpture // This array is used on the platform side to actually send the information assembly_array SACNAssemblies = AssemblyArray_Filter(State->Assemblies, AssemblyFilter_OutputsViaSACN, State->Transient); assembly_array UARTAssemblies = AssemblyArray_Filter(State->Assemblies, AssemblyFilter_OutputsViaUART, State->Transient); SACN_BuildOutputData(&State->SACN, OutputData, SACNAssemblies, &State->LedSystem); UART_BuildOutputData(OutputData, UARTAssemblies, &State->LedSystem, State->Transient); - - Editor_Render(State, Context, RenderBuffer); } CLEANUP_APPLICATION(CleanupApplication) diff --git a/src/app/patterns/blumen_patterns.h b/src/app/patterns/blumen_patterns.h index bd27bfc..4345524 100644 --- a/src/app/patterns/blumen_patterns.h +++ b/src/app/patterns/blumen_patterns.h @@ -380,13 +380,16 @@ Pattern_HueShift(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* r32 CycleProgress = FractR32(Time / CycleLength); r32 CycleBlend = (SinR32(Time) * .5f) + .5f; + v4 HSV = { CycleProgress * 360, 1, 1, 1 }; + v4 RGB = HSVToRGB(HSV); + for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) { v4 Pos = Leds->Positions[LedIndex]; r32 Dist = Pos.y - Height; - v4 HSV = { (ModR32(Dist, 25) / 25) * 360, 1, 1, 1 }; - v4 RGB = HSVToRGB(HSV); + //v4 HSV = { (ModR32(Dist, 25) / 25) * 360, 1, 1, 1 }; + //v4 RGB = HSVToRGB(HSV); u8 R = (u8)(RGB.x * 255); u8 G = (u8)(RGB.y * 255); diff --git a/src/app/platform_win32/win32_foldhaus.cpp b/src/app/platform_win32/win32_foldhaus.cpp index f0974e3..c055de0 100644 --- a/src/app/platform_win32/win32_foldhaus.cpp +++ b/src/app/platform_win32/win32_foldhaus.cpp @@ -546,10 +546,8 @@ WinMain ( Context.UpdateAndRender(&Context, InputQueue, &RenderBuffer, &OutputData); - RenderCommandBuffer(RenderBuffer); - ClearRenderBuffer(&RenderBuffer); - - if (true) + bool Multithread = true; + if (Multithread) { for (addressed_data_buffer* At = OutputData.Root; At != 0; @@ -561,6 +559,21 @@ WinMain ( Win32PushWorkOnQueue(&Win32WorkQueue.WorkQueue, Win32_SendAddressedDataBuffer_Job, ProcArg, ConstString("Send UART Data")); } } + else + { + for (addressed_data_buffer* At = OutputData.Root; + At != 0; + At = At->Next) + { + gs_data ProcArg = {}; + ProcArg.Memory = (u8*)At; + ProcArg.Size = sizeof(addressed_data_buffer); + Win32_SendAddressedDataBuffer_Job(ThreadContext, ProcArg); + } + } + + RenderCommandBuffer(RenderBuffer); + ClearRenderBuffer(&RenderBuffer); Mouse_Advance(&Context); diff --git a/src/sculpture_gen/gen_blumen_lumen.cpp b/src/sculpture_gen/gen_blumen_lumen.cpp index 00333da..126ef52 100644 --- a/src/sculpture_gen/gen_blumen_lumen.cpp +++ b/src/sculpture_gen/gen_blumen_lumen.cpp @@ -99,7 +99,7 @@ typedef struct u32* BloomInnerChannels; } flower_desc; -internal void +internal u32 BuildFlower(gs_string* OutputBuffer, flower_desc Desc) { @@ -149,6 +149,11 @@ BuildFlower(gs_string* OutputBuffer, flower_desc Desc) BuildLoop(OutputBuffer, FlowerStem); #endif + u32 StripsCount = BloomStemInner.SegmentsCount; + StripsCount += BloomStemOuter.SegmentsCount; + StripsCount += FlowerStem.SegmentsCount; + + return StripsCount; } // Just for brevity, no real function provided @@ -176,9 +181,11 @@ int main(int ArgCount, char** Args) "Blumen Lumen - Silver Spring", 100, v3{0, 0, 0}, - 69, + 63, ""); + u32 StripCount = 0; + u32 StemChannels[] = { FSC(2, 1), FSC(2, 2), FSC(2, 3), FSC(2, 4), FSC(2, 5), FSC(2, 6) }; u32 BloomOuterChannels[] = { FSC(1, 0), FSC(1, 1), FSC(1, 2), FSC(1, 3), FSC(1, 4), FSC(1, 5), FSC(1, 6), FSC(1, 7), FSC(2, 0) }; u32 BloomInnerChannels[] = { FSC(0, 0), FSC(0, 1), FSC(0, 2), FSC(0, 3), FSC(0, 4), FSC(0, 5) }; @@ -189,7 +196,7 @@ int main(int ArgCount, char** Args) F0.StemChannels = StemChannels; F0.BloomOuterChannels = BloomOuterChannels; F0.BloomInnerChannels = BloomInnerChannels; - BuildFlower(&OutputBuffer, F0); + StripCount += BuildFlower(&OutputBuffer, F0); flower_desc F1 = {}; F1.Pos = v3{0, 0, 0}; @@ -198,7 +205,7 @@ int main(int ArgCount, char** Args) F1.StemChannels = StemChannels; F1.BloomInnerChannels = BloomInnerChannels; F1.BloomOuterChannels = BloomOuterChannels; - BuildFlower(&OutputBuffer, F1); + StripCount += BuildFlower(&OutputBuffer, F1); flower_desc F2 = {}; F2.Pos = v3{1, 0, 0}; @@ -207,9 +214,10 @@ int main(int ArgCount, char** Args) F2.StemChannels = StemChannels; F2.BloomInnerChannels = BloomInnerChannels; F2.BloomOuterChannels = BloomOuterChannels; - BuildFlower(&OutputBuffer, F2); + StripCount += BuildFlower(&OutputBuffer, F2); - printf("%.*s\n", (u32)OutputBuffer.Length, OutputBuffer.Str); + //printf("%.*s\n", (u32)OutputBuffer.Length, OutputBuffer.Str); + printf("%d\n", StripCount); return 0; } From 63d204364a5855df15570ab5d6e25951790141d6 Mon Sep 17 00:00:00 2001 From: Peter Slattery Date: Sat, 6 Feb 2021 14:25:43 -0800 Subject: [PATCH 36/44] clean up after debugging lights --- src/app/editor/panels/foldhaus_panel_hierarchy.h | 12 ++++++++++-- src/app/engine/uart/foldhaus_uart.cpp | 8 ++------ src/app/interface.h | 16 ++++++++++++++++ 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/app/editor/panels/foldhaus_panel_hierarchy.h b/src/app/editor/panels/foldhaus_panel_hierarchy.h index e19cbb0..13d45fe 100644 --- a/src/app/editor/panels/foldhaus_panel_hierarchy.h +++ b/src/app/editor/panels/foldhaus_panel_hierarchy.h @@ -43,9 +43,14 @@ HierarchyView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Ren ui_PushLayout(&State->Interface, PanelBounds, LayoutDirection_TopDown, MakeString("Hierarchy Layout")); ui_BeginList(&State->Interface, MakeString("Hierarchy List"), 10, State->Assemblies.Count + 1); { - ui_BeginRow(&State->Interface, 2); + ui_column_spec Cols[2] = { + ui_column_spec{ UIColumnSize_Fill, 0 }, + ui_column_spec{ UIColumnSize_MaxWidth, 128 } + }; for (u32 i = 0; i < State->Assemblies.Count; i++) { + ui_BeginRow(&State->Interface, 2, &Cols[0]); + assembly Assembly = State->Assemblies.Values[i]; PrintF(&TempString, "%S", Assembly.Name); @@ -54,8 +59,12 @@ HierarchyView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Ren { UnloadAssembly(i, State, Context); } + + ui_EndRow(&State->Interface); } + + ui_BeginRow(&State->Interface, 2, &Cols[0]); ui_Label(&State->Interface, MakeString(" ")); if (ui_Button(&State->Interface, MakeString("+ Add Assembly"))) { @@ -63,7 +72,6 @@ HierarchyView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Ren FileView_SetMode(FileBrowser, FileViewMode_Save); Panel_PushModalOverride(Panel, FileBrowser, LoadAssemblyCallback); } - ui_EndRow(&State->Interface); } ui_EndList(&State->Interface); diff --git a/src/app/engine/uart/foldhaus_uart.cpp b/src/app/engine/uart/foldhaus_uart.cpp index 64157fa..94cded0 100644 --- a/src/app/engine/uart/foldhaus_uart.cpp +++ b/src/app/engine/uart/foldhaus_uart.cpp @@ -6,7 +6,7 @@ #ifndef FOLDHAUS_UART_CPP -internal uart_header* +internal void UART_SetChannelBuffer_Create(gs_memory_cursor* WriteCursor, uart_channel ChannelSettings, v2_strip Strip, led_buffer LedBuffer) { // NOTE(pjs): This is just here because the information is duplicated and I want to be sure @@ -48,8 +48,6 @@ UART_SetChannelBuffer_Create(gs_memory_cursor* WriteCursor, uart_channel Channel uart_footer* Footer = PushStructOnCursor(WriteCursor, uart_footer); UART_FillFooter(Footer, (u8*)Header); - - return Header; } internal void @@ -167,9 +165,7 @@ UART_BuildOutputData(addressed_data_buffer_list* Output, assembly_array Assembli v2_strip StripAt = Assembly.Strips[StripIdx]; ChannelSettings.PixelsCount = StripAt.LedCount; - uart_header* Header = UART_SetChannelBuffer_Create(&WriteCursor, ChannelSettings, StripAt, *LedBuffer); - - //At->Header[i] = Header; + UART_SetChannelBuffer_Create(&WriteCursor, ChannelSettings, StripAt, *LedBuffer); } UART_DrawAll_Create(&WriteCursor); diff --git a/src/app/interface.h b/src/app/interface.h index 34cf505..60c640a 100644 --- a/src/app/interface.h +++ b/src/app/interface.h @@ -847,6 +847,7 @@ enum ui_column_size_rule UIColumnSize_Fixed, UIColumnSize_Percent, UIColumnSize_Fill, + UIColumnSize_MaxWidth, }; struct ui_column_spec @@ -893,6 +894,20 @@ ui_BeginRow(ui_interface* Interface, u32 ColumnsMax, ui_column_spec* ColumnRules { FillColumnsCount += 1; }break; + + case UIColumnSize_MaxWidth: + { + if (RemainingSpace >= Spec.Width) + { + Column->XMax = Spec.Width; + } + else + { + Column->XMax = RemainingSpace; + } + RemainingSpace -= Column->XMax; + }break; + InvalidDefaultCase; } } @@ -911,6 +926,7 @@ ui_BeginRow(ui_interface* Interface, u32 ColumnsMax, ui_column_spec* ColumnRules { case UIColumnSize_Fixed: case UIColumnSize_Percent: + case UIColumnSize_MaxWidth: { ColumnWidth = Column->XMax; }break; From ac19ab97ba148e11274eabefdfefc7323deba61a Mon Sep 17 00:00:00 2001 From: Peter Slattery Date: Sat, 6 Feb 2021 15:10:14 -0800 Subject: [PATCH 37/44] saturday at foldspace --- src/app/blumen_lumen.cpp | 68 +++++++++++-------- src/app/blumen_lumen.h | 56 +++++++++++++++ .../platform_win32/win32_foldhaus_socket.h | 61 ++++++++++++++--- 3 files changed, 148 insertions(+), 37 deletions(-) diff --git a/src/app/blumen_lumen.cpp b/src/app/blumen_lumen.cpp index 3ea2102..d2e5a5c 100644 --- a/src/app/blumen_lumen.cpp +++ b/src/app/blumen_lumen.cpp @@ -23,7 +23,7 @@ BlumenLumen_MicListenJob(gs_thread_context* Ctx, u8* UserData) while (true) { -#if 0 +#if 1 // TODO(pjs): Removing this block for now - nothing is wrong with it except that SocketPeek is still blocking for some reason if (SocketPeek(Data->SocketManager, Data->ListenSocket)) { @@ -117,7 +117,7 @@ BlumenLumen_CustomInit(app_state* State, context Context) BLState->MicListenJobData.OutgoingMsgQueue = &BLState->OutgoingMsgQueue; BLState->MicListenJobData.ListenSocket = CreateSocket(Context.SocketManager, "127.0.0.1", "20185"); - //BLState->MicListenThread = CreateThread(Context.ThreadManager, BlumenLumen_MicListenJob, (u8*)&BLState->MicListenJobData); + BLState->MicListenThread = CreateThread(Context.ThreadManager, BlumenLumen_MicListenJob, (u8*)&BLState->MicListenJobData); gs_const_string SculpturePath = ConstString("data/test_blumen.fold"); LoadAssembly(&State->Assemblies, &State->LedSystem, State->Transient, Context, SculpturePath, State->GlobalLog); @@ -172,13 +172,13 @@ BlumenLumen_CustomInit(app_state* State, context Context) return Result; } -u8 temp = 0; - internal void BlumenLumen_CustomUpdate(gs_data UserData, app_state* State, context* Context) { blumen_lumen_state* BLState = (blumen_lumen_state*)UserData.Memory; + MotorTimeElapsed += Context->DeltaTime; + gs_string BlueString = MakeString("blue"); gs_string GreenString = MakeString("green"); gs_string ILoveYouString = MakeString("i_love_you"); @@ -208,33 +208,47 @@ BlumenLumen_CustomUpdate(gs_data UserData, app_state* State, context* Context) } } - if ((BLState->OutgoingMsgQueue.WriteHead >= BLState->OutgoingMsgQueue.ReadHead) || - (BLState->OutgoingMsgQueue.WriteHead < BLState->OutgoingMsgQueue.ReadHead)) + if (MotorTimeElapsed > OpenClosePeriod) { - u32 WriteIndex = BLState->OutgoingMsgQueue.WriteHead; - - gs_data* Msg = BLState->OutgoingMsgQueue.Buffers + WriteIndex; - if (Msg->Size == 0) + // NOTE(pjs): + MotorTimeElapsed = 0; + u8 Position = LastPosition; + if (LastPosition == 2) { - *Msg = PushSizeToData(&State->Permanent, sizeof(motor_packet)); + LastPosition = ClosedValue; } - motor_packet* Packet = (motor_packet*)Msg->Memory; - Packet->FlowerPositions[0] = temp; - Packet->FlowerPositions[1] = temp + 1; - Packet->FlowerPositions[2] = temp + 2; - temp++; - - // NOTE(pjs): We increment the write head AFTER we've written so that - // the network thread doesn't think the buffer is ready to send before - // the data is set. We want to avoid the case of: - // 1. Main Thread increments write head to 1 - // 2. Network Thread thinks theres a new message to send at 0 - // 3. Network Thread sends the message at 0 - // 4. Main Thread sets the message at 0 - BLState->OutgoingMsgQueue.WriteHead += 1; - if (BLState->OutgoingMsgQueue.WriteHead >= BLUMEN_MESSAGE_QUEUE_COUNT) + else { - BLState->OutgoingMsgQueue.WriteHead = 0; + LastPosition = OpenValue; + } + + if ((BLState->OutgoingMsgQueue.WriteHead >= BLState->OutgoingMsgQueue.ReadHead) || + (BLState->OutgoingMsgQueue.WriteHead < BLState->OutgoingMsgQueue.ReadHead)) + { + u32 WriteIndex = BLState->OutgoingMsgQueue.WriteHead; + + gs_data* Msg = BLState->OutgoingMsgQueue.Buffers + WriteIndex; + if (Msg->Size == 0) + { + *Msg = PushSizeToData(&State->Permanent, sizeof(motor_packet)); + } + motor_packet* Packet = (motor_packet*)Msg->Memory; + Packet->FlowerPositions[0] = Position; + Packet->FlowerPositions[1] = Position; + Packet->FlowerPositions[2] = Position; + + // NOTE(pjs): We increment the write head AFTER we've written so that + // the network thread doesn't think the buffer is ready to send before + // the data is set. We want to avoid the case of: + // 1. Main Thread increments write head to 1 + // 2. Network Thread thinks theres a new message to send at 0 + // 3. Network Thread sends the message at 0 + // 4. Main Thread sets the message at 0 + BLState->OutgoingMsgQueue.WriteHead += 1; + if (BLState->OutgoingMsgQueue.WriteHead >= BLUMEN_MESSAGE_QUEUE_COUNT) + { + BLState->OutgoingMsgQueue.WriteHead = 0; + } } } } diff --git a/src/app/blumen_lumen.h b/src/app/blumen_lumen.h index d5ce452..9e1b166 100644 --- a/src/app/blumen_lumen.h +++ b/src/app/blumen_lumen.h @@ -53,6 +53,62 @@ struct blumen_lumen_state platform_thread_handle MicListenThread; mic_listen_job_data MicListenJobData; }; + + + + + + + + + + + + + + + + + + +// If you change anything, exit lumenarium if its running +// then in this application hit f1 to compile then +// go to remedybg (the debugger) and hit f5 + + +// don't touch this +u8 LastPosition = 1; + +u8 ClosedValue = 1; +u8 OpenValue = 2; + + +r64 MotorTimeElapsed = 0; +r64 OpenClosePeriod = 15.0f; + + + + + + + + + + + + + + + + + + + + + + + + #define BLUMEN_LUMEN_H diff --git a/src/app/platform_win32/win32_foldhaus_socket.h b/src/app/platform_win32/win32_foldhaus_socket.h index dcbc1e8..bd5b5cd 100644 --- a/src/app/platform_win32/win32_foldhaus_socket.h +++ b/src/app/platform_win32/win32_foldhaus_socket.h @@ -154,19 +154,53 @@ Win32CreateSocket(platform_socket* Socket, char* Address, char* DefaultPort) InvalidCodePath; } + // If iMode == 0, blocking is enabled + // if iMode != 0, non-blocking mode is enabled + u_long iMode = 1; + Error = ioctlsocket(SocketHandle, FIONBIO, &iMode); + if (Error != NO_ERROR) + { + InvalidCodePath; + } + Error = connect(SocketHandle, InfoAt->ai_addr, (int)InfoAt->ai_addrlen); if (Error == SOCKET_ERROR) { - closesocket(SocketHandle); - continue; - } - else - { - Socket->PlatformHandle = (u8*)Win32Alloc(sizeof(SOCKET), 0); - *(SOCKET*)Socket->PlatformHandle = SocketHandle; - Result = true; - break; + u32 Status = WSAGetLastError(); + if (Status == WSAEWOULDBLOCK) + { +#if 0 + TIMEVAL Timeout = { 0, 500 }; + fd_set SocketSet = {}; + FD_ZERO(&SocketSet); + FD_SET(SocketHandle, &SocketSet); + Assert(FD_ISSET(SocketHandle, &SocketSet)); + Status = select(0, &SocketSet, 0, 0, {}); + if (Status == SOCKET_ERROR) + { + + } + else if (Status == 0) + { + } + else + { + + } +#endif + } + else + { + closesocket(SocketHandle); + continue; + } } + + + Socket->PlatformHandle = (u8*)Win32Alloc(sizeof(SOCKET), 0); + *(SOCKET*)Socket->PlatformHandle = SocketHandle; + Result = true; + break; } } else @@ -212,7 +246,14 @@ Win32SocketPeek(platform_socket* Socket) { // TODO(pjs): Error handling s32 Error = WSAGetLastError(); - InvalidCodePath; + if (Error == WSAEWOULDBLOCK) + { + // NOTE(pjs): + } + else + { + InvalidCodePath; + } } return Result; } From 3bc51afe7382ea63b0fe60ebb632c9a0ff1c1c51 Mon Sep 17 00:00:00 2001 From: Peter Slattery Date: Sat, 20 Feb 2021 13:14:54 -0800 Subject: [PATCH 38/44] Added a User Space Cleanup Proc, made BlumenLumen_CustomCleanup end its thread, and implemented a SocketQueryStatus function --- src/app/blumen_lumen.cpp | 65 +++++++++++-------- src/app/blumen_lumen.h | 4 ++ src/app/engine/user_space.cpp | 10 +++ src/app/engine/user_space.h | 4 ++ src/app/foldhaus_app.cpp | 1 + src/app/platform_win32/win32_foldhaus.cpp | 8 +-- .../platform_win32/win32_foldhaus_socket.h | 21 ++++-- .../win32_foldhaus_work_queue.h | 8 ++- src/gs_libs/gs_types.cpp | 25 +++++++ src/gs_libs/gs_types.h | 4 ++ 10 files changed, 113 insertions(+), 37 deletions(-) diff --git a/src/app/blumen_lumen.cpp b/src/app/blumen_lumen.cpp index d2e5a5c..f58e410 100644 --- a/src/app/blumen_lumen.cpp +++ b/src/app/blumen_lumen.cpp @@ -21,38 +21,41 @@ BlumenLumen_MicListenJob(gs_thread_context* Ctx, u8* UserData) u32 WeathermanIPV4 = (u32)UpackB4(WeathermanIPAddr); u32 WeathermanPort = 20185; - while (true) + while (*Data->Running) { #if 1 - // TODO(pjs): Removing this block for now - nothing is wrong with it except that SocketPeek is still blocking for some reason - if (SocketPeek(Data->SocketManager, Data->ListenSocket)) + if (SocketQueryStatus(Data->SocketManager, Data->ListenSocket)) { - // TODO(pjs): Make this a peek operation - Msg = SocketRecieve(Data->SocketManager, Data->ListenSocket, Ctx->Transient); - if (Msg.Size > 0) + // TODO(pjs): Removing this block for now - nothing is wrong with it except that SocketPeek is still blocking for some reason + if (SocketPeek(Data->SocketManager, Data->ListenSocket)) { - Data->MicPacketBuffer->Values[Data->MicPacketBuffer->WriteHead++] = Msg; - if (Data->MicPacketBuffer->WriteHead >= PACKETS_MAX) + // TODO(pjs): Make this a peek operation + Msg = SocketRecieve(Data->SocketManager, Data->ListenSocket, Ctx->Transient); + if (Msg.Size > 0) { - Data->MicPacketBuffer->WriteHead = 0; + Data->MicPacketBuffer->Values[Data->MicPacketBuffer->WriteHead++] = Msg; + if (Data->MicPacketBuffer->WriteHead >= PACKETS_MAX) + { + Data->MicPacketBuffer->WriteHead = 0; + } } } - } #endif - - while (Data->OutgoingMsgQueue->ReadHead != Data->OutgoingMsgQueue->WriteHead) - { - u32 ReadIndex = Data->OutgoingMsgQueue->ReadHead++; - if (Data->OutgoingMsgQueue->ReadHead >= BLUMEN_MESSAGE_QUEUE_COUNT) - { - Data->OutgoingMsgQueue->ReadHead = 0; - } - Msg = Data->OutgoingMsgQueue->Buffers[ReadIndex]; - u32 Address = WeathermanIPV4; - u32 Port = WeathermanPort; - s32 Flags = 0; - SocketSend(Data->SocketManager, Data->ListenSocket, Address, Port, Msg, Flags); + while (Data->OutgoingMsgQueue->ReadHead != Data->OutgoingMsgQueue->WriteHead) + { + u32 ReadIndex = Data->OutgoingMsgQueue->ReadHead++; + if (Data->OutgoingMsgQueue->ReadHead >= BLUMEN_MESSAGE_QUEUE_COUNT) + { + Data->OutgoingMsgQueue->ReadHead = 0; + } + + Msg = Data->OutgoingMsgQueue->Buffers[ReadIndex]; + u32 Address = WeathermanIPV4; + u32 Port = WeathermanPort; + s32 Flags = 0; + SocketSend(Data->SocketManager, Data->ListenSocket, Address, Port, Msg, Flags); + } } } @@ -112,6 +115,9 @@ BlumenLumen_CustomInit(app_state* State, context Context) Result = PushSizeToData(&State->Permanent, sizeof(blumen_lumen_state)); blumen_lumen_state* BLState = (blumen_lumen_state*)Result.Memory; + BLState->Running = true; + + BLState->MicListenJobData.Running = &BLState->Running; BLState->MicListenJobData.SocketManager = Context.SocketManager; BLState->MicListenJobData.MicPacketBuffer = &BLState->MicPacketBuffer; BLState->MicListenJobData.OutgoingMsgQueue = &BLState->OutgoingMsgQueue; @@ -208,18 +214,18 @@ BlumenLumen_CustomUpdate(gs_data UserData, app_state* State, context* Context) } } - if (MotorTimeElapsed > OpenClosePeriod) + if (MotorTimeElapsed > 60) { // NOTE(pjs): MotorTimeElapsed = 0; u8 Position = LastPosition; if (LastPosition == 2) { - LastPosition = ClosedValue; + LastPosition = 1; } else { - LastPosition = OpenValue; + LastPosition = 2; } if ((BLState->OutgoingMsgQueue.WriteHead >= BLState->OutgoingMsgQueue.ReadHead) || @@ -253,6 +259,12 @@ BlumenLumen_CustomUpdate(gs_data UserData, app_state* State, context* Context) } } +US_CUSTOM_CLEANUP(BlumenLumen_CustomCleanup) +{ + blumen_lumen_state* BLState = (blumen_lumen_state*)UserData.Memory; + BLState->Running = false; +} + internal user_space_desc BlumenLumen_UserSpaceCreate() { @@ -260,6 +272,7 @@ BlumenLumen_UserSpaceCreate() Result.LoadPatterns = BlumenLumen_LoadPatterns; Result.CustomInit = BlumenLumen_CustomInit; Result.CustomUpdate = BlumenLumen_CustomUpdate; + Result.CustomCleanup = BlumenLumen_CustomCleanup; return Result; } diff --git a/src/app/blumen_lumen.h b/src/app/blumen_lumen.h index 9e1b166..0ea9db5 100644 --- a/src/app/blumen_lumen.h +++ b/src/app/blumen_lumen.h @@ -35,6 +35,8 @@ typedef struct blumen_network_msg_queue // TODO(pjs): Refactor this -> blumen_network_job_state struct mic_listen_job_data { + bool* Running; + platform_socket_manager* SocketManager; packet_ringbuffer* MicPacketBuffer; platform_socket_handle_ ListenSocket; @@ -44,6 +46,8 @@ struct mic_listen_job_data struct blumen_lumen_state { + bool Running; + packet_ringbuffer MicPacketBuffer; blumen_network_msg_queue OutgoingMsgQueue; diff --git a/src/app/engine/user_space.cpp b/src/app/engine/user_space.cpp index 57ceb1c..752435a 100644 --- a/src/app/engine/user_space.cpp +++ b/src/app/engine/user_space.cpp @@ -32,5 +32,15 @@ US_CustomUpdate(user_space_desc* Desc, app_state* State, context* Context) } } +internal void +US_CustomCleanup(user_space_desc* Desc, app_state* State, context Context) +{ + if (Desc->CustomCleanup) + { + Desc->CustomCleanup(Desc->UserData, State, Context); + } +} + + #define USERSPACE_CPP #endif // USERSPACE_CPP \ No newline at end of file diff --git a/src/app/engine/user_space.h b/src/app/engine/user_space.h index 78b5318..8dc5f8a 100644 --- a/src/app/engine/user_space.h +++ b/src/app/engine/user_space.h @@ -14,11 +14,15 @@ typedef US_CUSTOM_INIT(us_custom_init_proc); #define US_CUSTOM_UPDATE(name) void name(gs_data UserData, app_state* State, context* Context) typedef US_CUSTOM_UPDATE(us_custom_update_proc); +#define US_CUSTOM_CLEANUP(name) void name(gs_data UserData, app_state* State, context Context) +typedef US_CUSTOM_CLEANUP(us_custom_cleanup_proc); + typedef struct user_space_desc { us_load_patterns_proc* LoadPatterns; us_custom_init_proc* CustomInit; us_custom_update_proc* CustomUpdate; + us_custom_cleanup_proc* CustomCleanup; gs_data UserData; } user_space_desc; diff --git a/src/app/foldhaus_app.cpp b/src/app/foldhaus_app.cpp index afb9fe2..fe40c48 100644 --- a/src/app/foldhaus_app.cpp +++ b/src/app/foldhaus_app.cpp @@ -113,6 +113,7 @@ UPDATE_AND_RENDER(UpdateAndRender) CLEANUP_APPLICATION(CleanupApplication) { app_state* State = (app_state*)Context.MemoryBase; + US_CustomCleanup(&State->UserSpaceDesc, State, Context); SACN_Cleanup(&State->SACN, Context); } diff --git a/src/app/platform_win32/win32_foldhaus.cpp b/src/app/platform_win32/win32_foldhaus.cpp index c055de0..96a0a57 100644 --- a/src/app/platform_win32/win32_foldhaus.cpp +++ b/src/app/platform_win32/win32_foldhaus.cpp @@ -497,7 +497,7 @@ WinMain ( *Context.ThreadManager = CreatePlatformThreadManager(Win32CreateThread, Win32KillThread); Context.SocketManager = PushStruct(&PlatformPermanent, platform_socket_manager); - *Context.SocketManager = CreatePlatformSocketManager(Win32CreateSocket, Win32CloseSocket, Win32SocketPeek, Win32SocketReceive, Win32SocketSend); + *Context.SocketManager = CreatePlatformSocketManager(Win32CreateSocket, Win32CloseSocket, Win32SocketQueryStatus, Win32SocketPeek, Win32SocketReceive, Win32SocketSend); win32_dll_refresh DLLRefresh = InitializeDLLHotReloading(DLLName, WorkingDLLName, DLLLockFileName); if (!ReloadAndLinkDLL(&DLLRefresh, &Context, &Win32WorkQueue.WorkQueue, true)) { return -1; } @@ -600,10 +600,10 @@ WinMain ( Context.CleanupApplication(Context); - Win32SocketSystem_Cleanup(); - Win32WorkQueue_Cleanup(); - Win32_TestCode_SocketReading_Cleanup(); + //Win32_TestCode_SocketReading_Cleanup(); + + Win32SocketSystem_Cleanup(); return 0; } diff --git a/src/app/platform_win32/win32_foldhaus_socket.h b/src/app/platform_win32/win32_foldhaus_socket.h index bd5b5cd..cbb4303 100644 --- a/src/app/platform_win32/win32_foldhaus_socket.h +++ b/src/app/platform_win32/win32_foldhaus_socket.h @@ -228,6 +228,14 @@ Win32CloseSocket(platform_socket* Socket) return true; } +internal bool +Win32SocketQueryStatus(platform_socket* Socket) +{ + SOCKET* Win32Sock = (SOCKET*)Socket->PlatformHandle; + bool Result = (*Win32Sock != INVALID_SOCKET); + return Result; +} + internal u32 Win32SocketPeek(platform_socket* Socket) { @@ -246,13 +254,14 @@ Win32SocketPeek(platform_socket* Socket) { // TODO(pjs): Error handling s32 Error = WSAGetLastError(); - if (Error == WSAEWOULDBLOCK) + switch (Error) { - // NOTE(pjs): - } - else - { - InvalidCodePath; + case WSAEWOULDBLOCK: + case WSAENOTCONN: + { + }break; + + InvalidDefaultCase; } } return Result; diff --git a/src/app/platform_win32/win32_foldhaus_work_queue.h b/src/app/platform_win32/win32_foldhaus_work_queue.h index 8fa0311..b3a2a36 100644 --- a/src/app/platform_win32/win32_foldhaus_work_queue.h +++ b/src/app/platform_win32/win32_foldhaus_work_queue.h @@ -236,9 +236,15 @@ Win32WorkQueue_Init(gs_memory_arena* Arena, u32 ThreadCount) internal void Win32WorkQueue_Cleanup() { + u32 Error = 0; for (u32 Thread = 0; Thread < Win32WorkQueue.ThreadCount; Thread++) { - TerminateThread(Win32WorkQueue.Threads[Thread].Handle, 0); + u32 Success = TerminateThread(Win32WorkQueue.Threads[Thread].Handle, 0); + if (!Success) + { + Error = GetLastError(); + InvalidCodePath; + } } } diff --git a/src/gs_libs/gs_types.cpp b/src/gs_libs/gs_types.cpp index f51a16d..814b47c 100644 --- a/src/gs_libs/gs_types.cpp +++ b/src/gs_libs/gs_types.cpp @@ -3359,6 +3359,11 @@ CLOSE_SOCKET(PlatformCloseSocket_Stub) return false; } +SOCKET_QUERY_STATUS(PlatformSocketQueryStatus_Stub) +{ + return false; +} + SOCKET_PEEK(PlatformSocketPeek_Stub) { return 0; @@ -3377,6 +3382,7 @@ SOCKET_SEND(PlatformSocketSend_Stub) internal platform_socket_manager CreatePlatformSocketManager(platform_create_socket* CreateSocketProc, platform_close_socket* CloseSocketProc, + platform_socket_query_status* SocketQueryStatusProc, platform_socket_peek* SocketPeekProc, platform_socket_receive* SocketRecieveProc, platform_socket_send* SocketSendProc) @@ -3384,6 +3390,7 @@ CreatePlatformSocketManager(platform_create_socket* CreateSocketProc, platform_socket_manager Result = {}; Result.CreateSocketProc = CreateSocketProc; Result.CloseSocketProc = CloseSocketProc; + Result.SocketQueryStatusProc = SocketQueryStatusProc; Result.SocketPeekProc = SocketPeekProc; Result.SocketRecieveProc = SocketRecieveProc; Result.SocketSendProc = SocketSendProc; @@ -3396,6 +3403,10 @@ CreatePlatformSocketManager(platform_create_socket* CreateSocketProc, { Result.CloseSocketProc = PlatformCloseSocket_Stub; } + if (!SocketQueryStatusProc) + { + Result.SocketQueryStatusProc = PlatformSocketQueryStatus_Stub; + } if (!SocketPeekProc) { Result.SocketPeekProc = PlatformSocketPeek_Stub; @@ -3464,6 +3475,20 @@ CloseSocket(platform_socket_manager* Manager, platform_socket_handle_ Handle) return Result; } +// NOTE(pjs): returns true if the socket is connected +// TODO(pjs): make this more descriptive? +internal bool +SocketQueryStatus(platform_socket_manager* Manager, platform_socket_handle_ SocketHandle) +{ + bool Result = false; + platform_socket* Socket = SocketManagerGetSocket(Manager, SocketHandle); + if (Socket) + { + Result = Manager->SocketQueryStatusProc(Socket); + } + return Result; +} + internal u32 SocketPeek(platform_socket_manager* Manager, platform_socket_handle_ SocketHandle) { diff --git a/src/gs_libs/gs_types.h b/src/gs_libs/gs_types.h index 04a64fb..ea9091d 100644 --- a/src/gs_libs/gs_types.h +++ b/src/gs_libs/gs_types.h @@ -1104,6 +1104,9 @@ typedef CREATE_SOCKET(platform_create_socket); #define CLOSE_SOCKET(name) bool name(platform_socket* Socket) typedef CLOSE_SOCKET(platform_close_socket); +#define SOCKET_QUERY_STATUS(name) bool name(platform_socket* Socket) +typedef SOCKET_QUERY_STATUS(platform_socket_query_status); + #define SOCKET_PEEK(name) u32 name(platform_socket* Socket) typedef SOCKET_PEEK(platform_socket_peek); @@ -1125,6 +1128,7 @@ typedef struct platform_socket_manager platform_create_socket* CreateSocketProc; platform_close_socket* CloseSocketProc; + platform_socket_query_status* SocketQueryStatusProc; platform_socket_peek* SocketPeekProc; platform_socket_receive* SocketRecieveProc; platform_socket_send* SocketSendProc; From 4deeb2470e386efd966196d93b4b4bfd2a770eeb Mon Sep 17 00:00:00 2001 From: Peter Slattery Date: Sat, 20 Feb 2021 14:14:39 -0800 Subject: [PATCH 39/44] added a brightness slider to the assembly debug panel's all red, green, blue, and white modes. --- .../panels/foldhaus_panel_assembly_debug.h | 69 +++++++++++-------- .../engine/assembly/foldhaus_assembly_debug.h | 12 ++-- src/app/interface.h | 9 +++ 3 files changed, 58 insertions(+), 32 deletions(-) diff --git a/src/app/editor/panels/foldhaus_panel_assembly_debug.h b/src/app/editor/panels/foldhaus_panel_assembly_debug.h index 5bdb699..2f4f1a2 100644 --- a/src/app/editor/panels/foldhaus_panel_assembly_debug.h +++ b/src/app/editor/panels/foldhaus_panel_assembly_debug.h @@ -59,39 +59,52 @@ AssemblyDebug_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Ren ui_EndLabeledDropdown(Interface); InterfaceAssert(Interface->PerFrameMemory); - if (State->AssemblyDebugState.Override == ADS_Override_TagWhite || - State->AssemblyDebugState.Override == ADS_Override_TagStripWhite) + switch (State->AssemblyDebugState.Override) { - ui_LabeledTextEntry(Interface, MakeString("Tag Name"), &State->AssemblyDebugState.TagName); - ui_LabeledTextEntry(Interface, MakeString("Tag Value"), &State->AssemblyDebugState.TagValue); - - if (State->AssemblyDebugState.Override == ADS_Override_TagStripWhite) + case ADS_Override_TagWhite: + case ADS_Override_TagStripWhite: { + ui_LabeledTextEntry(Interface, MakeString("Tag Name"), &State->AssemblyDebugState.TagName); + ui_LabeledTextEntry(Interface, MakeString("Tag Value"), &State->AssemblyDebugState.TagValue); + + if (State->AssemblyDebugState.Override == ADS_Override_TagStripWhite) + { + State->AssemblyDebugState.TargetAssembly = ui_LabeledTextEntryU64(Interface, MakeString("Assembly"), State->AssemblyDebugState.TargetAssembly); + + State->AssemblyDebugState.TargetStrip = ui_LabeledTextEntryU64(Interface, MakeString("Strip"), State->AssemblyDebugState.TargetStrip); + } + }break; + + case ADS_Override_ChannelWhite: + { + u64 Board = 0; + u64 Strip = 0; + Board = ui_LabeledTextEntryU64(Interface, MakeString("Board"), Board); + Strip = ui_LabeledTextEntryU64(Interface, MakeString("Strip"), Strip); + + State->AssemblyDebugState.TargetChannel = FSC(Board, Strip); + }break; + + case ADS_Override_AllRed: + case ADS_Override_AllGreen: + case ADS_Override_AllBlue: + case ADS_Override_AllWhite: + { + State->AssemblyDebugState.Brightness = (u8)ui_LabeledRangeSlider(Interface, MakeString("Brightness"), (r32)State->AssemblyDebugState.Brightness, 0, 255); + }break; + + default: + { + InterfaceAssert(Interface->PerFrameMemory); + State->AssemblyDebugState.TargetAssembly = ui_LabeledTextEntryU64(Interface, MakeString("Assembly"), State->AssemblyDebugState.TargetAssembly); + InterfaceAssert(Interface->PerFrameMemory); + State->AssemblyDebugState.TargetStrip = ui_LabeledTextEntryU64(Interface, MakeString("Strip"), State->AssemblyDebugState.TargetStrip); - } - } - else if (State->AssemblyDebugState.Override == ADS_Override_ChannelWhite) - { - u64 Board = 0; - u64 Strip = 0; - Board = ui_LabeledTextEntryU64(Interface, MakeString("Board"), Board); - Strip = ui_LabeledTextEntryU64(Interface, MakeString("Strip"), Strip); - - State->AssemblyDebugState.TargetChannel = FSC(Board, Strip); - } - else - { - InterfaceAssert(Interface->PerFrameMemory); - - State->AssemblyDebugState.TargetAssembly = ui_LabeledTextEntryU64(Interface, MakeString("Assembly"), State->AssemblyDebugState.TargetAssembly); - - InterfaceAssert(Interface->PerFrameMemory); - - State->AssemblyDebugState.TargetStrip = ui_LabeledTextEntryU64(Interface, MakeString("Strip"), State->AssemblyDebugState.TargetStrip); - - InterfaceAssert(Interface->PerFrameMemory); + + InterfaceAssert(Interface->PerFrameMemory); + }break; } ui_RangeSlider(Interface, MakeString("Test"), .5f, 0, 1); diff --git a/src/app/engine/assembly/foldhaus_assembly_debug.h b/src/app/engine/assembly/foldhaus_assembly_debug.h index 9a1cc12..07a3685 100644 --- a/src/app/engine/assembly/foldhaus_assembly_debug.h +++ b/src/app/engine/assembly/foldhaus_assembly_debug.h @@ -51,6 +51,8 @@ struct assembly_debug_state pixel TargetColor; u32 TargetChannel; + + u8 Brightness; }; internal assembly_debug_state @@ -107,6 +109,8 @@ AssemblyDebug_OverrideOutput(assembly_debug_state State, assembly_array Assembli assembly Assembly = Assemblies.Values[State.TargetAssembly]; led_buffer LedBuffer = LedSystem.Buffers[Assembly.LedBufferIndex]; + u8 V = State.Brightness; + switch (State.Override) { case ADS_Override_Strip: @@ -133,17 +137,17 @@ AssemblyDebug_OverrideOutput(assembly_debug_state State, assembly_array Assembli case ADS_Override_AllRed: { - AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{255, 0, 0}); + AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{V, 0, 0}); }break; case ADS_Override_AllGreen: { - AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{0, 255, 0}); + AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{0, V, 0}); }break; case ADS_Override_AllBlue: { - AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{0, 0, 255}); + AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{0, 0, V}); }break; case ADS_Override_AllOff: @@ -153,7 +157,7 @@ AssemblyDebug_OverrideOutput(assembly_debug_state State, assembly_array Assembli case ADS_Override_AllWhite: { - AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{255, 255, 255}); + AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{V, V, V}); }break; case ADS_Override_TagWhite: diff --git a/src/app/interface.h b/src/app/interface.h index 60c640a..f0942a7 100644 --- a/src/app/interface.h +++ b/src/app/interface.h @@ -1564,6 +1564,15 @@ ui_LabeledToggle(ui_interface* Interface, gs_string Label, bool Value) return Result; } +internal r32 +ui_LabeledRangeSlider(ui_interface* Interface, gs_string Label, r32 Value, r32 ValueMin, r32 ValueMax) +{ + ui_BeginLabelRow(Interface, Label); + r32 Result = ui_RangeSlider(Interface, Label, Value, ValueMin, ValueMax); + ui_EndRow(Interface); + return Result; +} + internal void ui_LabeledTextEntry(ui_interface* Interface, gs_string Label, gs_string* Value) { From 0807abc08eab5a7ad3d29c8200286c59019f1aa3 Mon Sep 17 00:00:00 2001 From: Peter Slattery Date: Sat, 20 Feb 2021 14:32:43 -0800 Subject: [PATCH 40/44] created default view for lumenarium --- src/app/editor/panels/foldhaus_panel_types.h | 1 - src/app/foldhaus_app.cpp | 22 +++++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/app/editor/panels/foldhaus_panel_types.h b/src/app/editor/panels/foldhaus_panel_types.h index 85c93ed..9177cdd 100644 --- a/src/app/editor/panels/foldhaus_panel_types.h +++ b/src/app/editor/panels/foldhaus_panel_types.h @@ -10,7 +10,6 @@ enum panel_type { PanelType_AnimationTimeline, PanelType_DMXView, PanelType_HierarchyView, - PanelType_NodeGraph, PanelType_ProfilerView, PanelType_AssemblyDebug, }; diff --git a/src/app/foldhaus_app.cpp b/src/app/foldhaus_app.cpp index fe40c48..a1537ea 100644 --- a/src/app/foldhaus_app.cpp +++ b/src/app/foldhaus_app.cpp @@ -61,7 +61,27 @@ INITIALIZE_APPLICATION(InitializeApplication) GlobalDebugServices->Interface.RenderSculpture = true; PanelSystem_Init(&State->PanelSystem, GlobalPanelDefs, GlobalPanelDefsCount, &State->Permanent); - PanelSystem_PushPanel(&State->PanelSystem, PanelType_SculptureView, State, Context); + { + panel* RootPanel = PanelSystem_PushPanel(&State->PanelSystem, PanelType_SculptureView, State, Context); + SplitPanel(RootPanel, .25f, PanelSplit_Horizontal, &State->PanelSystem, State, Context); + + panel* AnimPanel = RootPanel->Bottom; + Panel_SetType(AnimPanel, &State->PanelSystem, PanelType_AnimationTimeline, State, Context); + + panel* TopPanel = RootPanel->Top; + SplitPanel(TopPanel, .5f, PanelSplit_Vertical, &State->PanelSystem, State, Context); + + panel* LeftPanel = TopPanel->Left; + SplitPanel(LeftPanel, .5f, PanelSplit_Vertical, &State->PanelSystem, State, Context); + + panel* Profiler = LeftPanel->Right; + Panel_SetType(Profiler, &State->PanelSystem, PanelType_ProfilerView, State, Context); + + panel* Hierarchy = LeftPanel->Left; + Panel_SetType(Hierarchy, &State->PanelSystem, PanelType_HierarchyView, State, Context); + + } + State->Modes = OperationModeSystemInit(&State->Permanent, Context.ThreadContext); State->UserSpaceDesc = BlumenLumen_UserSpaceCreate(); From b470a63ec5c16b113d430dd4c7b6fd7adc372257 Mon Sep 17 00:00:00 2001 From: Peter Slattery Date: Sat, 20 Feb 2021 18:21:52 -0800 Subject: [PATCH 41/44] Now have thread safe plugging / unplugging of USBs / serial ports --- src/app/blumen_lumen.cpp | 2 +- src/app/engine/uart/foldhaus_uart.cpp | 5 -- src/app/foldhaus_app.cpp | 1 + src/app/platform_win32/win32_foldhaus.cpp | 8 ++- .../platform_win32/win32_foldhaus_serial.h | 65 ++++++++++++++++--- .../platform_win32/win32_foldhaus_socket.h | 27 ++++---- src/gs_libs/gs_types.cpp | 58 +++++++++++------ src/gs_libs/gs_types.h | 11 ++-- 8 files changed, 121 insertions(+), 56 deletions(-) diff --git a/src/app/blumen_lumen.cpp b/src/app/blumen_lumen.cpp index f58e410..323b8ae 100644 --- a/src/app/blumen_lumen.cpp +++ b/src/app/blumen_lumen.cpp @@ -123,7 +123,7 @@ BlumenLumen_CustomInit(app_state* State, context Context) BLState->MicListenJobData.OutgoingMsgQueue = &BLState->OutgoingMsgQueue; BLState->MicListenJobData.ListenSocket = CreateSocket(Context.SocketManager, "127.0.0.1", "20185"); - BLState->MicListenThread = CreateThread(Context.ThreadManager, BlumenLumen_MicListenJob, (u8*)&BLState->MicListenJobData); + //BLState->MicListenThread = CreateThread(Context.ThreadManager, BlumenLumen_MicListenJob, (u8*)&BLState->MicListenJobData); gs_const_string SculpturePath = ConstString("data/test_blumen.fold"); LoadAssembly(&State->Assemblies, &State->LedSystem, State->Transient, Context, SculpturePath, State->GlobalLog); diff --git a/src/app/engine/uart/foldhaus_uart.cpp b/src/app/engine/uart/foldhaus_uart.cpp index 94cded0..f18360f 100644 --- a/src/app/engine/uart/foldhaus_uart.cpp +++ b/src/app/engine/uart/foldhaus_uart.cpp @@ -130,11 +130,6 @@ UART_BuildOutputData(addressed_data_buffer_list* Output, assembly_array Assembli SLLPushOrInit(BuffersNeededHead, BuffersNeededTail, BufferSelected); BuffersNeededCount += 1; - - gs_string Temp = PushStringF(Transient, 256, "Found Com Port: %S\n\tStrip: %d\n", StripAt.UARTAddr.ComPort.ConstString, - StripIdx); - NullTerminate(&Temp); - OutputDebugString(Temp.Str); } Assert(BufferSelected->StripIndicesCount < BufferSelected->StripIndicesCountMax); diff --git a/src/app/foldhaus_app.cpp b/src/app/foldhaus_app.cpp index a1537ea..47590c0 100644 --- a/src/app/foldhaus_app.cpp +++ b/src/app/foldhaus_app.cpp @@ -56,6 +56,7 @@ INITIALIZE_APPLICATION(InitializeApplication) State->LedSystem = LedSystem_Create(Context.ThreadContext.Allocator, 128); State->AssemblyDebugState = AssemblyDebug_Create(&State->Permanent); + State->AssemblyDebugState.Brightness = 255; State->AssemblyDebugState.Override = ADS_Override_AllRed; GlobalDebugServices->Interface.RenderSculpture = true; diff --git a/src/app/platform_win32/win32_foldhaus.cpp b/src/app/platform_win32/win32_foldhaus.cpp index 96a0a57..c9208dc 100644 --- a/src/app/platform_win32/win32_foldhaus.cpp +++ b/src/app/platform_win32/win32_foldhaus.cpp @@ -404,6 +404,10 @@ Win32_SendAddressedDataBuffer(gs_thread_context Context, addressed_data_buffer* BuffersSent += 1; DataSizeSent += BufferAt->Data.Size; } + else + { + Win32SerialArray_Close(BufferAt->ComPort); + } } } else @@ -497,7 +501,7 @@ WinMain ( *Context.ThreadManager = CreatePlatformThreadManager(Win32CreateThread, Win32KillThread); Context.SocketManager = PushStruct(&PlatformPermanent, platform_socket_manager); - *Context.SocketManager = CreatePlatformSocketManager(Win32CreateSocket, Win32CloseSocket, Win32SocketQueryStatus, Win32SocketPeek, Win32SocketReceive, Win32SocketSend); + *Context.SocketManager = CreatePlatformSocketManager(Win32ConnectSocket, Win32CloseSocket, Win32SocketQueryStatus, Win32SocketPeek, Win32SocketReceive, Win32SocketSend); win32_dll_refresh DLLRefresh = InitializeDLLHotReloading(DLLName, WorkingDLLName, DLLLockFileName); if (!ReloadAndLinkDLL(&DLLRefresh, &Context, &Win32WorkQueue.WorkQueue, true)) { return -1; } @@ -546,7 +550,7 @@ WinMain ( Context.UpdateAndRender(&Context, InputQueue, &RenderBuffer, &OutputData); - bool Multithread = true; + bool Multithread = false; if (Multithread) { for (addressed_data_buffer* At = OutputData.Root; diff --git a/src/app/platform_win32/win32_foldhaus_serial.h b/src/app/platform_win32/win32_foldhaus_serial.h index 0368547..71b4c99 100644 --- a/src/app/platform_win32/win32_foldhaus_serial.h +++ b/src/app/platform_win32/win32_foldhaus_serial.h @@ -6,9 +6,9 @@ #ifndef WIN32_SERIAL_H global u32 Win32SerialHandlesCountMax; -global u32 Win32SerialHandlesCount; global HANDLE* Win32SerialHandles; global gs_string* Win32SerialPortNames; +global s32* Win32SerialPortFilled; DCB Win32SerialPort_GetState(HANDLE ComPortHandle) @@ -137,7 +137,18 @@ Win32SerialPort_Write(HANDLE PortHandle, gs_data Buffer) { OutputDebugStringA("Error: Unable to write to port\n"); s32 Error = GetLastError(); - //InvalidCodePath; + switch (Error) + { + case ERROR_OPERATION_ABORTED: + case ERROR_GEN_FAILURE: + { + // NOTE(pjs): Probably means that the serial port became invalid + // ie. the usb stick was removed + }break; + + case ERROR_INVALID_HANDLE: + InvalidDefaultCase; + } } return Success; @@ -183,12 +194,15 @@ Win32SerialArray_Create(gs_thread_context Context) DEBUG_TRACK_FUNCTION; Win32SerialHandlesCountMax = 32; - Win32SerialHandlesCount = 0; + Win32SerialHandles = AllocatorAllocArray(Context.Allocator, HANDLE, Win32SerialHandlesCountMax); Win32SerialPortNames = AllocatorAllocArray(Context.Allocator, gs_string, Win32SerialHandlesCountMax); + Win32SerialPortFilled = AllocatorAllocArray(Context.Allocator, s32, Win32SerialHandlesCountMax); + for (u32 i = 0; i < Win32SerialHandlesCountMax; i++) { Win32SerialPortNames[i] = AllocatorAllocString(Context.Allocator, 256); + Win32SerialPortFilled[i] = 0; } } @@ -197,10 +211,28 @@ Win32SerialArray_Push(HANDLE SerialHandle, gs_const_string PortName) { DEBUG_TRACK_FUNCTION; - Assert(Win32SerialHandlesCount < Win32SerialHandlesCountMax); - u32 Index = Win32SerialHandlesCount++; - Win32SerialHandles[Index] = SerialHandle; - PrintF(&Win32SerialPortNames[Index], "%S", PortName); + bool Found = false; + for (u32 i = 0; i < Win32SerialHandlesCountMax; i++) + { + bool WasFilled = InterlockedCompareExchange((LONG volatile*)Win32SerialPortFilled + i, 1, 0); + if (!WasFilled) + { + Win32SerialHandles[i] = SerialHandle; + PrintF(&Win32SerialPortNames[i], "%S", PortName); + Found = true; + break; + } + } + Assert(Found); +} + +void +Win32SerialArray_Pop(u32 Index) +{ + bool WasFilled = InterlockedCompareExchange((LONG volatile*)Win32SerialPortFilled + Index, 0, 1); + Assert(WasFilled); + Win32SerialPortFilled[Index] = false; + Win32SerialHandles[Index] = INVALID_HANDLE_VALUE; } HANDLE @@ -209,9 +241,10 @@ Win32SerialArray_Get(gs_const_string PortName) DEBUG_TRACK_FUNCTION; HANDLE PortHandle = INVALID_HANDLE_VALUE; - for (u32 i = 0; i < Win32SerialHandlesCount; i++) + for (u32 i = 0; i < Win32SerialHandlesCountMax; i++) { - if (StringsEqual(Win32SerialPortNames[i].ConstString, PortName)) + if (Win32SerialPortFilled[i] && + StringsEqual(Win32SerialPortNames[i].ConstString, PortName)) { PortHandle = Win32SerialHandles[i]; break; @@ -239,5 +272,19 @@ Win32SerialArray_GetOrOpen(gs_const_string PortName, u32 BaudRate, u8 ByteSize, return PortHandle; } +void +Win32SerialArray_Close(gs_const_string PortName) +{ + for (u32 i = 0; i < Win32SerialHandlesCountMax; i++) + { + if (Win32SerialPortFilled[i] && StringsEqual(Win32SerialPortNames[i].ConstString, PortName)) + { + Win32SerialPort_Close(Win32SerialHandles[i]); + Win32SerialArray_Pop(i); + break; + } + } +} + #define WIN32_SERIAL_H #endif // WIN32_SERIAL_H \ No newline at end of file diff --git a/src/app/platform_win32/win32_foldhaus_socket.h b/src/app/platform_win32/win32_foldhaus_socket.h index cbb4303..b42c8c9 100644 --- a/src/app/platform_win32/win32_foldhaus_socket.h +++ b/src/app/platform_win32/win32_foldhaus_socket.h @@ -132,7 +132,7 @@ Win32Socket_ConnectToAddress(char* Address, char* DefaultPort) } internal bool -Win32CreateSocket(platform_socket* Socket, char* Address, char* DefaultPort) +Win32ConnectSocket(platform_socket* Socket) { bool Result = false; @@ -142,7 +142,7 @@ Win32CreateSocket(platform_socket* Socket, char* Address, char* DefaultPort) Hints.ai_protocol = IPPROTO_TCP; addrinfo* PotentialConnections; - s32 Error = getaddrinfo(Address, DefaultPort, &Hints, &PotentialConnections); + s32 Error = getaddrinfo(Socket->Addr, Socket->Port, &Hints, &PotentialConnections); if (Error == 0) { for (addrinfo* InfoAt = PotentialConnections; InfoAt != NULL; InfoAt = InfoAt->ai_next) @@ -175,7 +175,7 @@ Win32CreateSocket(platform_socket* Socket, char* Address, char* DefaultPort) FD_ZERO(&SocketSet); FD_SET(SocketHandle, &SocketSet); Assert(FD_ISSET(SocketHandle, &SocketSet)); - Status = select(0, &SocketSet, 0, 0, {}); + Status = select(0, &SocketSet, 0, 0, (const TIMEVAL*)&Timeout); if (Status == SOCKET_ERROR) { @@ -196,7 +196,6 @@ Win32CreateSocket(platform_socket* Socket, char* Address, char* DefaultPort) } } - Socket->PlatformHandle = (u8*)Win32Alloc(sizeof(SOCKET), 0); *(SOCKET*)Socket->PlatformHandle = SocketHandle; Result = true; @@ -429,17 +428,17 @@ Win32Socket_Receive(win32_socket* Socket, gs_memory_arena* Storage) { // TODO(pjs): Error logging s32 Error = WSAGetLastError(); - if (Error == 10053) + switch (Error) { - // WSAECONNABORTED - aborted by the software - } - else if (Error == 10093) - { - // WSANOTINITIALISED - } - else - { - InvalidCodePath; + case WSAECONNABORTED: + case WSANOTINITIALISED: + break; + + case WSAENOTCONN: + { + + }break; + InvalidDefaultCase; } } Result.Size = BytesReceived; diff --git a/src/gs_libs/gs_types.cpp b/src/gs_libs/gs_types.cpp index 814b47c..611d868 100644 --- a/src/gs_libs/gs_types.cpp +++ b/src/gs_libs/gs_types.cpp @@ -3349,7 +3349,7 @@ KillThread(platform_thread_manager* Manager, platform_thread_handle Handle) // // Socket Manager -CREATE_SOCKET(PlatformCreateSocket_Stub) +CONNECT_SOCKET(PlatformConnectSocket_Stub) { return false; } @@ -3380,7 +3380,7 @@ SOCKET_SEND(PlatformSocketSend_Stub) } internal platform_socket_manager -CreatePlatformSocketManager(platform_create_socket* CreateSocketProc, +CreatePlatformSocketManager(platform_connect_socket* ConnectSocketProc, platform_close_socket* CloseSocketProc, platform_socket_query_status* SocketQueryStatusProc, platform_socket_peek* SocketPeekProc, @@ -3388,16 +3388,16 @@ CreatePlatformSocketManager(platform_create_socket* CreateSocketProc, platform_socket_send* SocketSendProc) { platform_socket_manager Result = {}; - Result.CreateSocketProc = CreateSocketProc; + Result.ConnectSocketProc = ConnectSocketProc; Result.CloseSocketProc = CloseSocketProc; Result.SocketQueryStatusProc = SocketQueryStatusProc; Result.SocketPeekProc = SocketPeekProc; Result.SocketRecieveProc = SocketRecieveProc; Result.SocketSendProc = SocketSendProc; - if (!CreateSocketProc) + if (!ConnectSocketProc) { - Result.CreateSocketProc = PlatformCreateSocket_Stub; + Result.ConnectSocketProc = PlatformConnectSocket_Stub; } if (!CloseSocketProc) { @@ -3422,6 +3422,33 @@ CreatePlatformSocketManager(platform_create_socket* CreateSocketProc, return Result; } +internal platform_socket* +SocketManagerGetSocket(platform_socket_manager* Manager, platform_socket_handle_ Handle) +{ + platform_socket* Result = 0; + if (Manager->SocketsUsed[Handle.Index]) + { + platform_socket* Socket = &Manager->Sockets[Handle.Index]; + if (Socket->PlatformHandle != 0) + { + Result = Socket; + } + } + return Result; +} + +internal bool +ConnectSocket(platform_socket_manager* Manager, platform_socket_handle_ Handle) +{ + bool Result = false; + platform_socket* Socket = SocketManagerGetSocket(Manager, Handle); + if (Socket) + { + Result = Manager->ConnectSocketProc(Socket); + } + return Result; +} + internal platform_socket_handle_ CreateSocket(platform_socket_manager* Manager, char* Addr, char* Port) { @@ -3438,23 +3465,12 @@ CreateSocket(platform_socket_manager* Manager, char* Addr, char* Port) Assert(Result.Index != 0); platform_socket* Socket = &Manager->Sockets[Result.Index]; - Manager->CreateSocketProc(Socket, Addr, Port); + CopyArray(Addr, Socket->Addr, char, CStringLength(Addr) + 1); + CopyArray(Port, Socket->Port, char, CStringLength(Port) + 1); + + bool Success = Manager->ConnectSocketProc(Socket); + Assert(Success); - return Result; -} - -internal platform_socket* -SocketManagerGetSocket(platform_socket_manager* Manager, platform_socket_handle_ Handle) -{ - platform_socket* Result = 0; - if (Manager->SocketsUsed[Handle.Index]) - { - platform_socket* Socket = &Manager->Sockets[Handle.Index]; - if (Socket->PlatformHandle != 0) - { - Result = Socket; - } - } return Result; } diff --git a/src/gs_libs/gs_types.h b/src/gs_libs/gs_types.h index ea9091d..e6ab857 100644 --- a/src/gs_libs/gs_types.h +++ b/src/gs_libs/gs_types.h @@ -575,7 +575,8 @@ CStringLength(char* Str) { char* At = Str; while (*At) { At++; } - return PointerDifference(At, Str); + u64 Result = PointerDifference(At, Str); + return Result; } #define StringExpand(str) (int)(str).Length, (str).Str @@ -1095,11 +1096,13 @@ typedef struct platform_socket_handle_ typedef struct platform_socket { + char Addr[128]; + char Port[32]; u8* PlatformHandle; } platform_socket; -#define CREATE_SOCKET(name) bool name(platform_socket* Socket, char* Addr, char* DefaultPort) -typedef CREATE_SOCKET(platform_create_socket); +#define CONNECT_SOCKET(name) bool name(platform_socket* Socket) +typedef CONNECT_SOCKET(platform_connect_socket); #define CLOSE_SOCKET(name) bool name(platform_socket* Socket) typedef CLOSE_SOCKET(platform_close_socket); @@ -1126,7 +1129,7 @@ typedef struct platform_socket_manager b8 SocketsUsed[SOCKETS_COUNT_MAX]; platform_socket Sockets[SOCKETS_COUNT_MAX]; - platform_create_socket* CreateSocketProc; + platform_connect_socket* ConnectSocketProc; platform_close_socket* CloseSocketProc; platform_socket_query_status* SocketQueryStatusProc; platform_socket_peek* SocketPeekProc; From 4765301c2293d8696c372c6a6004d28dbc55695a Mon Sep 17 00:00:00 2001 From: PS Date: Sun, 28 Feb 2021 14:35:14 -0800 Subject: [PATCH 42/44] Fixed gen_blumen_lumen to output sculpture spec again, and updated readme. --- README.md | 19 +++++++++++-------- src/sculpture_gen/gen_blumen_lumen.cpp | 4 ++-- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 2350f97..8628bfb 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,13 @@ ![Lumenarium Banner](./docs/images/splash.png) ## Build Lumenarium -Building Lumenarium requires having MSVC installed (sorry, Windows only for now!). At the moment, there are bunch of errors from the meta program but the program will still compile -1. Run build_meta.bat -2. Run build.bat -3. Launch win32_foldhaus.exe (locaated in the build folder) +Building Lumenarium requires having MSVC installed (sorry, Windows only for now!). +1. clone the repo onto your computer +2. Run the appropriate build batch file + - for Windows: use `build\build_app_msvc_win32_debug.bat` + - other platforms coming soon +3. `cd /app_run_tree` +4. `win32_msvc\debug\win32_foldhaus.exe` ## What Is Lumenarium? Lumenarium is our custom build light and motion control software. It allows us to design light and motion patterns for our sculptures, visualize the output long before the sculpture is built, and iterate in real time to achieve the best visual results quickly. @@ -26,7 +29,7 @@ The following features are under active development for integration in Lumenariu *** ### Sculpture File Format -Sculptures are specified via a structured text file so that it is easy to represent new sculptures, simply as strips of LEDs. +Sculptures are specified via a structured text file so that it is easy to represent new sculptures, simply as strips of LEDs. Documentation coming soon. @@ -36,13 +39,13 @@ Lumenarium supports SACN output, and ArtNet is in development, via a DMX system *** ### Live Visualization -We don't always have access to our physical sculptures while working on the lights and motion for them. Having a visualization of the sculpture lets us see what the patterns we develop will look like when running on the actual sculpture. +We don't always have access to our physical sculptures while working on the lights and motion for them. Having a visualization of the sculpture lets us see what the patterns we develop will look like when running on the actual sculpture. The visualization runs in real time, and mirrors the DMX output the sculptures will receive, so any changes made in the software are immediately reflected, both in the visualization and in the data sent over the network. *** ### Animation Timeline -One goal of Lumenarium is to enable fine-grained control over procedural light and motion patterns. Patterns can be arranged on a timeline for manual sequencing. +One goal of Lumenarium is to enable fine-grained control over procedural light and motion patterns. Patterns can be arranged on a timeline for manual sequencing. Coming Soon * Pattern Fading/Cross fading @@ -58,6 +61,6 @@ Coming Soon *** ### Live Compilation Reload -One of the most fulfilling parts of working on these sculptures is getting to iterate live on the lights and motion in front of the physical sculpture while on active display. While Lumenarium is designed to enable everyone to shape the visual identity of our sculptures, it also allows for low-level, fine grained control over the visual output as well. The software is split into a platform layer (currently Windows only, though there are plans to support Mac, and possibly Raspberry Pi), and an application library. The application library can be recompiled and hot loaded while the software is running to facilitate the fastest possible iteration time. +One of the most fulfilling parts of working on these sculptures is getting to iterate live on the lights and motion in front of the physical sculpture while on active display. While Lumenarium is designed to enable everyone to shape the visual identity of our sculptures, it also allows for low-level, fine grained control over the visual output as well. The software is split into a platform layer (currently Windows only, though there are plans to support Mac, and possibly Raspberry Pi), and an application library. The application library can be recompiled and hot loaded while the software is running to facilitate the fastest possible iteration time. To see how this works in detail see [Handmade Hero](https://guide.handmadehero.org/code/day022/) diff --git a/src/sculpture_gen/gen_blumen_lumen.cpp b/src/sculpture_gen/gen_blumen_lumen.cpp index 126ef52..dce5c4a 100644 --- a/src/sculpture_gen/gen_blumen_lumen.cpp +++ b/src/sculpture_gen/gen_blumen_lumen.cpp @@ -216,8 +216,8 @@ int main(int ArgCount, char** Args) F2.BloomOuterChannels = BloomOuterChannels; StripCount += BuildFlower(&OutputBuffer, F2); - //printf("%.*s\n", (u32)OutputBuffer.Length, OutputBuffer.Str); - printf("%d\n", StripCount); + printf("%.*s\n", (u32)OutputBuffer.Length, OutputBuffer.Str); + //printf("%d\n", StripCount); return 0; } From c7eb56724f4a0f33f621acccc58975cee44404f5 Mon Sep 17 00:00:00 2001 From: PS Date: Sun, 28 Feb 2021 15:18:39 -0800 Subject: [PATCH 43/44] implemented setting the working directory by finding a data folder in an ancestor directory of the exe files path --- src/app/platform_win32/win32_foldhaus.cpp | 79 +++++++++++++++++++ .../platform_win32/win32_foldhaus_fileio.h | 3 +- src/gs_libs/gs_types.cpp | 6 +- 3 files changed, 84 insertions(+), 4 deletions(-) diff --git a/src/app/platform_win32/win32_foldhaus.cpp b/src/app/platform_win32/win32_foldhaus.cpp index c9208dc..df968c8 100644 --- a/src/app/platform_win32/win32_foldhaus.cpp +++ b/src/app/platform_win32/win32_foldhaus.cpp @@ -446,6 +446,83 @@ ReloadAndLinkDLL(win32_dll_refresh* DLL, context* Context, gs_work_queue* WorkQu return Success; } +internal gs_const_string +GetExePath(HINSTANCE HInstance, gs_thread_context ThreadContext) +{ + gs_const_string Result = {}; + + u32 Error = 0; + u32 PathSize = MAX_PATH; + char* Path = PushArray(ThreadContext.Transient, char, PathSize); + DWORD Length = GetModuleFileNameA(HInstance, Path, PathSize); + + if (Length) + { + Error = GetLastError(); + if (Error == ERROR_INSUFFICIENT_BUFFER) { + // PathSize wasn't long enough + // TODO(pjs): handle this case + InvalidCodePath; + } + + Result.Str = Path; + Result.Length = (u64)Length; + } + else + { + Error = GetLastError(); + InvalidCodePath; + } + + return Result; +} + +internal bool +SetWorkingDirectory(HINSTANCE HInstance, gs_thread_context ThreadContext) +{ + bool Result = false; + + gs_const_string ExePath = GetExePath(HInstance, ThreadContext); + gs_string ScratchPath = PushString(ThreadContext.Transient, ExePath.Length + 128); + gs_string WorkingDirectory = PushString(ThreadContext.Transient, ExePath.Length + 128); + + while (WorkingDirectory.Length == 0) + { + s64 LastSlash = FindLastFromSet(ExePath, "\\/"); + if (LastSlash < 0) break; + + ExePath = Substring(ExePath, 0, LastSlash); + PrintF(&ScratchPath, "%S\\data", ExePath); + NullTerminate(&ScratchPath); + + gs_file_info PathInfo = GetFileInfo(ThreadContext.FileHandler, ScratchPath.ConstString); + if (PathInfo.Path.Length > 0 && + PathInfo.IsDirectory) { + PrintF(&WorkingDirectory, "%S", ExePath); + NullTerminate(&WorkingDirectory); + } + } + + if (WorkingDirectory.Length > 0) + { + OutputDebugStringA("Setting Working Directory\n"); + OutputDebugStringA(WorkingDirectory.Str); + + Result = SetCurrentDirectory(WorkingDirectory.Str); + if (!Result) + { + u32 Error = GetLastError(); + InvalidCodePath; + } + } + else + { + OutputDebugStringA("Error, no data folder found\n"); + } + + return Result; +} + int WINAPI WinMain ( HINSTANCE HInstance, @@ -456,6 +533,8 @@ WinMain ( { gs_thread_context ThreadContext = Win32CreateThreadContext(); + if (!SetWorkingDirectory(HInstance, ThreadContext)) return 1; + MainWindow = Win32CreateWindow (HInstance, "Foldhaus", 1440, 768, HandleWindowEvents); Win32UpdateWindowDimension(&MainWindow); diff --git a/src/app/platform_win32/win32_foldhaus_fileio.h b/src/app/platform_win32/win32_foldhaus_fileio.h index bfb93ac..95163ea 100644 --- a/src/app/platform_win32/win32_foldhaus_fileio.h +++ b/src/app/platform_win32/win32_foldhaus_fileio.h @@ -197,7 +197,8 @@ Win32EnumerateDirectoryIntoTempList(gs_file_handler FileHandler, temp_file_list* { u32 FilesCount = 0; - u32 IndexOfLastSlash = FindLastFromSet(Path, "\\/"); + s64 IndexOfLastSlash = FindLastFromSet(Path, "\\/"); + Assert(IndexOfLastSlash >= 0); gs_const_string SearchPath = Substring(Path, 0, IndexOfLastSlash + 1); WIN32_FIND_DATA FindFileData; diff --git a/src/gs_libs/gs_types.cpp b/src/gs_libs/gs_types.cpp index 611d868..197c270 100644 --- a/src/gs_libs/gs_types.cpp +++ b/src/gs_libs/gs_types.cpp @@ -1573,12 +1573,12 @@ FindFirstFromSet(gs_const_string String, char* SetArray) return Result; } -internal u64 +internal s64 FindLastFromSet(gs_const_string String, char* SetArray) { gs_const_string Set = ConstString(SetArray); - u64 Result = String.Length - 1; - for(s64 At = Result; At >= 0; At--) + s64 Result = -1; + for(s64 At = String.Length - 1; At >= 0; At--) { char CharAt = String.Str[At]; for (u64 SetAt = 0; SetAt < Set.Length; SetAt++) From b9dc967ad985bef8a8b7bf4c234f9f40f560b1bc Mon Sep 17 00:00:00 2001 From: PS Date: Sun, 28 Feb 2021 15:35:57 -0800 Subject: [PATCH 44/44] Readme updated with running and building instructions --- README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8628bfb..ddbba99 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,14 @@ Building Lumenarium requires having MSVC installed (sorry, Windows only for now! 2. Run the appropriate build batch file - for Windows: use `build\build_app_msvc_win32_debug.bat` - other platforms coming soon -3. `cd /app_run_tree` -4. `win32_msvc\debug\win32_foldhaus.exe` + +## Run Lumenarium +Windows - Debug +1. Just run `win32_msvc\debug\win32_foldhaus.exe` + +## Debug Lumenarium +###Windows +Building in debug mode outputs pdb file info that can be read by Visual Studio or RemedyBG (preferred debugging solution, but ymmv). You can just open the exe in either application and it'll find the pdb file in the same directory ## What Is Lumenarium? Lumenarium is our custom build light and motion control software. It allows us to design light and motion patterns for our sculptures, visualize the output long before the sculpture is built, and iterate in real time to achieve the best visual results quickly.