From 3140ff3fe6188927171c7e6c1d58bacab5f73666 Mon Sep 17 00:00:00 2001 From: Peter Slattery Date: Mon, 22 Mar 2021 20:58:52 -0700 Subject: [PATCH] Some pattern work, added a way to identify what COM ports are available on windows, implemented multithreading patterns, and added a path to turn all the lights off on shutdown --- build/build_app_msvc_win32_debug.bat | 4 +- src/app/engine/animation/foldhaus_animation.h | 2 +- .../animation/foldhaus_animation_renderer.cpp | 79 +++++++++- src/app/engine/assembly/foldhaus_assembly.h | 12 ++ src/app/foldhaus_app.cpp | 35 +++-- src/app/foldhaus_platform.h | 2 +- src/app/patterns/blumen_patterns.h | 135 +++++++++--------- src/app/platform_win32/win32_foldhaus.cpp | 63 ++++---- .../platform_win32/win32_foldhaus_serial.h | 76 ++++++++-- src/app/ss_blumen_lumen/blumen_lumen.cpp | 3 + src/gs_libs/gs_types.cpp | 19 +++ src/gs_libs/gs_types.h | 25 +++- src/serial_monitor/first.cpp | 2 +- 13 files changed, 329 insertions(+), 128 deletions(-) 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/engine/animation/foldhaus_animation.h b/src/app/engine/animation/foldhaus_animation.h index 33d466a..30c0589 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 diff --git a/src/app/engine/animation/foldhaus_animation_renderer.cpp b/src/app/engine/animation/foldhaus_animation_renderer.cpp index 16072ad..a22c417 100644 --- a/src/app/engine/animation/foldhaus_animation_renderer.cpp +++ b/src/app/engine/animation/foldhaus_animation_renderer.cpp @@ -89,14 +89,71 @@ 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); + +#if MULTITHREAD_PATTERN_RENDERING + 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 Pattern.Proc(Buffer, PatternArgs.Assembly, SecondsIntoBlock, PatternArgs.Transient, PatternArgs.UserData); +#endif +} + +internal void +AnimationSystem_EndRenderBlockToLedBuffer (context Context) +{ +#if MULTITHREAD_PATTERN_RENDERING + Context.GeneralWorkQueue->CompleteQueueWork(Context.GeneralWorkQueue, Context.ThreadContext); +#endif } // NOTE(pjs): This mirrors animation_layer_frame to account @@ -114,7 +171,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 +202,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(Context); } // Blend together any layers that have a hot and next hot buffer @@ -193,8 +253,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 +294,8 @@ AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Asse FromLayerBuffers, AssemblyLedBuffer, Patterns, - Transient); + Transient, + Context); led_buffer ConsolidatedBuffer = FromBuffer; if (ToAnim) { @@ -241,7 +305,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/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..a0d46e6 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,35 @@ 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; } #define BLUMEN_PATTERNS_H diff --git a/src/app/platform_win32/win32_foldhaus.cpp b/src/app/platform_win32/win32_foldhaus.cpp index 7edec1e..b9db4c6 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)) @@ -525,6 +525,37 @@ SetWorkingDirectory(HINSTANCE HInstance, gs_thread_context ThreadContext) #include "../../gs_libs/gs_path.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, @@ -689,31 +720,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); @@ -741,7 +748,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..2a0e150 100644 --- a/src/app/ss_blumen_lumen/blumen_lumen.cpp +++ b/src/app/ss_blumen_lumen/blumen_lumen.cpp @@ -133,8 +133,11 @@ BlumenLumen_LoadPatterns(app_state* State) Patterns_PushPattern(Patterns, Pattern_FlowerColorToWhite); Patterns_PushPattern(Patterns, Pattern_BasicFlowers); // 15 + Patterns_PushPattern(Patterns, Pattern_Wavy); Patterns_PushPattern(Patterns, Pattern_Patchy); Patterns_PushPattern(Patterns, Pattern_Leafy); + Patterns_PushPattern(Patterns, Pattern_LeafyPatchy); + Patterns_PushPattern(Patterns, Pattern_WavyPatchy); } internal v4 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");