From 3140ff3fe6188927171c7e6c1d58bacab5f73666 Mon Sep 17 00:00:00 2001 From: Peter Slattery Date: Mon, 22 Mar 2021 20:58:52 -0700 Subject: [PATCH 1/3] 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"); From 4d0d916d97cf83de1fb8beea8ccf408396ec7870 Mon Sep 17 00:00:00 2001 From: Peter Slattery Date: Mon, 22 Mar 2021 22:36:33 -0700 Subject: [PATCH 2/3] More pattern work, fixed a problem where switching animations in the timeline window would overwrite fields of the new animation because the interface was caching the previous interfaces values, and created helpers to load animations from files. --- src/app/editor/interface.h | 23 ++++++++ .../foldhaus_panel_animation_timeline.h | 35 ++++++----- src/app/engine/animation/foldhaus_animation.h | 16 ++++- .../animation/foldhaus_animation_renderer.cpp | 58 +++++++++++-------- .../foldhaus_animation_serializer.cpp | 16 ++++- src/app/patterns/blumen_patterns.h | 35 +++++++++++ src/app/ss_blumen_lumen/blumen_lumen.cpp | 58 +++++++++++-------- 7 files changed, 174 insertions(+), 67 deletions(-) diff --git a/src/app/editor/interface.h b/src/app/editor/interface.h index 6b91bef..f06c16a 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, gs_string Identifier) +{ + gs_string Result = PushStringF(Interface->PerFrameMemory, + Category.Length + Identifier.Length, + "%S%S", + Category.ConstString, + Identifier.ConstString); + 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, gs_string Identifier) +{ + gs_string Name = ui_PushLayoutCategoryName(Interface, Category, Identifier); + return ui_PushLayout(Interface, Bounds, FillDir, Name); +} static ui_widget* ui_PushLayout(ui_interface* Interface, gs_string Name, bool Inset = true) @@ -851,6 +868,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, gs_string Identifier) +{ + gs_string Name = ui_PushLayoutCategoryName(Interface, Category, Identifier); + ui_PopLayout(Interface, Name); +} static ui_widget* ui_BeginRow(ui_interface* Interface, u32 ColumnsMax) diff --git a/src/app/editor/panels/foldhaus_panel_animation_timeline.h b/src/app/editor/panels/foldhaus_panel_animation_timeline.h index 886b1a3..b0b7dcc 100644 --- a/src/app/editor/panels/foldhaus_panel_animation_timeline.h +++ b/src/app/editor/panels/foldhaus_panel_animation_timeline.h @@ -15,6 +15,8 @@ struct animation_timeline_state handle SelectedBlockHandle; animation_handle EditingAnimationHandle; u32 SelectedAnimationLayer; + + animation_handle NextActiveAnim; }; inline u32 @@ -504,13 +506,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; } } @@ -762,11 +761,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 @@ -775,7 +772,7 @@ AnimInfoView_Render(animation_timeline_state* TimelineState, animation* ActiveAn animation_system* AnimSystem = &State->AnimationSystem; ui_interface* Interface = &State->Interface; - ui_PushLayout(Interface, Bounds, LayoutDirection_TopDown, MakeString("AnimInfo Layout")); + ui_PushLayout(Interface, Bounds, LayoutDirection_TopDown, MakeString("AnimInfo Layout"), ActiveAnim->Name); ui_FillRect(&State->Interface, Bounds, Interface->Style.PanelBG); @@ -796,7 +793,7 @@ AnimInfoView_Render(animation_timeline_state* TimelineState, animation* ActiveAn { animation_handle NewHandle = {}; NewHandle.Index = i; - AnimationTimeline_SetActiveAnimation(NewHandle, TimelineState, AnimSystem); + AnimationTimeline_SetActiveAnimation(NewHandle, TimelineState); } } } @@ -899,7 +896,7 @@ AnimInfoView_Render(animation_timeline_state* TimelineState, animation* ActiveAn AnimationTimeline_AddAnimationBlockCommand(TimelineState, State, Context); } } - ui_PopLayout(Interface, MakeString("AnimInfo Layout")); + ui_PopLayout(Interface, MakeString("AnimInfo Layout"), ActiveAnim->Name); } internal void @@ -917,11 +914,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 +942,13 @@ 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; + } } #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 30c0589..12281fe 100644 --- a/src/app/engine/animation/foldhaus_animation.h +++ b/src/app/engine/animation/foldhaus_animation.h @@ -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; } @@ -604,6 +613,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 a22c417..f43184b 100644 --- a/src/app/engine/animation/foldhaus_animation_renderer.cpp +++ b/src/app/engine/animation/foldhaus_animation_renderer.cpp @@ -123,37 +123,45 @@ AnimationSystem_BeginRenderBlockToLedBuffer(animation_system* System, animation_ 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++) + if (System->Multithreaded && Pattern.Multithreaded) { - 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; + u32 JobsCount = 4; + u32 LedsPerJob = Buffer->LedCount / JobsCount; - Context.GeneralWorkQueue->PushWorkOnQueue(Context.GeneralWorkQueue, - (thread_proc*)AnimationSystem_RenderAnimationToLedBufferJob, - Data, - ConstString("Render Pattern To Buffer")); + 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); } -#else - Pattern.Proc(Buffer, PatternArgs.Assembly, SecondsIntoBlock, PatternArgs.Transient, PatternArgs.UserData); -#endif } internal void -AnimationSystem_EndRenderBlockToLedBuffer (context Context) +AnimationSystem_EndRenderBlockToLedBuffer (animation_system* System, context Context) { -#if MULTITHREAD_PATTERN_RENDERING - Context.GeneralWorkQueue->CompleteQueueWork(Context.GeneralWorkQueue, Context.ThreadContext); -#endif + if (System->Multithreaded) + { + Context.GeneralWorkQueue->CompleteQueueWork(Context.GeneralWorkQueue, Context.ThreadContext); + } } // NOTE(pjs): This mirrors animation_layer_frame to account @@ -212,7 +220,7 @@ RenderAnimationToLedBuffer (animation_system* System, AnimationSystem_BeginRenderBlockToLedBuffer(System, Block, &TempBuffer, Patterns, PatternArgs, Context); } - AnimationSystem_EndRenderBlockToLedBuffer(Context); + AnimationSystem_EndRenderBlockToLedBuffer(System, Context); } // Blend together any layers that have a hot and next hot buffer 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/patterns/blumen_patterns.h b/src/app/patterns/blumen_patterns.h index a0d46e6..ee59638 100644 --- a/src/app/patterns/blumen_patterns.h +++ b/src/app/patterns/blumen_patterns.h @@ -1187,6 +1187,41 @@ internal void 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/ss_blumen_lumen/blumen_lumen.cpp b/src/app/ss_blumen_lumen/blumen_lumen.cpp index 2a0e150..29bf6a1 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,28 +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_Wavy); - Patterns_PushPattern(Patterns, Pattern_Patchy); - Patterns_PushPattern(Patterns, Pattern_Leafy); - Patterns_PushPattern(Patterns, Pattern_LeafyPatchy); - Patterns_PushPattern(Patterns, Pattern_WavyPatchy); + 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 @@ -183,6 +186,7 @@ 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"); @@ -216,13 +220,19 @@ BlumenLumen_CustomInit(app_state* State, context Context) Anim2.PlayableRange.Max = SecondsToFrames(15, State->AnimationSystem); Animation_AddLayer(&Anim2, MakeString("Base Layer"), BlendMode_Overwrite, &State->AnimationSystem); - Animation_AddBlock(&Anim2, 0, Anim0.PlayableRange.Max, Patterns_IndexToHandle(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++) { From 0e7596cafc728c73fe78c97451ce43b65617cfa1 Mon Sep 17 00:00:00 2001 From: Peter Slattery Date: Mon, 22 Mar 2021 23:12:55 -0700 Subject: [PATCH 3/3] Implemented masking the inner strips on blumen --- src/app/editor/interface.h | 28 ++++++--- .../foldhaus_panel_animation_timeline.h | 49 +++++++++------ src/app/engine/animation/foldhaus_animation.h | 32 ++++++++++ src/app/ss_blumen_lumen/blumen_lumen.cpp | 61 +++++++++++-------- 4 files changed, 117 insertions(+), 53 deletions(-) diff --git a/src/app/editor/interface.h b/src/app/editor/interface.h index f06c16a..4b4d13e 100644 --- a/src/app/editor/interface.h +++ b/src/app/editor/interface.h @@ -753,13 +753,13 @@ ui_PushOverlayLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction } static gs_string -ui_PushLayoutCategoryName(ui_interface* Interface, gs_string Category, gs_string Identifier) +ui_PushLayoutCategoryName(ui_interface* Interface, gs_string Category, u32 Value) { gs_string Result = PushStringF(Interface->PerFrameMemory, - Category.Length + Identifier.Length, - "%S%S", + Category.Length + 25, + "%S%d", Category.ConstString, - Identifier.ConstString); + Value); return Result; } @@ -782,9 +782,9 @@ ui_PushLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir return Result; } static ui_widget* -ui_PushLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir, gs_string Category, gs_string Identifier) +ui_PushLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir, gs_string Category, u32 Value) { - gs_string Name = ui_PushLayoutCategoryName(Interface, Category, Identifier); + gs_string Name = ui_PushLayoutCategoryName(Interface, Category, Value); return ui_PushLayout(Interface, Bounds, FillDir, Name); } @@ -854,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); @@ -869,9 +878,9 @@ ui_PopLayout(ui_interface* Interface, gs_string LayoutName) } } static void -ui_PopLayout(ui_interface* Interface, gs_string Category, gs_string Identifier) +ui_PopLayout(ui_interface* Interface, gs_string Category, u32 Value) { - gs_string Name = ui_PushLayoutCategoryName(Interface, Category, Identifier); + gs_string Name = ui_PushLayoutCategoryName(Interface, Category, Value); ui_PopLayout(Interface, Name); } @@ -1073,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 b0b7dcc..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,7 @@ struct animation_timeline_state frame_range VisibleRange; handle SelectedBlockHandle; animation_handle EditingAnimationHandle; - u32 SelectedAnimationLayer; + s32 SelectedAnimationLayer; animation_handle NextActiveAnim; }; @@ -265,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); @@ -638,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; @@ -771,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"), ActiveAnim->Name); + ui_PushLayout(Interface, Bounds, LayoutDirection_TopDown, MakeString("AnimInfo Layout"), ActiveAnimHandle.Index); ui_FillRect(&State->Interface, Bounds, Interface->Style.PanelBG); @@ -803,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) @@ -850,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")); @@ -896,7 +906,7 @@ AnimInfoView_Render(animation_timeline_state* TimelineState, animation* ActiveAn AnimationTimeline_AddAnimationBlockCommand(TimelineState, State, Context); } } - ui_PopLayout(Interface, MakeString("AnimInfo Layout"), ActiveAnim->Name); + ui_PopLayout(Interface, MakeString("AnimInfo Layout")); } internal void @@ -948,6 +958,7 @@ AnimationTimeline_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* { State->AnimationSystem.ActiveFadeGroup.From = TimelineState->NextActiveAnim; TimelineState->EditingAnimationHandle = TimelineState->NextActiveAnim; + TimelineState->SelectedAnimationLayer = -1; } } diff --git a/src/app/engine/animation/foldhaus_animation.h b/src/app/engine/animation/foldhaus_animation.h index 12281fe..91204c7 100644 --- a/src/app/engine/animation/foldhaus_animation.h +++ b/src/app/engine/animation/foldhaus_animation.h @@ -419,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) { diff --git a/src/app/ss_blumen_lumen/blumen_lumen.cpp b/src/app/ss_blumen_lumen/blumen_lumen.cpp index 29bf6a1..7361fd4 100644 --- a/src/app/ss_blumen_lumen/blumen_lumen.cpp +++ b/src/app/ss_blumen_lumen/blumen_lumen.cpp @@ -188,40 +188,32 @@ BlumenLumen_CustomInit(app_state* State, context Context) #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(20), 0); - BLState->AnimHandles[2] = AnimationArray_Push(&State->AnimationSystem.Animations, Anim2); State->AnimationSystem.ActiveFadeGroup.From = BLState->AnimHandles[2]; @@ -417,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++) { @@ -430,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