From 4d0d916d97cf83de1fb8beea8ccf408396ec7870 Mon Sep 17 00:00:00 2001 From: Peter Slattery Date: Mon, 22 Mar 2021 22:36:33 -0700 Subject: [PATCH] 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++) {