Lumenarium/foldhaus_channel.cpp

262 lines
7.4 KiB
C++

inline void
SetTransition(pattern_transition* Transition, r32 Duration, r32 Elapsed)
{
Transition->Duration = Duration;
Transition->TimeElapsed = Elapsed;
}
internal void
InitLEDChannelSystem (led_channel_system* System, memory_arena* ParentStorage, s32 StorageSize)
{
System->Channels = 0;
System->ChannelCount = 0;
InitMemoryArena(&System->Storage, PushSize(ParentStorage, StorageSize), StorageSize, 0);
System->FreeList = 0;
}
inline void
ResetChannel (led_channel* Channel, led_channel_system* ChannelSystem)
{
if (Channel->Patterns == 0)
{
Channel->Patterns = PushArray(&ChannelSystem->Storage,
pattern_index_id_key,
CHANNEL_MAX_PATTERNS);
}
Channel->ActivePatterns = 0;
Channel->ActivePatternIndex = -1;
SetTransition(&Channel->Transition, 3, 0);
Channel->BlendMode = ChannelBlend_Override;
Channel->ChannelID = ChannelIDAccumulator++;
Channel->Next = 0;
}
internal led_channel*
AddLEDChannel (led_channel_system* ChannelSystem)
{
led_channel* Channel = 0;
if (ChannelSystem->FreeList)
{
Channel = ChannelSystem->FreeList;
ChannelSystem->FreeList = ChannelSystem->FreeList->Next;
}
else
{
Channel = PushStruct(&ChannelSystem->Storage, led_channel);
}
ResetChannel(Channel, ChannelSystem);
Channel->Next = ChannelSystem->Channels;
ChannelSystem->Channels = Channel;
ChannelSystem->ChannelCount++;
return Channel;
}
internal b32
RemoveLEDChannel_ (led_channel* PrevChannel, led_channel* ToRemove, led_channel_system* ChannelSystem)
{
b32 Result = true;
if (PrevChannel->Next == ToRemove)
{
PrevChannel->Next = ToRemove->Next;
ToRemove->Next = ChannelSystem->FreeList;
ChannelSystem->FreeList = ToRemove;
ChannelSystem->ChannelCount--;
Result = true;
}
else
{
Result = false;
}
return Result;
}
internal b32
RemoveLEDChannel (led_channel* Channel, led_channel_system* ChannelSystem)
{
b32 Result = true;
led_channel* Cursor = ChannelSystem->Channels;
for (s32 i = 0;
(Cursor->Next != Channel && i < ChannelSystem->ChannelCount);
Cursor = Cursor->Next, i++){}
Result = RemoveLEDChannel_(Cursor, Channel, ChannelSystem);
return Result;
}
internal b32
RemoveLEDChannel (s32 Index, led_channel_system* ChannelSystem)
{
Assert(Index < ChannelSystem->ChannelCount);
b32 Result = true;
if (Index == 0)
{
led_channel* FirstChannel = ChannelSystem->Channels;
ChannelSystem->Channels = FirstChannel->Next;
FirstChannel->Next = ChannelSystem->FreeList;
ChannelSystem->FreeList = FirstChannel;
ChannelSystem->ChannelCount--;
Result = true;
}
else
{
led_channel* PrevChannel = ChannelSystem->Channels;
for (s32 i = 0; i < Index - 1; i++)
{
PrevChannel = PrevChannel->Next;
}
Result = RemoveLEDChannel_(PrevChannel, PrevChannel->Next, ChannelSystem);
}
return Result;
}
internal led_channel*
GetChannelByIndex (s32 Index, led_channel_system ChannelSystem)
{
Assert(Index < ChannelSystem.ChannelCount);
led_channel* Result = ChannelSystem.Channels;
for (s32 i = 0; i < Index; i++)
{
Result = Result->Next;
}
return Result;
}
internal void
AddPatternKeyToChannel (pattern_index_id_key Key, led_channel* Channel)
{
Assert(Channel->ActivePatterns < CHANNEL_MAX_PATTERNS);
Channel->Patterns[Channel->ActivePatterns++] = Key;
}
internal b32
RemovePatternKeyFromChannel (pattern_index_id_key Key, led_channel* Channel)
{
b32 Result = false;
s32 RemoveFrom = -1;
for (s32 i = 0; i < Channel->ActivePatterns; i++)
{
if (Channel->Patterns[i].ID == Key.ID)
{
RemoveFrom = i;
}
}
if (RemoveFrom >= 0)
{
for (s32 j = 0; j < Channel->ActivePatterns; j++)
{
Channel->Patterns[j] = Channel->Patterns[j + 1];
}
Channel->ActivePatterns--;
Result = true;
}
return Result;
}
internal void
PushPatternKeyOnUpdateList (pattern_index_id_key Key,
pattern_push_color_proc* PushColorProc,
patterns_update_list* UpdateList,
memory_arena* Storage)
{
if (UpdateList->Used >= UpdateList->Size)
{
if (!UpdateList->Next)
{
UpdateList->Next = PushStruct(Storage, patterns_update_list);
UpdateList->Next->Size = UpdateList->Size;
UpdateList->Next->Used = 0;
UpdateList->Next->Patterns = PushArray(Storage, pattern_update_list_entry, UpdateList->Next->Size);
}
PushPatternKeyOnUpdateList(Key, PushColorProc, UpdateList->Next, Storage);
}
else
{
pattern_update_list_entry Entry = {};
Entry.Key = Key;
Entry.PushColorProc = PushColorProc;
UpdateList->Patterns[UpdateList->Used++] = Entry;
}
}
internal void
UpdateChannel (led_channel* Channel,
patterns_update_list* PatternsNeedUpdateList,
r32 DeltaTime,
memory_arena* Storage)
{
// Update Transition
Channel->Transition.TimeElapsed += DeltaTime;
if (Channel->Transition.TimeElapsed >= Channel->Transition.Duration ||
(Channel->ActivePatternIndex < 0 && Channel->ActivePatterns > 0))
{
Channel->Transition.TimeElapsed -= Channel->Transition.Duration;
Channel->ActivePatternIndex++;
if (Channel->ActivePatternIndex >= Channel->ActivePatterns)
{
Channel->ActivePatternIndex = 0;
}
}
// Create Active Pattern List
if (Channel->ActivePatterns > 0)
{
Assert(Channel->ActivePatternIndex >= 0 && Channel->ActivePatternIndex < Channel->ActivePatterns);
pattern_push_color_proc* PushColorProc = 0;
switch (Channel->BlendMode)
{
case ChannelBlend_Override: { PushColorProc = PushColor_Override; } break;
case ChannelBlend_Add: { PushColorProc = PushColor_Add; } break;
case ChannelBlend_Multiply: { PushColorProc = PushColor_Multiply; } break;
default:
{
InvalidCodePath;
}break;
}
PushPatternKeyOnUpdateList(Channel->Patterns[Channel->ActivePatternIndex],
PushColorProc,
PatternsNeedUpdateList, Storage);
}
}
internal patterns_update_list
UpdateAllChannels (led_channel_system* ChannelSystem, r32 DeltaTime, memory_arena* Transient)
{
patterns_update_list Result = {};
// NOTE(Peter): The initial size of this array is ChannelCount * 2 b/c at the moment, in the worst case,
// we need to update the two patterns a channel is blending between, and there isn't a case where we'd
// update 3 per channel
Result.Size = ChannelSystem->ChannelCount * 2;
Result.Used = 0;
Result.Patterns = PushArray(Transient, pattern_update_list_entry, Result.Size);
Result.Next = 0;
for (led_channel* Channel = ChannelSystem->Channels;
Channel;
Channel = Channel->Next)
{
UpdateChannel(Channel, &Result, DeltaTime, Transient);
}
return Result;
}