From 71547b05dcbe96e087489ce19c88745ea44df528 Mon Sep 17 00:00:00 2001 From: PS Date: Sun, 10 Jan 2021 16:25:35 -0800 Subject: [PATCH] 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