on frames with overlapping blocks, the blocks are blended together

This commit is contained in:
PS 2020-11-14 13:41:27 -08:00
parent a6c8d0c955
commit 5e6ac25490
3 changed files with 136 additions and 24 deletions

View File

@ -88,8 +88,12 @@ struct animation_array
struct animation_layer_frame struct animation_layer_frame
{ {
animation_block Hot; animation_block Hot;
bool HasHot;
animation_block NextHot; animation_block NextHot;
bool HasNextHot; bool HasNextHot;
r32 HotOpacity;
}; };
// NOTE(pjs): This is an evaluated frame - across all layers in an // NOTE(pjs): This is an evaluated frame - across all layers in an
@ -97,9 +101,7 @@ struct animation_layer_frame
struct animation_frame struct animation_frame
{ {
animation_layer_frame* Layers; animation_layer_frame* Layers;
b8* LayersFilled;
u32 LayersCount; u32 LayersCount;
u32 LayersCountMax;
// NOTE(pjs): These are all parallel arrays of equal length // NOTE(pjs): These are all parallel arrays of equal length
animation_block* Blocks; animation_block* Blocks;
@ -438,6 +440,10 @@ AnimationSystem_CalculateAnimationFrame(animation_system* System, gs_memory_aren
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(System); animation* ActiveAnim = AnimationSystem_GetActiveAnimation(System);
animation_frame Result = {0}; animation_frame Result = {0};
Result.LayersCount = ActiveAnim->Layers.Count;
Result.Layers = PushArray(Arena, animation_layer_frame, Result.LayersCount);
ZeroArray(Result.Layers, animation_frame, Result.LayersCount);
Result.BlocksCountMax = ActiveAnim->Layers.Count; Result.BlocksCountMax = ActiveAnim->Layers.Count;
Result.Blocks = PushArray(Arena, animation_block, Result.BlocksCountMax); Result.Blocks = PushArray(Arena, animation_block, Result.BlocksCountMax);
Result.BlocksFilled = PushArray(Arena, b8, Result.BlocksCountMax); Result.BlocksFilled = PushArray(Arena, b8, Result.BlocksCountMax);
@ -449,6 +455,39 @@ AnimationSystem_CalculateAnimationFrame(animation_system* System, gs_memory_aren
if (FrameIsInRange(Block.Range, System->CurrentFrame)) if (FrameIsInRange(Block.Range, System->CurrentFrame))
{ {
animation_layer_frame* Layer = Result.Layers + Block.Layer;
if (Layer->HasHot)
{
// NOTE(pjs): With current implementation, we don't allow
// animations to hvae more than 2 concurrent blocks in the
// timeline
Assert(!Layer->HasNextHot);
// NOTE(pjs): Make sure that Hot comes before NextHot
if (Layer->Hot.Range.Min < Block.Range.Min)
{
Layer->NextHot = Block;
}
else
{
Layer->NextHot = Layer->Hot;
Layer->Hot = Block;
}
Layer->HasNextHot = true;
frame_range BlendRange = {};
BlendRange.Min = Layer->NextHot.Range.Min;
BlendRange.Max = Layer->Hot.Range.Max;
Layer->HotOpacity = 1.0f - FrameToPercentRange(System->CurrentFrame, BlendRange);
}
else
{
Layer->Hot = Block;
Layer->HotOpacity = 1.0f;
Layer->HasHot = true;
}
// TODO(pjs): Get rid of these fields, they're redundant now
Result.BlocksFilled[Block.Layer] = true; Result.BlocksFilled[Block.Layer] = true;
Result.Blocks[Block.Layer] = Block; Result.Blocks[Block.Layer] = Block;
Result.BlocksCount++; Result.BlocksCount++;

View File

@ -11,6 +11,18 @@ LedBlend_Overwrite(pixel PixelA, pixel PixelB)
return PixelB; return PixelB;
} }
internal pixel
LedBlend_Overwrite(pixel PixelA, pixel PixelB, r32 Opacity)
{
pixel Result = {};
r32 BOpacity = 1.0f - Opacity;
Result.R = (u8)((PixelA.R * Opacity) + (PixelB.R * BOpacity));
Result.G = (u8)((PixelA.G * Opacity) + (PixelB.G * BOpacity));
Result.B = (u8)((PixelA.B * Opacity) + (PixelB.B * BOpacity));
return Result;
}
internal pixel internal pixel
LedBlend_Add(pixel PixelA, pixel PixelB) LedBlend_Add(pixel PixelA, pixel PixelB)
{ {
@ -68,6 +80,18 @@ LedBlend_GetProc(blend_mode BlendMode)
return Result; return Result;
} }
internal void
AnimationSystem_RenderBlockToLedBuffer(animation_system* System, animation_block Block, led_buffer* Buffer, assembly Assembly, animation_pattern* Patterns, gs_memory_arena* Transient)
{
u32 FramesIntoBlock = System->CurrentFrame - Block.Range.Min;
r32 SecondsIntoBlock = FramesIntoBlock * System->SecondsPerFrame;
// :AnimProcHandle
u32 AnimationProcIndex = Block.AnimationProcHandle - 1;
animation_proc* AnimationProc = Patterns[AnimationProcIndex].Proc;
AnimationProc(Buffer, Assembly, SecondsIntoBlock, Transient);
}
internal void internal void
AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Assemblies, AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Assemblies,
led_system* LedSystem, led_system* LedSystem,
@ -80,7 +104,15 @@ AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Asse
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(System); animation* ActiveAnim = AnimationSystem_GetActiveAnimation(System);
animation_frame CurrFrame = AnimationSystem_CalculateAnimationFrame(System, Transient); animation_frame CurrFrame = AnimationSystem_CalculateAnimationFrame(System, Transient);
led_buffer* LayerLedBuffers = PushArray(Transient, led_buffer, CurrFrame.BlocksCountMax); // NOTE(pjs): This mirrors animation_layer_frame to account
// for overlapping
struct layer_led_buffer
{
led_buffer HotBuffer;
led_buffer NextHotBuffer;
};
layer_led_buffer* LayerBuffers = PushArray(Transient, layer_led_buffer, CurrFrame.LayersCount);
for (u32 AssemblyIndex = 0; AssemblyIndex < Assemblies.Count; AssemblyIndex++) for (u32 AssemblyIndex = 0; AssemblyIndex < Assemblies.Count; AssemblyIndex++)
{ {
@ -88,32 +120,61 @@ AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Asse
led_buffer* AssemblyLedBuffer = LedSystemGetBuffer(LedSystem, Assembly->LedBufferIndex); led_buffer* AssemblyLedBuffer = LedSystemGetBuffer(LedSystem, Assembly->LedBufferIndex);
// Create the LayerLEDBuffers // Create the LayerLEDBuffers
for (u32 Layer = 0; Layer < CurrFrame.BlocksCountMax; Layer++) for (u32 Layer = 0; Layer < CurrFrame.LayersCount; Layer++)
{ {
led_buffer TempBuffer = {}; layer_led_buffer TempBuffer = {};
TempBuffer.LedCount = AssemblyLedBuffer->LedCount; if (CurrFrame.Layers[Layer].HasHot)
TempBuffer.Positions = AssemblyLedBuffer->Positions; {
TempBuffer.Colors = PushArray(Transient, pixel, TempBuffer.LedCount); TempBuffer.HotBuffer.LedCount = AssemblyLedBuffer->LedCount;
LedBuffer_ClearToBlack(&TempBuffer); TempBuffer.HotBuffer.Positions = AssemblyLedBuffer->Positions;
TempBuffer.HotBuffer.Colors = PushArray(Transient, pixel, TempBuffer.HotBuffer.LedCount);
LedBuffer_ClearToBlack(&TempBuffer.HotBuffer);
}
LayerLedBuffers[Layer] = TempBuffer; if (CurrFrame.Layers[Layer].HasNextHot)
{
TempBuffer.NextHotBuffer.LedCount = AssemblyLedBuffer->LedCount;
TempBuffer.NextHotBuffer.Positions = AssemblyLedBuffer->Positions;
TempBuffer.NextHotBuffer.Colors = PushArray(Transient, pixel, TempBuffer.HotBuffer.LedCount);
LedBuffer_ClearToBlack(&TempBuffer.NextHotBuffer);
}
LayerBuffers[Layer] = TempBuffer;
} }
// Render Each layer's block to the appropriate temp buffer // Render Each layer's block to the appropriate temp buffer
for (u32 Layer = 0; Layer < CurrFrame.BlocksCountMax; Layer++) for (u32 Layer = 0; Layer < CurrFrame.LayersCount; Layer++)
{ {
led_buffer TempBuffer = LayerLedBuffers[Layer]; animation_layer_frame LayerFrame = CurrFrame.Layers[Layer];
if (LayerFrame.HasHot)
{
led_buffer TempBuffer = LayerBuffers[Layer].HotBuffer;
animation_block Block = LayerFrame.Hot;
AnimationSystem_RenderBlockToLedBuffer(System, Block, &TempBuffer, *Assembly, Patterns, Transient);
}
if (!CurrFrame.BlocksFilled[Layer]) { continue; } if (LayerFrame.HasNextHot)
animation_block Block = CurrFrame.Blocks[Layer]; {
led_buffer TempBuffer = LayerBuffers[Layer].NextHotBuffer;
animation_block Block = LayerFrame.NextHot;
AnimationSystem_RenderBlockToLedBuffer(System, Block, &TempBuffer, *Assembly, Patterns, Transient);
}
}
u32 FramesIntoBlock = CurrentFrame - Block.Range.Min; // Blend together any layers that have a hot and next hot buffer
r32 SecondsIntoBlock = FramesIntoBlock * System->SecondsPerFrame; for (u32 Layer = 0; Layer < CurrFrame.LayersCount; Layer++)
{
// :AnimProcHandle animation_layer_frame LayerFrame = CurrFrame.Layers[Layer];
u32 AnimationProcIndex = Block.AnimationProcHandle - 1; layer_led_buffer LayerBuffer = LayerBuffers[Layer];
animation_proc* AnimationProc = Patterns[AnimationProcIndex].Proc; if (LayerFrame.HasNextHot)
AnimationProc(&TempBuffer, *Assembly, SecondsIntoBlock, Transient); {
for (u32 LED = 0; LED < AssemblyLedBuffer->LedCount; LED++)
{
pixel A = LayerBuffer.HotBuffer.Colors[LED];
pixel B = LayerBuffer.NextHotBuffer.Colors[LED];
LayerBuffer.HotBuffer.Colors[LED] = LedBlend_Overwrite(A, B, LayerFrame.HotOpacity);
}
}
} }
// Consolidate Temp Buffers // Consolidate Temp Buffers
@ -127,7 +188,7 @@ AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Asse
for (u32 LED = 0; LED < AssemblyLedBuffer->LedCount; LED++) for (u32 LED = 0; LED < AssemblyLedBuffer->LedCount; LED++)
{ {
pixel A = AssemblyLedBuffer->Colors[LED]; pixel A = AssemblyLedBuffer->Colors[LED];
pixel B = LayerLedBuffers[Layer].Colors[LED]; pixel B = LayerBuffers[Layer].HotBuffer.Colors[LED];
AssemblyLedBuffer->Colors[LED] = Blend(A, B); AssemblyLedBuffer->Colors[LED] = Blend(A, B);
} }
} }

View File

@ -202,6 +202,17 @@ TestPatternThree(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)
{
for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++)
{
Leds->Colors[LedIndex].R = 0;
Leds->Colors[LedIndex].B = 255;
Leds->Colors[LedIndex].G = 255;
}
}
// END TEMPORARY PATTERNS // END TEMPORARY PATTERNS
internal void internal void
@ -210,11 +221,12 @@ EndCurrentOperationMode(app_state* State)
DeactivateCurrentOperationMode(&State->Modes); DeactivateCurrentOperationMode(&State->Modes);
} }
s32 GlobalAnimationPatternsCount = 3; s32 GlobalAnimationPatternsCount = 4;
animation_pattern GlobalAnimationPatterns[] = { animation_pattern GlobalAnimationPatterns[] = {
{ "Test Pattern One", 16, TestPatternOne }, { "Test Pattern One", 16, TestPatternOne },
{ "Test Pattern Two", 16, TestPatternTwo }, { "Test Pattern Two", 16, TestPatternTwo },
{ "Test Pattern Three", 18, TestPatternThree }, { "Test Pattern Three", 18, TestPatternThree },
{ "Pattern_AllGreen", 16, Pattern_AllGreen },
}; };
#include "editor/panels/foldhaus_panel_types.h" #include "editor/panels/foldhaus_panel_types.h"