diff --git a/build/build_app_msvc_win32_debug.bat b/build/build_app_msvc_win32_debug.bat index 663ae28..eec2df0 100644 --- a/build/build_app_msvc_win32_debug.bat +++ b/build/build_app_msvc_win32_debug.bat @@ -25,12 +25,12 @@ 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 +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 Winspool.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\serial_monitor\first.cpp /Feserial_monitor.exe /link %CommonLinkerFlags% user32.lib winmm.lib gdi32.lib Winspool.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/src/app/editor/interface.h b/src/app/editor/interface.h index 6b91bef..4b4d13e 100644 --- a/src/app/editor/interface.h +++ b/src/app/editor/interface.h @@ -752,6 +752,17 @@ ui_PushOverlayLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction return Result; } +static gs_string +ui_PushLayoutCategoryName(ui_interface* Interface, gs_string Category, u32 Value) +{ + gs_string Result = PushStringF(Interface->PerFrameMemory, + Category.Length + 25, + "%S%d", + Category.ConstString, + Value); + return Result; +} + static ui_widget* ui_PushLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir, gs_string Name) { @@ -770,6 +781,12 @@ ui_PushLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir Interface->ActiveLayout = Result; return Result; } +static ui_widget* +ui_PushLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir, gs_string Category, u32 Value) +{ + gs_string Name = ui_PushLayoutCategoryName(Interface, Category, Value); + return ui_PushLayout(Interface, Bounds, FillDir, Name); +} static ui_widget* ui_PushLayout(ui_interface* Interface, gs_string Name, bool Inset = true) @@ -837,7 +854,16 @@ ui_PopLayout(ui_interface* Interface, gs_string LayoutName) // 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)); + // + // We use StringsEqualUpToLength here becuase its possible that + // the current layout used the Category + Identifier method + // for generating Layout->String. And if Identifier was a string + // that was edited within the scope of this layout, then + // Layout->String and LayoutName will no longer match. + // + // This is a compromise that will at least let us know if + // we aren't popping all our layouts correctly. + Assert(StringsEqualUpToLength(Layout->String, LayoutName, LayoutName.Length)); ui_ExpandToFitChildren(Layout); @@ -851,6 +877,12 @@ ui_PopLayout(ui_interface* Interface, gs_string LayoutName) ui_CommitBounds(Interface->ActiveLayout, Layout->Bounds); } } +static void +ui_PopLayout(ui_interface* Interface, gs_string Category, u32 Value) +{ + gs_string Name = ui_PushLayoutCategoryName(Interface, Category, Value); + ui_PopLayout(Interface, Name); +} static ui_widget* ui_BeginRow(ui_interface* Interface, u32 ColumnsMax) @@ -1050,6 +1082,7 @@ ui_EvaluateWidget(ui_interface* Interface, ui_widget* Widget, rect2 Bounds) else { OutChar(&State->EditString, Interface->TempInputString.Str[i]); + Interface->CursorPosition += 1; } } } diff --git a/src/app/editor/panels/foldhaus_panel_animation_timeline.h b/src/app/editor/panels/foldhaus_panel_animation_timeline.h index 886b1a3..d319a0e 100644 --- a/src/app/editor/panels/foldhaus_panel_animation_timeline.h +++ b/src/app/editor/panels/foldhaus_panel_animation_timeline.h @@ -14,7 +14,9 @@ struct animation_timeline_state frame_range VisibleRange; handle SelectedBlockHandle; animation_handle EditingAnimationHandle; - u32 SelectedAnimationLayer; + s32 SelectedAnimationLayer; + + animation_handle NextActiveAnim; }; inline u32 @@ -263,7 +265,8 @@ AnimationTimeline_AddAnimationBlockCommand(animation_timeline_state* TimelineSta if ((EndFrame - StartFrame) > 0) { animation_pattern_handle PatternHandle = Patterns_IndexToHandle(0); - u32 Layer = TimelineState->SelectedAnimationLayer; + s32 Layer = TimelineState->SelectedAnimationLayer; + Assert(Layer >= 0); handle NewBlockHandle = Animation_AddBlock(ActiveAnim, StartFrame, EndFrame, PatternHandle, Layer); @@ -504,13 +507,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, State->Patterns); - NewAnim.FileInfo = AnimFile.FileInfo; - - animation_handle NewAnimHandle = AnimationArray_Push(&State->AnimationSystem.Animations, NewAnim); + animation_handle NewAnimHandle = AnimationSystem_LoadAnimationFromFile(&State->AnimationSystem, + State->Patterns, + Context, + FileInfo.Path); State->AnimationSystem.ActiveFadeGroup.From = NewAnimHandle; } } @@ -639,7 +639,7 @@ LayerList_Render(animation_timeline_state* TimelineState, animation* ActiveAnim, if (ActiveAnim) { v2 LayerTextPos = {}; - for (u32 i = 0; i < ActiveAnim->Layers.Count; i++) + for (s32 i = 0; i < (s32)ActiveAnim->Layers.Count; i++) { anim_layer* Layer = ActiveAnim->Layers.Values + i; @@ -762,11 +762,9 @@ PANEL_MODAL_OVERRIDE_CALLBACK(AnimInfoView_SaveAnimFileCallback) } internal void -AnimationTimeline_SetActiveAnimation (animation_handle Handle, animation_timeline_state* TimelineState, - animation_system* System) +AnimationTimeline_SetActiveAnimation (animation_handle Handle, animation_timeline_state* TimelineState) { - System->ActiveFadeGroup.From = Handle; - TimelineState->EditingAnimationHandle = Handle; + TimelineState->NextActiveAnim = Handle; } internal void @@ -774,8 +772,9 @@ AnimInfoView_Render(animation_timeline_state* TimelineState, animation* ActiveAn { animation_system* AnimSystem = &State->AnimationSystem; + animation_handle ActiveAnimHandle = State->AnimationSystem.ActiveFadeGroup.From; ui_interface* Interface = &State->Interface; - ui_PushLayout(Interface, Bounds, LayoutDirection_TopDown, MakeString("AnimInfo Layout")); + ui_PushLayout(Interface, Bounds, LayoutDirection_TopDown, MakeString("AnimInfo Layout"), ActiveAnimHandle.Index); ui_FillRect(&State->Interface, Bounds, Interface->Style.PanelBG); @@ -796,7 +795,7 @@ AnimInfoView_Render(animation_timeline_state* TimelineState, animation* ActiveAn { animation_handle NewHandle = {}; NewHandle.Index = i; - AnimationTimeline_SetActiveAnimation(NewHandle, TimelineState, AnimSystem); + AnimationTimeline_SetActiveAnimation(NewHandle, TimelineState); } } } @@ -806,18 +805,22 @@ AnimInfoView_Render(animation_timeline_state* TimelineState, animation* ActiveAn { if (ui_Button(Interface, MakeString("New"))) { - animation NewAnim = {}; - NewAnim.Name = PushString(State->AnimationSystem.Storage, 256); + animation_desc Desc = {}; + Desc.NameSize = 256; + Desc.LayersCount = 8; + Desc.BlocksCount = 8; + Desc.MinFrames = 0; + Desc.MaxFrames = SecondsToFrames(15, State->AnimationSystem); + animation NewAnim = Animation_Create(Desc, &State->AnimationSystem); animation_handle NewAnimHandle = AnimationArray_Push(&State->AnimationSystem.Animations, NewAnim); - State->AnimationSystem.ActiveFadeGroup.From = NewAnimHandle; + AnimationTimeline_SetActiveAnimation(NewAnimHandle, TimelineState); } if (ActiveAnim && 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 - animation_handle ActiveAnimHandle = State->AnimationSystem.ActiveFadeGroup.From; animation ActiveAnimation = *AnimationArray_GetSafe(State->AnimationSystem.Animations, ActiveAnimHandle); if (!ActiveAnimation.FileInfo.Path.Str) @@ -853,22 +856,26 @@ AnimInfoView_Render(animation_timeline_state* TimelineState, animation* ActiveAn ui_Label(Interface, MakeString("Layer")); - u32 LayerIndex = TimelineState->SelectedAnimationLayer; - anim_layer* SelectedLayer = ActiveAnim->Layers.Values + LayerIndex; - - ui_TextEntry(Interface, MakeString("Layer Name"), &SelectedLayer->Name); - gs_string BlendStr = BlendModeStrings[SelectedLayer->BlendMode]; - if (ui_BeginLabeledDropdown(Interface, MakeString("Blend Mode"), BlendStr)) + s32 LayerIndex = TimelineState->SelectedAnimationLayer; + anim_layer* SelectedLayer = 0; + if (LayerIndex >= 0) { - for (u32 i = 0; i < BlendMode_Count; i++) + SelectedLayer = ActiveAnim->Layers.Values + LayerIndex; + + ui_TextEntry(Interface, MakeString("Layer Name"), &SelectedLayer->Name); + gs_string BlendStr = BlendModeStrings[SelectedLayer->BlendMode]; + if (ui_BeginLabeledDropdown(Interface, MakeString("Blend Mode"), BlendStr)) { - if (ui_Button(Interface, BlendModeStrings[i])) + for (u32 i = 0; i < BlendMode_Count; i++) { - SelectedLayer->BlendMode = (blend_mode)i; + if (ui_Button(Interface, BlendModeStrings[i])) + { + SelectedLayer->BlendMode = (blend_mode)i; + } } } + ui_EndLabeledDropdown(Interface); } - ui_EndLabeledDropdown(Interface); ui_Label(Interface, MakeString("Pattern")); @@ -917,11 +924,12 @@ AnimationTimeline_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* animation* ActiveAnim = 0; animation_handle Handle = State->AnimationSystem.ActiveFadeGroup.From; - TimelineState->EditingAnimationHandle = Handle; if (IsValid(Handle)) { animation_array Animations = State->AnimationSystem.Animations; ActiveAnim = AnimationArray_GetSafe(Animations, Handle); + TimelineState->EditingAnimationHandle = Handle; + TimelineState->NextActiveAnim = Handle; } ui_FillRect(&State->Interface, PanelBounds, v4{.1f,.1f,.1f,1.f}); @@ -944,6 +952,14 @@ AnimationTimeline_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* LayerList_Render(TimelineState, ActiveAnim, LayersBounds, Panel, RenderBuffer, State, Context); TimeRange_Render(TimelineState, ActiveAnim, TimeRangeBounds, RenderBuffer, State, Context); AnimInfoView_Render(TimelineState, ActiveAnim, InfoBounds, Panel, RenderBuffer, State, Context); + + if (!AnimHandlesAreEqual(TimelineState->NextActiveAnim, + Handle)) + { + State->AnimationSystem.ActiveFadeGroup.From = TimelineState->NextActiveAnim; + TimelineState->EditingAnimationHandle = TimelineState->NextActiveAnim; + TimelineState->SelectedAnimationLayer = -1; + } } #define FOLDHAUS_PANEL_ANIMATION_TIMELINE_H diff --git a/src/app/engine/animation/foldhaus_animation.h b/src/app/engine/animation/foldhaus_animation.h index 33d466a..91204c7 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, u8* UserData) +#define ANIMATION_PROC(name) void name(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) typedef ANIMATION_PROC(animation_proc); struct frame_range @@ -164,6 +164,8 @@ struct animation_system r32 SecondsPerFrame; b32 TimelineShouldAdvance; + // Settings + bool Multithreaded; }; // NOTE(pjs): A Pattern is a named procedure which can be used as @@ -174,6 +176,7 @@ struct animation_pattern char* Name; s32 NameLength; animation_proc* Proc; + bool Multithreaded; }; struct animation_pattern_array @@ -250,9 +253,14 @@ Patterns_Create(gs_memory_arena* Arena, s32 CountMax) return Result; } -#define Patterns_PushPattern(array, proc) Patterns_PushPattern_((array), (proc), Stringify(proc), sizeof(Stringify(proc)) - 1) +#define PATTERN_MULTITHREADED true +#define PATTERN_SINGLETHREADED false + +#define Patterns_PushPattern(array, proc, multithread) \ +Patterns_PushPattern_((array), (proc), Stringify(proc), sizeof(Stringify(proc)) - 1, (multithread)) + internal void -Patterns_PushPattern_(animation_pattern_array* Array, animation_proc* Proc, char* Name, u32 NameLength) +Patterns_PushPattern_(animation_pattern_array* Array, animation_proc* Proc, char* Name, u32 NameLength, bool Multithreaded) { Assert(Array->Count < Array->CountMax); @@ -260,6 +268,7 @@ Patterns_PushPattern_(animation_pattern_array* Array, animation_proc* Proc, char Pattern.Name = Name; Pattern.NameLength = NameLength; Pattern.Proc = Proc; + Pattern.Multithreaded = Multithreaded; Array->Values[Array->Count++] = Pattern; } @@ -410,6 +419,38 @@ AnimationArray_GetSafe(animation_array Array, animation_handle Handle) // // Animation +typedef struct animation_desc +{ + u32 NameSize; + char* Name; + + u32 LayersCount; + u32 BlocksCount; + + u32 MinFrames; + u32 MaxFrames; +} animation_desc; + +internal animation +Animation_Create(animation_desc Desc, animation_system* System) +{ + animation Result = {}; + u32 NameLen = Desc.NameSize; + if (Desc.Name) + { + NameLen = Max(CStringLength(Desc.Name), NameLen); + Result.Name = PushStringF(System->Storage, NameLen, "%s", Desc.Name); + } else { + Result.Name = PushStringF(System->Storage, NameLen, "[New Animation]"); + } + + Result.Layers = AnimLayerArray_Create(System->Storage, Desc.LayersCount); + Result.Blocks_ = AnimBlockArray_Create(System->Storage, Desc.BlocksCount); + Result.PlayableRange.Min = Desc.MinFrames; + Result.PlayableRange.Max = Desc.MaxFrames; + return Result; +} + internal handle Animation_AddBlock(animation* Animation, u32 StartFrame, s32 EndFrame, animation_pattern_handle AnimationProcHandle, u32 LayerIndex) { @@ -604,6 +645,9 @@ AnimationSystem_Init(animation_system_desc Desc) Clear(&Result.ActiveFadeGroup.To); Result.ActiveFadeGroup.FadeElapsed = 0; + // Settings + Result.Multithreaded = true; + return Result; } diff --git a/src/app/engine/animation/foldhaus_animation_renderer.cpp b/src/app/engine/animation/foldhaus_animation_renderer.cpp index 16072ad..f43184b 100644 --- a/src/app/engine/animation/foldhaus_animation_renderer.cpp +++ b/src/app/engine/animation/foldhaus_animation_renderer.cpp @@ -89,14 +89,79 @@ struct pattern_args u8* UserData; }; -internal void -AnimationSystem_RenderBlockToLedBuffer(animation_system* System, animation_block Block, led_buffer* Buffer, animation_pattern_array Patterns, pattern_args PatternArgs) +struct render_anim_to_led_buffer_job_data { + animation_pattern Pattern; + led_buffer Buffer; + led_buffer_range BufferRange; + pattern_args PatternArgs; + r32 SecondsIntoBlock; +}; + +internal void +AnimationSystem_RenderAnimationToLedBufferJob(gs_thread_context Context, gs_data Data) +{ + render_anim_to_led_buffer_job_data JobData = *(render_anim_to_led_buffer_job_data*)Data.Memory; + JobData.Pattern.Proc(&JobData.Buffer, + JobData.BufferRange, + JobData.PatternArgs.Assembly, + JobData.SecondsIntoBlock, + JobData.PatternArgs.Transient, + JobData.PatternArgs.UserData); +} + +#define MULTITHREAD_PATTERN_RENDERING 1 + +internal void +AnimationSystem_BeginRenderBlockToLedBuffer(animation_system* System, animation_block Block, led_buffer* Buffer, animation_pattern_array Patterns, pattern_args PatternArgs, + context Context) +{ + DEBUG_TRACK_FUNCTION; + u32 FramesIntoBlock = System->CurrentFrame - Block.Range.Min; r32 SecondsIntoBlock = FramesIntoBlock * System->SecondsPerFrame; animation_pattern Pattern = Patterns_GetPattern(Patterns, Block.AnimationProcHandle); - Pattern.Proc(Buffer, PatternArgs.Assembly, SecondsIntoBlock, PatternArgs.Transient, PatternArgs.UserData); + + if (System->Multithreaded && Pattern.Multithreaded) + { + u32 JobsCount = 4; + u32 LedsPerJob = Buffer->LedCount / JobsCount; + + for (u32 i = 0; i < JobsCount; i++) + { + gs_data Data = PushSizeToData(Context.ThreadContext.Transient, sizeof(render_anim_to_led_buffer_job_data)); + render_anim_to_led_buffer_job_data* JobData = (render_anim_to_led_buffer_job_data*)Data.Memory; + JobData->Pattern = Pattern; + JobData->Buffer = *Buffer; + JobData->BufferRange.First = LedsPerJob * i; + JobData->BufferRange.OnePastLast = LedsPerJob * (i + 1); + JobData->PatternArgs = PatternArgs; + JobData->SecondsIntoBlock = SecondsIntoBlock; + + Context.GeneralWorkQueue->PushWorkOnQueue(Context.GeneralWorkQueue, + (thread_proc*)AnimationSystem_RenderAnimationToLedBufferJob, + Data, + ConstString("Render Pattern To Buffer")); + } + } + else + { + led_buffer_range Range = {}; + Range.First = 0; + Range.OnePastLast = Buffer->LedCount; + + Pattern.Proc(Buffer, Range, PatternArgs.Assembly, SecondsIntoBlock, PatternArgs.Transient, PatternArgs.UserData); + } +} + +internal void +AnimationSystem_EndRenderBlockToLedBuffer (animation_system* System, context Context) +{ + if (System->Multithreaded) + { + Context.GeneralWorkQueue->CompleteQueueWork(Context.GeneralWorkQueue, Context.ThreadContext); + } } // NOTE(pjs): This mirrors animation_layer_frame to account @@ -114,7 +179,8 @@ RenderAnimationToLedBuffer (animation_system* System, layer_led_buffer* LayerBuffers, led_buffer* AssemblyLedBuffer, animation_pattern_array Patterns, - gs_memory_arena* Transient) + gs_memory_arena* Transient, + context Context) { led_buffer AccBuffer = LedBuffer_CreateCopyCleared(*AssemblyLedBuffer, Transient); @@ -144,15 +210,17 @@ RenderAnimationToLedBuffer (animation_system* System, { led_buffer TempBuffer = LayerBuffers[Layer].HotBuffer; animation_block Block = LayerFrame.Hot; - AnimationSystem_RenderBlockToLedBuffer(System, Block, &TempBuffer, Patterns, PatternArgs); + AnimationSystem_BeginRenderBlockToLedBuffer(System, Block, &TempBuffer, Patterns, PatternArgs, Context); } if (LayerFrame.HasNextHot) { led_buffer TempBuffer = LayerBuffers[Layer].NextHotBuffer; animation_block Block = LayerFrame.NextHot; - AnimationSystem_RenderBlockToLedBuffer(System, Block, &TempBuffer, Patterns, PatternArgs); + AnimationSystem_BeginRenderBlockToLedBuffer(System, Block, &TempBuffer, Patterns, PatternArgs, Context); } + + AnimationSystem_EndRenderBlockToLedBuffer(System, Context); } // Blend together any layers that have a hot and next hot buffer @@ -193,8 +261,11 @@ AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Asse led_system* LedSystem, animation_pattern_array Patterns, gs_memory_arena* Transient, + context Context, u8* UserData) { + DEBUG_TRACK_FUNCTION; + s32 CurrentFrame = System->CurrentFrame; r32 FrameTime = CurrentFrame * System->SecondsPerFrame; @@ -231,7 +302,8 @@ AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Asse FromLayerBuffers, AssemblyLedBuffer, Patterns, - Transient); + Transient, + Context); led_buffer ConsolidatedBuffer = FromBuffer; if (ToAnim) { @@ -241,7 +313,8 @@ AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Asse ToLayerBuffers, AssemblyLedBuffer, Patterns, - Transient); + Transient, + Context); r32 BlendPercent = FadeGroup.FadeElapsed / FadeGroup.FadeDuration; LedBuffer_Blend(FromBuffer, ToBuffer, &ConsolidatedBuffer, LedBlend_Lerp, (u8*)&BlendPercent); diff --git a/src/app/engine/animation/foldhaus_animation_serializer.cpp b/src/app/engine/animation/foldhaus_animation_serializer.cpp index effbcda..9227328 100644 --- a/src/app/engine/animation/foldhaus_animation_serializer.cpp +++ b/src/app/engine/animation/foldhaus_animation_serializer.cpp @@ -182,9 +182,23 @@ AnimParser_Parse(gs_string File, gs_memory_arena* Arena, animation_pattern_array } } } - return Result; } +internal animation +AnimParser_Parse(gs_data File, gs_memory_arena* Arena, animation_pattern_array AnimPatterns) +{ + gs_string FileString = MakeString((char*)File.Memory, File.Size); + return AnimParser_Parse(FileString, Arena, AnimPatterns); +} +internal animation_handle +AnimationSystem_LoadAnimationFromFile(animation_system* System, animation_pattern_array AnimPatterns, context Context, gs_const_string FilePath) +{ + gs_file AnimFile = ReadEntireFile(Context.ThreadContext.FileHandler, FilePath); + animation NewAnim = AnimParser_Parse(AnimFile.Data, System->Storage, AnimPatterns); + NewAnim.FileInfo = AnimFile.FileInfo; + animation_handle NewAnimHandle = AnimationArray_Push(&System->Animations, NewAnim); + return NewAnimHandle; +} #define FOLDHAUS_ANIMATION_SERIALIZER_CPP #endif // FOLDHAUS_ANIMATION_SERIALIZER_CPP \ No newline at end of file diff --git a/src/app/engine/assembly/foldhaus_assembly.h b/src/app/engine/assembly/foldhaus_assembly.h index d1a2562..0744e8e 100644 --- a/src/app/engine/assembly/foldhaus_assembly.h +++ b/src/app/engine/assembly/foldhaus_assembly.h @@ -32,6 +32,12 @@ struct led_buffer v4* Positions; }; +struct led_buffer_range +{ + u32 First; + u32 OnePastLast; +}; + struct led_system { gs_allocator PlatformMemory; @@ -184,6 +190,8 @@ LedBuffer_ClearToBlack(led_buffer* Buffer) internal void LedBuffer_Copy(led_buffer From, led_buffer* To) { + DEBUG_TRACK_FUNCTION; + Assert(From.LedCount == To->LedCount); u32 LedCount = To->LedCount; for (u32 i = 0; i < LedCount; i++) @@ -195,6 +203,8 @@ LedBuffer_Copy(led_buffer From, led_buffer* To) internal void LedBuffer_Blend(led_buffer A, led_buffer B, led_buffer* Dest, led_blend_proc* BlendProc, u8* UserData) { + DEBUG_TRACK_FUNCTION; + Assert(A.LedCount == B.LedCount); Assert(Dest->LedCount == A.LedCount); Assert(BlendProc); @@ -211,6 +221,8 @@ LedBuffer_Blend(led_buffer A, led_buffer B, led_buffer* Dest, led_blend_proc* Bl internal led_buffer LedBuffer_CreateCopyCleared (led_buffer Buffer, gs_memory_arena* Arena) { + DEBUG_TRACK_FUNCTION; + led_buffer Result = {}; Result.LedCount = Buffer.LedCount; Result.Positions = Buffer.Positions; diff --git a/src/app/foldhaus_app.cpp b/src/app/foldhaus_app.cpp index e5c1fed..5519446 100644 --- a/src/app/foldhaus_app.cpp +++ b/src/app/foldhaus_app.cpp @@ -95,6 +95,21 @@ INITIALIZE_APPLICATION(InitializeApplication) State->RunEditor = true; } +internal void +BuildAssemblyData (app_state* State, context Context, addressed_data_buffer_list* OutputData) +{ + +#define SEND_DATA +#ifdef SEND_DATA + // 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); +#endif +} + UPDATE_AND_RENDER(UpdateAndRender) { DEBUG_TRACK_FUNCTION; @@ -119,6 +134,7 @@ UPDATE_AND_RENDER(UpdateAndRender) &State->LedSystem, State->Patterns, State->Transient, + *Context, State->UserSpaceDesc.UserData.Memory); } @@ -133,20 +149,21 @@ UPDATE_AND_RENDER(UpdateAndRender) Editor_Render(State, Context, RenderBuffer); } -#define SEND_DATA -#ifdef SEND_DATA - // 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); -#endif + BuildAssemblyData(State, *Context, OutputData); } CLEANUP_APPLICATION(CleanupApplication) { app_state* State = (app_state*)Context.MemoryBase; + + for (u32 i = 0; i < State->Assemblies.Count; i++) + { + assembly Assembly = State->Assemblies.Values[i]; + led_buffer LedBuffer = State->LedSystem.Buffers[Assembly.LedBufferIndex]; + AssemblyDebug_OverrideWithColor(Assembly, LedBuffer, pixel{0, 0, 0}); + } + BuildAssemblyData(State, Context, OutputData); + US_CustomCleanup(&State->UserSpaceDesc, State, Context); SACN_Cleanup(&State->SACN, Context); } diff --git a/src/app/foldhaus_platform.h b/src/app/foldhaus_platform.h index 8a30d92..f464603 100644 --- a/src/app/foldhaus_platform.h +++ b/src/app/foldhaus_platform.h @@ -76,7 +76,7 @@ typedef UPDATE_AND_RENDER(update_and_render); #define RELOAD_STATIC_DATA(name) void name(context Context, debug_services* DebugServices) typedef RELOAD_STATIC_DATA(reload_static_data); -#define CLEANUP_APPLICATION(name) void name(context Context) +#define CLEANUP_APPLICATION(name) void name(context Context, addressed_data_buffer_list* OutputData) typedef CLEANUP_APPLICATION(cleanup_application); // Platform Functions diff --git a/src/app/patterns/blumen_patterns.h b/src/app/patterns/blumen_patterns.h index 1a4a10a..ee59638 100644 --- a/src/app/patterns/blumen_patterns.h +++ b/src/app/patterns/blumen_patterns.h @@ -411,30 +411,30 @@ GetColor(v4* Colors, u32 ColorsCount, r32 Percent) } internal void -SolidColorPattern(led_buffer* Leds, pixel Color) +SolidColorPattern(led_buffer* Leds, led_buffer_range Range, pixel Color) { - for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) + for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++) { Leds->Colors[LedIndex] = Color; } } internal void -Pattern_Blue(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +Pattern_Blue(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) { pixel Blue = pixel{0, 0, 255}; - SolidColorPattern(Leds, Blue); + SolidColorPattern(Leds, Range, Blue); } internal void -Pattern_Green(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +Pattern_Green(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) { pixel Green = pixel{0, 255, 0}; - SolidColorPattern(Leds, Green); + SolidColorPattern(Leds, Range, Green); } internal void -Pattern_FlowerColors(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +Pattern_FlowerColors(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) { r32 CycleTime = 10; r32 CyclePercent = ModR32(Time, CycleTime) / CycleTime; @@ -442,7 +442,7 @@ Pattern_FlowerColors(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_ar v4 CA = GetColor(FlowerAColors, FLOWER_COLORS_COUNT, CyclePercent); v4 CB = GetColor(FlowerAColors, FLOWER_COLORS_COUNT, 1.0f - CyclePercent); - for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) + for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++) { v4 P = Leds->Positions[LedIndex]; r32 Pct = (Abs(ModR32(P.y, 150) / 150) + CycleTime) * PiR32; @@ -453,7 +453,7 @@ Pattern_FlowerColors(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_ar } internal void -TestPatternOne(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +TestPatternOne(led_buffer* Leds, led_buffer_range Range, 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); @@ -485,7 +485,7 @@ TestPatternOne(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* T } internal void -TestPatternTwo(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +TestPatternTwo(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) { r32 PeriodicTime = (Time / PiR32) * 2; @@ -504,7 +504,7 @@ TestPatternTwo(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* T r32 OuterRadiusSquared = 1000000; r32 InnerRadiusSquared = 0; - for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) + for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++) { v4 Position = Leds->Positions[LedIndex]; @@ -537,7 +537,7 @@ TestPatternTwo(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* T } internal void -TestPatternThree(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +TestPatternThree(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) { v4 GreenCenter = v4{0, 0, 150, 1}; r32 GreenRadius = Abs(SinR32(Time)) * 200; @@ -548,7 +548,7 @@ TestPatternThree(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* r32 FadeDist = 35; - for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) + for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++) { v4 LedPosition = Leds->Positions[LedIndex]; u8 Red = 0; @@ -702,7 +702,7 @@ while (Hue > 360.0f) { Hue -= 360.0f; } } internal void -Pattern_HueShift(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +Pattern_HueShift(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) { r32 Height = SinR32(Time) * 25; @@ -713,7 +713,7 @@ Pattern_HueShift(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* v4 HSV = { CycleProgress * 360, 1, 1, 1 }; v4 RGB = HSVToRGB(HSV); - for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) + for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++) { v4 Pos = Leds->Positions[LedIndex]; r32 Dist = Pos.y - Height; @@ -732,7 +732,7 @@ Pattern_HueShift(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* } internal void -Pattern_HueFade(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +Pattern_HueFade(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) { r32 HueBase = ModR32(Time * 50, 360); @@ -740,7 +740,7 @@ Pattern_HueFade(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* r32 CycleProgress = FractR32(Time / CycleLength); r32 CycleBlend = (SinR32(Time) * .5f) + .5f; - for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) + for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++) { v4 Pos = Leds->Positions[LedIndex]; r32 Hue = HueBase + Pos.y + Pos.x; @@ -752,9 +752,9 @@ Pattern_HueFade(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* } internal void -Pattern_AllGreen(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +Pattern_AllGreen(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) { - for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) + for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++) { u32 I = LedIndex + 1; Leds->Colors[LedIndex] = {}; @@ -781,7 +781,7 @@ PatternHash(r32 Seed) } internal void -Pattern_Spots(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +Pattern_Spots(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) { pixel ColorA = { 0, 255, 255 }; pixel ColorB = { 255, 0, 255 }; @@ -790,7 +790,7 @@ Pattern_Spots(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Tr Time *= Speed; r32 ScaleA = 2 * SinR32(Time / 5); r32 ScaleB = 2.4f * CosR32(Time / 2.5f); - for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) + for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++) { v4 P = Leds->Positions[LedIndex]; r32 V = P.y; @@ -807,10 +807,10 @@ Pattern_Spots(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Tr } internal void -Pattern_LighthouseRainbow(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +Pattern_LighthouseRainbow(led_buffer* Leds, led_buffer_range Range, 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++) + for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++) { v2 Vector = v2{ Leds->Positions[LedIndex].x, @@ -828,7 +828,7 @@ Pattern_LighthouseRainbow(led_buffer* Leds, assembly Assembly, r32 Time, gs_memo } internal void -Pattern_SmoothGrowRainbow(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +Pattern_SmoothGrowRainbow(led_buffer* Leds, led_buffer_range Range, 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; @@ -850,7 +850,7 @@ Pattern_SmoothGrowRainbow(led_buffer* Leds, assembly Assembly, r32 Time, gs_memo } internal void -Pattern_GrowAndFade(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +Pattern_GrowAndFade(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) { r32 PercentCycle = ModR32(Time, 10) / 10; v4 HSV = { PercentCycle * 360, 1, 1, 1 }; @@ -859,7 +859,7 @@ Pattern_GrowAndFade(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_are r32 RefHeight = -100 + (Smoothstep(PercentCycle * 1.4f) * 400); r32 RefBrightness = 1.0f - Smoothstep(PercentCycle); - for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) + for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++) { v4 P = Leds->Positions[LedIndex]; @@ -873,7 +873,7 @@ 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) +Pattern_ColorToWhite(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) { r32 FadeBottomBase = 50; r32 FadeTop = 125; @@ -935,7 +935,7 @@ 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) +Pattern_FlowerColorToWhite(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) { r32 FadeBottomBase = 50; r32 FadeTop = 125; @@ -999,7 +999,7 @@ v4* FBC = &FlowerBColors[0]; v4* FCC = &FlowerCColors[0]; internal void -Pattern_BasicFlowers(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +Pattern_BasicFlowers(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) { if (TLastFrame > Time) { @@ -1042,16 +1042,11 @@ Pattern_BasicFlowers(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_ar } internal void -Pattern_Wavy(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +Pattern_Wavy(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) { + DEBUG_TRACK_FUNCTION; -} - -internal void -Pattern_Patchy(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) -{ -#if 0 - for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) + for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++) { v4 P = Leds->Positions[LedIndex]; @@ -1072,8 +1067,14 @@ Pattern_Patchy(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* T Leds->Colors[LedIndex] = V4ToRGBPixel(C); //Leds->Colors[LedIndex] = pixel{NV, NV, NV}; } -#elif 1 - for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) +} + +internal void +Pattern_Patchy(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +{ + DEBUG_TRACK_FUNCTION; + + for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++) { v4 P = Leds->Positions[LedIndex]; r32 LedRange = 300.0f; @@ -1093,37 +1094,17 @@ Pattern_Patchy(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* T v4 C = CA + CB; Leds->Colors[LedIndex] = V4ToRGBPixel(C); } -#else - for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) - { - v4 P = Leds->Positions[LedIndex]; - r32 LedRange = 300.0f; - r32 ScaleFactor = 1.0f / LedRange; - v3 Pp = P.xyz + v3{150, 100, 0}; - - r32 NoiseA = Fbm3D((Pp / 35), Time * 0.5f); - //NoiseA = PowR32(NoiseA, 3); - NoiseA = Smoothstep(NoiseA); - v4 CA = v4{1, 0, 1, 1} * NoiseA; - - r32 NoiseB = Noise3D((Pp / 35) + v3{0, 0, Time * 5}); - NoiseB = PowR32(NoiseB, 3); - NoiseB = Smoothstep(NoiseB); - v4 CB = v4{0, 1, 1, 1}; - - v4 C = V4Lerp(NoiseB, CA, CB); - Leds->Colors[LedIndex] = V4ToRGBPixel(C); - } -#endif } internal void -Pattern_Leafy(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +Pattern_Leafy(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) { + DEBUG_TRACK_FUNCTION; + v4* Colors = &FlowerBColors[0]; - for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) + for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++) { v4 P = Leds->Positions[LedIndex]; @@ -1177,15 +1158,70 @@ Pattern_Leafy(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Tr } internal void -Pattern_LeafyPatchy(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +Pattern_LeafyPatchy(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) { - + DEBUG_TRACK_FUNCTION; + for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++) + { + v4 P = Leds->Positions[LedIndex]; + r32 LedRange = 300.0f; + r32 ScaleFactor = 1.0f / LedRange; + v3 Pp = P.xyz + v3{150, 100, 0}; + + r32 NoiseA = Fbm3D((Pp / 35), Time * 0.5f); + //NoiseA = PowR32(NoiseA, 3); + NoiseA = Smoothstep(NoiseA); + v4 CA = v4{1, 0, 1, 1} * NoiseA; + + r32 NoiseB = Noise3D((Pp / 35) + v3{0, 0, Time * 5}); + NoiseB = PowR32(NoiseB, 3); + NoiseB = Smoothstep(NoiseB); + v4 CB = v4{0, 1, 1, 1}; + + v4 C = V4Lerp(NoiseB, CA, CB); + Leds->Colors[LedIndex] = V4ToRGBPixel(C); + } } internal void -Pattern_WavyPatchy(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +Pattern_WavyPatchy(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) { + DEBUG_TRACK_FUNCTION; + gs_random_series Random = InitRandomSeries(24601); + + r32 LightSpeedMin = 1; + r32 LightSpeedMax = 5; + + r32 LightHueMin = (ModR32(Time, 10) / 10) * 360; + r32 LightHueMax = ModR32((LightHueMin + 45), 360) ; + + s32 LightTailLength = 10; + for (u32 StripIndex = 0; StripIndex < Assembly.StripCount; StripIndex++) + { + v2_strip Strip = Assembly.Strips[StripIndex]; + + r32 LightHue = LerpR32(NextRandomUnilateral(&Random), + LightHueMin, + LightHueMax); + r32 LightStartHeight = NextRandomUnilateral(&Random); + r32 LightSpeed = LerpR32(NextRandomUnilateral(&Random), + LightSpeedMin, + LightSpeedMax); + r32 LightCurrentHeight = LightStartHeight + (LightSpeed * Time * 0.1f); + s32 StartIndex = (s32)(LightCurrentHeight * (r32)Strip.LedCount) % Strip.LedCount; + + for (s32 i = 0; i < LightTailLength; i++) + { + s32 StripLedIndex = StartIndex + i; + if (StripLedIndex >= (s32)Strip.LedCount) continue; + + u32 LedIndex = Strip.LedLUT[StripLedIndex]; + r32 PctTail = ((r32)i / (r32)LightTailLength); + v4 C = HSVToRGB(v4{LightHue, 1, 1, 1}) * PctTail; + Leds->Colors[LedIndex] = V4ToRGBPixel(C); + } + } } #define BLUMEN_PATTERNS_H diff --git a/src/app/platform_win32/win32_foldhaus.cpp b/src/app/platform_win32/win32_foldhaus.cpp index 452405e..28769ba 100644 --- a/src/app/platform_win32/win32_foldhaus.cpp +++ b/src/app/platform_win32/win32_foldhaus.cpp @@ -396,7 +396,7 @@ Win32_SendAddressedDataBuffer(gs_thread_context Context, addressed_data_buffer* { if (BufferAt->ComPort.Length > 0) { - HANDLE SerialPort = Win32SerialArray_GetOrOpen(BufferAt->ComPort, 2000000, 8, NOPARITY, 1); + HANDLE SerialPort = Win32SerialArray_GetOrOpen(BufferAt->ComPort, 2000000, 8, NOPARITY, 1, Context.Transient); if (SerialPort != INVALID_HANDLE_VALUE) { if (Win32SerialPort_Write(SerialPort, BufferAt->Data)) @@ -524,9 +524,39 @@ SetWorkingDirectory(HINSTANCE HInstance, gs_thread_context ThreadContext) } #include "../../gs_libs/gs_path.h" - #include "../../gs_libs/gs_csv.h" +internal void +Win32_SendOutputData(gs_thread_context ThreadContext, addressed_data_buffer_list OutputData) +{ + bool Multithread = true; + if (Multithread) + { + 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")); + } + } + 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); + } + } + +} + int WINAPI WinMain ( HINSTANCE HInstance, @@ -707,31 +737,7 @@ WinMain ( Context.UpdateAndRender(&Context, InputQueue, &RenderBuffer, &OutputData); - bool Multithread = false; - if (Multithread) - { - 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")); - } - } - 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); - } - } + Win32_SendOutputData(ThreadContext, OutputData); RenderCommandBuffer(RenderBuffer); ClearRenderBuffer(&RenderBuffer); @@ -759,7 +765,9 @@ WinMain ( LastFrameEnd = GetWallClock(); } - Context.CleanupApplication(Context); + Context.CleanupApplication(Context, &OutputData); + Win32_SendOutputData(ThreadContext, OutputData); + Win32DoQueueWorkUntilDone(&Win32WorkQueue.WorkQueue, Context.ThreadContext); Win32WorkQueue_Cleanup(); //Win32_TestCode_SocketReading_Cleanup(); diff --git a/src/app/platform_win32/win32_foldhaus_serial.h b/src/app/platform_win32/win32_foldhaus_serial.h index f82e198..a1244a9 100644 --- a/src/app/platform_win32/win32_foldhaus_serial.h +++ b/src/app/platform_win32/win32_foldhaus_serial.h @@ -70,20 +70,74 @@ Win32SerialPort_SetState(HANDLE ComPortHandle, u32 BaudRate, u8 ByteSize, u8 Par bool Success = SetCommState(ComPortHandle, &ControlSettings); } +gs_const_string_array +Win32SerialPorts_List(gs_memory_arena* Arena, gs_memory_arena* Transient) +{ + gs_const_string_array Result = {}; + + DWORD SizeNeeded0 = 0; + DWORD CountReturned0 = 0; + EnumPorts(NULL, 1, 0, 0, &SizeNeeded0, &CountReturned0); + Assert(GetLastError() == ERROR_INSUFFICIENT_BUFFER); + + DWORD SizeNeeded1 = 0; + DWORD CountReturned1 = 0; + PORT_INFO_1* PortsArray = (PORT_INFO_1*)PushSize(Transient, SizeNeeded0); + if (EnumPorts(NULL, + 1, + (u8*)PortsArray, + SizeNeeded0, + &SizeNeeded1, + &CountReturned1)) + { + Result.CountMax = (u64)CountReturned1; + Result.Strings = PushArray(Arena, gs_const_string, Result.CountMax); + + for (; Result.Count < Result.CountMax; Result.Count++) + { + u64 Index = Result.Count; + u64 StrLen = CStringLength(PortsArray[Index].pName); + gs_string Str = PushString(Arena, StrLen); + PrintF(&Str, "%.*s", StrLen, PortsArray[Index].pName); + Result.Strings[Result.Count] = Str.ConstString; + } + } + + return Result; +} + +bool +Win32SerialPort_Exists(char* PortName, gs_memory_arena* Transient) +{ + bool Result = false; + if (PortName != 0) + { + gs_const_string PortIdent = ConstString(PortName); + u32 IdentBegin = FindLast(PortIdent, '\\') + 1; + PortIdent = Substring(PortIdent, IdentBegin, PortIdent.Length); + + gs_const_string_array PortsAvailable = Win32SerialPorts_List(Transient, Transient); + + for (u64 i = 0; i < PortsAvailable.Count; i++) + { + gs_const_string AvailablePortName = PortsAvailable.Strings[i]; + if (StringsEqualUpToLength(AvailablePortName, PortIdent, PortIdent.Length)) + { + Result = true; + break; + } + } + } + return Result; +} + HANDLE -Win32SerialPort_Open(char* PortName) +Win32SerialPort_Open(char* PortName, gs_memory_arena* Transient) { DEBUG_TRACK_FUNCTION; HANDLE ComPortHandle = INVALID_HANDLE_VALUE;; - WIN32_FIND_DATA FindData; - HANDLE ComPortExists = FindFirstFile(PortName, &FindData); - - // TODO(PS): we aren't sure yet if FindFirstFile will actually work - // for the purpose of checking to see if a ComPort actually exists. - // When you go to Foldspace next time, make sure we are still connecting - // the sculpture - if (ComPortExists != INVALID_HANDLE_VALUE) + if (Win32SerialPort_Exists(PortName, Transient)) { ComPortHandle = CreateFile(PortName, @@ -289,7 +343,7 @@ Win32SerialArray_Get(gs_const_string PortName) } HANDLE -Win32SerialArray_GetOrOpen(gs_const_string PortName, u32 BaudRate, u8 ByteSize, u8 Parity, u8 StopBits) +Win32SerialArray_GetOrOpen(gs_const_string PortName, u32 BaudRate, u8 ByteSize, u8 Parity, u8 StopBits, gs_memory_arena* Transient) { DEBUG_TRACK_FUNCTION; @@ -297,7 +351,7 @@ Win32SerialArray_GetOrOpen(gs_const_string PortName, u32 BaudRate, u8 ByteSize, if (PortHandle == INVALID_HANDLE_VALUE) { Assert(IsNullTerminated(PortName)); - PortHandle = Win32SerialPort_Open(PortName.Str); + PortHandle = Win32SerialPort_Open(PortName.Str, Transient); if (PortHandle != INVALID_HANDLE_VALUE) { Win32SerialPort_SetState(PortHandle, BaudRate, ByteSize, Parity, StopBits); diff --git a/src/app/ss_blumen_lumen/blumen_lumen.cpp b/src/app/ss_blumen_lumen/blumen_lumen.cpp index fe97067..7361fd4 100644 --- a/src/app/ss_blumen_lumen/blumen_lumen.cpp +++ b/src/app/ss_blumen_lumen/blumen_lumen.cpp @@ -43,6 +43,9 @@ MessageQueue_Write(blumen_network_msg_queue* Queue, gs_data Msg) Assert(Msg.Size <= DEFAULT_QUEUE_ENTRY_SIZE); u32 Index = Queue->WriteHead; + Assert(Index >= 0 && + Index < BLUMEN_MESSAGE_QUEUE_COUNT); + gs_data* Dest = Queue->Buffers + Index; CopyMemoryTo(Msg.Memory, Dest->Memory, Msg.Size); Dest->Size = Msg.Size; @@ -50,7 +53,7 @@ MessageQueue_Write(blumen_network_msg_queue* Queue, gs_data Msg) // NOTE(pjs): We increment write head at the end of writing so that // a reader thread doesn't pull the message off before we've finished // filling it out - Queue->WriteHead++; + Queue->WriteHead = (Queue->WriteHead + 1) % BLUMEN_MESSAGE_QUEUE_COUNT; return true; } @@ -116,25 +119,28 @@ BlumenLumen_LoadPatterns(app_state* State) } 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); - Patterns_PushPattern(Patterns, Pattern_FlowerColors); - Patterns_PushPattern(Patterns, Pattern_FlowerColorToWhite); - Patterns_PushPattern(Patterns, Pattern_BasicFlowers); + Patterns_PushPattern(Patterns, TestPatternOne, PATTERN_MULTITHREADED); + Patterns_PushPattern(Patterns, TestPatternTwo, PATTERN_MULTITHREADED); + Patterns_PushPattern(Patterns, TestPatternThree, PATTERN_MULTITHREADED); + Patterns_PushPattern(Patterns, Pattern_AllGreen, PATTERN_MULTITHREADED); + Patterns_PushPattern(Patterns, Pattern_HueShift, PATTERN_MULTITHREADED); + Patterns_PushPattern(Patterns, Pattern_HueFade, PATTERN_MULTITHREADED); + Patterns_PushPattern(Patterns, Pattern_Spots, PATTERN_MULTITHREADED); + Patterns_PushPattern(Patterns, Pattern_LighthouseRainbow, PATTERN_MULTITHREADED); + Patterns_PushPattern(Patterns, Pattern_SmoothGrowRainbow, PATTERN_MULTITHREADED); + Patterns_PushPattern(Patterns, Pattern_GrowAndFade, PATTERN_MULTITHREADED); + Patterns_PushPattern(Patterns, Pattern_ColorToWhite, PATTERN_MULTITHREADED); + Patterns_PushPattern(Patterns, Pattern_Blue, PATTERN_MULTITHREADED); + Patterns_PushPattern(Patterns, Pattern_Green, PATTERN_MULTITHREADED); + Patterns_PushPattern(Patterns, Pattern_FlowerColors, PATTERN_MULTITHREADED); + Patterns_PushPattern(Patterns, Pattern_FlowerColorToWhite, PATTERN_MULTITHREADED); + Patterns_PushPattern(Patterns, Pattern_BasicFlowers, PATTERN_MULTITHREADED); // 15 - Patterns_PushPattern(Patterns, Pattern_Patchy); - Patterns_PushPattern(Patterns, Pattern_Leafy); + Patterns_PushPattern(Patterns, Pattern_Wavy, PATTERN_MULTITHREADED); + Patterns_PushPattern(Patterns, Pattern_Patchy, PATTERN_MULTITHREADED); + Patterns_PushPattern(Patterns, Pattern_Leafy, PATTERN_MULTITHREADED); + Patterns_PushPattern(Patterns, Pattern_LeafyPatchy, PATTERN_MULTITHREADED); + Patterns_PushPattern(Patterns, Pattern_WavyPatchy, PATTERN_SINGLETHREADED); } internal v4 @@ -180,46 +186,45 @@ BlumenLumen_CustomInit(app_state* State, context Context) gs_const_string SculpturePath = ConstString("data/test_blumen.fold"); LoadAssembly(&State->Assemblies, &State->LedSystem, State->Transient, Context, SculpturePath, State->GlobalLog); +#if 0 { // 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_desc Desc = {}; + Desc.NameSize = 256; + Desc.LayersCount = 8; + Desc.BlocksCount = 8; + Desc.MinFrames = 0; + Desc.MaxFrames = SecondsToFrames(15, State->AnimationSystem); + + animation_desc Desc0 = Desc; + Desc.Name = "test_anim_zero"; + animation Anim0 = Animation_Create(Desc0, &State->AnimationSystem); Animation_AddLayer(&Anim0, MakeString("Base Layer"), BlendMode_Overwrite, &State->AnimationSystem); - Animation_AddBlock(&Anim0, 0, Anim0.PlayableRange.Max, Patterns_IndexToHandle(15), 0); - BLState->AnimHandles[0] = AnimationArray_Push(&State->AnimationSystem.Animations, Anim0); - 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_desc Desc1 = Desc; + Desc1.Name = "test_anim_one"; + animation Anim1 = Animation_Create(Desc1, &State->AnimationSystem); Animation_AddLayer(&Anim1, MakeString("Base Layer"), BlendMode_Overwrite, &State->AnimationSystem); - Animation_AddBlock(&Anim1, 0, Anim0.PlayableRange.Max, Patterns_IndexToHandle(12), 0); - BLState->AnimHandles[1] = 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_desc Desc2 = Desc; + Desc2.Name = "i_love_you"; + animation Anim2 = Animation_Create(Desc2, &State->AnimationSystem);; Animation_AddLayer(&Anim2, MakeString("Base Layer"), BlendMode_Overwrite, &State->AnimationSystem); - - Animation_AddBlock(&Anim2, 0, Anim0.PlayableRange.Max, Patterns_IndexToHandle(16), 0); - + Animation_AddBlock(&Anim2, 0, Anim0.PlayableRange.Max, Patterns_IndexToHandle(20), 0); BLState->AnimHandles[2] = AnimationArray_Push(&State->AnimationSystem.Animations, Anim2); State->AnimationSystem.ActiveFadeGroup.From = BLState->AnimHandles[2]; - State->AnimationSystem.TimelineShouldAdvance = true; } // End Animation Playground +#endif + animation_handle DemoPatternsAnim = AnimationSystem_LoadAnimationFromFile(&State->AnimationSystem, + State->Patterns, + Context, + ConstString("data/demo_patterns.foldanim")); + State->AnimationSystem.ActiveFadeGroup.From = DemoPatternsAnim; + State->AnimationSystem.TimelineShouldAdvance = true; for (u32 i = 0; i < FLOWER_COLORS_COUNT; i++) { @@ -404,6 +409,7 @@ BlumenLumen_CustomUpdate(gs_data UserData, app_state* State, context* Context) } } // Dim the leds based on temp data +#define DIM_LED_BRIGHTNESS 1 #if DIM_LED_BRIGHTNESS for (u32 i = 0; i < State->LedSystem.BuffersCount; i++) { @@ -417,7 +423,25 @@ BlumenLumen_CustomUpdate(gs_data UserData, app_state* State, context* Context) } } - // TODO(pjs): dim stem to 50% + // TODO(PS): This should really only happen if we think the + // flower _might_ be open + for (u32 a = 0; a < State->Assemblies.Count; a++) + { + assembly Assembly = State->Assemblies.Values[a]; + led_buffer Buffer = State->LedSystem.Buffers[Assembly.LedBufferIndex]; + + led_strip_list TopStrips = AssemblyStripsGetWithTagValue(Assembly, ConstString("section"), ConstString("inner_bloom"), State->Transient); + for (u32 s = 0; s < TopStrips.Count; s++) + { + u32 SIndex = TopStrips.StripIndices[s]; + v2_strip Strip = Assembly.Strips[SIndex]; + for (u32 l = 0; l < Strip.LedCount; l++) + { + u32 LIndex = Strip.LedLUT[l]; + Buffer.Colors[LIndex] = {0}; + } + } + } #endif // Send Status Packet diff --git a/src/gs_libs/gs_types.cpp b/src/gs_libs/gs_types.cpp index 1b59488..ca3336d 100644 --- a/src/gs_libs/gs_types.cpp +++ b/src/gs_libs/gs_types.cpp @@ -1557,6 +1557,25 @@ FindFirst(gs_string String, char C) return FindFirst(String.ConstString, 0, C); } +internal s64 +FindLast(char* String, s64 StartIndex, char C) +{ + s64 Result = -1; + s64 i = 0; + while (String[i] != 0 && i < StartIndex) + { + i++; + } + while (String[i]) + { + if (String[i] == C) + { + Result = i; + } + i++; + } + return Result; +} internal s64 FindLast(gs_const_string String, u64 StartIndex, char C) { diff --git a/src/gs_libs/gs_types.h b/src/gs_libs/gs_types.h index 792f2de..243f51b 100644 --- a/src/gs_libs/gs_types.h +++ b/src/gs_libs/gs_types.h @@ -232,7 +232,7 @@ struct u64_array # define InvalidDefaultCase default: { AssertBreak("invalid default case"); } break; # define StaticAssert(c) \ enum { \ - Glue(gs_AssertFail_, __LINE__) = 1 / (int)(!!(c)), \ +Glue(gs_AssertFail_, __LINE__) = 1 / (int)(!!(c)), \ } #else # define Assert(c) @@ -560,7 +560,7 @@ struct gs_const_string_array { gs_const_string* Strings; u64 Count; - u64 Used; + u64 CountMax; }; struct gs_string_array @@ -579,6 +579,27 @@ CStringLength(char* Str) return Result; } +internal bool +CStringsEqual(char* A, char* B) +{ + bool Result = true; + + char* AAt = A; + char* BAt = B; + while (AAt[0] && BAt[0]) + { + if (AAt[0] != BAt[0]) + { + Result = false; + break; + } + AAt++; + BAt++; + } + if (AAt[0] != 0 || BAt[0] != 0) { Result = false; } + return Result; +} + #define StringExpand(str) (int)(str).Length, (str).Str #define LitString(cstr) gs_const_string{(char*)(cstr), CStringLength((char*)cstr) } diff --git a/src/serial_monitor/first.cpp b/src/serial_monitor/first.cpp index 1f0c6d6..4ef8ccc 100644 --- a/src/serial_monitor/first.cpp +++ b/src/serial_monitor/first.cpp @@ -93,7 +93,7 @@ int main(int ArgCount, char** Args) { gs_thread_context Ctx = Win32CreateThreadContext(); - HANDLE SerialHandle = Win32SerialPort_Open("\\\\.\\COM9"); + HANDLE SerialHandle = Win32SerialPort_Open("\\\\.\\COM9", Ctx.Transient); Win32SerialPort_SetState(SerialHandle, 2000000, 8, 0, 1); gs_const_string OutFileName = ConstString("./serial_dump.data");