pulled animation update and render functions out of foldhaus_app.cpp
This commit is contained in:
parent
a52d8645e6
commit
708ac91afe
|
@ -14,6 +14,10 @@ struct frame_range
|
||||||
s32 Max;
|
s32 Max;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// NOTE(pjs): An animation block is a time range paired with an
|
||||||
|
// animation_pattern (see below). While a timeline's current time
|
||||||
|
// is within the range of a block, that particular block's animation
|
||||||
|
// will run
|
||||||
struct animation_block
|
struct animation_block
|
||||||
{
|
{
|
||||||
frame_range Range;
|
frame_range Range;
|
||||||
|
@ -37,6 +41,8 @@ enum blend_mode
|
||||||
BlendMode_Count,
|
BlendMode_Count,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef pixel led_blend_proc(pixel PixelA, pixel PixelB);
|
||||||
|
|
||||||
global gs_const_string BlendModeStrings[] = {
|
global gs_const_string BlendModeStrings[] = {
|
||||||
ConstString("Overwrite"),
|
ConstString("Overwrite"),
|
||||||
ConstString("Add"),
|
ConstString("Add"),
|
||||||
|
@ -57,11 +63,15 @@ struct anim_layer_array
|
||||||
u32 CountMax;
|
u32 CountMax;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// NOTE(pjs): An animation is a stack of layers, each of which
|
||||||
|
// is a timeline of animation blocks.
|
||||||
struct animation
|
struct animation
|
||||||
{
|
{
|
||||||
gs_string Name;
|
gs_string Name;
|
||||||
|
|
||||||
anim_layer_array Layers;
|
anim_layer_array Layers;
|
||||||
|
// TODO(pjs): Pretty sure Blocks_ should be obsolete and
|
||||||
|
// Layers should contain their own blocks
|
||||||
animation_block_array Blocks_;
|
animation_block_array Blocks_;
|
||||||
|
|
||||||
frame_range PlayableRange;
|
frame_range PlayableRange;
|
||||||
|
@ -74,6 +84,8 @@ struct animation_array
|
||||||
u32 CountMax;
|
u32 CountMax;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// NOTE(pjs): This is an evaluated frame - across all layers in an
|
||||||
|
// animation, these are the blocks that need to be run
|
||||||
struct animation_frame
|
struct animation_frame
|
||||||
{
|
{
|
||||||
// NOTE(pjs): These are all parallel arrays of equal length
|
// NOTE(pjs): These are all parallel arrays of equal length
|
||||||
|
@ -102,7 +114,9 @@ struct animation_system
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO(pjs): Better name - something like animation_prototype
|
// NOTE(pjs): A Pattern is a named procedure which can be used as
|
||||||
|
// an element of an animation. Patterns are sequenced on a timeline
|
||||||
|
// and blended via layers to create an animation
|
||||||
struct animation_pattern
|
struct animation_pattern
|
||||||
{
|
{
|
||||||
char* Name;
|
char* Name;
|
||||||
|
@ -431,5 +445,29 @@ AnimationSystem_CalculateAnimationFrame(animation_system* System, gs_memory_aren
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
AnimationSystem_Update(animation_system* System)
|
||||||
|
{
|
||||||
|
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(System);
|
||||||
|
if (System->TimelineShouldAdvance) {
|
||||||
|
// TODO(Peter): Revisit this. This implies that the framerate of the animation system
|
||||||
|
// is tied to the framerate of the simulation. That seems correct to me, but I'm not sure
|
||||||
|
System->CurrentFrame += 1;
|
||||||
|
|
||||||
|
// Loop back to the beginning
|
||||||
|
if (System->CurrentFrame > ActiveAnim->PlayableRange.Max)
|
||||||
|
{
|
||||||
|
System->CurrentFrame = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool
|
||||||
|
AnimationSystem_NeedsRender(animation_system System)
|
||||||
|
{
|
||||||
|
bool Result = (System.CurrentFrame != System.LastUpdatedFrame);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
#define FOLDHAUS_ANIMATION
|
#define FOLDHAUS_ANIMATION
|
||||||
#endif // FOLDHAUS_ANIMATION
|
#endif // FOLDHAUS_ANIMATION
|
|
@ -0,0 +1,126 @@
|
||||||
|
//
|
||||||
|
// File: foldhaus_animation_renderer.cpp
|
||||||
|
// Author: Peter Slattery
|
||||||
|
// Creation Date: 2020-11-14
|
||||||
|
//
|
||||||
|
#ifndef FOLDHAUS_ANIMATION_RENDERER_CPP
|
||||||
|
|
||||||
|
internal pixel
|
||||||
|
LedBlend_Overwrite(pixel PixelA, pixel PixelB)
|
||||||
|
{
|
||||||
|
return PixelB;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal pixel
|
||||||
|
LedBlend_Add(pixel PixelA, pixel PixelB)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
LedBlend_Multiply(pixel PixelA, pixel PixelB)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
LedBlend_Overlay(pixel PixelA, pixel PixelB)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
AnimationSystem_RenderToLedBuffers(animation_system* System, assembly_array Assemblies,
|
||||||
|
led_system* LedSystem,
|
||||||
|
animation_pattern* Patterns,
|
||||||
|
gs_memory_arena* Transient)
|
||||||
|
{
|
||||||
|
s32 CurrentFrame = System->CurrentFrame;
|
||||||
|
r32 FrameTime = CurrentFrame * System->SecondsPerFrame;
|
||||||
|
|
||||||
|
animation_frame CurrFrame = AnimationSystem_CalculateAnimationFrame(System, Transient);
|
||||||
|
|
||||||
|
led_buffer* LayerLEDBuffers = PushArray(Transient, led_buffer, CurrFrame.BlocksCountMax);
|
||||||
|
for (u32 AssemblyIndex = 0; AssemblyIndex < Assemblies.Count; AssemblyIndex++)
|
||||||
|
{
|
||||||
|
assembly* Assembly = &Assemblies.Values[AssemblyIndex];
|
||||||
|
led_buffer* AssemblyLedBuffer = LedSystemGetBuffer(LedSystem, Assembly->LedBufferIndex);
|
||||||
|
|
||||||
|
for (u32 Layer = 0; Layer < CurrFrame.BlocksCountMax; Layer++)
|
||||||
|
{
|
||||||
|
if (!CurrFrame.BlocksFilled[Layer]) { continue; }
|
||||||
|
animation_block Block = CurrFrame.Blocks[Layer];
|
||||||
|
|
||||||
|
// Prep Temp Buffer
|
||||||
|
LayerLEDBuffers[Layer] = *AssemblyLedBuffer;
|
||||||
|
LayerLEDBuffers[Layer].Colors = PushArray(Transient, pixel, AssemblyLedBuffer->LedCount);
|
||||||
|
|
||||||
|
u32 FramesIntoBlock = CurrentFrame - Block.Range.Min;
|
||||||
|
r32 SecondsIntoBlock = FramesIntoBlock * System->SecondsPerFrame;
|
||||||
|
|
||||||
|
// :AnimProcHandle
|
||||||
|
u32 AnimationProcIndex = Block.AnimationProcHandle - 1;
|
||||||
|
animation_proc* AnimationProc = Patterns[AnimationProcIndex].Proc;
|
||||||
|
AnimationProc(&LayerLEDBuffers[Layer], *Assembly, SecondsIntoBlock, Transient);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Consolidate Temp Buffers
|
||||||
|
// We do this in reverse order so that they go from top to bottom
|
||||||
|
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(System);
|
||||||
|
for (u32 Layer = 0; Layer < CurrFrame.BlocksCountMax; Layer++)
|
||||||
|
{
|
||||||
|
if (!CurrFrame.BlocksFilled[Layer]) { continue; }
|
||||||
|
|
||||||
|
led_blend_proc* Blend = LedBlend_GetProc(ActiveAnim->Layers.Values[Layer].BlendMode);
|
||||||
|
Assert(Blend != 0);
|
||||||
|
for (u32 LED = 0; LED < AssemblyLedBuffer->LedCount; LED++)
|
||||||
|
{
|
||||||
|
pixel A = AssemblyLedBuffer->Colors[LED];
|
||||||
|
pixel B = LayerLEDBuffers[Layer].Colors[LED];
|
||||||
|
AssemblyLedBuffer->Colors[LED] = Blend(A, B);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define FOLDHAUS_ANIMATION_RENDERER_CPP
|
||||||
|
#endif // FOLDHAUS_ANIMATION_RENDERER_CPP
|
|
@ -168,104 +168,15 @@ UPDATE_AND_RENDER(UpdateAndRender)
|
||||||
|
|
||||||
Editor_Update(State, Context, InputQueue);
|
Editor_Update(State, Context, InputQueue);
|
||||||
|
|
||||||
|
AnimationSystem_Update(&State->AnimationSystem);
|
||||||
|
if (AnimationSystem_NeedsRender(State->AnimationSystem))
|
||||||
{
|
{
|
||||||
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem);
|
State->AnimationSystem.LastUpdatedFrame = State->AnimationSystem.CurrentFrame;
|
||||||
if (State->AnimationSystem.TimelineShouldAdvance) {
|
AnimationSystem_RenderToLedBuffers(&State->AnimationSystem,
|
||||||
// TODO(Peter): Revisit this. This implies that the framerate of the animation system
|
State->Assemblies,
|
||||||
// is tied to the framerate of the simulation. That seems correct to me, but I'm not sure
|
&State->LedSystem,
|
||||||
State->AnimationSystem.CurrentFrame += 1;
|
GlobalAnimationPatterns,
|
||||||
|
State->Transient);
|
||||||
// Loop back to the beginning
|
|
||||||
if (State->AnimationSystem.CurrentFrame > ActiveAnim->PlayableRange.Max)
|
|
||||||
{
|
|
||||||
State->AnimationSystem.CurrentFrame = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
s32 CurrentFrame = State->AnimationSystem.CurrentFrame;
|
|
||||||
if (CurrentFrame != State->AnimationSystem.LastUpdatedFrame)
|
|
||||||
{
|
|
||||||
State->AnimationSystem.LastUpdatedFrame = CurrentFrame;
|
|
||||||
r32 FrameTime = CurrentFrame * State->AnimationSystem.SecondsPerFrame;
|
|
||||||
|
|
||||||
animation_frame CurrFrame = AnimationSystem_CalculateAnimationFrame(&State->AnimationSystem, State->Transient);
|
|
||||||
|
|
||||||
led_buffer* LayerLEDBuffers = PushArray(State->Transient, led_buffer, CurrFrame.BlocksCountMax);
|
|
||||||
for (u32 AssemblyIndex = 0; AssemblyIndex < State->Assemblies.Count; AssemblyIndex++)
|
|
||||||
{
|
|
||||||
assembly* Assembly = &State->Assemblies.Values[AssemblyIndex];
|
|
||||||
led_buffer* AssemblyLedBuffer = LedSystemGetBuffer(&State->LedSystem, Assembly->LedBufferIndex);
|
|
||||||
|
|
||||||
for (u32 Layer = 0; Layer < CurrFrame.BlocksCountMax; Layer++)
|
|
||||||
{
|
|
||||||
if (!CurrFrame.BlocksFilled[Layer]) { continue; }
|
|
||||||
animation_block Block = CurrFrame.Blocks[Layer];
|
|
||||||
|
|
||||||
// Prep Temp Buffer
|
|
||||||
LayerLEDBuffers[Layer] = *AssemblyLedBuffer;
|
|
||||||
LayerLEDBuffers[Layer].Colors = PushArray(State->Transient, pixel, AssemblyLedBuffer->LedCount);
|
|
||||||
|
|
||||||
u32 FramesIntoBlock = CurrentFrame - Block.Range.Min;
|
|
||||||
r32 SecondsIntoBlock = FramesIntoBlock * State->AnimationSystem.SecondsPerFrame;
|
|
||||||
|
|
||||||
// :AnimProcHandle
|
|
||||||
u32 AnimationProcIndex = Block.AnimationProcHandle - 1;
|
|
||||||
animation_proc* AnimationProc = GlobalAnimationPatterns[AnimationProcIndex].Proc;
|
|
||||||
AnimationProc(&LayerLEDBuffers[Layer], *Assembly, SecondsIntoBlock, State->Transient);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Consolidate Temp Buffers
|
|
||||||
// We do this in reverse order so that they go from top to bottom
|
|
||||||
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem);
|
|
||||||
for (u32 Layer = 0; Layer < CurrFrame.BlocksCountMax; Layer++)
|
|
||||||
{
|
|
||||||
if (!CurrFrame.BlocksFilled[Layer]) { continue; }
|
|
||||||
|
|
||||||
switch (ActiveAnim->Layers.Values[Layer].BlendMode)
|
|
||||||
{
|
|
||||||
case BlendMode_Overwrite:
|
|
||||||
{
|
|
||||||
for (u32 LED = 0; LED < AssemblyLedBuffer->LedCount; LED++)
|
|
||||||
{
|
|
||||||
AssemblyLedBuffer->Colors[LED] = LayerLEDBuffers[Layer].Colors[LED];
|
|
||||||
}
|
|
||||||
}break;
|
|
||||||
|
|
||||||
case BlendMode_Add:
|
|
||||||
{
|
|
||||||
for (u32 LED = 0; LED < AssemblyLedBuffer->LedCount; LED++)
|
|
||||||
{
|
|
||||||
u32 R = (u32)AssemblyLedBuffer->Colors[LED].R + (u32)LayerLEDBuffers[Layer].Colors[LED].R;
|
|
||||||
u32 G = (u32)AssemblyLedBuffer->Colors[LED].G + (u32)LayerLEDBuffers[Layer].Colors[LED].G;
|
|
||||||
u32 B = (u32)AssemblyLedBuffer->Colors[LED].B + (u32)LayerLEDBuffers[Layer].Colors[LED].B;
|
|
||||||
|
|
||||||
AssemblyLedBuffer->Colors[LED].R = (u8)Min(R, (u32)255);
|
|
||||||
AssemblyLedBuffer->Colors[LED].G = (u8)Min(G, (u32)255);
|
|
||||||
AssemblyLedBuffer->Colors[LED].B = (u8)Min(B, (u32)255);
|
|
||||||
}
|
|
||||||
}break;
|
|
||||||
|
|
||||||
case BlendMode_Multiply:
|
|
||||||
{
|
|
||||||
for (u32 LED = 0; LED < AssemblyLedBuffer->LedCount; LED++)
|
|
||||||
{
|
|
||||||
r32 DR = (r32)AssemblyLedBuffer->Colors[LED].R / 255.f;
|
|
||||||
r32 DG = (r32)AssemblyLedBuffer->Colors[LED].G / 255.f;
|
|
||||||
r32 DB = (r32)AssemblyLedBuffer->Colors[LED].B / 255.f;
|
|
||||||
|
|
||||||
r32 SR = (r32)LayerLEDBuffers[Layer].Colors[LED].R / 255.f;
|
|
||||||
r32 SG = (r32)LayerLEDBuffers[Layer].Colors[LED].G / 255.f;
|
|
||||||
r32 SB = (r32)LayerLEDBuffers[Layer].Colors[LED].B / 255.f;
|
|
||||||
|
|
||||||
AssemblyLedBuffer->Colors[LED].R = (u8)((DR * SR) * 255.f);
|
|
||||||
AssemblyLedBuffer->Colors[LED].G = (u8)((DG * SG) * 255.f);
|
|
||||||
AssemblyLedBuffer->Colors[LED].B = (u8)((DB * SB) * 255.f);
|
|
||||||
}
|
|
||||||
}break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -38,6 +38,7 @@ typedef struct panel panel;
|
||||||
|
|
||||||
#include "engine/animation/foldhaus_animation.h"
|
#include "engine/animation/foldhaus_animation.h"
|
||||||
#include "engine/animation/foldhaus_animation_serializer.cpp"
|
#include "engine/animation/foldhaus_animation_serializer.cpp"
|
||||||
|
#include "engine/animation/foldhaus_animation_renderer.cpp"
|
||||||
|
|
||||||
struct app_state
|
struct app_state
|
||||||
{
|
{
|
||||||
|
|
|
@ -454,6 +454,10 @@ WinMain (
|
||||||
gs_thread_context ThreadContext = Win32CreateThreadContext();
|
gs_thread_context ThreadContext = Win32CreateThreadContext();
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
// NOTE(pjs): UART TEST CODE
|
||||||
|
// NOTE(pjs): UART TEST CODE
|
||||||
|
// NOTE(pjs): UART TEST CODE
|
||||||
|
|
||||||
u32 LedCount = 48;
|
u32 LedCount = 48;
|
||||||
u32 MessageBaseSize = sizeof(uart_header) + sizeof(uart_channel) + sizeof(uart_footer);
|
u32 MessageBaseSize = sizeof(uart_header) + sizeof(uart_channel) + sizeof(uart_footer);
|
||||||
MessageBaseSize += sizeof(u8) * 3 * LedCount;
|
MessageBaseSize += sizeof(u8) * 3 * LedCount;
|
||||||
|
@ -580,6 +584,10 @@ WinMain (
|
||||||
WSAStartup(MAKEWORD(2, 2), &WSAData);
|
WSAStartup(MAKEWORD(2, 2), &WSAData);
|
||||||
Win32Sockets = Win32SocketArray_Create(16, &PlatformPermanent);
|
Win32Sockets = Win32SocketArray_Create(16, &PlatformPermanent);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// NOTE(pjs): SOCKET READING TEST CODE
|
||||||
|
// NOTE(pjs): SOCKET READING TEST CODE
|
||||||
|
// NOTE(pjs): SOCKET READING TEST CODE
|
||||||
|
|
||||||
win32_socket TestSocket = Win32Socket_ConnectToAddress("127.0.0.1", "20185");
|
win32_socket TestSocket = Win32Socket_ConnectToAddress("127.0.0.1", "20185");
|
||||||
test_microphone_packet* Recv = 0;
|
test_microphone_packet* Recv = 0;
|
||||||
|
@ -593,6 +601,7 @@ WinMain (
|
||||||
}
|
}
|
||||||
ClearArena(ThreadContext.Transient);
|
ClearArena(ThreadContext.Transient);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
Win32SerialArray_Create(ThreadContext);
|
Win32SerialArray_Create(ThreadContext);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue