Lumenarium/src/app/engine/assembly/foldhaus_assembly.cpp

269 lines
8.5 KiB
C++

//
// File: foldhaus_assembly.cpp
// Author: Peter Slattery
// Creation Date: 2020-01-01
//
#ifndef FOLDHAUS_ASSEMBLY_CPP
///////////////////////////
//
// Assembly Array
//
///////////////////////////
internal assembly_array
AssemblyArray_Create(u32 CountMax, gs_memory_arena* Storage)
{
assembly_array Result = {0};
Result.CountMax = CountMax;
Result.Values = PushArray(Storage, assembly, Result.CountMax);
return Result;
}
internal u32
AssemblyArray_Push(assembly_array* Array, assembly Assembly)
{
Assert(Array->Count < Array->CountMax);
u32 Index = Array->Count++;
Array->Values[Index] = Assembly;
return Index;
}
internal assembly*
AssemblyArray_Take(assembly_array* Array)
{
u32 Index = AssemblyArray_Push(Array, {});
assembly* Result = Array->Values + Index;
return Result;
}
internal void
AssemblyArray_RemoveAt(assembly_array* Array, u32 Index)
{
u32 LastAssemblyIndex = --Array->Count;
Array->Values[Index] = Array->Values[LastAssemblyIndex];
}
typedef bool assembly_array_filter_proc(assembly A);
bool AssemblyFilter_OutputsViaSACN(assembly A) { return A.OutputMode == NetworkProtocol_SACN; }
bool AssemblyFilter_OutputsViaUART(assembly A) { return A.OutputMode == NetworkProtocol_UART; }
internal assembly_array
AssemblyArray_Filter(assembly_array Array, assembly_array_filter_proc* Filter, gs_memory_arena* Storage)
{
assembly_array Result = AssemblyArray_Create(Array.Count, Storage);
for (u32 i = 0; i < Array.Count; i++)
{
assembly At = Array.Values[i];
if (Filter(At))
{
AssemblyArray_Push(&Result, At);
}
}
return Result;
}
///////////////////////////
//
// LedSystem
//
///////////////////////////
internal led_system
LedSystem_Create(gs_allocator PlatformMemory, u32 BuffersMax)
{
led_system Result = {};
Result.PlatformMemory = PlatformMemory;
// TODO(Peter): Since we have access to PlatformMemory, just realloc Buffers when we fill it up
Result.BuffersCountMax = BuffersMax;
Result.Buffers = AllocatorAllocArray(PlatformMemory, led_buffer, Result.BuffersCountMax);
return Result;
}
internal u32
LedSystemTakeFreeBuffer(led_system* System, u32 LedCount)
{
s32 Result = -1;
if (System->BuffersCount < System->BuffersCountMax)
{
Result = System->BuffersCount++;
}
else
{
// NOTE(Peter): Look for a buffer that's flagged as empty
for (u32 i = 0; i < System->BuffersCount; i++)
{
if (System->Buffers[i].LedCount == 0
&& System->Buffers[i].Colors == 0
&& System->Buffers[i].Positions == 0)
{
Result = i;
break;
}
}
Assert(Result >= 0); // NOTE(Peter): We ran out of room for led buffers
}
led_buffer* Buffer = &System->Buffers[Result];
Buffer->LedCount = LedCount;
Buffer->Colors = AllocatorAllocArray(System->PlatformMemory, pixel, Buffer->LedCount);
Buffer->Positions = AllocatorAllocArray(System->PlatformMemory, v4, Buffer->LedCount);
System->LedsCountTotal += LedCount;
return (u32)Result;
}
internal void
LedSystemFreeBuffer(led_system* System, u32 BufferIndex)
{
Assert(BufferIndex < System->BuffersCountMax);
led_buffer* Buffer = &System->Buffers[BufferIndex];
AllocatorFreeArray(System->PlatformMemory, Buffer->Colors, pixel, Buffer->LedCount);
AllocatorFreeArray(System->PlatformMemory, Buffer->Positions, v4, Buffer->LedCount);
System->LedsCountTotal -= Buffer->LedCount;
*Buffer = {};
}
internal void
LedBufferSetLed(led_buffer* Buffer, u32 Led, v4 Position)
{
Assert(Led < Buffer->LedCount);
Buffer->Positions[Led] = Position;
}
internal u32
Assembly_ConstructStrip(assembly* Assembly, led_buffer* LedBuffer, v2_strip* StripAt, strip_gen_data GenData, v4 RootPosition, u32 LedStartIndex, u32 LedLUTStartIndex)
{
u32 LedsAdded = 0;
switch (GenData.Method)
{
case StripGeneration_InterpolatePoints:
{
strip_gen_interpolate_points InterpPoints = GenData.InterpolatePoints;
v4 WS_StripStart = RootPosition + ToV4Point(InterpPoints.StartPosition * Assembly->Scale);
v4 WS_StripEnd = RootPosition + ToV4Point(InterpPoints.EndPosition * Assembly->Scale);
v4 SingleStep = (WS_StripEnd - WS_StripStart) / (r32)InterpPoints.LedCount;
for (u32 Step = 0; Step < InterpPoints.LedCount; Step++)
{
s32 LedIndex = LedStartIndex + LedsAdded++;
v4 LedPosition = WS_StripStart + (SingleStep * Step);
LedBufferSetLed(LedBuffer, LedIndex, LedPosition);
StripAt->LedLUT[Step + LedLUTStartIndex] = LedIndex;
}
}break;
case StripGeneration_Sequence:
{
strip_gen_sequence Sequence = GenData.Sequence;
for (u32 i = 0; i < Sequence.ElementsCount; i++)
{
strip_gen_data SegmentGenData = Sequence.Elements[i];
LedsAdded += Assembly_ConstructStrip(Assembly, LedBuffer, StripAt, SegmentGenData, RootPosition, LedStartIndex + LedsAdded, LedsAdded);
}
}break;
InvalidDefaultCase;
}
return LedsAdded;
}
internal void
ConstructAssemblyFromDefinition (assembly* Assembly, led_system* LedSystem)
{
Assembly->LedBufferIndex = LedSystemTakeFreeBuffer(LedSystem, Assembly->LedCountTotal);
led_buffer* LedBuffer = LedSystemGetBuffer(LedSystem, Assembly->LedBufferIndex);
v4 RootPosition = ToV4Vec(Assembly->Center);
// Add Leds
u32 LedsAdded = 0;
for (u32 StripIdx = 0; StripIdx < Assembly->StripCount; StripIdx++)
{
v2_strip* StripAt = &Assembly->Strips[StripIdx];
StripAt->LedLUT = PushArray(&Assembly->Arena, u32, StripAt->LedCount);
strip_gen_data GenData = StripAt->GenerationData;
LedsAdded += Assembly_ConstructStrip(Assembly, LedBuffer, StripAt, GenData, RootPosition, LedsAdded, 0);
}
}
internal void
LoadAssembly (assembly_array* Assemblies, led_system* LedSystem, gs_memory_arena* Scratch, context Context, gs_const_string Path, event_log* GlobalLog)
{
gs_file AssemblyFile = ReadEntireFile(Context.ThreadContext.FileHandler, Path);
if (FileNoError(AssemblyFile))
{
gs_string AssemblyFileText = MakeString((char*)AssemblyFile.Memory);
s32 IndexOfLastSlash = FindLast(Path, '\\');
gs_const_string FileName = Substring(Path, IndexOfLastSlash + 1, Path.Length);
assembly* NewAssembly = AssemblyArray_Take(Assemblies);
NewAssembly->Arena = CreateMemoryArena(Context.ThreadContext.Allocator);
if (ParseAssemblyFile(NewAssembly, FileName, AssemblyFileText, Scratch))
{
ConstructAssemblyFromDefinition(NewAssembly, LedSystem);
}
else
{
FreeMemoryArena(&NewAssembly->Arena);
Assemblies->Count -= 1;
}
}
else
{
LogError(GlobalLog, "Unable to load assembly file");
}
}
internal void
UnloadAssembly (u32 AssemblyIndex, app_state* State, context Context)
{
Assert(AssemblyIndex < State->Assemblies.Count);
assembly* Assembly = &State->Assemblies.Values[AssemblyIndex];
LedSystemFreeBuffer(&State->LedSystem, Assembly->LedBufferIndex);
FreeMemoryArena(&Assembly->Arena);
AssemblyArray_RemoveAt(&State->Assemblies, AssemblyIndex);
}
// Querying Assemblies
internal led_strip_list
AssemblyStripsGetWithTagValue(assembly Assembly, gs_const_string TagName, gs_const_string TagValue, gs_memory_arena* Storage)
{
led_strip_list Result = {0};
// TODO(pjs): @Optimization
// We can probably come back here and do this allocation procedurally, or in buckets, or with
// a linked list. But for now, I just want to get this up and running
Result.CountMax = Assembly.StripCount;
Result.StripIndices = PushArray(Storage, u32, Result.CountMax);
u64 NameHash = HashDJB2ToU32(StringExpand(TagName));
u64 ValueHash = 0;
if (TagValue.Length > 0)
{
ValueHash = HashDJB2ToU32(StringExpand(TagValue));
}
for (u32 StripIndex = 0; StripIndex < Assembly.StripCount; StripIndex++)
{
v2_strip StripAt = Assembly.Strips[StripIndex];
if (AssemblyStrip_HasTagValue(StripAt, NameHash, ValueHash))
{
Result.StripIndices[Result.Count++] = StripIndex;
}
}
return Result;
}
#define FOLDHAUS_ASSEMBLY_CPP
#endif // FOLDHAUS_ASSEMBLY_CPP