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.

This commit is contained in:
Peter Slattery 2021-03-22 22:36:33 -07:00
parent 3140ff3fe6
commit 4d0d916d97
7 changed files with 174 additions and 67 deletions

View File

@ -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)

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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++)
{