2020-11-14 20:19:36 +00:00
|
|
|
//
|
|
|
|
// File: foldhaus_animation_renderer.cpp
|
|
|
|
// Author: Peter Slattery
|
|
|
|
// Creation Date: 2020-11-14
|
|
|
|
//
|
|
|
|
#ifndef FOLDHAUS_ANIMATION_RENDERER_CPP
|
|
|
|
|
|
|
|
internal pixel
|
2021-03-18 05:15:37 +00:00
|
|
|
LedBlend_Overwrite(pixel PixelA, pixel PixelB, u8* UserData)
|
2020-11-14 20:19:36 +00:00
|
|
|
{
|
|
|
|
return PixelB;
|
|
|
|
}
|
|
|
|
|
2020-11-14 21:41:27 +00:00
|
|
|
internal pixel
|
2021-03-18 05:15:37 +00:00
|
|
|
LedBlend_Lerp(pixel PixelA, pixel PixelB, u8* UserData)
|
2020-11-14 21:41:27 +00:00
|
|
|
{
|
2021-03-18 05:15:37 +00:00
|
|
|
r32 BOpacity = *(r32*)UserData;
|
|
|
|
|
2020-11-14 21:41:27 +00:00
|
|
|
pixel Result = {};
|
|
|
|
|
2021-03-18 05:15:37 +00:00
|
|
|
r32 AOpacity = 1.0f - BOpacity;
|
|
|
|
Result.R = (u8)((PixelA.R * AOpacity) + (PixelB.R * BOpacity));
|
|
|
|
Result.G = (u8)((PixelA.G * AOpacity) + (PixelB.G * BOpacity));
|
|
|
|
Result.B = (u8)((PixelA.B * AOpacity) + (PixelB.B * BOpacity));
|
2020-11-14 21:41:27 +00:00
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2020-11-14 20:19:36 +00:00
|
|
|
internal pixel
|
2021-03-18 05:15:37 +00:00
|
|
|
LedBlend_Add(pixel PixelA, pixel PixelB, u8* UserData)
|
2020-11-14 20:19:36 +00:00
|
|
|
{
|
|
|
|
pixel Result = {};
|
|
|
|
|
|
|
|
u32 R = (u32)PixelA.R + (u32)PixelB.R;
|
|
|
|
u32 G = (u32)PixelA.G + (u32)PixelB.G;
|
|
|
|
u32 B = (u32)PixelA.B + (u32)PixelB.B;
|
|
|
|
|
|
|
|
Result.R = (u8)Min(R, (u32)255);
|
|
|
|
Result.G = (u8)Min(G, (u32)255);
|
|
|
|
Result.B = (u8)Min(B, (u32)255);
|
|
|
|
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal pixel
|
2021-03-18 05:15:37 +00:00
|
|
|
LedBlend_Multiply(pixel PixelA, pixel PixelB, u8* UserData)
|
2020-11-14 20:19:36 +00:00
|
|
|
{
|
|
|
|
pixel Result = {};
|
|
|
|
|
|
|
|
r32 DR = (r32)PixelA.R / 255.f;
|
|
|
|
r32 DG = (r32)PixelA.G / 255.f;
|
|
|
|
r32 DB = (r32)PixelA.B / 255.f;
|
|
|
|
|
|
|
|
r32 SR = (r32)PixelB.R / 255.f;
|
|
|
|
r32 SG = (r32)PixelB.G / 255.f;
|
|
|
|
r32 SB = (r32)PixelB.B / 255.f;
|
|
|
|
|
|
|
|
Result.R = (u8)((DR * SR) * 255.f);
|
|
|
|
Result.G = (u8)((DG * SG) * 255.f);
|
|
|
|
Result.B = (u8)((DB * SB) * 255.f);
|
|
|
|
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal pixel
|
2021-03-18 05:15:37 +00:00
|
|
|
LedBlend_Overlay(pixel PixelA, pixel PixelB, u8* UserData)
|
2020-11-14 20:19:36 +00:00
|
|
|
{
|
|
|
|
pixel Result = {};
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal led_blend_proc*
|
|
|
|
LedBlend_GetProc(blend_mode BlendMode)
|
|
|
|
{
|
|
|
|
led_blend_proc* Result = 0;
|
|
|
|
switch (BlendMode)
|
|
|
|
{
|
|
|
|
case BlendMode_Overwrite: { Result = LedBlend_Overwrite; }break;
|
|
|
|
case BlendMode_Add: { Result = LedBlend_Add; }break;
|
|
|
|
case BlendMode_Multiply: { Result = LedBlend_Multiply; }break;
|
|
|
|
InvalidDefaultCase;
|
|
|
|
}
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2021-03-18 05:15:37 +00:00
|
|
|
struct pattern_args
|
|
|
|
{
|
|
|
|
assembly Assembly;
|
|
|
|
gs_memory_arena* Transient;
|
|
|
|
u8* UserData;
|
|
|
|
};
|
|
|
|
|
2021-03-23 03:58:52 +00:00
|
|
|
struct render_anim_to_led_buffer_job_data
|
|
|
|
{
|
|
|
|
animation_pattern Pattern;
|
|
|
|
led_buffer Buffer;
|
|
|
|
led_buffer_range BufferRange;
|
|
|
|
pattern_args PatternArgs;
|
|
|
|
r32 SecondsIntoBlock;
|
|
|
|
};
|
|
|
|
|
2020-11-14 21:41:27 +00:00
|
|
|
internal void
|
2021-03-23 03:58:52 +00:00
|
|
|
AnimationSystem_RenderAnimationToLedBufferJob(gs_thread_context Context, gs_data Data)
|
2020-11-14 21:41:27 +00:00
|
|
|
{
|
2021-03-23 03:58:52 +00:00
|
|
|
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;
|
|
|
|
|
2020-11-14 21:41:27 +00:00
|
|
|
u32 FramesIntoBlock = System->CurrentFrame - Block.Range.Min;
|
|
|
|
r32 SecondsIntoBlock = FramesIntoBlock * System->SecondsPerFrame;
|
|
|
|
|
2021-01-11 00:25:35 +00:00
|
|
|
animation_pattern Pattern = Patterns_GetPattern(Patterns, Block.AnimationProcHandle);
|
2021-03-23 03:58:52 +00:00
|
|
|
|
2021-03-23 05:36:33 +00:00
|
|
|
if (System->Multithreaded && Pattern.Multithreaded)
|
2021-03-23 03:58:52 +00:00
|
|
|
{
|
2021-03-23 05:36:33 +00:00
|
|
|
u32 JobsCount = 4;
|
|
|
|
u32 LedsPerJob = Buffer->LedCount / JobsCount;
|
2021-03-23 03:58:52 +00:00
|
|
|
|
2021-03-23 05:36:33 +00:00
|
|
|
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);
|
2021-03-23 03:58:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void
|
2021-03-23 05:36:33 +00:00
|
|
|
AnimationSystem_EndRenderBlockToLedBuffer (animation_system* System, context Context)
|
2021-03-23 03:58:52 +00:00
|
|
|
{
|
2021-03-23 05:36:33 +00:00
|
|
|
if (System->Multithreaded)
|
|
|
|
{
|
|
|
|
Context.GeneralWorkQueue->CompleteQueueWork(Context.GeneralWorkQueue, Context.ThreadContext);
|
|
|
|
}
|
2021-03-18 05:15:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NOTE(pjs): This mirrors animation_layer_frame to account
|
|
|
|
// for overlapping
|
|
|
|
struct layer_led_buffer
|
|
|
|
{
|
|
|
|
led_buffer HotBuffer;
|
|
|
|
led_buffer NextHotBuffer;
|
|
|
|
};
|
|
|
|
|
|
|
|
internal led_buffer
|
|
|
|
RenderAnimationToLedBuffer (animation_system* System,
|
|
|
|
pattern_args PatternArgs,
|
|
|
|
animation_frame CurrFrame,
|
|
|
|
layer_led_buffer* LayerBuffers,
|
|
|
|
led_buffer* AssemblyLedBuffer,
|
|
|
|
animation_pattern_array Patterns,
|
2021-03-23 03:58:52 +00:00
|
|
|
gs_memory_arena* Transient,
|
|
|
|
context Context)
|
2021-03-18 05:15:37 +00:00
|
|
|
{
|
|
|
|
led_buffer AccBuffer = LedBuffer_CreateCopyCleared(*AssemblyLedBuffer, Transient);
|
|
|
|
|
|
|
|
// Create the LayerLEDBuffers
|
|
|
|
for (u32 Layer = 0; Layer < CurrFrame.LayersCount; Layer++)
|
|
|
|
{
|
|
|
|
layer_led_buffer TempBuffer = {};
|
|
|
|
|
|
|
|
if (CurrFrame.Layers[Layer].HasHot)
|
|
|
|
{
|
|
|
|
TempBuffer.HotBuffer = LedBuffer_CreateCopyCleared(*AssemblyLedBuffer, Transient);
|
|
|
|
|
|
|
|
if (CurrFrame.Layers[Layer].HasNextHot)
|
|
|
|
{
|
|
|
|
TempBuffer.NextHotBuffer = LedBuffer_CreateCopyCleared(*AssemblyLedBuffer, Transient);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
LayerBuffers[Layer] = TempBuffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Render Each layer's block to the appropriate temp buffer
|
|
|
|
for (u32 Layer = 0; Layer < CurrFrame.LayersCount; Layer++)
|
|
|
|
{
|
|
|
|
animation_layer_frame LayerFrame = CurrFrame.Layers[Layer];
|
|
|
|
if (LayerFrame.HasHot)
|
|
|
|
{
|
|
|
|
led_buffer TempBuffer = LayerBuffers[Layer].HotBuffer;
|
|
|
|
animation_block Block = LayerFrame.Hot;
|
2021-03-23 03:58:52 +00:00
|
|
|
AnimationSystem_BeginRenderBlockToLedBuffer(System, Block, &TempBuffer, Patterns, PatternArgs, Context);
|
2021-03-18 05:15:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (LayerFrame.HasNextHot)
|
|
|
|
{
|
|
|
|
led_buffer TempBuffer = LayerBuffers[Layer].NextHotBuffer;
|
|
|
|
animation_block Block = LayerFrame.NextHot;
|
2021-03-23 03:58:52 +00:00
|
|
|
AnimationSystem_BeginRenderBlockToLedBuffer(System, Block, &TempBuffer, Patterns, PatternArgs, Context);
|
2021-03-18 05:15:37 +00:00
|
|
|
}
|
2021-03-23 03:58:52 +00:00
|
|
|
|
2021-03-23 05:36:33 +00:00
|
|
|
AnimationSystem_EndRenderBlockToLedBuffer(System, Context);
|
2021-03-18 05:15:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Blend together any layers that have a hot and next hot buffer
|
|
|
|
for (u32 Layer = 0; Layer < CurrFrame.LayersCount; Layer++)
|
|
|
|
{
|
|
|
|
animation_layer_frame LayerFrame = CurrFrame.Layers[Layer];
|
|
|
|
layer_led_buffer LayerBuffer = LayerBuffers[Layer];
|
|
|
|
if (LayerFrame.HasNextHot)
|
|
|
|
{
|
|
|
|
LedBuffer_Blend(LayerBuffer.HotBuffer,
|
|
|
|
LayerBuffer.NextHotBuffer,
|
|
|
|
&LayerBuffer.HotBuffer,
|
|
|
|
LedBlend_Lerp,
|
|
|
|
(u8*)&LayerFrame.NextHotOpacity);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Consolidate Temp Buffers back into AssemblyLedBuffer
|
|
|
|
// We do this in reverse order so that they go from top to bottom
|
|
|
|
for (u32 Layer = 0; Layer < CurrFrame.LayersCount; Layer++)
|
|
|
|
{
|
|
|
|
if (CurrFrame.Layers[Layer].HasHot)
|
|
|
|
{
|
|
|
|
led_blend_proc* Blend = LedBlend_GetProc(CurrFrame.Layers[Layer].BlendMode);
|
|
|
|
LedBuffer_Blend(AccBuffer,
|
|
|
|
LayerBuffers[Layer].HotBuffer,
|
|
|
|
&AccBuffer,
|
|
|
|
Blend,
|
|
|
|
0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return AccBuffer;
|
2020-11-14 21:41:27 +00:00
|
|
|
}
|
|
|
|
|
2020-11-14 20:19:36 +00:00
|
|
|
internal void
|
|
|
|
AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Assemblies,
|
|
|
|
led_system* LedSystem,
|
2021-01-11 00:25:35 +00:00
|
|
|
animation_pattern_array Patterns,
|
2021-01-16 22:02:25 +00:00
|
|
|
gs_memory_arena* Transient,
|
2021-03-23 03:58:52 +00:00
|
|
|
context Context,
|
2021-01-16 22:02:25 +00:00
|
|
|
u8* UserData)
|
2020-11-14 20:19:36 +00:00
|
|
|
{
|
2021-03-23 03:58:52 +00:00
|
|
|
DEBUG_TRACK_FUNCTION;
|
|
|
|
|
2020-11-14 20:19:36 +00:00
|
|
|
s32 CurrentFrame = System->CurrentFrame;
|
|
|
|
r32 FrameTime = CurrentFrame * System->SecondsPerFrame;
|
|
|
|
|
2021-03-18 05:15:37 +00:00
|
|
|
#if 1
|
|
|
|
animation_array Animations = System->Animations;
|
|
|
|
animation_fade_group FadeGroup = System->ActiveFadeGroup;
|
2020-11-14 20:19:36 +00:00
|
|
|
|
2021-03-18 05:15:37 +00:00
|
|
|
animation* FromAnim = AnimationArray_Get(Animations, FadeGroup.From);
|
|
|
|
animation_frame FromFrame = AnimationSystem_CalculateAnimationFrame(System, FromAnim, Transient);
|
|
|
|
layer_led_buffer* FromLayerBuffers = PushArray(Transient, layer_led_buffer, FromFrame.LayersCount);
|
2020-11-14 21:41:27 +00:00
|
|
|
|
2021-03-18 05:15:37 +00:00
|
|
|
animation* ToAnim = AnimationArray_Get(Animations, FadeGroup.To);
|
|
|
|
animation_frame ToFrame = {0};
|
|
|
|
layer_led_buffer* ToLayerBuffers = 0;
|
|
|
|
if (ToAnim)
|
|
|
|
{
|
|
|
|
ToFrame = AnimationSystem_CalculateAnimationFrame(System, ToAnim, Transient);
|
|
|
|
ToLayerBuffers = PushArray(Transient, layer_led_buffer, ToFrame.LayersCount);
|
|
|
|
}
|
2020-11-14 20:47:51 +00:00
|
|
|
|
2020-11-14 20:19:36 +00:00
|
|
|
for (u32 AssemblyIndex = 0; AssemblyIndex < Assemblies.Count; AssemblyIndex++)
|
|
|
|
{
|
2021-03-18 05:15:37 +00:00
|
|
|
assembly Assembly = Assemblies.Values[AssemblyIndex];
|
|
|
|
led_buffer* AssemblyLedBuffer = LedSystemGetBuffer(LedSystem, Assembly.LedBufferIndex);
|
2020-11-14 20:19:36 +00:00
|
|
|
|
2021-03-18 05:15:37 +00:00
|
|
|
pattern_args PatternArgs = {};
|
|
|
|
PatternArgs.Assembly = Assembly;
|
|
|
|
PatternArgs.Transient = Transient;
|
|
|
|
PatternArgs.UserData = UserData;
|
2020-11-14 20:47:51 +00:00
|
|
|
|
2021-03-18 05:15:37 +00:00
|
|
|
led_buffer FromBuffer = RenderAnimationToLedBuffer(System,
|
|
|
|
PatternArgs,
|
|
|
|
FromFrame,
|
|
|
|
FromLayerBuffers,
|
|
|
|
AssemblyLedBuffer,
|
|
|
|
Patterns,
|
2021-03-23 03:58:52 +00:00
|
|
|
Transient,
|
|
|
|
Context);
|
2021-03-18 05:15:37 +00:00
|
|
|
led_buffer ConsolidatedBuffer = FromBuffer;
|
|
|
|
|
|
|
|
if (ToAnim) {
|
|
|
|
led_buffer ToBuffer = RenderAnimationToLedBuffer(System,
|
|
|
|
PatternArgs,
|
|
|
|
ToFrame,
|
|
|
|
ToLayerBuffers,
|
|
|
|
AssemblyLedBuffer,
|
|
|
|
Patterns,
|
2021-03-23 03:58:52 +00:00
|
|
|
Transient,
|
|
|
|
Context);
|
2020-11-14 20:19:36 +00:00
|
|
|
|
2021-03-18 05:15:37 +00:00
|
|
|
r32 BlendPercent = FadeGroup.FadeElapsed / FadeGroup.FadeDuration;
|
|
|
|
LedBuffer_Blend(FromBuffer, ToBuffer, &ConsolidatedBuffer, LedBlend_Lerp, (u8*)&BlendPercent);
|
2020-11-14 21:41:27 +00:00
|
|
|
}
|
|
|
|
|
2021-03-18 05:15:37 +00:00
|
|
|
LedBuffer_Copy(ConsolidatedBuffer, AssemblyLedBuffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(System);
|
|
|
|
animation_frame CurrFrame = AnimationSystem_CalculateAnimationFrame(System, ActiveAnim, Transient);
|
|
|
|
|
|
|
|
for (u32 AssemblyIndex = 0; AssemblyIndex < Assemblies.Count; AssemblyIndex++)
|
|
|
|
{
|
|
|
|
assembly Assembly = Assemblies.Values[AssemblyIndex];
|
|
|
|
led_buffer* AssemblyLedBuffer = LedSystemGetBuffer(LedSystem, Assembly.LedBufferIndex);
|
2020-11-14 20:19:36 +00:00
|
|
|
|
2021-03-18 05:15:37 +00:00
|
|
|
pattern_args PatternArgs = {};
|
|
|
|
PatternArgs.Assembly = Assembly;
|
|
|
|
PatternArgs.Transient = Transient;
|
|
|
|
PatternArgs.UserData = UserData;
|
|
|
|
|
|
|
|
led_buffer AccBuffer = RenderAnimationToLedBuffer(System,
|
|
|
|
PatternArgs,
|
|
|
|
CurrFrame,
|
|
|
|
LayerBuffers,
|
|
|
|
AssemblyLedBuffer,
|
|
|
|
Patterns,
|
|
|
|
Transient);
|
|
|
|
LedBuffer_Copy(AccBuffer, AssemblyLedBuffer);
|
2020-11-14 20:19:36 +00:00
|
|
|
}
|
2021-01-11 08:02:42 +00:00
|
|
|
|
2021-03-18 05:15:37 +00:00
|
|
|
#endif
|
|
|
|
|
2021-01-11 08:02:42 +00:00
|
|
|
System->LastUpdatedFrame = System->CurrentFrame;
|
2020-11-14 20:19:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#define FOLDHAUS_ANIMATION_RENDERER_CPP
|
|
|
|
#endif // FOLDHAUS_ANIMATION_RENDERER_CPP
|