on frames with overlapping blocks, the blocks are blended together
This commit is contained in:
parent
a6c8d0c955
commit
5e6ac25490
|
@ -88,8 +88,12 @@ struct animation_array
|
|||
struct animation_layer_frame
|
||||
{
|
||||
animation_block Hot;
|
||||
bool HasHot;
|
||||
|
||||
animation_block NextHot;
|
||||
bool HasNextHot;
|
||||
|
||||
r32 HotOpacity;
|
||||
};
|
||||
|
||||
// NOTE(pjs): This is an evaluated frame - across all layers in an
|
||||
|
@ -97,9 +101,7 @@ struct animation_layer_frame
|
|||
struct animation_frame
|
||||
{
|
||||
animation_layer_frame* Layers;
|
||||
b8* LayersFilled;
|
||||
u32 LayersCount;
|
||||
u32 LayersCountMax;
|
||||
|
||||
// NOTE(pjs): These are all parallel arrays of equal length
|
||||
animation_block* Blocks;
|
||||
|
@ -438,6 +440,10 @@ AnimationSystem_CalculateAnimationFrame(animation_system* System, gs_memory_aren
|
|||
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(System);
|
||||
|
||||
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.Blocks = PushArray(Arena, animation_block, 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))
|
||||
{
|
||||
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.Blocks[Block.Layer] = Block;
|
||||
Result.BlocksCount++;
|
||||
|
|
|
@ -11,6 +11,18 @@ LedBlend_Overwrite(pixel PixelA, pixel 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
|
||||
LedBlend_Add(pixel PixelA, pixel PixelB)
|
||||
{
|
||||
|
@ -68,6 +80,18 @@ LedBlend_GetProc(blend_mode BlendMode)
|
|||
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
|
||||
AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Assemblies,
|
||||
led_system* LedSystem,
|
||||
|
@ -80,7 +104,15 @@ AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Asse
|
|||
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(System);
|
||||
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++)
|
||||
{
|
||||
|
@ -88,32 +120,61 @@ AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Asse
|
|||
led_buffer* AssemblyLedBuffer = LedSystemGetBuffer(LedSystem, Assembly->LedBufferIndex);
|
||||
|
||||
// Create the LayerLEDBuffers
|
||||
for (u32 Layer = 0; Layer < CurrFrame.BlocksCountMax; Layer++)
|
||||
for (u32 Layer = 0; Layer < CurrFrame.LayersCount; Layer++)
|
||||
{
|
||||
led_buffer TempBuffer = {};
|
||||
TempBuffer.LedCount = AssemblyLedBuffer->LedCount;
|
||||
TempBuffer.Positions = AssemblyLedBuffer->Positions;
|
||||
TempBuffer.Colors = PushArray(Transient, pixel, TempBuffer.LedCount);
|
||||
LedBuffer_ClearToBlack(&TempBuffer);
|
||||
layer_led_buffer TempBuffer = {};
|
||||
if (CurrFrame.Layers[Layer].HasHot)
|
||||
{
|
||||
TempBuffer.HotBuffer.LedCount = AssemblyLedBuffer->LedCount;
|
||||
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
|
||||
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; }
|
||||
animation_block Block = CurrFrame.Blocks[Layer];
|
||||
|
||||
u32 FramesIntoBlock = CurrentFrame - Block.Range.Min;
|
||||
r32 SecondsIntoBlock = FramesIntoBlock * System->SecondsPerFrame;
|
||||
|
||||
// :AnimProcHandle
|
||||
u32 AnimationProcIndex = Block.AnimationProcHandle - 1;
|
||||
animation_proc* AnimationProc = Patterns[AnimationProcIndex].Proc;
|
||||
AnimationProc(&TempBuffer, *Assembly, SecondsIntoBlock, Transient);
|
||||
if (LayerFrame.HasNextHot)
|
||||
{
|
||||
led_buffer TempBuffer = LayerBuffers[Layer].NextHotBuffer;
|
||||
animation_block Block = LayerFrame.NextHot;
|
||||
AnimationSystem_RenderBlockToLedBuffer(System, Block, &TempBuffer, *Assembly, Patterns, Transient);
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
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
|
||||
|
@ -127,7 +188,7 @@ AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Asse
|
|||
for (u32 LED = 0; LED < AssemblyLedBuffer->LedCount; 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
internal void
|
||||
|
@ -210,11 +221,12 @@ EndCurrentOperationMode(app_state* State)
|
|||
DeactivateCurrentOperationMode(&State->Modes);
|
||||
}
|
||||
|
||||
s32 GlobalAnimationPatternsCount = 3;
|
||||
s32 GlobalAnimationPatternsCount = 4;
|
||||
animation_pattern GlobalAnimationPatterns[] = {
|
||||
{ "Test Pattern One", 16, TestPatternOne },
|
||||
{ "Test Pattern Two", 16, TestPatternTwo },
|
||||
{ "Test Pattern Three", 18, TestPatternThree },
|
||||
{ "Pattern_AllGreen", 16, Pattern_AllGreen },
|
||||
};
|
||||
|
||||
#include "editor/panels/foldhaus_panel_types.h"
|
||||
|
|
Loading…
Reference in New Issue